diff --git a/example/lib_buffer_unpack.c b/example/lib_buffer_unpack.c new file mode 100644 index 00000000..1d6fe39e --- /dev/null +++ b/example/lib_buffer_unpack.c @@ -0,0 +1,119 @@ +#include +#include +#include + + +typedef struct receiver { + msgpack_sbuffer sbuf; + size_t rest; +} receiver; + +receiver r; + +size_t receiver_init(receiver *r) { + msgpack_packer pk; + + msgpack_sbuffer_init(&r->sbuf); + msgpack_packer_init(&pk, &r->sbuf, msgpack_sbuffer_write); + /* 1st object */ + msgpack_pack_array(&pk, 3); + msgpack_pack_int(&pk, 1); + msgpack_pack_true(&pk); + msgpack_pack_str(&pk, 7); + msgpack_pack_str_body(&pk, "example", 7); + /* 2nd object */ + msgpack_pack_str(&pk, 6); + msgpack_pack_str_body(&pk, "second", 6); + /* 3rd object */ + msgpack_pack_array(&pk, 2); + msgpack_pack_int(&pk, 42); + msgpack_pack_false(&pk); + r->rest = r->sbuf.size; +} + +size_t receiver_recv(receiver *r, char* buf, size_t try_size) { + size_t off = r->sbuf.size - r->rest; + + size_t actual_size = try_size; + if (actual_size > r->rest) actual_size = r->rest; + + memcpy(buf, r->sbuf.data + off, actual_size); + r->rest -= actual_size; + + return actual_size; +} + +#define EACH_RECV_SIZE 4 + +void unpack(receiver* r) { + /* buf is allocated by unpacker. */ + msgpack_unpacker* unp = msgpack_unpacker_new(100); + msgpack_unpacked result; + msgpack_unpack_return ret; + char* buf; + size_t recv_len; + + msgpack_unpacked_init(&result); + if (msgpack_unpacker_buffer_capacity(unp) < EACH_RECV_SIZE) { + bool expanded = msgpack_unpacker_reserve_buffer(unp, 100); + assert(expanded); + } + buf = msgpack_unpacker_buffer(unp); + + recv_len = receiver_recv(r, buf, EACH_RECV_SIZE); + msgpack_unpacker_buffer_consumed(unp, recv_len); + + + int recv_count = 0; + while (recv_len > 0) { + int i = 0; + printf("receive count: %d %d bytes received.:\n", recv_count++, recv_len); + ret = msgpack_unpacker_next(unp, &result); + while (ret == MSGPACK_UNPACK_SUCCESS) { + msgpack_object obj = result.data; + + /* Use obj. */ + printf("Object no %d:\n", i++); + msgpack_object_print(stdout, obj); + printf("\n"); + /* If you want to allocate something on the zone, you can use zone. */ + /* msgpack_zone* zone = result.zone; */ + /* The lifetime of the obj and the zone, */ + + ret = msgpack_unpacker_next(unp, &result); + } + if (ret == MSGPACK_UNPACK_PARSE_ERROR) { + printf("The data in the buf is invalid format.\n"); + msgpack_unpacked_destroy(&result); + return; + } + if (msgpack_unpacker_buffer_capacity(unp) < EACH_RECV_SIZE) { + bool expanded = msgpack_unpacker_reserve_buffer(unp, 100); + assert(expanded); + } + buf = msgpack_unpacker_buffer(unp); + recv_len = receiver_recv(r, buf, 4); + msgpack_unpacker_buffer_consumed(unp, recv_len); + } + msgpack_unpacked_destroy(&result); +} + +int main(void) { + receiver r; + receiver_init(&r); + + unpack(&r); + + return 0; +} + +/* Output */ + +/* +Object no 1: +[1, true, "example"] +Object no 2: +"second" +Object no 3: +[42, false] +*/ diff --git a/example/user_buffer_unpack.c b/example/user_buffer_unpack.c new file mode 100644 index 00000000..d8b25c2a --- /dev/null +++ b/example/user_buffer_unpack.c @@ -0,0 +1,75 @@ +#include +#include +#include + +void prepare(msgpack_sbuffer* sbuf) { + msgpack_packer pk; + + msgpack_packer_init(&pk, sbuf, msgpack_sbuffer_write); + /* 1st object */ + msgpack_pack_array(&pk, 3); + msgpack_pack_int(&pk, 1); + msgpack_pack_true(&pk); + msgpack_pack_str(&pk, 7); + msgpack_pack_str_body(&pk, "example", 7); + /* 2nd object */ + msgpack_pack_str(&pk, 6); + msgpack_pack_str_body(&pk, "second", 6); + /* 3rd object */ + msgpack_pack_array(&pk, 2); + msgpack_pack_int(&pk, 42); + msgpack_pack_false(&pk); +} + +void unpack(char const* buf, size_t len) { + /* buf is allocated by client. */ + msgpack_unpacked result; + size_t off = 0; + msgpack_unpack_return ret; + int i = 0; + msgpack_unpacked_init(&result); + ret = msgpack_unpack_next(&result, buf, len, &off); + while (ret == MSGPACK_UNPACK_SUCCESS) { + msgpack_object obj = result.data; + + /* Use obj. */ + printf("Object no %d:\n", i++); + msgpack_object_print(stdout, obj); + printf("\n"); + /* If you want to allocate something on the zone, you can use zone. */ + /* msgpack_zone* zone = result.zone; */ + /* The lifetime of the obj and the zone, */ + + ret = msgpack_unpack_next(&result, buf, len, &off); + } + msgpack_unpacked_destroy(&result); + + if (ret == MSGPACK_UNPACK_CONTINUE) { + printf("All msgpack_object in the buffer is consumed.\n"); + } + else if (ret == MSGPACK_UNPACK_PARSE_ERROR) { + printf("The data in the buf is invalid format.\n"); + } +} + +int main(void) { + msgpack_sbuffer sbuf; + msgpack_sbuffer_init(&sbuf); + + prepare(&sbuf); + unpack(sbuf.data, sbuf.size); + + msgpack_sbuffer_destroy(&sbuf); + return 0; +} + +/* Output */ + +/* +Object no 1: +[1, true, "example"] +Object no 2: +"second" +Object no 3: +[42, false] +*/ diff --git a/include/msgpack/unpack.h b/include/msgpack/unpack.h index b5ad757c..66b0b0f6 100644 --- a/include/msgpack/unpack.h +++ b/include/msgpack/unpack.h @@ -38,7 +38,17 @@ typedef struct msgpack_unpacked { msgpack_object data; } msgpack_unpacked; -bool msgpack_unpack_next(msgpack_unpacked* result, +typedef enum { + MSGPACK_UNPACK_SUCCESS = 2, + MSGPACK_UNPACK_EXTRA_BYTES = 1, + MSGPACK_UNPACK_CONTINUE = 0, + MSGPACK_UNPACK_PARSE_ERROR = -1, + MSGPACK_UNPACK_NOMEM_ERROR = -2 +} msgpack_unpack_return; + + +msgpack_unpack_return +msgpack_unpack_next(msgpack_unpacked* result, const char* data, size_t len, size_t* off); /** @} */ @@ -136,7 +146,7 @@ static inline void msgpack_unpacker_buffer_consumed(msgpack_unpacker* mpac, si * Returns true if it successes. Otherwise false is returned. * @param pac pointer to an initialized msgpack_unpacked object. */ -bool msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* pac); +msgpack_unpack_return msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* pac); /** * Initializes a msgpack_unpacked object. @@ -174,20 +184,14 @@ static inline size_t msgpack_unpacker_message_size(const msgpack_unpacker* mpac) /** @} */ -// obsolete -typedef enum { - MSGPACK_UNPACK_SUCCESS = 2, - MSGPACK_UNPACK_EXTRA_BYTES = 1, - MSGPACK_UNPACK_CONTINUE = 0, - MSGPACK_UNPACK_PARSE_ERROR = -1 -} msgpack_unpack_return; - // obsolete msgpack_unpack_return msgpack_unpack(const char* data, size_t len, size_t* off, msgpack_zone* result_zone, msgpack_object* result); + + static inline size_t msgpack_unpacker_parsed_size(const msgpack_unpacker* mpac); bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac); diff --git a/src/unpack.c b/src/unpack.c index 01661055..8b68efe6 100644 --- a/src/unpack.c +++ b/src/unpack.c @@ -390,25 +390,24 @@ void msgpack_unpacker_reset(msgpack_unpacker* mpac) mpac->parsed = 0; } -bool msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* result) +msgpack_unpack_return msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* result) { - if(result->zone != NULL) { - msgpack_zone_free(result->zone); - } - int ret = msgpack_unpacker_execute(mpac); - if(ret <= 0) { + if(ret < 0) { result->zone = NULL; memset(&result->data, 0, sizeof(msgpack_object)); - return false; + return MSGPACK_UNPACK_PARSE_ERROR; } + if(ret == 0) { + return MSGPACK_UNPACK_CONTINUE; + } result->zone = msgpack_unpacker_release_zone(mpac); result->data = msgpack_unpacker_data(mpac); msgpack_unpacker_reset(mpac); - return true; + return MSGPACK_UNPACK_SUCCESS; } @@ -450,7 +449,8 @@ msgpack_unpack(const char* data, size_t len, size_t* off, return MSGPACK_UNPACK_SUCCESS; } -bool msgpack_unpack_next(msgpack_unpacked* result, +msgpack_unpack_return +msgpack_unpack_next(msgpack_unpacked* result, const char* data, size_t len, size_t* off) { msgpack_unpacked_destroy(result); @@ -459,29 +459,39 @@ bool msgpack_unpack_next(msgpack_unpacked* result, if(off != NULL) { noff = *off; } if(len <= noff) { - return false; + return MSGPACK_UNPACK_CONTINUE; } - msgpack_zone* z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE); + if (!result->zone) { + result->zone = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE); + } + + if (!result->zone) { + return MSGPACK_UNPACK_NOMEM_ERROR; + } template_context ctx; template_init(&ctx); - ctx.user.z = z; + ctx.user.z = result->zone; ctx.user.referenced = false; int e = template_execute(&ctx, data, len, &noff); - if(e <= 0) { - msgpack_zone_free(z); - return false; + if(e < 0) { + msgpack_zone_free(result->zone); + result->zone = NULL; + return MSGPACK_UNPACK_PARSE_ERROR; } if(off != NULL) { *off = noff; } - result->zone = z; + if(e == 0) { + return MSGPACK_UNPACK_CONTINUE; + } + result->data = template_data(&ctx); - return true; + return MSGPACK_UNPACK_SUCCESS; } #if defined(MSGPACK_OLD_COMPILER_BUS_ERROR_WORKAROUND) diff --git a/test/streaming_c.cc b/test/streaming_c.cc index 87708b5a..159eef76 100644 --- a/test/streaming_c.cc +++ b/test/streaming_c.cc @@ -54,7 +54,7 @@ TEST(streaming, basic) msgpack_unpacker_buffer_consumed(&pac, 1); - while(msgpack_unpacker_next(&pac, &result)) { + while(msgpack_unpacker_next(&pac, &result) == MSGPACK_UNPACK_SUCCESS) { unpacked = 1; msgpack_object obj = result.data; msgpack_object e;