/** * @file serialize.h * @brief Бинарная сериализация структур с динамическим выделением памяти * * Поддерживает структуры с полями переменной длины (ASCIIZ, ARRAY) через указатели. * При десериализации автоматически выделяет память через u_malloc. * * Формат буфера: * [header_len байт][сериализованные данные] * * Пример использования: * @code * // Сериализация * uint8_t header[] = {0x01, 0x02, 0x03, 0x04}; * serialize_encode(&orig, &schema, header, &buf, &len); * * // Десериализация (данные без заголовка) * uint8_t* data = buf + schema.header_len; * serialize_decode(data, len - schema.header_len, &schema, &restored); * * // Освобождение * serialize_free(&schema, &restored); * u_free(buf); * @endcode */ #ifndef SERIALIZE_H #define SERIALIZE_H #include #include #include "../lib/mem.h" /** * @brief Описание одного поля структуры для сериализации */ struct SerializeField { uint16_t offset; ///< смещение указателя в структуре uint8_t elem_size; ///< 0=fixed, 1=ASCIIZ, >1=ARRAY (размер элемента в байтах) uint16_t max_size; ///< макс. длина для ASCIIZ / макс. кол-во для ARRAY uint8_t has_len; ///< 1 если есть length field uint8_t len_type; ///< 1=UINT8, 2=UINT16 uint16_t len_offset; ///< смещение length поля в структуре }; /** * @brief Схема структуры для сериализации */ struct SerializeSchema { uint16_t field_count; ///< число полей uint16_t struct_size; ///< размер структуры для allocate uint16_t header_len; ///< длина заголовка (произвольные байты в начале) const struct SerializeField* fields; ///< массив описаний полей }; #define SERIALIZE_ERR_OK 0 ///< успех #define SERIALIZE_ERR_BUF -1 ///< ошибка выделения памяти #define SERIALIZE_ERR_NULL -2 ///< null указатель /** * @brief Сериализация структуры в бинарный буфер * @param structure указатель на исходную структуру * @param schema схема структуры * @param header заголовок (или NULL если header_len=0) * @param out_buf [out] выходной буфер (выделяется через u_malloc) * @param out_len [out] размер буфера * @return SERIALIZE_ERR_OK или код ошибки * * Формат выходного буфера: * [header_len байт][сериализованные данные] */ int serialize_encode(const void* structure, const struct SerializeSchema* schema, const uint8_t* header, uint8_t** out_buf, size_t* out_len); /** * @brief Десериализация из буфера в структуру * @param in_buf буфер БЕЗ заголовка (уже смещённый на header_len) * @param in_len размер данных (без header) * @param schema схема структуры * @param structure [out] указатель на восстановленную структуру * @return SERIALIZE_ERR_OK или код ошибки * * Внимание: in_buf должен быть без заголовка! * Буфер со смещением: uint8_t* data = buf + schema.header_len; * Длина без header: size_t data_len = total_len - schema.header_len; */ int serialize_decode(const uint8_t* in_buf, size_t in_len, const struct SerializeSchema* schema, void** structure); /** * @brief Освобождение структуры и всех её указателей * @param schema схема структуры * @param structure [inout] указатель на структуру (устанавливается в NULL) * * Освобождает структуру и все её динамические указатели (ASCIIZ, ARRAY). */ void serialize_free(const struct SerializeSchema* schema, void** structure); #endif // SERIALIZE_H