/** * @file serialize.h * @brief Бинарная сериализация структур с динамическим выделением памяти * * Библиотека преобразует C-структуру, содержащую: * - фиксированные поля, * - ASCIIZ-строки (char*), * - динамические массивы (uint8_t* / char*), * - singly-linked списки * в компактный бинарный буфер и обратно. * * Поддерживаемые типы полей (см. SERIALIZE_TYPE_*): * 0 — фиксированные данные (встроены в структуру) * 1 — ASCIIZ-строка (char*, длина = strlen) * 2 — массив ровно из 1 элемента (указатель) * 3 — массив, количество элементов в UINT8 (по len_offset) * 4 — массив, количество элементов в UINT16 (по len_offset) * 5 — массив, количество элементов в UINT32 (по len_offset) * 6 — singly-linked list (next-указатель по смещению len_offset) * * Особенности: * • Все динамические данные (строки, массивы, списки) выделяются через u_malloc. * • При encode длина переменных полей кодируется всегда 2 байтами (uint16_t, big-endian). * • Для linked list в буфере сохраняется только количество узлов + сырые данные узлов * (next-указатели НЕ сериализуются, они восстанавливаются при decode). * • serialize_decode принимает буфер БЕЗ заголовка. * • serialize_free освобождает ВСЮ структуру и все вложенные динамические объекты. * • Поля в schema.fields должны идти в порядке возрастания offset. * • max_size (если > 0) — жёсткий лимит размера выходного буфера. * * @example * // 1. Описание структуры * typedef struct Node { * uint32_t value; * struct Node* next; // next по offset = 4 * } Node; * * typedef struct { * uint8_t id; * char* name; * uint8_t name_len; * uint8_t* data; * uint16_t data_cnt; * Node* list; // linked list * } MyStruct; * * // 2. Схема * static const struct SerializeField my_fields[] = { * {offsetof(MyStruct, id), 1, SERIALIZE_TYPE_FIXED, 0}, * {offsetof(MyStruct, name), 1, SERIALIZE_TYPE_ARRAY_U8, offsetof(MyStruct, name_len)}, * {offsetof(MyStruct, data), 1, SERIALIZE_TYPE_ARRAY_U16, offsetof(MyStruct, data_cnt)}, * {offsetof(MyStruct, list), sizeof(Node), SERIALIZE_TYPE_LINKED, offsetof(Node, next)} * }; * * static const struct SerializeSchema my_schema = { * .field_count = 4, * .struct_size = sizeof(MyStruct), * .max_size = 4096, // опционально * .header_len = 4, * .fields = my_fields * }; * * // 3. Использование * uint8_t header[] = {0x01, 0x02, 0x03, 0x04}; * uint8_t *buf = NULL; * size_t len; * * serialize_encode(&orig, &my_schema, header, &buf, &len); * * MyStruct *restored = NULL; * uint8_t *data = buf + my_schema.header_len; * serialize_decode(data, len - my_schema.header_len, &my_schema, (void**)&restored); * * serialize_free(&my_schema, (void**)&restored); * u_free(buf); */ #ifndef SERIALIZE_H #define SERIALIZE_H #include #include #include "../lib/mem.h" #define SERIALIZE_TYPE_FIXED 0 ///< фиксированные данные, elem_size = размер #define SERIALIZE_TYPE_ASCIIZ 1 ///< char* (ASCIIZ, длина = strlen) #define SERIALIZE_TYPE_ARRAY_FIXED 2 ///< *array ровно 1 элемент #define SERIALIZE_TYPE_ARRAY_U8 3 ///< *array, счётчик UINT8 #define SERIALIZE_TYPE_ARRAY_U16 4 ///< *array, счётчик UINT16 #define SERIALIZE_TYPE_ARRAY_U32 5 ///< *array, счётчик UINT32 #define SERIALIZE_TYPE_LINKED 6 ///< linked_list (next по смещению len_offset) /** * @brief Описание одного поля структуры для сериализации */ struct SerializeField { uint16_t offset; ///< смещение поля в структуре uint8_t elem_size; ///< размер элемента (для fixed = размер данных, для array/linked = размер одного элемента) uint8_t type; ///< SERIALIZE_TYPE_* uint16_t len_offset; ///< смещение поля-счётчика (игнорируется для type 0,1,2) }; /** * @brief Схема структуры для сериализации */ struct SerializeSchema { uint16_t field_count; ///< число полей uint16_t struct_size; ///< размер основной структуры uint16_t max_size; ///< максимальный размер сериализованных данных (0 = без ограничения) uint16_t header_len; ///< длина заголовка const struct SerializeField* fields; }; #define SERIALIZE_ERR_OK 0 ///< успех #define SERIALIZE_ERR_BUF -1 ///< ошибка выделения памяти #define SERIALIZE_ERR_NULL -2 ///< NULL-указатель #define SERIALIZE_ERR_SIZE -3 ///< превышен max_size #define SERIALIZE_ERR_NOTSUP -4 ///< неподдерживаемый тип int serialize_encode(const void* structure, const struct SerializeSchema* schema, const uint8_t* header, uint8_t** out_buf, size_t* out_len); int serialize_decode(const uint8_t* in_buf, size_t in_len, const struct SerializeSchema* schema, void** structure); void serialize_free(const struct SerializeSchema* schema, void** structure); #endif // SERIALIZE_H