liteserver / binn

Binary Serialization
Apache License 2.0
440 stars 58 forks source link

binn_map() and binn_create(BINN_MAP) create different outputs #6

Closed mannol closed 7 years ago

mannol commented 7 years ago

This code produces hex output: e10f02000000022001000000032001

uint8_t out[1000];
binn* obj = binn_map();
binn_map_set_int16(obj, 2, 1);
binn_map_set_int16(obj, 3, 1);
memcpy(out, binn_ptr(obj), binn_size(obj)); //  << the said output

However, this code produces the following hex output: 306000009dc8e10f02000000022001

uint8_t out[1000];
binn obj[1];
binn_create(obj, BINN_MAP, 1000, out);
binn_map_set_int16(obj, 2, 1);
binn_map_set_int16(obj, 3, 1);
// now the out[] contains the said output

The consequence:

// in the first case
binn_load((void*)out); // << works
binn_load((void*)(out + 6)); // << fails
// in the second case
binn_load((void*)out); // << fails
binn_load((void*)(out + 6)); // << works

From the outputs I see the data is arranged in different order: 1: e10f02000000022001000000032001 2: 306000009dc8e10f02000000022001

Is that normal? If so, how could one know when the data starts without calling binn_load() twice?

kroggen commented 7 years ago

Hi mannol

To get the content of the binn we must always use the binn_ptr function. In your second example you are not using it.

Note that the binn header in the serialized data output has a variable size depending on the amount of data it has inside, so the binn_ptr function will return a pointer inside the buffer that don't need to be the start of the buffer.

In your example the binn_ptr will return a pointer to out + 6 (as you have tried bellow. Good catch!). The initial bytes are not used in this case.

You should not use (out + 6) too. Always use the start of the buffer, either the one returned by the binn_ptr function or a copy of the returned buffer in another app.

There are some usage examples here in the repo.

kroggen commented 7 years ago

So the second example should be something like:

uint8_t out[1000];
binn obj[1];
binn_create(obj, BINN_MAP, 1000, out);
binn_map_set_int16(obj, 2, 1);
binn_map_set_int16(obj, 3, 1);
do_something(binn_ptr(obj), binn_size(obj));
binn_free(obj);
mannol commented 7 years ago

Ah, now I get it! Thanks.

kroggen commented 7 years ago

OK. Notice also that you don't need to use the binn_load function.

The read functions can read values directly from the serialized buffer.

Example:

...
char *buffer = binn_ptr(map);
short value = binn_map_int16(buffer, 2);
...
mannol commented 7 years ago

@kroggen That's interesting. Is the map/object key lookup in linear complexity?

kroggen commented 7 years ago

Yep, it uses a linear search so the binn code is simpler and smaller.