Browse Source

1

congestion
Evgeny 6 months ago
parent
commit
5dc8ad6784
  1. 247
      lib/serialize.c
  2. 82
      lib/serialize.h
  3. 82
      tests/test_serialize.c

247
lib/serialize.c

@ -2,62 +2,58 @@
#include "serialize.h" #include "serialize.h"
#include <string.h> #include <string.h>
static uint16_t varint_encode(uint8_t* out, uint16_t val) { static uint16_t length_encode(uint8_t* out, uint16_t val) {
if (val < 0x80) {
if (out) out[0] = (uint8_t)val;
return 1;
}
if (out) { if (out) {
out[0] = (uint8_t)(0x80 | (val >> 8)); out[0] = (uint8_t)(val >> 8);
out[1] = (uint8_t)(val & 0xFF); out[1] = (uint8_t)val;
} }
return 2; return 2;
} }
static uint16_t varint_decode(const uint8_t* in, size_t in_len, size_t* consumed) { static uint16_t length_decode(const uint8_t* in, size_t in_len, size_t* consumed) {
if (!in || in_len < 1) { if (!in || in_len < 2) {
if (consumed) *consumed = 0;
return 0;
}
if ((in[0] & 0x80) == 0) {
if (consumed) *consumed = 1;
return in[0];
}
if (in_len < 2) {
if (consumed) *consumed = 0; if (consumed) *consumed = 0;
return 0; return 0;
} }
if (consumed) *consumed = 2; if (consumed) *consumed = 2;
return ((in[0] & 0x3F) << 8) | in[1]; return ((uint16_t)in[0] << 8) | in[1];
} }
static size_t get_len_field(const uint8_t* data, const struct SerializeField* f) { static size_t get_len_field(const uint8_t* data, const struct SerializeField* f) {
if (!f || !data || !f->has_len) return 0; if (!f || !data || f->len_type == 0) return 0;
const uint8_t* len_ptr = data + f->len_offset; const uint8_t* len_ptr = data + f->len_offset;
if (f->len_type == 1) { if (f->len_type == 1) {
return *len_ptr; return *len_ptr;
} } else if (f->len_type == 2) {
if (f->len_type == 2) { return *(const uint16_t*)len_ptr;
return *(uint16_t*)len_ptr; } else if (f->len_type == 4) {
return *(const uint32_t*)len_ptr;
} }
return 0; return 0;
} }
static void set_len_field(uint8_t* data, const struct SerializeField* f, size_t len) { static void set_len_field(uint8_t* data, const struct SerializeField* f, size_t len) {
if (!f || !data || !f->has_len) return; if (!f || !data || f->len_type == 0) return;
uint8_t* len_ptr = data + f->len_offset; uint8_t* len_ptr = data + f->len_offset;
if (f->len_type == 1) { if (f->len_type == 1) {
*len_ptr = (uint8_t)len; *len_ptr = (uint8_t)len;
} else if (f->len_type == 2) { } else if (f->len_type == 2) {
*(uint16_t*)len_ptr = (uint16_t)len; *(uint16_t*)len_ptr = (uint16_t)len;
} else if (f->len_type == 4) {
*(uint32_t*)len_ptr = (uint32_t)len;
} }
} }
static size_t fixed_field_size(const struct SerializeSchema* schema, size_t idx) { static size_t fixed_field_size(const struct SerializeSchema* schema, size_t idx) {
if (idx + 1 < schema->field_count) { if (idx >= schema->field_count) return 0;
return schema->fields[idx + 1].offset - schema->fields[idx].offset; const struct SerializeField* f = &schema->fields[idx];
} if (f->elem_size != 0) return 0;
return 0;
size_t next_offset = (idx + 1 < schema->field_count) ?
schema->fields[idx + 1].offset :
schema->struct_size;
return (next_offset > f->offset) ? (next_offset - f->offset) : 0;
} }
int serialize_encode(const void* structure, int serialize_encode(const void* structure,
@ -66,154 +62,209 @@ int serialize_encode(const void* structure,
uint8_t** out_buf, uint8_t** out_buf,
size_t* out_len) { size_t* out_len) {
if (!schema || !structure || !out_buf || !out_len) return SERIALIZE_ERR_NULL; if (!schema || !structure || !out_buf || !out_len) return SERIALIZE_ERR_NULL;
const uint8_t* data = (const uint8_t*)structure; const uint8_t* data = (const uint8_t*)structure;
size_t total = schema->header_len; size_t total = schema->header_len;
for (size_t i = 0; i < schema->field_count; i++) { for (size_t i = 0; i < schema->field_count; i++) {
const struct SerializeField* f = &schema->fields[i]; const struct SerializeField* f = &schema->fields[i];
if (f->elem_size == 0) { if (f->elem_size == 0) {
total += fixed_field_size(schema, i); total += fixed_field_size(schema, i);
} else if (f->elem_size == 1) {
const char* str = *(const char**)(data + f->offset);
size_t len = f->has_len ? get_len_field(data, f) : (str ? strlen(str) : 0);
if (len > f->max_size) len = f->max_size;
total += varint_encode(NULL, (uint16_t)len);
total += len + 1;
} else { } else {
size_t len = f->has_len ? get_len_field(data, f) : f->max_size; size_t raw_len;
if (len > f->max_size) len = f->max_size; if (f->elem_size == 1) { // string
total += varint_encode(NULL, (uint16_t)len); const char* str = *(const char**)(data + f->offset);
total += len * f->elem_size; raw_len = (f->len_type != 0) ? get_len_field(data, f)
: (str ? strlen(str) : 0);
} else { // array
const uint8_t* arr = *(const uint8_t**)(data + f->offset);
raw_len = (f->len_type != 0) ? get_len_field(data, f)
: f->max_size;
if (raw_len > 0 && !arr) raw_len = 0;
}
uint16_t len = (raw_len > f->max_size) ? f->max_size : (uint16_t)raw_len;
total += length_encode(NULL, len);
if (f->elem_size == 1) {
total += (size_t)len + 1; // data + null terminator
} else {
total += (size_t)len * f->elem_size;
}
} }
} }
uint8_t* buf = u_malloc(total); uint8_t* buf = u_malloc(total);
if (!buf) return SERIALIZE_ERR_BUF; if (!buf) return SERIALIZE_ERR_BUF;
uint8_t* ptr = buf; uint8_t* ptr = buf;
if (header && schema->header_len > 0) { if (header && schema->header_len > 0) {
memcpy(ptr, header, schema->header_len); memcpy(ptr, header, schema->header_len);
ptr += schema->header_len; ptr += schema->header_len;
} }
for (size_t i = 0; i < schema->field_count; i++) { for (size_t i = 0; i < schema->field_count; i++) {
const struct SerializeField* f = &schema->fields[i]; const struct SerializeField* f = &schema->fields[i];
const uint8_t* fld = data + f->offset; const uint8_t* fld = data + f->offset;
if (f->elem_size == 0) { if (f->elem_size == 0) {
size_t sz = fixed_field_size(schema, i); size_t sz = fixed_field_size(schema, i);
memcpy(ptr, fld, sz); if (sz > 0) {
ptr += sz; memcpy(ptr, fld, sz);
} else if (f->elem_size == 1) { ptr += sz;
}
} else if (f->elem_size == 1) { // string
const char* str = *(const char**)fld; const char* str = *(const char**)fld;
size_t len = f->has_len ? get_len_field(data, f) : (str ? strlen(str) : 0); size_t raw_len = (f->len_type != 0) ? get_len_field(data, f)
if (len > f->max_size) len = f->max_size; : (str ? strlen(str) : 0);
ptr += varint_encode(ptr, (uint16_t)len); uint16_t len = (raw_len > f->max_size) ? f->max_size : (uint16_t)raw_len;
if (len > 0 && !str) len = 0;
ptr += length_encode(ptr, len);
if (len > 0) { if (len > 0) {
memcpy(ptr, str, len); memcpy(ptr, str, len);
ptr += len; ptr += len;
} }
*ptr++ = 0; *ptr++ = '\0';
} else { } else { // array
const uint8_t* arr = *(const uint8_t**)fld; const uint8_t* arr = *(const uint8_t**)fld;
size_t len = f->has_len ? get_len_field(data, f) : f->max_size; size_t raw_len = (f->len_type != 0) ? get_len_field(data, f)
if (len > f->max_size) len = f->max_size; : f->max_size;
ptr += varint_encode(ptr, (uint16_t)len); uint16_t len = (raw_len > f->max_size) ? f->max_size : (uint16_t)raw_len;
if (arr && len > 0) { if (len > 0 && !arr) len = 0;
memcpy(ptr, arr, len * f->elem_size);
ptr += len * f->elem_size; ptr += length_encode(ptr, len);
if (len > 0 && arr) {
memcpy(ptr, arr, (size_t)len * f->elem_size);
ptr += (size_t)len * f->elem_size;
} }
} }
} }
*out_buf = buf; *out_buf = buf;
*out_len = ptr - buf; *out_len = ptr - buf;
return SERIALIZE_ERR_OK; return SERIALIZE_ERR_OK;
} }
int serialize_decode(const uint8_t* in_buf, int serialize_decode(const uint8_t* in_buf,
size_t in_len, size_t in_len,
const struct SerializeSchema* schema, const struct SerializeSchema* schema,
void** structure) { void** structure) {
if (!in_buf || !schema || !structure) return SERIALIZE_ERR_NULL; if (!in_buf || !schema || !structure) {
if (structure) *structure = NULL;
return SERIALIZE_ERR_NULL;
}
void* obj = u_malloc(schema->struct_size); void* obj = u_malloc(schema->struct_size);
if (!obj) { if (!obj) {
*structure = NULL; *structure = NULL;
return SERIALIZE_ERR_BUF; return SERIALIZE_ERR_BUF;
} }
memset(obj, 0, schema->struct_size);
const uint8_t* ptr = in_buf; const uint8_t* ptr = in_buf;
const uint8_t* end = in_buf + in_len; const uint8_t* end = in_buf + in_len;
uint8_t* data = (uint8_t*)obj; uint8_t* data = (uint8_t*)obj;
size_t consumed; size_t consumed;
for (size_t i = 0; i < schema->field_count; i++) { for (size_t i = 0; i < schema->field_count; i++) {
const struct SerializeField* f = &schema->fields[i]; const struct SerializeField* f = &schema->fields[i];
if (f->elem_size == 0) { if (f->elem_size == 0) {
size_t sz = fixed_field_size(schema, i); size_t sz = fixed_field_size(schema, i);
if (ptr + sz > end) { if (ptr + sz > end) {
u_free(obj); serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF;
}
if (sz > 0) {
memcpy(data + f->offset, ptr, sz);
ptr += sz;
}
} else if (f->elem_size == 1) { // string
uint16_t len = length_decode(ptr, end - ptr, &consumed);
if (consumed == 0) {
serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF; return SERIALIZE_ERR_BUF;
} }
memcpy(data + f->offset, ptr, sz);
ptr += sz;
} else if (f->elem_size == 1) {
uint16_t len = varint_decode(ptr, end - ptr, &consumed);
if (len > f->max_size) len = f->max_size;
ptr += consumed; ptr += consumed;
size_t copy_len = len < (size_t)(end - ptr) ? len : (size_t)(end - ptr);
if (len > f->max_size) len = f->max_size;
size_t needed = (size_t)len + 1;
if ((size_t)(end - ptr) < needed) {
serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF;
}
char* str = NULL; char* str = NULL;
if (len > 0) { if (len == 0) {
str = u_malloc(1);
if (str) str[0] = '\0';
} else {
str = u_malloc(len + 1); str = u_malloc(len + 1);
if (str) { if (str) {
if (copy_len > 0) memcpy(str, ptr, copy_len); memcpy(str, ptr, len);
str[copy_len] = 0; str[len] = '\0';
} }
} else {
str = u_malloc(1);
if (str) str[0] = 0;
} }
*(char**)(data + f->offset) = str; *(char**)(data + f->offset) = str;
if (f->has_len) { if (f->len_type != 0) set_len_field(data, f, len);
set_len_field(data, f, len);
if (str == NULL) {
serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF;
}
ptr += needed;
} else { // array
uint16_t len = length_decode(ptr, end - ptr, &consumed);
if (consumed == 0) {
serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF;
} }
ptr += len + 1;
} else {
uint16_t len = varint_decode(ptr, end - ptr, &consumed);
if (len > f->max_size) len = f->max_size;
ptr += consumed; ptr += consumed;
size_t arr_sz = len * f->elem_size;
if (len > f->max_size) len = f->max_size;
size_t arr_sz = (size_t)len * f->elem_size;
if ((size_t)(end - ptr) < arr_sz) {
serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF;
}
uint8_t* arr = NULL; uint8_t* arr = NULL;
if (arr_sz > 0) { if (arr_sz > 0) {
arr = u_malloc(arr_sz); arr = u_malloc(arr_sz);
if (arr && ptr + arr_sz <= end) { if (arr) memcpy(arr, ptr, arr_sz);
memcpy(arr, ptr, arr_sz);
}
} }
*(uint8_t**)(data + f->offset) = arr; *(uint8_t**)(data + f->offset) = arr;
if (f->has_len) { if (f->len_type != 0) set_len_field(data, f, len);
set_len_field(data, f, len);
if (arr_sz > 0 && arr == NULL) {
serialize_free(schema, &obj);
*structure = NULL;
return SERIALIZE_ERR_BUF;
} }
ptr += arr_sz; ptr += arr_sz;
} }
} }
*structure = obj; *structure = obj;
return SERIALIZE_ERR_OK; return SERIALIZE_ERR_OK;
} }
void serialize_free(const struct SerializeSchema* schema, void** structure) { void serialize_free(const struct SerializeSchema* schema, void** structure) {
if (!schema || !structure || !*structure) return; if (!schema || !structure || !*structure) return;
uint8_t* data = (uint8_t*)*structure; uint8_t* data = (uint8_t*)*structure;
for (size_t i = 0; i < schema->field_count; i++) { for (size_t i = 0; i < schema->field_count; i++) {
const struct SerializeField* f = &schema->fields[i]; const struct SerializeField* f = &schema->fields[i];
if (f->elem_size == 1) { if (f->elem_size == 1) {
char* str = *(char**)(data + f->offset); char* str = *(char**)(data + f->offset);
if (str) { if (str) {
@ -228,7 +279,7 @@ void serialize_free(const struct SerializeSchema* schema, void** structure) {
} }
} }
} }
u_free(*structure); u_free(*structure);
*structure = NULL; *structure = NULL;
} }

82
lib/serialize.h

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

82
tests/test_serialize.c

@ -1,57 +1,55 @@
// test_serialize.c - Unit tests for serialize library with dynamic allocation // test_serialize.c - Unit tests for serialize library with dynamic allocation
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stddef.h> // для offsetof
#include <assert.h> #include <assert.h>
#include "../lib/serialize.h" #include "../lib/serialize.h"
#define TEST(name) do { \ #define TEST(name) do { \
printf("TEST: %-40s ", name); fflush(stdout); \ printf("TEST: %-40s ", name); fflush(stdout); \
} while(0) } while(0)
#define PASS() do { puts("PASS"); } while(0)
#define PASS() do { puts("PASS"); } while(0) #define FAIL(msg) do { printf("FAIL: %s\n", msg); exit(1); } while(0)
#define FAIL(msg) do { printf("FAIL: %s\n", msg); exit(1); } while(0)
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
uint8_t id; uint8_t id;
uint16_t port; uint16_t port;
uint32_t ip; uint32_t ip;
uint64_t big_val; uint64_t big_val;
int8_t signed_val; int8_t signed_val;
int32_t signed32; int32_t signed32;
uint8_t name_len; uint8_t name_len;
char* name; char* name;
uint8_t addr_cnt; uint8_t addr_cnt;
uint8_t* addrs; uint8_t* addrs;
} TestStruct; } TestStruct;
#pragma pack(pop) #pragma pack(pop)
static const struct SerializeField test_fields[] = { static const struct SerializeField test_fields[] = {
{offsetof(TestStruct, id), 0, 0, 0, 0, 0}, {offsetof(TestStruct, id), 0, 0, 0, 0}, // fixed
{offsetof(TestStruct, port), 0, 0, 0, 0, 0}, {offsetof(TestStruct, port), 0, 0, 0, 0}, // fixed
{offsetof(TestStruct, ip), 0, 0, 0, 0, 0}, {offsetof(TestStruct, ip), 0, 0, 0, 0}, // fixed
{offsetof(TestStruct, big_val), 0, 0, 0, 0, 0}, {offsetof(TestStruct, big_val), 0, 0, 0, 0}, // fixed
{offsetof(TestStruct, signed_val), 0, 0, 0, 0, 0}, {offsetof(TestStruct, signed_val),0, 0, 0, 0}, // fixed
{offsetof(TestStruct, signed32), 0, 0, 0, 0, 0}, {offsetof(TestStruct, signed32), 0, 0, 0, 0}, // fixed
{offsetof(TestStruct, name), 1, 64, 1, 1, offsetof(TestStruct, name_len)}, {offsetof(TestStruct, name), 1, 64, 1, offsetof(TestStruct, name_len)}, // string + uint8 len
{offsetof(TestStruct, addrs), 1, 16, 1, 1, offsetof(TestStruct, addr_cnt)}, {offsetof(TestStruct, addrs), 1, 16, 1, offsetof(TestStruct, addr_cnt)} // byte array + uint8 len
}; };
static const struct SerializeSchema test_schema = { static const struct SerializeSchema test_schema = {
.field_count = sizeof(test_fields) / sizeof(test_fields[0]), .field_count = sizeof(test_fields) / sizeof(test_fields[0]),
.struct_size = sizeof(TestStruct), .struct_size = sizeof(TestStruct),
.header_len = 4, .header_len = 4,
.fields = test_fields .fields = test_fields
}; };
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
static void test_alloc_roundtrip(void) { static void test_alloc_roundtrip(void) {
uint8_t* buf = NULL; uint8_t* buf = NULL;
size_t len; size_t len;
TestStruct orig = { TestStruct orig = {
.id = 1, .id = 1,
.port = 443, .port = 443,
@ -72,60 +70,60 @@ static void test_alloc_roundtrip(void) {
orig.addrs[6] = 0; orig.addrs[6] = 0;
orig.addrs[7] = 1; orig.addrs[7] = 1;
orig.addr_cnt = 8; orig.addr_cnt = 8;
uint8_t header[] = {0x01, 0x02, 0x03, 0x04}; uint8_t header[] = {0x01, 0x02, 0x03, 0x04};
TEST("serialize_encode with header"); TEST("serialize_encode with header");
int r = serialize_encode(&orig, &test_schema, header, &buf, &len); int r = serialize_encode(&orig, &test_schema, header, &buf, &len);
if (r != SERIALIZE_ERR_OK) FAIL("serialize_encode failed"); if (r != SERIALIZE_ERR_OK) FAIL("serialize_encode failed");
PASS(); PASS();
TestStruct* restored = NULL; TestStruct* restored = NULL;
TEST("serialize_decode (data without header)"); TEST("serialize_decode (data without header)");
uint8_t* data_ptr = buf + test_schema.header_len; uint8_t* data_ptr = buf + test_schema.header_len;
r = serialize_decode(data_ptr, len - test_schema.header_len, &test_schema, (void**)&restored); r = serialize_decode(data_ptr, len - test_schema.header_len, &test_schema, (void**)&restored);
if (r != SERIALIZE_ERR_OK) FAIL("serialize_decode failed"); if (r != SERIALIZE_ERR_OK) FAIL("serialize_decode failed");
PASS(); PASS();
TEST("check restored not NULL"); TEST("check restored not NULL");
if (!restored) FAIL("restored is NULL"); if (!restored) FAIL("restored is NULL");
PASS(); PASS();
TEST("check id"); TEST("check id");
if (restored->id != orig.id) FAIL("id mismatch"); if (restored->id != orig.id) FAIL("id mismatch");
PASS(); PASS();
TEST("check port"); TEST("check port");
if (restored->port != orig.port) FAIL("port mismatch"); if (restored->port != orig.port) FAIL("port mismatch");
PASS(); PASS();
TEST("check asciiz"); TEST("check asciiz");
if (!restored->name || strcmp(restored->name, "hello") != 0) FAIL("name mismatch"); if (!restored->name || strcmp(restored->name, "hello") != 0) FAIL("name mismatch");
PASS(); PASS();
TEST("check array"); TEST("check array");
if (!restored->addrs || restored->addrs[0] != 192) FAIL("addrs[0] mismatch"); if (!restored->addrs || restored->addrs[0] != 192) FAIL("addrs[0] mismatch");
PASS(); PASS();
TEST("check name_len"); TEST("check name_len");
if (restored->name_len != 5) FAIL("name_len mismatch"); if (restored->name_len != 5) FAIL("name_len mismatch");
PASS(); PASS();
TEST("check addr_cnt"); TEST("check addr_cnt");
if (restored->addr_cnt != 8) FAIL("addr_cnt mismatch"); if (restored->addr_cnt != 8) FAIL("addr_cnt mismatch");
PASS(); PASS();
TEST("serialize_free"); TEST("serialize_free");
serialize_free(&test_schema, (void**)&restored); serialize_free(&test_schema, (void**)&restored);
if (restored) FAIL("ptr should be NULL"); if (restored) FAIL("ptr should be NULL");
PASS(); PASS();
u_free(buf); u_free(buf);
} }
static void test_free(void) { static void test_free(void) {
uint8_t* buf = NULL; uint8_t* buf = NULL;
size_t len; size_t len;
TestStruct orig = { TestStruct orig = {
.id = 2, .id = 2,
.port = 9000, .port = 9000,
@ -138,25 +136,25 @@ static void test_free(void) {
orig.addrs[2] = 0; orig.addrs[2] = 0;
orig.addrs[3] = 1; orig.addrs[3] = 1;
orig.addr_cnt = 4; orig.addr_cnt = 4;
uint8_t header2[] = {0xFF, 0xEE, 0xDD, 0xCC}; uint8_t header2[] = {0xFF, 0xEE, 0xDD, 0xCC};
TEST("serialize_encode for free"); TEST("serialize_encode for free");
int r = serialize_encode(&orig, &test_schema, header2, &buf, &len); int r = serialize_encode(&orig, &test_schema, header2, &buf, &len);
if (r != SERIALIZE_ERR_OK) FAIL("serialize_encode failed"); if (r != SERIALIZE_ERR_OK) FAIL("serialize_encode failed");
PASS(); PASS();
TestStruct* restored = NULL; TestStruct* restored = NULL;
TEST("serialize_decode for free"); TEST("serialize_decode for free");
uint8_t* data_ptr2 = buf + test_schema.header_len; uint8_t* data_ptr2 = buf + test_schema.header_len;
r = serialize_decode(data_ptr2, len - test_schema.header_len, &test_schema, (void**)&restored); r = serialize_decode(data_ptr2, len - test_schema.header_len, &test_schema, (void**)&restored);
if (r != SERIALIZE_ERR_OK) FAIL("serialize_decode failed"); if (r != SERIALIZE_ERR_OK) FAIL("serialize_decode failed");
PASS(); PASS();
TEST("serialize_free"); TEST("serialize_free");
serialize_free(&test_schema, (void**)&restored); serialize_free(&test_schema, (void**)&restored);
if (restored) FAIL("ptr should be NULL"); if (restored) FAIL("ptr should be NULL");
PASS(); PASS();
u_free(buf); u_free(buf);
free(orig.name); free(orig.name);
u_free(orig.addrs); u_free(orig.addrs);
@ -164,11 +162,11 @@ static void test_free(void) {
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
int main(void) { int main(void) {
printf("=== Serialize Library Tests ===\n\n"); printf("=== Serialize Library Tests (updated for new len_type) ===\n\n");
test_alloc_roundtrip(); test_alloc_roundtrip();
test_free(); test_free();
printf("\n=== All tests passed ===\n"); printf("\n=== All tests passed ===\n");
return 0; return 0;
} }

Loading…
Cancel
Save