Showing the changes to src/lua_cmsgpack.c (1 of 4 files). Show all
Unified · Split
| @@ -0,0 +1,729 @@ | |||
| 1 | #include <math.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <stdint.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <assert.h> | ||
| 6 | |||
| 7 | #include "lua.h" | ||
| 8 | #include "lauxlib.h" | ||
| 9 | |||
| 10 | #define LUACMSGPACK_VERSION "lua-cmsgpack 0.3.0" | ||
| 11 | #define LUACMSGPACK_COPYRIGHT "Copyright (C) 2012, Salvatore Sanfilippo" | ||
| 12 | #define LUACMSGPACK_DESCRIPTION "MessagePack C implementation for Lua" | ||
| 13 | |||
| 14 | #define LUACMSGPACK_MAX_NESTING 16 /* Max tables nesting. */ | ||
| 15 | |||
| 16 | /* ============================================================================== | ||
| 17 | * MessagePack implementation and bindings for Lua 5.1. | ||
| 18 | * Copyright(C) 2012 Salvatore Sanfilippo <antirez@gmail.com> | ||
| 19 | * | ||
| 20 | * http://github.com/antirez/lua-cmsgpack | ||
| 21 | * | ||
| 22 | * For MessagePack specification check the following web site: | ||
| 23 | * http://wiki.msgpack.org/display/MSGPACK/Format+specification | ||
| 24 | * | ||
| 25 | * See Copyright Notice at the end of this file. | ||
| 26 | * | ||
| 27 | * CHANGELOG: | ||
| 28 | * 19-Feb-2012 (ver 0.1.0): Initial release. | ||
| 29 | * 20-Feb-2012 (ver 0.2.0): Tables encoding improved. | ||
| 30 | * 20-Feb-2012 (ver 0.2.1): Minor bug fixing. | ||
| 31 | * 20-Feb-2012 (ver 0.3.0): Module renamed lua-cmsgpack (was lua-msgpack). | ||
| 32 | * ============================================================================ */ | ||
| 33 | |||
| 34 | /* --------------------------- Endian conversion -------------------------------- | ||
| 35 | * We use it only for floats and doubles, all the other conversions are performed | ||
| 36 | * in an endian independent fashion. So the only thing we need is a function | ||
| 37 | * that swaps a binary string if the arch is little endian (and left it untouched | ||
| 38 | * otherwise). */ | ||
| 39 | |||
| 40 | /* Reverse memory bytes if arch is little endian. Given the conceptual | ||
| 41 | * simplicity of the Lua build system we prefer to check for endianess at runtime. | ||
| 42 | * The performance difference should be acceptable. */ | ||
| 43 | static void memrevifle(void *ptr, size_t len) { | ||
| 44 | unsigned char *p = ptr, *e = p+len-1, aux; | ||
| 45 | int test = 1; | ||
| 46 | unsigned char *testp = (unsigned char*) &test; | ||
| 47 | |||
| 48 | if (testp[0] == 0) return; /* Big endian, nothign to do. */ | ||
| 49 | len /= 2; | ||
| 50 | while(len--) { | ||
| 51 | aux = *p; | ||
| 52 | *p = *e; | ||
| 53 | *e = aux; | ||
| 54 | p++; | ||
| 55 | e--; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | /* ----------------------------- String buffer ---------------------------------- | ||
| 60 | * This is a simple implementation of string buffers. The only opereation | ||
| 61 | * supported is creating empty buffers and appending bytes to it. | ||
| 62 | * The string buffer uses 2x preallocation on every realloc for O(N) append | ||
| 63 | * behavior. */ | ||
| 64 | |||
| 65 | typedef struct mp_buf { | ||
| 66 | unsigned char *b; | ||
| 67 | size_t len, free; | ||
| 68 | } mp_buf; | ||
| 69 | |||
| 70 | static mp_buf *mp_buf_new(void) { | ||
| 71 | mp_buf *buf = malloc(sizeof(*buf)); | ||
| 72 | |||
| 73 | buf->b = NULL; | ||
| 74 | buf->len = buf->free = 0; | ||
| 75 | return buf; | ||
| 76 | } | ||
| 77 | |||
| 78 | void mp_buf_append(mp_buf *buf, const unsigned char *s, size_t len) { | ||
| 79 | if (buf->free < len) { | ||
| 80 | size_t newlen = buf->len+len; | ||
| 81 | |||
| 82 | buf->b = realloc(buf->b,newlen*2); | ||
| 83 | buf->free = newlen; | ||
| 84 | } | ||
| 85 | memcpy(buf->b+buf->len,s,len); | ||
| 86 | buf->len += len; | ||
| 87 | buf->free -= len; | ||
| 88 | } | ||
| 89 | |||
| 90 | void mp_buf_free(mp_buf *buf) { | ||
| 91 | free(buf->b); | ||
| 92 | free(buf); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* ------------------------------ String cursor ---------------------------------- | ||
| 96 | * This simple data structure is used for parsing. Basically you create a cursor | ||
| 97 | * using a string pointer and a length, then it is possible to access the | ||
| 98 | * current string position with cursor->p, check the remaining length | ||
| 99 | * in cursor->left, and finally consume more string using | ||
| 100 | * mp_cur_consume(cursor,len), to advance 'p' and subtract 'left'. | ||
| 101 | * An additional field cursor->error is set to zero on initialization and can | ||
| 102 | * be used to report errors. */ | ||
| 103 | |||
| 104 | #define MP_CUR_ERROR_NONE 0 | ||
| 105 | #define MP_CUR_ERROR_EOF 1 /* Not enough data to complete the opereation. */ | ||
| 106 | #define MP_CUR_ERROR_BADFMT 2 /* Bad data format */ | ||
| 107 | |||
| 108 | typedef struct mp_cur { | ||
| 109 | const unsigned char *p; | ||
| 110 | size_t left; | ||
| 111 | int err; | ||
| 112 | } mp_cur; | ||
| 113 | |||
| 114 | static mp_cur *mp_cur_new(const unsigned char *s, size_t len) { | ||
| 115 | mp_cur *cursor = malloc(sizeof(*cursor)); | ||
| 116 | |||
| 117 | cursor->p = s; | ||
| 118 | cursor->left = len; | ||
| 119 | cursor->err = MP_CUR_ERROR_NONE; | ||
| 120 | return cursor; | ||
| 121 | } | ||
| 122 | |||
| 123 | static void mp_cur_free(mp_cur *cursor) { | ||
| 124 | free(cursor); | ||
| 125 | } | ||
| 126 | |||
| 127 | #define mp_cur_consume(_c,_len) do { _c->p += _len; _c->left -= _len; } while(0) | ||
| 128 | |||
| 129 | /* When there is not enough room we set an error in the cursor and return, this | ||
| 130 | * is very common across the code so we have a macro to make the code look | ||
| 131 | * a bit simpler. */ | ||
| 132 | #define mp_cur_need(_c,_len) do { \ | ||
| 133 | if (_c->left < _len) { \ | ||
| 134 | _c->err = MP_CUR_ERROR_EOF; \ | ||
| 135 | return; \ | ||
| 136 | } \ | ||
| 137 | } while(0) | ||
| 138 | |||
| 139 | /* --------------------------- Low level MP encoding -------------------------- */ | ||
| 140 | |||
| 141 | static void mp_encode_bytes(mp_buf *buf, const unsigned char *s, size_t len) { | ||
| 142 | unsigned char hdr[5]; | ||
| 143 | int hdrlen; | ||
| 144 | |||
| 145 | if (len < 32) { | ||
| 146 | hdr[0] = 0xa0 | (len&0xff); /* fix raw */ | ||
| 147 | hdrlen = 1; | ||
| 148 | } else if (len <= 0xffff) { | ||
| 149 | hdr[0] = 0xda; | ||
| 150 | hdr[1] = (len&0xff00)>>8; | ||
| 151 | hdr[2] = len&0xff; | ||
| 152 | hdrlen = 3; | ||
| 153 | } else { | ||
| 154 | hdr[0] = 0xdb; | ||
| 155 | hdr[1] = (len&0xff000000)>>24; | ||
| 156 | hdr[2] = (len&0xff0000)>>16; | ||
| 157 | hdr[3] = (len&0xff00)>>8; | ||
| 158 | hdr[4] = len&0xff; | ||
| 159 | hdrlen = 5; | ||
| 160 | } | ||
| 161 | mp_buf_append(buf,hdr,hdrlen); | ||
| 162 | mp_buf_append(buf,s,len); | ||
| 163 | } | ||
| 164 | |||
| 165 | /* we assume IEEE 754 internal format for single and double precision floats. */ | ||
| 166 | static void mp_encode_double(mp_buf *buf, double d) { | ||
| 167 | unsigned char b[9]; | ||
| 168 | float f = d; | ||
| 169 | |||
| 170 | assert(sizeof(f) == 4 && sizeof(d) == 8); | ||
| 171 | if (d == (double)f) { | ||
| 172 | b[0] = 0xca; /* float IEEE 754 */ | ||
| 173 | memcpy(b+1,&f,4); | ||
| 174 | memrevifle(b+1,4); | ||
| 175 | mp_buf_append(buf,b,5); | ||
| 176 | } else if (sizeof(d) == 8) { | ||
| 177 | b[0] = 0xcb; /* double IEEE 754 */ | ||
| 178 | memcpy(b+1,&d,8); | ||
| 179 | memrevifle(b+1,8); | ||
| 180 | mp_buf_append(buf,b,9); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | static void mp_encode_int(mp_buf *buf, int64_t n) { | ||
| 185 | unsigned char b[9]; | ||
| 186 | int enclen; | ||
| 187 | |||
| 188 | if (n >= 0) { | ||
| 189 | if (n <= 127) { | ||
| 190 | b[0] = n & 0x7f; /* positive fixnum */ | ||
| 191 | enclen = 1; | ||
| 192 | } else if (n <= 0xff) { | ||
| 193 | b[0] = 0xcc; /* uint 8 */ | ||
| 194 | b[1] = n & 0xff; | ||
| 195 | enclen = 2; | ||
| 196 | } else if (n <= 0xffff) { | ||
| 197 | b[0] = 0xcd; /* uint 16 */ | ||
| 198 | b[1] = (n & 0xff00) >> 8; | ||
| 199 | b[2] = n & 0xff; | ||
| 200 | enclen = 3; | ||
| 201 | } else if (n <= 0xffffffffLL) { | ||
| 202 | b[0] = 0xce; /* uint 32 */ | ||
| 203 | b[1] = (n & 0xff000000) >> 24; | ||
| 204 | b[2] = (n & 0xff0000) >> 16; | ||
| 205 | b[3] = (n & 0xff00) >> 8; | ||
| 206 | b[4] = n & 0xff; | ||
| 207 | enclen = 5; | ||
| 208 | } else { | ||
| 209 | b[0] = 0xcf; /* uint 64 */ | ||
| 210 | b[1] = (n & 0xff00000000000000LL) >> 56; | ||
| 211 | b[2] = (n & 0xff000000000000LL) >> 48; | ||
| 212 | b[3] = (n & 0xff0000000000LL) >> 40; | ||
| 213 | b[4] = (n & 0xff00000000LL) >> 32; | ||
| 214 | b[5] = (n & 0xff000000) >> 24; | ||
| 215 | b[6] = (n & 0xff0000) >> 16; | ||
| 216 | b[7] = (n & 0xff00) >> 8; | ||
| 217 | b[8] = n & 0xff; | ||
| 218 | enclen = 9; | ||
| 219 | } | ||
| 220 | } else { | ||
| 221 | if (n >= -32) { | ||
| 222 | b[0] = ((char)n); /* negative fixnum */ | ||
| 223 | enclen = 1; | ||
| 224 | } else if (n >= -128) { | ||
| 225 | b[0] = 0xd0; /* int 8 */ | ||
| 226 | b[1] = n & 0xff; | ||
| 227 | enclen = 2; | ||
| 228 | } else if (n >= -32768) { | ||
| 229 | b[0] = 0xd1; /* int 16 */ | ||
| 230 | b[1] = (n & 0xff00) >> 8; | ||
| 231 | b[2] = n & 0xff; | ||
| 232 | enclen = 3; | ||
| 233 | } else if (n >= -2147483648LL) { | ||
| 234 | b[0] = 0xd2; /* int 32 */ | ||
| 235 | b[1] = (n & 0xff000000) >> 24; | ||
| 236 | b[2] = (n & 0xff0000) >> 16; | ||
| 237 | b[3] = (n & 0xff00) >> 8; | ||
| 238 | b[4] = n & 0xff; | ||
| 239 | enclen = 5; | ||
| 240 | } else { | ||
| 241 | b[0] = 0xd3; /* int 64 */ | ||
| 242 | b[1] = (n & 0xff00000000000000LL) >> 56; | ||
| 243 | b[2] = (n & 0xff000000000000LL) >> 48; | ||
| 244 | b[3] = (n & 0xff0000000000LL) >> 40; | ||
| 245 | b[4] = (n & 0xff00000000LL) >> 32; | ||
| 246 | b[5] = (n & 0xff000000) >> 24; | ||
| 247 | b[6] = (n & 0xff0000) >> 16; | ||
| 248 | b[7] = (n & 0xff00) >> 8; | ||
| 249 | b[8] = n & 0xff; | ||
| 250 | enclen = 9; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | mp_buf_append(buf,b,enclen); | ||
| 254 | } | ||
| 255 | |||
| 256 | static void mp_encode_array(mp_buf *buf, int64_t n) { | ||
| 257 | unsigned char b[5]; | ||
| 258 | int enclen; | ||
| 259 | |||
| 260 | if (n <= 15) { | ||
| 261 | b[0] = 0x90 | (n & 0xf); /* fix array */ | ||
| 262 | enclen = 1; | ||
| 263 | } else if (n <= 65535) { | ||
| 264 | b[0] = 0xdc; /* array 16 */ | ||
| 265 | b[1] = (n & 0xff00) >> 8; | ||
| 266 | b[2] = n & 0xff; | ||
| 267 | enclen = 3; | ||
| 268 | } else { | ||
| 269 | b[0] = 0xdd; /* array 32 */ | ||
| 270 | b[1] = (n & 0xff000000) >> 24; | ||
| 271 | b[2] = (n & 0xff0000) >> 16; | ||
| 272 | b[3] = (n & 0xff00) >> 8; | ||
| 273 | b[4] = n & 0xff; | ||
| 274 | enclen = 5; | ||
| 275 | } | ||
| 276 | mp_buf_append(buf,b,enclen); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void mp_encode_map(mp_buf *buf, int64_t n) { | ||
| 280 | unsigned char b[5]; | ||
| 281 | int enclen; | ||
| 282 | |||
| 283 | if (n <= 15) { | ||
| 284 | b[0] = 0x80 | (n & 0xf); /* fix map */ | ||
| 285 | enclen = 1; | ||
| 286 | } else if (n <= 65535) { | ||
| 287 | b[0] = 0xde; /* map 16 */ | ||
| 288 | b[1] = (n & 0xff00) >> 8; | ||
| 289 | b[2] = n & 0xff; | ||
| 290 | enclen = 3; | ||
| 291 | } else { | ||
| 292 | b[0] = 0xdf; /* map 32 */ | ||
| 293 | b[1] = (n & 0xff000000) >> 24; | ||
| 294 | b[2] = (n & 0xff0000) >> 16; | ||
| 295 | b[3] = (n & 0xff00) >> 8; | ||
| 296 | b[4] = n & 0xff; | ||
| 297 | enclen = 5; | ||
| 298 | } | ||
| 299 | mp_buf_append(buf,b,enclen); | ||
| 300 | } | ||
| 301 | |||
| 302 | /* ----------------------------- Lua types encoding --------------------------- */ | ||
| 303 | |||
| 304 | static void mp_encode_lua_string(lua_State *L, mp_buf *buf) { | ||
| 305 | size_t len; | ||
| 306 | const char *s; | ||
| 307 | |||
| 308 | s = lua_tolstring(L,-1,&len); | ||
| 309 | mp_encode_bytes(buf,(const unsigned char*)s,len); | ||
| 310 | } | ||
| 311 | |||
| 312 | static void mp_encode_lua_bool(lua_State *L, mp_buf *buf) { | ||
| 313 | unsigned char b = lua_toboolean(L,-1) ? 0xc3 : 0xc2; | ||
| 314 | mp_buf_append(buf,&b,1); | ||
| 315 | } | ||
| 316 | |||
| 317 | static void mp_encode_lua_number(lua_State *L, mp_buf *buf) { | ||
| 318 | lua_Number n = lua_tonumber(L,-1); | ||
| 319 | |||
| 320 | if (floor(n) != n) { | ||
| 321 | mp_encode_double(buf,(double)n); | ||
| 322 | } else { | ||
| 323 | mp_encode_int(buf,(int64_t)n); | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level); | ||
| 328 | |||
| 329 | /* Convert a lua table into a message pack list. */ | ||
| 330 | static void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) { | ||
| 331 | size_t len = lua_objlen(L,-1), j; | ||
| 332 | |||
| 333 | mp_encode_array(buf,len); | ||
| 334 | for (j = 1; j <= len; j++) { | ||
| 335 | lua_pushnumber(L,j); | ||
| 336 | lua_gettable(L,-2); | ||
| 337 | mp_encode_lua_type(L,buf,level+1); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | /* Convert a lua table into a message pack key-value map. */ | ||
| 342 | static void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) { | ||
| 343 | size_t len = 0; | ||
| 344 | |||
| 345 | /* First step: count keys into table. No other way to do it with the | ||
| 346 | * Lua API, we need to iterate a first time. Note that an alternative | ||
| 347 | * would be to do a single run, and then hack the buffer to insert the | ||
| 348 | * map opcodes for message pack. Too hachish for this lib. */ | ||
| 349 | lua_pushnil(L); | ||
| 350 | while(lua_next(L,-2)) { | ||
| 351 | lua_pop(L,1); /* remove value, keep key for next iteration. */ | ||
| 352 | len++; | ||
| 353 | } | ||
| 354 | |||
| 355 | /* Step two: actually encoding of the map. */ | ||
| 356 | mp_encode_map(buf,len); | ||
| 357 | lua_pushnil(L); | ||
| 358 | while(lua_next(L,-2)) { | ||
| 359 | /* Stack: ... key value */ | ||
| 360 | lua_pushvalue(L,-2); /* Stack: ... key value key */ | ||
| 361 | mp_encode_lua_type(L,buf,level+1); /* encode key */ | ||
| 362 | mp_encode_lua_type(L,buf,level+1); /* encode val */ | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | /* Returns true if the Lua table on top of the stack is exclusively composed | ||
| 367 | * of keys from numerical keys from 1 up to N, with N being the total number | ||
| 368 | * of elements, without any hole in the middle. */ | ||
| 369 | static int table_is_an_array(lua_State *L) { | ||
| 370 | long count = 0, max = 0, idx = 0; | ||
| 371 | lua_Number n; | ||
| 372 | |||
| 373 | lua_pushnil(L); | ||
| 374 | while(lua_next(L,-2)) { | ||
| 375 | /* Stack: ... key value */ | ||
| 376 | lua_pop(L,1); /* Stack: ... key */ | ||
| 377 | if (!lua_isnumber(L,-1)) goto not_array; | ||
| 378 | n = lua_tonumber(L,-1); | ||
| 379 | idx = n; | ||
| 380 | if (idx != n || idx < 1) goto not_array; | ||
| 381 | count++; | ||
| 382 | max = idx; | ||
| 383 | } | ||
| 384 | /* We have the total number of elements in "count". Also we have | ||
| 385 | * the max index encountered in "idx". We can't reach this code | ||
| 386 | * if there are indexes <= 0. If you also note that there can not be | ||
| 387 | * repeated keys into a table, you have that if idx==count you are sure | ||
| 388 | * that there are all the keys form 1 to count (both included). */ | ||
| 389 | return idx == count; | ||
| 390 | |||
| 391 | not_array: | ||
| 392 | lua_pop(L,1); | ||
| 393 | return 0; | ||
| 394 | } | ||
| 395 | |||
| 396 | /* If the length operator returns non-zero, that is, there is at least | ||
| 397 | * an object at key '1', we serialize to message pack list. Otherwise | ||
| 398 | * we use a map. */ | ||
| 399 | static void mp_encode_lua_table(lua_State *L, mp_buf *buf, int level) { | ||
| 400 | if (table_is_an_array(L)) | ||
| 401 | mp_encode_lua_table_as_array(L,buf,level); | ||
| 402 | else | ||
| 403 | mp_encode_lua_table_as_map(L,buf,level); | ||
| 404 | } | ||
| 405 | |||
| 406 | static void mp_encode_lua_null(lua_State *L, mp_buf *buf) { | ||
| 407 | unsigned char b[1]; | ||
| 408 | |||
| 409 | b[0] = 0xc0; | ||
| 410 | mp_buf_append(buf,b,1); | ||
| 411 | } | ||
| 412 | |||
| 413 | static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level) { | ||
| 414 | int t = lua_type(L,-1); | ||
| 415 | |||
| 416 | /* Limit the encoding of nested tables to a specfiied maximum depth, so that | ||
| 417 | * we survive when called against circular references in tables. */ | ||
| 418 | if (t == LUA_TTABLE && level == LUACMSGPACK_MAX_NESTING) t = LUA_TNIL; | ||
| 419 | switch(t) { | ||
| 420 | case LUA_TSTRING: mp_encode_lua_string(L,buf); break; | ||
| 421 | case LUA_TBOOLEAN: mp_encode_lua_bool(L,buf); break; | ||
| 422 | case LUA_TNUMBER: mp_encode_lua_number(L,buf); break; | ||
| 423 | case LUA_TTABLE: mp_encode_lua_table(L,buf,level); break; | ||
| 424 | default: mp_encode_lua_null(L,buf); break; | ||
| 425 | } | ||
| 426 | lua_pop(L,1); | ||
| 427 | } | ||
| 428 | |||
| 429 | static int mp_pack(lua_State *L) { | ||
| 430 | mp_buf *buf = mp_buf_new(); | ||
| 431 | |||
| 432 | mp_encode_lua_type(L,buf,0); | ||
| 433 | lua_pushlstring(L,(char*)buf->b,buf->len); | ||
| 434 | mp_buf_free(buf); | ||
| 435 | return 1; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* --------------------------------- Decoding --------------------------------- */ | ||
| 439 | |||
| 440 | void mp_decode_to_lua_type(lua_State *L, mp_cur *c); | ||
| 441 | |||
| 442 | void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) { | ||
| 443 | int index = 1; | ||
| 444 | |||
| 445 | lua_newtable(L); | ||
| 446 | while(len--) { | ||
| 447 | lua_pushnumber(L,index++); | ||
| 448 | mp_decode_to_lua_type(L,c); | ||
| 449 | if (c->err) return; | ||
| 450 | lua_settable(L,-3); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) { | ||
| 455 | lua_newtable(L); | ||
| 456 | while(len--) { | ||
| 457 | mp_decode_to_lua_type(L,c); /* key */ | ||
| 458 | if (c->err) return; | ||
| 459 | mp_decode_to_lua_type(L,c); /* value */ | ||
| 460 | if (c->err) return; | ||
| 461 | lua_settable(L,-3); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | /* Decode a Message Pack raw object pointed by the string cursor 'c' to | ||
| 466 | * a Lua type, that is left as the only result on the stack. */ | ||
| 467 | void mp_decode_to_lua_type(lua_State *L, mp_cur *c) { | ||
| 468 | mp_cur_need(c,1); | ||
| 469 | switch(c->p[0]) { | ||
| 470 | case 0xcc: /* uint 8 */ | ||
| 471 | mp_cur_need(c,2); | ||
| 472 | lua_pushnumber(L,c->p[1]); | ||
| 473 | mp_cur_consume(c,2); | ||
| 474 | break; | ||
| 475 | case 0xd0: /* int 8 */ | ||
| 476 | mp_cur_need(c,2); | ||
| 477 | lua_pushnumber(L,(char)c->p[1]); | ||
| 478 | mp_cur_consume(c,2); | ||
| 479 | break; | ||
| 480 | case 0xcd: /* uint 16 */ | ||
| 481 | mp_cur_need(c,3); | ||
| 482 | lua_pushnumber(L, | ||
| 483 | (c->p[1] << 8) | | ||
| 484 | c->p[2]); | ||
| 485 | mp_cur_consume(c,3); | ||
| 486 | break; | ||
| 487 | case 0xd1: /* int 16 */ | ||
| 488 | mp_cur_need(c,3); | ||
| 489 | lua_pushnumber(L,(int16_t) | ||
| 490 | (c->p[1] << 8) | | ||
| 491 | c->p[2]); | ||
| 492 | mp_cur_consume(c,3); | ||
| 493 | break; | ||
| 494 | case 0xce: /* uint 32 */ | ||
| 495 | mp_cur_need(c,5); | ||
| 496 | lua_pushnumber(L, | ||
| 497 | ((uint32_t)c->p[1] << 24) | | ||
| 498 | ((uint32_t)c->p[2] << 16) | | ||
| 499 | ((uint32_t)c->p[3] << 8) | | ||
| 500 | (uint32_t)c->p[4]); | ||
| 501 | mp_cur_consume(c,5); | ||
| 502 | break; | ||
| 503 | case 0xd2: /* int 32 */ | ||
| 504 | mp_cur_need(c,5); | ||
| 505 | lua_pushnumber(L, | ||
| 506 | ((int32_t)c->p[1] << 24) | | ||
| 507 | ((int32_t)c->p[2] << 16) | | ||
| 508 | ((int32_t)c->p[3] << 8) | | ||
| 509 | (int32_t)c->p[4]); | ||
| 510 | mp_cur_consume(c,5); | ||
| 511 | break; | ||
| 512 | case 0xcf: /* uint 64 */ | ||
| 513 | mp_cur_need(c,9); | ||
| 514 | lua_pushnumber(L, | ||
| 515 | ((uint64_t)c->p[1] << 56) | | ||
| 516 | ((uint64_t)c->p[2] << 48) | | ||
| 517 | ((uint64_t)c->p[3] << 40) | | ||
| 518 | ((uint64_t)c->p[4] << 32) | | ||
| 519 | ((uint64_t)c->p[5] << 24) | | ||
| 520 | ((uint64_t)c->p[6] << 16) | | ||
| 521 | ((uint64_t)c->p[7] << 8) | | ||
| 522 | (uint64_t)c->p[8]); | ||
| 523 | mp_cur_consume(c,9); | ||
| 524 | break; | ||
| 525 | case 0xd3: /* int 64 */ | ||
| 526 | mp_cur_need(c,9); | ||
| 527 | lua_pushnumber(L, | ||
| 528 | ((int64_t)c->p[1] << 56) | | ||
| 529 | ((int64_t)c->p[2] << 48) | | ||
| 530 | ((int64_t)c->p[3] << 40) | | ||
| 531 | ((int64_t)c->p[4] << 32) | | ||
| 532 | ((int64_t)c->p[5] << 24) | | ||
| 533 | ((int64_t)c->p[6] << 16) | | ||
| 534 | ((int64_t)c->p[7] << 8) | | ||
| 535 | (int64_t)c->p[8]); | ||
| 536 | mp_cur_consume(c,9); | ||
| 537 | break; | ||
| 538 | case 0xc0: /* nil */ | ||
| 539 | lua_pushnil(L); | ||
| 540 | mp_cur_consume(c,1); | ||
| 541 | break; | ||
| 542 | case 0xc3: /* true */ | ||
| 543 | lua_pushboolean(L,1); | ||
| 544 | mp_cur_consume(c,1); | ||
| 545 | break; | ||
| 546 | case 0xc2: /* false */ | ||
| 547 | lua_pushboolean(L,0); | ||
| 548 | mp_cur_consume(c,1); | ||
| 549 | break; | ||
| 550 | case 0xca: /* float */ | ||
| 551 | mp_cur_need(c,5); | ||
| 552 | assert(sizeof(float) == 4); | ||
| 553 | { | ||
| 554 | float f; | ||
| 555 | memcpy(&f,c->p+1,4); | ||
| 556 | memrevifle(&f,4); | ||
| 557 | lua_pushnumber(L,f); | ||
| 558 | mp_cur_consume(c,5); | ||
| 559 | } | ||
| 560 | break; | ||
| 561 | case 0xcb: /* double */ | ||
| 562 | mp_cur_need(c,9); | ||
| 563 | assert(sizeof(double) == 8); | ||
| 564 | { | ||
| 565 | double d; | ||
| 566 | memcpy(&d,c->p+1,8); | ||
| 567 | memrevifle(&d,8); | ||
| 568 | lua_pushnumber(L,d); | ||
| 569 | mp_cur_consume(c,9); | ||
| 570 | } | ||
| 571 | break; | ||
| 572 | case 0xda: /* raw 16 */ | ||
| 573 | mp_cur_need(c,3); | ||
| 574 | { | ||
| 575 | size_t l = (c->p[1] << 8) | c->p[2]; | ||
| 576 | mp_cur_need(c,3+l); | ||
| 577 | lua_pushlstring(L,(char*)c->p+3,l); | ||
| 578 | mp_cur_consume(c,3+l); | ||
| 579 | } | ||
| 580 | break; | ||
| 581 | case 0xdb: /* raw 32 */ | ||
| 582 | mp_cur_need(c,5); | ||
| 583 | { | ||
| 584 | size_t l = (c->p[1] << 24) | | ||
| 585 | (c->p[2] << 16) | | ||
| 586 | (c->p[3] << 8) | | ||
| 587 | c->p[4]; | ||
| 588 | mp_cur_need(c,5+l); | ||
| 589 | lua_pushlstring(L,(char*)c->p+5,l); | ||
| 590 | mp_cur_consume(c,5+l); | ||
| 591 | } | ||
| 592 | break; | ||
| 593 | case 0xdc: /* array 16 */ | ||
| 594 | mp_cur_need(c,3); | ||
| 595 | { | ||
| 596 | size_t l = (c->p[1] << 8) | c->p[2]; | ||
| 597 | mp_cur_consume(c,3); | ||
| 598 | mp_decode_to_lua_array(L,c,l); | ||
| 599 | } | ||
| 600 | break; | ||
| 601 | case 0xdd: /* array 32 */ | ||
| 602 | mp_cur_need(c,5); | ||
| 603 | { | ||
| 604 | size_t l = (c->p[1] << 24) | | ||
| 605 | (c->p[2] << 16) | | ||
| 606 | (c->p[3] << 8) | | ||
| 607 | c->p[4]; | ||
| 608 | mp_cur_consume(c,5); | ||
| 609 | mp_decode_to_lua_array(L,c,l); | ||
| 610 | } | ||
| 611 | break; | ||
| 612 | case 0xde: /* map 16 */ | ||
| 613 | mp_cur_need(c,3); | ||
| 614 | { | ||
| 615 | size_t l = (c->p[1] << 8) | c->p[2]; | ||
| 616 | mp_cur_consume(c,3); | ||
| 617 | mp_decode_to_lua_hash(L,c,l); | ||
| 618 | } | ||
| 619 | break; | ||
| 620 | case 0xdf: /* map 32 */ | ||
| 621 | mp_cur_need(c,5); | ||
| 622 | { | ||
| 623 | size_t l = (c->p[1] << 24) | | ||
| 624 | (c->p[2] << 16) | | ||
| 625 | (c->p[3] << 8) | | ||
| 626 | c->p[4]; | ||
| 627 | mp_cur_consume(c,5); | ||
| 628 | mp_decode_to_lua_hash(L,c,l); | ||
| 629 | } | ||
| 630 | break; | ||
| 631 | default: /* types that can't be idenitified by first byte value. */ | ||
| 632 | if ((c->p[0] & 0x80) == 0) { /* positive fixnum */ | ||
| 633 | lua_pushnumber(L,c->p[0]); | ||
| 634 | mp_cur_consume(c,1); | ||
| 635 | } else if ((c->p[0] & 0xe0) == 0xe0) { /* negative fixnum */ | ||
| 636 | lua_pushnumber(L,(signed char)c->p[0]); | ||
| 637 | mp_cur_consume(c,1); | ||
| 638 | } else if ((c->p[0] & 0xe0) == 0xa0) { /* fix raw */ | ||
| 639 | size_t l = c->p[0] & 0x1f; | ||
| 640 | mp_cur_need(c,1+l); | ||
| 641 | lua_pushlstring(L,(char*)c->p+1,l); | ||
| 642 | mp_cur_consume(c,1+l); | ||
| 643 | } else if ((c->p[0] & 0xf0) == 0x90) { /* fix map */ | ||
| 644 | size_t l = c->p[0] & 0xf; | ||
| 645 | mp_cur_consume(c,1); | ||
| 646 | mp_decode_to_lua_array(L,c,l); | ||
| 647 | } else if ((c->p[0] & 0xf0) == 0x80) { /* fix map */ | ||
| 648 | size_t l = c->p[0] & 0xf; | ||
| 649 | mp_cur_consume(c,1); | ||
| 650 | mp_decode_to_lua_hash(L,c,l); | ||
| 651 | } else { | ||
| 652 | c->err = MP_CUR_ERROR_BADFMT; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | } | ||
| 656 | |||
| 657 | static int mp_unpack(lua_State *L) { | ||
| 658 | size_t len; | ||
| 659 | const unsigned char *s; | ||
| 660 | mp_cur *c; | ||
| 661 | |||
| 662 | if (!lua_isstring(L,-1)) { | ||
| 663 | lua_pushstring(L,"MessagePack decoding needs a string as input."); | ||
| 664 | lua_error(L); | ||
| 665 | } | ||
| 666 | |||
| 667 | s = (const unsigned char*) lua_tolstring(L,-1,&len); | ||
| 668 | c = mp_cur_new(s,len); | ||
| 669 | mp_decode_to_lua_type(L,c); | ||
| 670 | |||
| 671 | if (c->err == MP_CUR_ERROR_EOF) { | ||
| 672 | mp_cur_free(c); | ||
| 673 | lua_pushstring(L,"Missing bytes in input."); | ||
| 674 | lua_error(L); | ||
| 675 | } else if (c->err == MP_CUR_ERROR_BADFMT) { | ||
| 676 | mp_cur_free(c); | ||
| 677 | lua_pushstring(L,"Bad data format in input."); | ||
| 678 | lua_error(L); | ||
| 679 | } else if (c->left != 0) { | ||
| 680 | mp_cur_free(c); | ||
| 681 | lua_pushstring(L,"Extra bytes in input."); | ||
| 682 | lua_error(L); | ||
| 683 | } | ||
| 684 | mp_cur_free(c); | ||
| 685 | return 1; | ||
| 686 | } | ||
| 687 | |||
| 688 | /* ---------------------------------------------------------------------------- */ | ||
| 689 | |||
| 690 | static const struct luaL_Reg thislib[] = { | ||
| 691 | {"pack", mp_pack}, | ||
| 692 | {"unpack", mp_unpack}, | ||
| 693 | {NULL, NULL} | ||
| 694 | }; | ||
| 695 | |||
| 696 | LUALIB_API int luaopen_cmsgpack (lua_State *L) { | ||
| 697 | luaL_register(L, "cmsgpack", thislib); | ||
| 698 | |||
| 699 | lua_pushliteral(L, LUACMSGPACK_VERSION); | ||
| 700 | lua_setfield(L, -2, "_VERSION"); | ||
| 701 | lua_pushliteral(L, LUACMSGPACK_COPYRIGHT); | ||
| 702 | lua_setfield(L, -2, "_COPYRIGHT"); | ||
| 703 | lua_pushliteral(L, LUACMSGPACK_DESCRIPTION); | ||
| 704 | lua_setfield(L, -2, "_DESCRIPTION"); | ||
| 705 | return 1; | ||
| 706 | } | ||
| 707 | |||
| 708 | /****************************************************************************** | ||
| 709 | * Copyright (C) 2012 Salvatore Sanfilippo. All rights reserved. | ||
| 710 | * | ||
| 711 | * Permission is hereby granted, free of charge, to any person obtaining | ||
| 712 | * a copy of this software and associated documentation files (the | ||
| 713 | * "Software"), to deal in the Software without restriction, including | ||
| 714 | * without limitation the rights to use, copy, modify, merge, publish, | ||
| 715 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 716 | * permit persons to whom the Software is furnished to do so, subject to | ||
| 717 | * the following conditions: | ||
| 718 | * | ||
| 719 | * The above copyright notice and this permission notice shall be | ||
| 720 | * included in all copies or substantial portions of the Software. | ||
| 721 | * | ||
| 722 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 723 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 724 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| 725 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
| 726 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 727 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 728 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 729 | ******************************************************************************/ | ||