Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: hello_message_pack
unpack.c
00001 /* 00002 * MessagePack for C unpacking routine 00003 * 00004 * Copyright (C) 2008-2009 FURUHASHI Sadayuki 00005 * 00006 * Distributed under the Boost Software License, Version 1.0. 00007 * (See accompanying file LICENSE_1_0.txt or copy at 00008 * http://www.boost.org/LICENSE_1_0.txt) 00009 */ 00010 #include "include/unpack.h" 00011 #include "include/unpack_define.h" 00012 #include "include/util.h" 00013 #include <stdlib.h> 00014 00015 #ifdef _msgpack_atomic_counter_header 00016 #include _msgpack_atomic_counter_header 00017 #endif 00018 00019 00020 typedef struct { 00021 msgpack_zone* z; 00022 bool referenced; 00023 } unpack_user; 00024 00025 00026 #define msgpack_unpack_struct(name) \ 00027 struct template ## name 00028 00029 #define msgpack_unpack_func(ret, name) \ 00030 ret template ## name 00031 00032 #define msgpack_unpack_callback(name) \ 00033 template_callback ## name 00034 00035 #define msgpack_unpack_object msgpack_object 00036 00037 #define msgpack_unpack_user unpack_user 00038 00039 00040 struct template_context; 00041 typedef struct template_context template_context; 00042 00043 static void template_init(template_context* ctx); 00044 00045 static msgpack_object template_data(template_context* ctx); 00046 00047 static int template_execute( 00048 template_context* ctx, const char* data, size_t len, size_t* off); 00049 00050 00051 static inline msgpack_object template_callback_root(unpack_user* u) 00052 { 00053 msgpack_object o; 00054 MSGPACK_UNUSED(u); 00055 o.type = MSGPACK_OBJECT_NIL; 00056 return o; 00057 } 00058 00059 static inline int template_callback_uint8(unpack_user* u, uint8_t d, msgpack_object* o) 00060 { 00061 MSGPACK_UNUSED(u); 00062 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00063 o->via.u64 = d; 00064 return 0; 00065 } 00066 00067 static inline int template_callback_uint16(unpack_user* u, uint16_t d, msgpack_object* o) 00068 { 00069 MSGPACK_UNUSED(u); 00070 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00071 o->via.u64 = d; 00072 return 0; 00073 } 00074 00075 static inline int template_callback_uint32(unpack_user* u, uint32_t d, msgpack_object* o) 00076 { 00077 MSGPACK_UNUSED(u); 00078 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00079 o->via.u64 = d; 00080 return 0; 00081 } 00082 00083 static inline int template_callback_uint64(unpack_user* u, uint64_t d, msgpack_object* o) 00084 { 00085 MSGPACK_UNUSED(u); 00086 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00087 o->via.u64 = d; 00088 return 0; 00089 } 00090 00091 static inline int template_callback_int8(unpack_user* u, int8_t d, msgpack_object* o) 00092 { 00093 MSGPACK_UNUSED(u); 00094 if(d >= 0) { 00095 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00096 o->via.u64 = (uint64_t)d; 00097 return 0; 00098 } 00099 else { 00100 o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER; 00101 o->via.i64 = d; 00102 return 0; 00103 } 00104 } 00105 00106 static inline int template_callback_int16(unpack_user* u, int16_t d, msgpack_object* o) 00107 { 00108 MSGPACK_UNUSED(u); 00109 if(d >= 0) { 00110 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00111 o->via.u64 = (uint64_t)d; 00112 return 0; 00113 } 00114 else { 00115 o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER; 00116 o->via.i64 = d; 00117 return 0; 00118 } 00119 } 00120 00121 static inline int template_callback_int32(unpack_user* u, int32_t d, msgpack_object* o) 00122 { 00123 MSGPACK_UNUSED(u); 00124 if(d >= 0) { 00125 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00126 o->via.u64 = (uint64_t)d; 00127 return 0; 00128 } 00129 else { 00130 o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER; 00131 o->via.i64 = d; 00132 return 0; 00133 } 00134 } 00135 00136 static inline int template_callback_int64(unpack_user* u, int64_t d, msgpack_object* o) 00137 { 00138 MSGPACK_UNUSED(u); 00139 if(d >= 0) { 00140 o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; 00141 o->via.u64 = (uint64_t)d; 00142 return 0; 00143 } 00144 else { 00145 o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER; 00146 o->via.i64 = d; 00147 return 0; 00148 } 00149 } 00150 00151 static inline int template_callback_float(unpack_user* u, float d, msgpack_object* o) 00152 { 00153 MSGPACK_UNUSED(u); 00154 o->type = MSGPACK_OBJECT_FLOAT; 00155 o->via.f64 = d; 00156 return 0; 00157 } 00158 00159 static inline int template_callback_double(unpack_user* u, double d, msgpack_object* o) 00160 { 00161 MSGPACK_UNUSED(u); 00162 o->type = MSGPACK_OBJECT_FLOAT; 00163 o->via.f64 = d; 00164 return 0; 00165 } 00166 00167 static inline int template_callback_nil(unpack_user* u, msgpack_object* o) 00168 { 00169 MSGPACK_UNUSED(u); 00170 o->type = MSGPACK_OBJECT_NIL; 00171 return 0; 00172 } 00173 00174 static inline int template_callback_true(unpack_user* u, msgpack_object* o) 00175 { 00176 MSGPACK_UNUSED(u); 00177 o->type = MSGPACK_OBJECT_BOOLEAN; 00178 o->via.boolean = true; 00179 return 0; 00180 } 00181 00182 static inline int template_callback_false(unpack_user* u, msgpack_object* o) 00183 { 00184 MSGPACK_UNUSED(u); 00185 o->type = MSGPACK_OBJECT_BOOLEAN; 00186 o->via.boolean = false; 00187 return 0; 00188 } 00189 00190 static inline int template_callback_array(unpack_user* u, unsigned int n, msgpack_object* o) 00191 { 00192 o->type = MSGPACK_OBJECT_ARRAY; 00193 o->via.array.size = 0; 00194 o->via.array.ptr = (msgpack_object*)msgpack_zone_malloc(u->z, n*sizeof(msgpack_object)); 00195 if(o->via.array.ptr == NULL) { return -1; } 00196 return 0; 00197 } 00198 00199 static inline int template_callback_array_item(unpack_user* u, msgpack_object* c, msgpack_object o) 00200 { 00201 MSGPACK_UNUSED(u); 00202 #if defined(__GNUC__) && !defined(__clang__) 00203 memcpy(&c->via.array.ptr[c->via.array.size], &o, sizeof(msgpack_object)); 00204 #else /* __GNUC__ && !__clang__ */ 00205 c->via.array.ptr[c->via.array.size] = o; 00206 #endif /* __GNUC__ && !__clang__ */ 00207 ++c->via.array.size; 00208 return 0; 00209 } 00210 00211 static inline int template_callback_map(unpack_user* u, unsigned int n, msgpack_object* o) 00212 { 00213 o->type = MSGPACK_OBJECT_MAP; 00214 o->via.map.size = 0; 00215 o->via.map.ptr = (msgpack_object_kv*)msgpack_zone_malloc(u->z, n*sizeof(msgpack_object_kv)); 00216 if(o->via.map.ptr == NULL) { return -1; } 00217 return 0; 00218 } 00219 00220 static inline int template_callback_map_item(unpack_user* u, msgpack_object* c, msgpack_object k, msgpack_object v) 00221 { 00222 MSGPACK_UNUSED(u); 00223 #if defined(__GNUC__) && !defined(__clang__) 00224 memcpy(&c->via.map.ptr[c->via.map.size].key, &k, sizeof(msgpack_object)); 00225 memcpy(&c->via.map.ptr[c->via.map.size].val, &v, sizeof(msgpack_object)); 00226 #else /* __GNUC__ && !__clang__ */ 00227 c->via.map.ptr[c->via.map.size].key = k; 00228 c->via.map.ptr[c->via.map.size].val = v; 00229 #endif /* __GNUC__ && !__clang__ */ 00230 ++c->via.map.size; 00231 return 0; 00232 } 00233 00234 static inline int template_callback_str(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o) 00235 { 00236 MSGPACK_UNUSED(u); 00237 MSGPACK_UNUSED(b); 00238 o->type = MSGPACK_OBJECT_STR; 00239 o->via.str.ptr = p; 00240 o->via.str.size = l; 00241 u->referenced = true; 00242 return 0; 00243 } 00244 00245 static inline int template_callback_bin(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o) 00246 { 00247 MSGPACK_UNUSED(u); 00248 MSGPACK_UNUSED(b); 00249 o->type = MSGPACK_OBJECT_BIN; 00250 o->via.bin.ptr = p; 00251 o->via.bin.size = l; 00252 u->referenced = true; 00253 return 0; 00254 } 00255 00256 static inline int template_callback_ext(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o) 00257 { 00258 MSGPACK_UNUSED(u); 00259 MSGPACK_UNUSED(b); 00260 o->type = MSGPACK_OBJECT_EXT; 00261 o->via.ext.type = *p; 00262 o->via.ext.ptr = p + 1; 00263 o->via.ext.size = l - 1; 00264 u->referenced = true; 00265 return 0; 00266 } 00267 00268 #include "include/unpack_template.h" 00269 00270 00271 #define CTX_CAST(m) ((template_context*)(m)) 00272 #define CTX_REFERENCED(mpac) CTX_CAST((mpac)->ctx)->user.referenced 00273 00274 #define COUNTER_SIZE (sizeof(_msgpack_atomic_counter_t)) 00275 00276 00277 static inline void init_count(void* buffer) 00278 { 00279 *(volatile _msgpack_atomic_counter_t*)buffer = 1; 00280 } 00281 00282 static inline void decr_count(void* buffer) 00283 { 00284 // atomic if(--*(_msgpack_atomic_counter_t*)buffer == 0) { free(buffer); } 00285 if(_msgpack_sync_decr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer) == 0) { 00286 free(buffer); 00287 } 00288 } 00289 00290 static inline void incr_count(void* buffer) 00291 { 00292 // atomic ++*(_msgpack_atomic_counter_t*)buffer; 00293 _msgpack_sync_incr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer); 00294 } 00295 00296 static inline _msgpack_atomic_counter_t get_count(void* buffer) 00297 { 00298 return *(volatile _msgpack_atomic_counter_t*)buffer; 00299 } 00300 00301 bool msgpack_unpacker_init(msgpack_unpacker* mpac, size_t initial_buffer_size) 00302 { 00303 char* buffer; 00304 void* ctx; 00305 msgpack_zone* z; 00306 00307 if(initial_buffer_size < COUNTER_SIZE) { 00308 initial_buffer_size = COUNTER_SIZE; 00309 } 00310 00311 buffer = (char*)malloc(initial_buffer_size); 00312 if(buffer == NULL) { 00313 return false; 00314 } 00315 00316 ctx = malloc(sizeof(template_context)); 00317 if(ctx == NULL) { 00318 free(buffer); 00319 return false; 00320 } 00321 00322 z = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE); 00323 if(z == NULL) { 00324 free(ctx); 00325 free(buffer); 00326 return false; 00327 } 00328 00329 mpac->buffer = buffer; 00330 mpac->used = COUNTER_SIZE; 00331 mpac->free = initial_buffer_size - mpac->used; 00332 mpac->off = COUNTER_SIZE; 00333 mpac->parsed = 0; 00334 mpac->initial_buffer_size = initial_buffer_size; 00335 mpac->z = z; 00336 mpac->ctx = ctx; 00337 00338 init_count(mpac->buffer); 00339 00340 template_init(CTX_CAST(mpac->ctx)); 00341 CTX_CAST(mpac->ctx)->user.z = mpac->z; 00342 CTX_CAST(mpac->ctx)->user.referenced = false; 00343 00344 return true; 00345 } 00346 00347 void msgpack_unpacker_destroy(msgpack_unpacker* mpac) 00348 { 00349 msgpack_zone_free(mpac->z); 00350 free(mpac->ctx); 00351 decr_count(mpac->buffer); 00352 } 00353 00354 msgpack_unpacker* msgpack_unpacker_new(size_t initial_buffer_size) 00355 { 00356 msgpack_unpacker* mpac = (msgpack_unpacker*)malloc(sizeof(msgpack_unpacker)); 00357 if(mpac == NULL) { 00358 return NULL; 00359 } 00360 00361 if(!msgpack_unpacker_init(mpac, initial_buffer_size)) { 00362 free(mpac); 00363 return NULL; 00364 } 00365 00366 return mpac; 00367 } 00368 00369 void msgpack_unpacker_free(msgpack_unpacker* mpac) 00370 { 00371 msgpack_unpacker_destroy(mpac); 00372 free(mpac); 00373 } 00374 00375 bool msgpack_unpacker_expand_buffer(msgpack_unpacker* mpac, size_t size) 00376 { 00377 if(mpac->used == mpac->off && get_count(mpac->buffer) == 1 00378 && !CTX_REFERENCED(mpac)) { 00379 // rewind buffer 00380 mpac->free += mpac->used - COUNTER_SIZE; 00381 mpac->used = COUNTER_SIZE; 00382 mpac->off = COUNTER_SIZE; 00383 00384 if(mpac->free >= size) { 00385 return true; 00386 } 00387 } 00388 00389 if(mpac->off == COUNTER_SIZE) { 00390 char* tmp; 00391 size_t next_size = (mpac->used + mpac->free) * 2; // include COUNTER_SIZE 00392 while(next_size < size + mpac->used) { 00393 size_t tmp_next_size = next_size * 2; 00394 if (tmp_next_size <= next_size) { 00395 next_size = size + mpac->used; 00396 break; 00397 } 00398 next_size = tmp_next_size; 00399 } 00400 00401 tmp = (char*)realloc(mpac->buffer, next_size); 00402 if(tmp == NULL) { 00403 return false; 00404 } 00405 00406 mpac->buffer = tmp; 00407 mpac->free = next_size - mpac->used; 00408 00409 } else { 00410 char* tmp; 00411 size_t next_size = mpac->initial_buffer_size; // include COUNTER_SIZE 00412 size_t not_parsed = mpac->used - mpac->off; 00413 while(next_size < size + not_parsed + COUNTER_SIZE) { 00414 size_t tmp_next_size = next_size * 2; 00415 if (tmp_next_size <= next_size) { 00416 next_size = size + not_parsed + COUNTER_SIZE; 00417 break; 00418 } 00419 next_size = tmp_next_size; 00420 } 00421 00422 tmp = (char*)malloc(next_size); 00423 if(tmp == NULL) { 00424 return false; 00425 } 00426 00427 init_count(tmp); 00428 00429 memcpy(tmp+COUNTER_SIZE, mpac->buffer+mpac->off, not_parsed); 00430 00431 if(CTX_REFERENCED(mpac)) { 00432 if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) { 00433 free(tmp); 00434 return false; 00435 } 00436 CTX_REFERENCED(mpac) = false; 00437 } else { 00438 decr_count(mpac->buffer); 00439 } 00440 00441 mpac->buffer = tmp; 00442 mpac->used = not_parsed + COUNTER_SIZE; 00443 mpac->free = next_size - mpac->used; 00444 mpac->off = COUNTER_SIZE; 00445 } 00446 00447 return true; 00448 } 00449 00450 int msgpack_unpacker_execute(msgpack_unpacker* mpac) 00451 { 00452 size_t off = mpac->off; 00453 int ret = template_execute(CTX_CAST(mpac->ctx), 00454 mpac->buffer, mpac->used, &mpac->off); 00455 if(mpac->off > off) { 00456 mpac->parsed += mpac->off - off; 00457 } 00458 return ret; 00459 } 00460 00461 msgpack_object msgpack_unpacker_data(msgpack_unpacker* mpac) 00462 { 00463 return template_data(CTX_CAST(mpac->ctx)); 00464 } 00465 00466 msgpack_zone* msgpack_unpacker_release_zone(msgpack_unpacker* mpac) 00467 { 00468 msgpack_zone* r; 00469 msgpack_zone* old; 00470 00471 if(!msgpack_unpacker_flush_zone(mpac)) { 00472 return NULL; 00473 } 00474 00475 r = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE); 00476 if(r == NULL) { 00477 return NULL; 00478 } 00479 00480 old = mpac->z; 00481 mpac->z = r; 00482 CTX_CAST(mpac->ctx)->user.z = mpac->z; 00483 00484 return old; 00485 } 00486 00487 void msgpack_unpacker_reset_zone(msgpack_unpacker* mpac) 00488 { 00489 msgpack_zone_clear(mpac->z); 00490 } 00491 00492 bool msgpack_unpacker_flush_zone(msgpack_unpacker* mpac) 00493 { 00494 if(CTX_REFERENCED(mpac)) { 00495 if(!msgpack_zone_push_finalizer(mpac->z, decr_count, mpac->buffer)) { 00496 return false; 00497 } 00498 CTX_REFERENCED(mpac) = false; 00499 00500 incr_count(mpac->buffer); 00501 } 00502 00503 return true; 00504 } 00505 00506 void msgpack_unpacker_reset(msgpack_unpacker* mpac) 00507 { 00508 template_init(CTX_CAST(mpac->ctx)); 00509 // don't reset referenced flag 00510 mpac->parsed = 0; 00511 } 00512 00513 msgpack_unpack_return msgpack_unpacker_next(msgpack_unpacker* mpac, msgpack_unpacked* result) 00514 { 00515 int ret; 00516 00517 msgpack_unpacked_destroy(result); 00518 00519 ret = msgpack_unpacker_execute(mpac); 00520 00521 if(ret < 0) { 00522 result->zone = NULL; 00523 memset(&result->data, 0, sizeof(msgpack_object)); 00524 return MSGPACK_UNPACK_PARSE_ERROR; 00525 } 00526 00527 if(ret == 0) { 00528 return MSGPACK_UNPACK_CONTINUE; 00529 } 00530 result->zone = msgpack_unpacker_release_zone(mpac); 00531 result->data = msgpack_unpacker_data(mpac); 00532 msgpack_unpacker_reset(mpac); 00533 00534 return MSGPACK_UNPACK_SUCCESS; 00535 } 00536 00537 00538 msgpack_unpack_return 00539 msgpack_unpack(const char* data, size_t len, size_t* off, 00540 msgpack_zone* result_zone, msgpack_object* result) 00541 { 00542 size_t noff = 0; 00543 if(off != NULL) { noff = *off; } 00544 00545 if(len <= noff) { 00546 // FIXME 00547 return MSGPACK_UNPACK_CONTINUE; 00548 } 00549 else { 00550 int e; 00551 template_context ctx; 00552 template_init(&ctx); 00553 00554 ctx.user.z = result_zone; 00555 ctx.user.referenced = false; 00556 00557 e = template_execute(&ctx, data, len, &noff); 00558 if(e < 0) { 00559 return MSGPACK_UNPACK_PARSE_ERROR; 00560 } 00561 00562 if(off != NULL) { *off = noff; } 00563 00564 if(e == 0) { 00565 return MSGPACK_UNPACK_CONTINUE; 00566 } 00567 00568 *result = template_data(&ctx); 00569 00570 if(noff < len) { 00571 return MSGPACK_UNPACK_EXTRA_BYTES; 00572 } 00573 00574 return MSGPACK_UNPACK_SUCCESS; 00575 } 00576 } 00577 00578 msgpack_unpack_return 00579 msgpack_unpack_next(msgpack_unpacked* result, 00580 const char* data, size_t len, size_t* off) 00581 { 00582 size_t noff = 0; 00583 msgpack_unpacked_destroy(result); 00584 00585 if(off != NULL) { noff = *off; } 00586 00587 if(len <= noff) { 00588 return MSGPACK_UNPACK_CONTINUE; 00589 } 00590 00591 if (!result->zone) { 00592 result->zone = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE); 00593 } 00594 00595 if (!result->zone) { 00596 return MSGPACK_UNPACK_NOMEM_ERROR; 00597 } 00598 else { 00599 int e; 00600 template_context ctx; 00601 template_init(&ctx); 00602 00603 ctx.user.z = result->zone; 00604 ctx.user.referenced = false; 00605 00606 e = template_execute(&ctx, data, len, &noff); 00607 if(e < 0) { 00608 msgpack_zone_free(result->zone); 00609 result->zone = NULL; 00610 return MSGPACK_UNPACK_PARSE_ERROR; 00611 } 00612 00613 00614 if(e == 0) { 00615 return MSGPACK_UNPACK_CONTINUE; 00616 } 00617 00618 if(off != NULL) { *off = noff; } 00619 00620 result->data = template_data(&ctx); 00621 00622 return MSGPACK_UNPACK_SUCCESS; 00623 } 00624 } 00625 00626 #if defined(MSGPACK_OLD_COMPILER_BUS_ERROR_WORKAROUND) 00627 // FIXME: Dirty hack to avoid a bus error caused by OS X's old gcc. 00628 static void dummy_function_to_avoid_bus_error() 00629 { 00630 } 00631 #endif
Generated on Tue Jul 12 2022 22:51:46 by
1.7.2