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 | +******************************************************************************/ | |