How to unpack and extract data using msgpack-c?

I am currently trying to use msgpack in a project written in C. I am using msgpack to serialize the contents of a structure, which then needs to be sent over the network and deserialized back to the corresponding struct on the other side.

A compressed version of what I'm trying to do:

#include <stdio.h> #include <msgpack.h> #include <stdbool.h> typedef someStruct{ uint32_t a; uint32_t b; float c; } someStruct; int main (void){ someStruct data; /* ... Fill 'data' with some data for test purposes ...*/ msgpack_sbuffer* buff = msgpack_sbuffer_new(); msgpack_packer* pck = msgpack_packer_new(buff, msgpack_sbuffer_write); someStruct* structs = malloc(sizeof(someStruct) * 10); /* ... Fill 'structs' with members containing test data ... */ // Serialize msgpack_pack_array (pck, 10); int i; for(i = 0 ; i < 10 ; i++){ msgpack_pack_array (pck, 3); msgpack_pack_uint32 (pck, structs[i].a); msgpack_pack_uint32 (pck, structs[i].b); msgpack_pack_float (pck, structs[i].c); } free(structs); msgpack_packer_free(pck); // Deserialize msgpack_unpacked msg; msgpack_unpacked_init(&msg); bool deserialize_success = msgpack_unpack_next (&msg, buff->data, buff->size, NULL); if(!deserialize_success) /* Error */ msgpack_object obj = msg.data; msgpack_object_print(stdout,obj); // This seems to work perfectly, indicating serialize / deserialize works as intended... someStruct deserialized_data; /* Insert code to extract and cast deserialized data to 'deserialized_data */ // Clean msgpack_sbuffer_free(buff); msgpack_packer_free(pck); return 0; } 

The specified code is more or less torn right from here , which seems to be one of the few msgpack-c resources.

Can someone point me in the right direction to a way to "recreate" the original structure on the other side of the wire? The only way to find deserialized data is to use the msgpack_object_print () call to print from the messagepack_object file. However, this works, so I'm sure there is data.

Do I need to somehow iterate over serialized data and use msgpack_unpack_next () with an offset to extract each element of someStruct? Using memcpy for local byte buffer?

Any help is much appreciated!

+6
source share
1 answer

Below is a rewritten version that illustrates how to pack / unpack your data.

The whole idea is to pack each subsequent field of your structure in a continuous order and apply (of course) the same logic during unpacking.

Right after the package, you can use the buffer as you want (for example, send over the network, save to disk, etc.).

 #include <stdio.h> #include <assert.h> #include <msgpack.h> typedef struct some_struct { uint32_t a; uint32_t b; float c; } some_struct; static char *pack(const some_struct *s, int num, int *size); static some_struct *unpack(const void *ptr, int size, int *num); /* Fixtures */ some_struct ary[] = { { 1234, 5678, 3.14f }, { 4321, 8765, 4.13f }, { 2143, 6587, 1.34f } }; int main(void) { /** PACK */ int size; char *buf = pack(ary, sizeof(ary)/sizeof(ary[0]), &size); printf("pack %zd struct(s): %d byte(s)\n", sizeof(ary)/sizeof(ary[0]), size); /** UNPACK */ int num; some_struct *s = unpack(buf, size, &num); printf("unpack: %d struct(s)\n", num); /** CHECK */ assert(num == (int) sizeof(ary)/sizeof(ary[0])); for (int i = 0; i < num; i++) { assert(s[i].a == ary[i].a); assert(s[i].b == ary[i].b); assert(s[i].c == ary[i].c); } printf("check ok. Exiting...\n"); free(buf); free(s); return 0; } static char *pack(const some_struct *s, int num, int *size) { assert(num > 0); char *buf = NULL; msgpack_sbuffer sbuf; msgpack_sbuffer_init(&sbuf); msgpack_packer pck; msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); /* The array will store `num` contiguous blocks made of a, b, c attributes */ msgpack_pack_array(&pck, 3 * num); for (int i = 0; i < num; ++i) { msgpack_pack_uint32(&pck, s[i].a); msgpack_pack_uint32(&pck, s[i].b); msgpack_pack_float(&pck, s[i].c); } *size = sbuf.size; buf = malloc(sbuf.size); memcpy(buf, sbuf.data, sbuf.size); msgpack_sbuffer_destroy(&sbuf); return buf; } static some_struct *unpack(const void *ptr, int size, int *num) { some_struct *s = NULL; msgpack_unpacked msg; msgpack_unpacked_init(&msg); if (msgpack_unpack_next(&msg, ptr, size, NULL)) { msgpack_object root = msg.data; if (root.type == MSGPACK_OBJECT_ARRAY) { assert(root.via.array.size % 3 == 0); *num = root.via.array.size / 3; s = malloc(root.via.array.size*sizeof(*s)); for (int i = 0, j = 0; i < root.via.array.size; i += 3, j++) { s[j].a = root.via.array.ptr[i].via.u64; s[j].b = root.via.array.ptr[i + 1].via.u64; s[j].c = root.via.array.ptr[i + 2].via.dec; } } } msgpack_unpacked_destroy(&msg); return s; } 
+6
source

All Articles