Hideaki Tai / msgpack-embedded

Dependents:   hello_message_pack

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers unpack.c Source File

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