You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

130 lines
6.1 KiB

/**
* @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 <stdint.h>
#include <stddef.h>
#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