xref: /redis-3.2.3/deps/lua/src/lua_cmsgpack.c (revision 66e2bdf2)
136e6637dSantirez #include <math.h>
236e6637dSantirez #include <stdlib.h>
336e6637dSantirez #include <stdint.h>
436e6637dSantirez #include <string.h>
536e6637dSantirez #include <assert.h>
636e6637dSantirez 
736e6637dSantirez #include "lua.h"
836e6637dSantirez #include "lauxlib.h"
936e6637dSantirez 
1090b6337cSMatt Stancliff #define LUACMSGPACK_NAME        "cmsgpack"
1190b6337cSMatt Stancliff #define LUACMSGPACK_SAFE_NAME   "cmsgpack_safe"
1290b6337cSMatt Stancliff #define LUACMSGPACK_VERSION     "lua-cmsgpack 0.4.0"
1336e6637dSantirez #define LUACMSGPACK_COPYRIGHT   "Copyright (C) 2012, Salvatore Sanfilippo"
1436e6637dSantirez #define LUACMSGPACK_DESCRIPTION "MessagePack C implementation for Lua"
1536e6637dSantirez 
1690b6337cSMatt Stancliff /* Allows a preprocessor directive to override MAX_NESTING */
1790b6337cSMatt Stancliff #ifndef LUACMSGPACK_MAX_NESTING
1860643710SMatt Stancliff     #define LUACMSGPACK_MAX_NESTING  16 /* Max tables nesting. */
1990b6337cSMatt Stancliff #endif
2090b6337cSMatt Stancliff 
2190b6337cSMatt Stancliff /* Check if float or double can be an integer without loss of precision */
22ff25d189Santirez #define IS_INT_TYPE_EQUIVALENT(x, T) (!isinf(x) && (T)(x) == (x))
2390b6337cSMatt Stancliff 
2490b6337cSMatt Stancliff #define IS_INT64_EQUIVALENT(x) IS_INT_TYPE_EQUIVALENT(x, int64_t)
2590b6337cSMatt Stancliff #define IS_INT_EQUIVALENT(x) IS_INT_TYPE_EQUIVALENT(x, int)
2690b6337cSMatt Stancliff 
2760643710SMatt Stancliff /* If size of pointer is equal to a 4 byte integer, we're on 32 bits. */
2860643710SMatt Stancliff #if UINTPTR_MAX == UINT_MAX
2960643710SMatt Stancliff     #define BITS_32 1
3060643710SMatt Stancliff #else
3160643710SMatt Stancliff     #define BITS_32 0
3260643710SMatt Stancliff #endif
3360643710SMatt Stancliff 
3460643710SMatt Stancliff #if BITS_32
3560643710SMatt Stancliff     #define lua_pushunsigned(L, n) lua_pushnumber(L, n)
3660643710SMatt Stancliff #else
3790b6337cSMatt Stancliff     #define lua_pushunsigned(L, n) lua_pushinteger(L, n)
3890b6337cSMatt Stancliff #endif
3990b6337cSMatt Stancliff 
4090b6337cSMatt Stancliff /* =============================================================================
4190b6337cSMatt Stancliff  * MessagePack implementation and bindings for Lua 5.1/5.2.
4236e6637dSantirez  * Copyright(C) 2012 Salvatore Sanfilippo <[email protected]>
4336e6637dSantirez  *
4436e6637dSantirez  * http://github.com/antirez/lua-cmsgpack
4536e6637dSantirez  *
4636e6637dSantirez  * For MessagePack specification check the following web site:
4736e6637dSantirez  * http://wiki.msgpack.org/display/MSGPACK/Format+specification
4836e6637dSantirez  *
4936e6637dSantirez  * See Copyright Notice at the end of this file.
5036e6637dSantirez  *
5136e6637dSantirez  * CHANGELOG:
5236e6637dSantirez  * 19-Feb-2012 (ver 0.1.0): Initial release.
5336e6637dSantirez  * 20-Feb-2012 (ver 0.2.0): Tables encoding improved.
5436e6637dSantirez  * 20-Feb-2012 (ver 0.2.1): Minor bug fixing.
5536e6637dSantirez  * 20-Feb-2012 (ver 0.3.0): Module renamed lua-cmsgpack (was lua-msgpack).
5690b6337cSMatt Stancliff  * 04-Apr-2014 (ver 0.3.1): Lua 5.2 support and minor bug fix.
5790b6337cSMatt Stancliff  * 07-Apr-2014 (ver 0.4.0): Multiple pack/unpack, lua allocator, efficiency.
5890b6337cSMatt Stancliff  * ========================================================================== */
5936e6637dSantirez 
6090b6337cSMatt Stancliff /* -------------------------- Endian conversion --------------------------------
6190b6337cSMatt Stancliff  * We use it only for floats and doubles, all the other conversions performed
6236e6637dSantirez  * in an endian independent fashion. So the only thing we need is a function
6390b6337cSMatt Stancliff  * that swaps a binary string if arch is little endian (and left it untouched
6436e6637dSantirez  * otherwise). */
6536e6637dSantirez 
6636e6637dSantirez /* Reverse memory bytes if arch is little endian. Given the conceptual
6790b6337cSMatt Stancliff  * simplicity of the Lua build system we prefer check for endianess at runtime.
6836e6637dSantirez  * The performance difference should be acceptable. */
6936e6637dSantirez static void memrevifle(void *ptr, size_t len) {
7090b6337cSMatt Stancliff     unsigned char   *p = (unsigned char *)ptr,
7190b6337cSMatt Stancliff                     *e = (unsigned char *)p+len-1,
7290b6337cSMatt Stancliff                     aux;
7336e6637dSantirez     int test = 1;
7436e6637dSantirez     unsigned char *testp = (unsigned char*) &test;
7536e6637dSantirez 
7660643710SMatt Stancliff     if (testp[0] == 0) return; /* Big endian, nothing to do. */
7736e6637dSantirez     len /= 2;
7836e6637dSantirez     while(len--) {
7936e6637dSantirez         aux = *p;
8036e6637dSantirez         *p = *e;
8136e6637dSantirez         *e = aux;
8236e6637dSantirez         p++;
8336e6637dSantirez         e--;
8436e6637dSantirez     }
8536e6637dSantirez }
8636e6637dSantirez 
8790b6337cSMatt Stancliff /* ---------------------------- String buffer ----------------------------------
8860643710SMatt Stancliff  * This is a simple implementation of string buffers. The only operation
8936e6637dSantirez  * supported is creating empty buffers and appending bytes to it.
9036e6637dSantirez  * The string buffer uses 2x preallocation on every realloc for O(N) append
9136e6637dSantirez  * behavior.  */
9236e6637dSantirez 
9336e6637dSantirez typedef struct mp_buf {
9490b6337cSMatt Stancliff     lua_State *L;
9536e6637dSantirez     unsigned char *b;
9636e6637dSantirez     size_t len, free;
9736e6637dSantirez } mp_buf;
9836e6637dSantirez 
9990b6337cSMatt Stancliff static void *mp_realloc(lua_State *L, void *target, size_t osize,size_t nsize) {
10090b6337cSMatt Stancliff     void *(*local_realloc) (void *, void *, size_t osize, size_t nsize) = NULL;
10190b6337cSMatt Stancliff     void *ud;
10236e6637dSantirez 
10390b6337cSMatt Stancliff     local_realloc = lua_getallocf(L, &ud);
10490b6337cSMatt Stancliff 
10590b6337cSMatt Stancliff     return local_realloc(ud, target, osize, nsize);
10690b6337cSMatt Stancliff }
10790b6337cSMatt Stancliff 
10890b6337cSMatt Stancliff static mp_buf *mp_buf_new(lua_State *L) {
10990b6337cSMatt Stancliff     mp_buf *buf = NULL;
11090b6337cSMatt Stancliff 
11190b6337cSMatt Stancliff     /* Old size = 0; new size = sizeof(*buf) */
11260643710SMatt Stancliff     buf = (mp_buf*)mp_realloc(L, NULL, 0, sizeof(*buf));
11390b6337cSMatt Stancliff 
11490b6337cSMatt Stancliff     buf->L = L;
11536e6637dSantirez     buf->b = NULL;
11636e6637dSantirez     buf->len = buf->free = 0;
11736e6637dSantirez     return buf;
11836e6637dSantirez }
11936e6637dSantirez 
12090b6337cSMatt Stancliff static void mp_buf_append(mp_buf *buf, const unsigned char *s, size_t len) {
12136e6637dSantirez     if (buf->free < len) {
12236e6637dSantirez         size_t newlen = buf->len+len;
12336e6637dSantirez 
12490b6337cSMatt Stancliff         buf->b = (unsigned char*)mp_realloc(buf->L, buf->b, buf->len, newlen*2);
12536e6637dSantirez         buf->free = newlen;
12636e6637dSantirez     }
12736e6637dSantirez     memcpy(buf->b+buf->len,s,len);
12836e6637dSantirez     buf->len += len;
12936e6637dSantirez     buf->free -= len;
13036e6637dSantirez }
13136e6637dSantirez 
13236e6637dSantirez void mp_buf_free(mp_buf *buf) {
13390b6337cSMatt Stancliff     mp_realloc(buf->L, buf->b, buf->len, 0); /* realloc to 0 = free */
13490b6337cSMatt Stancliff     mp_realloc(buf->L, buf, sizeof(*buf), 0);
13536e6637dSantirez }
13636e6637dSantirez 
13790b6337cSMatt Stancliff /* ---------------------------- String cursor ----------------------------------
13836e6637dSantirez  * This simple data structure is used for parsing. Basically you create a cursor
13936e6637dSantirez  * using a string pointer and a length, then it is possible to access the
14036e6637dSantirez  * current string position with cursor->p, check the remaining length
14136e6637dSantirez  * in cursor->left, and finally consume more string using
14236e6637dSantirez  * mp_cur_consume(cursor,len), to advance 'p' and subtract 'left'.
14336e6637dSantirez  * An additional field cursor->error is set to zero on initialization and can
14436e6637dSantirez  * be used to report errors. */
14536e6637dSantirez 
14636e6637dSantirez #define MP_CUR_ERROR_NONE   0
14760643710SMatt Stancliff #define MP_CUR_ERROR_EOF    1   /* Not enough data to complete operation. */
14836e6637dSantirez #define MP_CUR_ERROR_BADFMT 2   /* Bad data format */
14936e6637dSantirez 
15036e6637dSantirez typedef struct mp_cur {
15136e6637dSantirez     const unsigned char *p;
15236e6637dSantirez     size_t left;
15336e6637dSantirez     int err;
15436e6637dSantirez } mp_cur;
15536e6637dSantirez 
15690b6337cSMatt Stancliff static void mp_cur_init(mp_cur *cursor, const unsigned char *s, size_t len) {
15736e6637dSantirez     cursor->p = s;
15836e6637dSantirez     cursor->left = len;
15936e6637dSantirez     cursor->err = MP_CUR_ERROR_NONE;
16036e6637dSantirez }
16136e6637dSantirez 
16236e6637dSantirez #define mp_cur_consume(_c,_len) do { _c->p += _len; _c->left -= _len; } while(0)
16336e6637dSantirez 
16460643710SMatt Stancliff /* When there is not enough room we set an error in the cursor and return. This
16536e6637dSantirez  * is very common across the code so we have a macro to make the code look
16636e6637dSantirez  * a bit simpler. */
16736e6637dSantirez #define mp_cur_need(_c,_len) do { \
16836e6637dSantirez     if (_c->left < _len) { \
16936e6637dSantirez         _c->err = MP_CUR_ERROR_EOF; \
17036e6637dSantirez         return; \
17136e6637dSantirez     } \
17236e6637dSantirez } while(0)
17336e6637dSantirez 
17490b6337cSMatt Stancliff /* ------------------------- Low level MP encoding -------------------------- */
17536e6637dSantirez 
17636e6637dSantirez static void mp_encode_bytes(mp_buf *buf, const unsigned char *s, size_t len) {
17736e6637dSantirez     unsigned char hdr[5];
17836e6637dSantirez     int hdrlen;
17936e6637dSantirez 
18036e6637dSantirez     if (len < 32) {
18136e6637dSantirez         hdr[0] = 0xa0 | (len&0xff); /* fix raw */
18236e6637dSantirez         hdrlen = 1;
18336e6637dSantirez     } else if (len <= 0xffff) {
18436e6637dSantirez         hdr[0] = 0xda;
18536e6637dSantirez         hdr[1] = (len&0xff00)>>8;
18636e6637dSantirez         hdr[2] = len&0xff;
18736e6637dSantirez         hdrlen = 3;
18836e6637dSantirez     } else {
18936e6637dSantirez         hdr[0] = 0xdb;
19036e6637dSantirez         hdr[1] = (len&0xff000000)>>24;
19136e6637dSantirez         hdr[2] = (len&0xff0000)>>16;
19236e6637dSantirez         hdr[3] = (len&0xff00)>>8;
19336e6637dSantirez         hdr[4] = len&0xff;
19436e6637dSantirez         hdrlen = 5;
19536e6637dSantirez     }
19636e6637dSantirez     mp_buf_append(buf,hdr,hdrlen);
19736e6637dSantirez     mp_buf_append(buf,s,len);
19836e6637dSantirez }
19936e6637dSantirez 
20036e6637dSantirez /* we assume IEEE 754 internal format for single and double precision floats. */
20136e6637dSantirez static void mp_encode_double(mp_buf *buf, double d) {
20236e6637dSantirez     unsigned char b[9];
20336e6637dSantirez     float f = d;
20436e6637dSantirez 
20536e6637dSantirez     assert(sizeof(f) == 4 && sizeof(d) == 8);
20636e6637dSantirez     if (d == (double)f) {
20736e6637dSantirez         b[0] = 0xca;    /* float IEEE 754 */
20836e6637dSantirez         memcpy(b+1,&f,4);
20936e6637dSantirez         memrevifle(b+1,4);
21036e6637dSantirez         mp_buf_append(buf,b,5);
21136e6637dSantirez     } else if (sizeof(d) == 8) {
21236e6637dSantirez         b[0] = 0xcb;    /* double IEEE 754 */
21336e6637dSantirez         memcpy(b+1,&d,8);
21436e6637dSantirez         memrevifle(b+1,8);
21536e6637dSantirez         mp_buf_append(buf,b,9);
21636e6637dSantirez     }
21736e6637dSantirez }
21836e6637dSantirez 
21936e6637dSantirez static void mp_encode_int(mp_buf *buf, int64_t n) {
22036e6637dSantirez     unsigned char b[9];
22136e6637dSantirez     int enclen;
22236e6637dSantirez 
22336e6637dSantirez     if (n >= 0) {
22436e6637dSantirez         if (n <= 127) {
22536e6637dSantirez             b[0] = n & 0x7f;    /* positive fixnum */
22636e6637dSantirez             enclen = 1;
22736e6637dSantirez         } else if (n <= 0xff) {
22836e6637dSantirez             b[0] = 0xcc;        /* uint 8 */
22936e6637dSantirez             b[1] = n & 0xff;
23036e6637dSantirez             enclen = 2;
23136e6637dSantirez         } else if (n <= 0xffff) {
23236e6637dSantirez             b[0] = 0xcd;        /* uint 16 */
23336e6637dSantirez             b[1] = (n & 0xff00) >> 8;
23436e6637dSantirez             b[2] = n & 0xff;
23536e6637dSantirez             enclen = 3;
23636e6637dSantirez         } else if (n <= 0xffffffffLL) {
23736e6637dSantirez             b[0] = 0xce;        /* uint 32 */
23836e6637dSantirez             b[1] = (n & 0xff000000) >> 24;
23936e6637dSantirez             b[2] = (n & 0xff0000) >> 16;
24036e6637dSantirez             b[3] = (n & 0xff00) >> 8;
24136e6637dSantirez             b[4] = n & 0xff;
24236e6637dSantirez             enclen = 5;
24336e6637dSantirez         } else {
24436e6637dSantirez             b[0] = 0xcf;        /* uint 64 */
24536e6637dSantirez             b[1] = (n & 0xff00000000000000LL) >> 56;
24636e6637dSantirez             b[2] = (n & 0xff000000000000LL) >> 48;
24736e6637dSantirez             b[3] = (n & 0xff0000000000LL) >> 40;
24836e6637dSantirez             b[4] = (n & 0xff00000000LL) >> 32;
24936e6637dSantirez             b[5] = (n & 0xff000000) >> 24;
25036e6637dSantirez             b[6] = (n & 0xff0000) >> 16;
25136e6637dSantirez             b[7] = (n & 0xff00) >> 8;
25236e6637dSantirez             b[8] = n & 0xff;
25336e6637dSantirez             enclen = 9;
25436e6637dSantirez         }
25536e6637dSantirez     } else {
25636e6637dSantirez         if (n >= -32) {
257*66e2bdf2Santirez             b[0] = ((signed char)n);   /* negative fixnum */
25836e6637dSantirez             enclen = 1;
25936e6637dSantirez         } else if (n >= -128) {
26036e6637dSantirez             b[0] = 0xd0;        /* int 8 */
26136e6637dSantirez             b[1] = n & 0xff;
26236e6637dSantirez             enclen = 2;
26336e6637dSantirez         } else if (n >= -32768) {
26436e6637dSantirez             b[0] = 0xd1;        /* int 16 */
26536e6637dSantirez             b[1] = (n & 0xff00) >> 8;
26636e6637dSantirez             b[2] = n & 0xff;
26736e6637dSantirez             enclen = 3;
26836e6637dSantirez         } else if (n >= -2147483648LL) {
26936e6637dSantirez             b[0] = 0xd2;        /* int 32 */
27036e6637dSantirez             b[1] = (n & 0xff000000) >> 24;
27136e6637dSantirez             b[2] = (n & 0xff0000) >> 16;
27236e6637dSantirez             b[3] = (n & 0xff00) >> 8;
27336e6637dSantirez             b[4] = n & 0xff;
27436e6637dSantirez             enclen = 5;
27536e6637dSantirez         } else {
27636e6637dSantirez             b[0] = 0xd3;        /* int 64 */
27736e6637dSantirez             b[1] = (n & 0xff00000000000000LL) >> 56;
27836e6637dSantirez             b[2] = (n & 0xff000000000000LL) >> 48;
27936e6637dSantirez             b[3] = (n & 0xff0000000000LL) >> 40;
28036e6637dSantirez             b[4] = (n & 0xff00000000LL) >> 32;
28136e6637dSantirez             b[5] = (n & 0xff000000) >> 24;
28236e6637dSantirez             b[6] = (n & 0xff0000) >> 16;
28336e6637dSantirez             b[7] = (n & 0xff00) >> 8;
28436e6637dSantirez             b[8] = n & 0xff;
28536e6637dSantirez             enclen = 9;
28636e6637dSantirez         }
28736e6637dSantirez     }
28836e6637dSantirez     mp_buf_append(buf,b,enclen);
28936e6637dSantirez }
29036e6637dSantirez 
29136e6637dSantirez static void mp_encode_array(mp_buf *buf, int64_t n) {
29236e6637dSantirez     unsigned char b[5];
29336e6637dSantirez     int enclen;
29436e6637dSantirez 
29536e6637dSantirez     if (n <= 15) {
29636e6637dSantirez         b[0] = 0x90 | (n & 0xf);    /* fix array */
29736e6637dSantirez         enclen = 1;
29836e6637dSantirez     } else if (n <= 65535) {
29936e6637dSantirez         b[0] = 0xdc;                /* array 16 */
30036e6637dSantirez         b[1] = (n & 0xff00) >> 8;
30136e6637dSantirez         b[2] = n & 0xff;
30236e6637dSantirez         enclen = 3;
30336e6637dSantirez     } else {
30436e6637dSantirez         b[0] = 0xdd;                /* array 32 */
30536e6637dSantirez         b[1] = (n & 0xff000000) >> 24;
30636e6637dSantirez         b[2] = (n & 0xff0000) >> 16;
30736e6637dSantirez         b[3] = (n & 0xff00) >> 8;
30836e6637dSantirez         b[4] = n & 0xff;
30936e6637dSantirez         enclen = 5;
31036e6637dSantirez     }
31136e6637dSantirez     mp_buf_append(buf,b,enclen);
31236e6637dSantirez }
31336e6637dSantirez 
31436e6637dSantirez static void mp_encode_map(mp_buf *buf, int64_t n) {
31536e6637dSantirez     unsigned char b[5];
31636e6637dSantirez     int enclen;
31736e6637dSantirez 
31836e6637dSantirez     if (n <= 15) {
31936e6637dSantirez         b[0] = 0x80 | (n & 0xf);    /* fix map */
32036e6637dSantirez         enclen = 1;
32136e6637dSantirez     } else if (n <= 65535) {
32236e6637dSantirez         b[0] = 0xde;                /* map 16 */
32336e6637dSantirez         b[1] = (n & 0xff00) >> 8;
32436e6637dSantirez         b[2] = n & 0xff;
32536e6637dSantirez         enclen = 3;
32636e6637dSantirez     } else {
32736e6637dSantirez         b[0] = 0xdf;                /* map 32 */
32836e6637dSantirez         b[1] = (n & 0xff000000) >> 24;
32936e6637dSantirez         b[2] = (n & 0xff0000) >> 16;
33036e6637dSantirez         b[3] = (n & 0xff00) >> 8;
33136e6637dSantirez         b[4] = n & 0xff;
33236e6637dSantirez         enclen = 5;
33336e6637dSantirez     }
33436e6637dSantirez     mp_buf_append(buf,b,enclen);
33536e6637dSantirez }
33636e6637dSantirez 
33790b6337cSMatt Stancliff /* --------------------------- Lua types encoding --------------------------- */
33836e6637dSantirez 
33936e6637dSantirez static void mp_encode_lua_string(lua_State *L, mp_buf *buf) {
34036e6637dSantirez     size_t len;
34136e6637dSantirez     const char *s;
34236e6637dSantirez 
34336e6637dSantirez     s = lua_tolstring(L,-1,&len);
34436e6637dSantirez     mp_encode_bytes(buf,(const unsigned char*)s,len);
34536e6637dSantirez }
34636e6637dSantirez 
34736e6637dSantirez static void mp_encode_lua_bool(lua_State *L, mp_buf *buf) {
34836e6637dSantirez     unsigned char b = lua_toboolean(L,-1) ? 0xc3 : 0xc2;
34936e6637dSantirez     mp_buf_append(buf,&b,1);
35036e6637dSantirez }
35136e6637dSantirez 
35290b6337cSMatt Stancliff /* Lua 5.3 has a built in 64-bit integer type */
35390b6337cSMatt Stancliff static void mp_encode_lua_integer(lua_State *L, mp_buf *buf) {
35460643710SMatt Stancliff #if (LUA_VERSION_NUM < 503) && BITS_32
35560643710SMatt Stancliff     lua_Number i = lua_tonumber(L,-1);
35660643710SMatt Stancliff #else
35790b6337cSMatt Stancliff     lua_Integer i = lua_tointeger(L,-1);
35860643710SMatt Stancliff #endif
35990b6337cSMatt Stancliff     mp_encode_int(buf, (int64_t)i);
36090b6337cSMatt Stancliff }
36190b6337cSMatt Stancliff 
36290b6337cSMatt Stancliff /* Lua 5.2 and lower only has 64-bit doubles, so we need to
36390b6337cSMatt Stancliff  * detect if the double may be representable as an int
36490b6337cSMatt Stancliff  * for Lua < 5.3 */
36536e6637dSantirez static void mp_encode_lua_number(lua_State *L, mp_buf *buf) {
36636e6637dSantirez     lua_Number n = lua_tonumber(L,-1);
36736e6637dSantirez 
36890b6337cSMatt Stancliff     if (IS_INT64_EQUIVALENT(n)) {
36990b6337cSMatt Stancliff         mp_encode_lua_integer(L, buf);
37036e6637dSantirez     } else {
37190b6337cSMatt Stancliff         mp_encode_double(buf,(double)n);
37236e6637dSantirez     }
37336e6637dSantirez }
37436e6637dSantirez 
37536e6637dSantirez static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level);
37636e6637dSantirez 
37736e6637dSantirez /* Convert a lua table into a message pack list. */
37836e6637dSantirez static void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) {
37990b6337cSMatt Stancliff #if LUA_VERSION_NUM < 502
38036e6637dSantirez     size_t len = lua_objlen(L,-1), j;
38190b6337cSMatt Stancliff #else
38290b6337cSMatt Stancliff     size_t len = lua_rawlen(L,-1), j;
38390b6337cSMatt Stancliff #endif
38436e6637dSantirez 
38536e6637dSantirez     mp_encode_array(buf,len);
38636e6637dSantirez     for (j = 1; j <= len; j++) {
38736e6637dSantirez         lua_pushnumber(L,j);
38836e6637dSantirez         lua_gettable(L,-2);
38936e6637dSantirez         mp_encode_lua_type(L,buf,level+1);
39036e6637dSantirez     }
39136e6637dSantirez }
39236e6637dSantirez 
39336e6637dSantirez /* Convert a lua table into a message pack key-value map. */
39436e6637dSantirez static void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) {
39536e6637dSantirez     size_t len = 0;
39636e6637dSantirez 
39736e6637dSantirez     /* First step: count keys into table. No other way to do it with the
39836e6637dSantirez      * Lua API, we need to iterate a first time. Note that an alternative
39936e6637dSantirez      * would be to do a single run, and then hack the buffer to insert the
40060643710SMatt Stancliff      * map opcodes for message pack. Too hackish for this lib. */
40136e6637dSantirez     lua_pushnil(L);
40236e6637dSantirez     while(lua_next(L,-2)) {
40336e6637dSantirez         lua_pop(L,1); /* remove value, keep key for next iteration. */
40436e6637dSantirez         len++;
40536e6637dSantirez     }
40636e6637dSantirez 
40736e6637dSantirez     /* Step two: actually encoding of the map. */
40836e6637dSantirez     mp_encode_map(buf,len);
40936e6637dSantirez     lua_pushnil(L);
41036e6637dSantirez     while(lua_next(L,-2)) {
41136e6637dSantirez         /* Stack: ... key value */
41236e6637dSantirez         lua_pushvalue(L,-2); /* Stack: ... key value key */
41336e6637dSantirez         mp_encode_lua_type(L,buf,level+1); /* encode key */
41436e6637dSantirez         mp_encode_lua_type(L,buf,level+1); /* encode val */
41536e6637dSantirez     }
41636e6637dSantirez }
41736e6637dSantirez 
41836e6637dSantirez /* Returns true if the Lua table on top of the stack is exclusively composed
41936e6637dSantirez  * of keys from numerical keys from 1 up to N, with N being the total number
42036e6637dSantirez  * of elements, without any hole in the middle. */
42136e6637dSantirez static int table_is_an_array(lua_State *L) {
42290b6337cSMatt Stancliff     int count = 0, max = 0;
42390b6337cSMatt Stancliff #if LUA_VERSION_NUM < 503
42436e6637dSantirez     lua_Number n;
42590b6337cSMatt Stancliff #else
42690b6337cSMatt Stancliff     lua_Integer n;
42790b6337cSMatt Stancliff #endif
42890b6337cSMatt Stancliff 
42990b6337cSMatt Stancliff     /* Stack top on function entry */
43090b6337cSMatt Stancliff     int stacktop;
43190b6337cSMatt Stancliff 
43290b6337cSMatt Stancliff     stacktop = lua_gettop(L);
43336e6637dSantirez 
43436e6637dSantirez     lua_pushnil(L);
43536e6637dSantirez     while(lua_next(L,-2)) {
43636e6637dSantirez         /* Stack: ... key value */
43736e6637dSantirez         lua_pop(L,1); /* Stack: ... key */
43890b6337cSMatt Stancliff         /* The <= 0 check is valid here because we're comparing indexes. */
43990b6337cSMatt Stancliff #if LUA_VERSION_NUM < 503
44060643710SMatt Stancliff         if ((LUA_TNUMBER != lua_type(L,-1)) || (n = lua_tonumber(L, -1)) <= 0 ||
44160643710SMatt Stancliff             !IS_INT_EQUIVALENT(n))
44290b6337cSMatt Stancliff #else
44360643710SMatt Stancliff         if (!lua_isinteger(L,-1) || (n = lua_tointeger(L, -1)) <= 0)
44490b6337cSMatt Stancliff #endif
44560643710SMatt Stancliff         {
44690b6337cSMatt Stancliff             lua_settop(L, stacktop);
44790b6337cSMatt Stancliff             return 0;
44890b6337cSMatt Stancliff         }
44990b6337cSMatt Stancliff         max = (n > max ? n : max);
45036e6637dSantirez         count++;
45136e6637dSantirez     }
45236e6637dSantirez     /* We have the total number of elements in "count". Also we have
45390b6337cSMatt Stancliff      * the max index encountered in "max". We can't reach this code
45436e6637dSantirez      * if there are indexes <= 0. If you also note that there can not be
45590b6337cSMatt Stancliff      * repeated keys into a table, you have that if max==count you are sure
45636e6637dSantirez      * that there are all the keys form 1 to count (both included). */
45790b6337cSMatt Stancliff     lua_settop(L, stacktop);
45890b6337cSMatt Stancliff     return max == count;
45936e6637dSantirez }
46036e6637dSantirez 
46136e6637dSantirez /* If the length operator returns non-zero, that is, there is at least
46236e6637dSantirez  * an object at key '1', we serialize to message pack list. Otherwise
46336e6637dSantirez  * we use a map. */
46436e6637dSantirez static void mp_encode_lua_table(lua_State *L, mp_buf *buf, int level) {
46536e6637dSantirez     if (table_is_an_array(L))
46636e6637dSantirez         mp_encode_lua_table_as_array(L,buf,level);
46736e6637dSantirez     else
46836e6637dSantirez         mp_encode_lua_table_as_map(L,buf,level);
46936e6637dSantirez }
47036e6637dSantirez 
47136e6637dSantirez static void mp_encode_lua_null(lua_State *L, mp_buf *buf) {
47236e6637dSantirez     unsigned char b[1];
47390b6337cSMatt Stancliff     (void)L;
47436e6637dSantirez 
47536e6637dSantirez     b[0] = 0xc0;
47636e6637dSantirez     mp_buf_append(buf,b,1);
47736e6637dSantirez }
47836e6637dSantirez 
47936e6637dSantirez static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level) {
48036e6637dSantirez     int t = lua_type(L,-1);
48136e6637dSantirez 
48260643710SMatt Stancliff     /* Limit the encoding of nested tables to a specified maximum depth, so that
48336e6637dSantirez      * we survive when called against circular references in tables. */
48436e6637dSantirez     if (t == LUA_TTABLE && level == LUACMSGPACK_MAX_NESTING) t = LUA_TNIL;
48536e6637dSantirez     switch(t) {
48636e6637dSantirez     case LUA_TSTRING: mp_encode_lua_string(L,buf); break;
48736e6637dSantirez     case LUA_TBOOLEAN: mp_encode_lua_bool(L,buf); break;
48890b6337cSMatt Stancliff     case LUA_TNUMBER:
48990b6337cSMatt Stancliff     #if LUA_VERSION_NUM < 503
49090b6337cSMatt Stancliff         mp_encode_lua_number(L,buf); break;
49190b6337cSMatt Stancliff     #else
49290b6337cSMatt Stancliff         if (lua_isinteger(L, -1)) {
49390b6337cSMatt Stancliff             mp_encode_lua_integer(L, buf);
49490b6337cSMatt Stancliff         } else {
49590b6337cSMatt Stancliff             mp_encode_lua_number(L, buf);
49690b6337cSMatt Stancliff         }
49790b6337cSMatt Stancliff         break;
49890b6337cSMatt Stancliff     #endif
49936e6637dSantirez     case LUA_TTABLE: mp_encode_lua_table(L,buf,level); break;
50036e6637dSantirez     default: mp_encode_lua_null(L,buf); break;
50136e6637dSantirez     }
50236e6637dSantirez     lua_pop(L,1);
50336e6637dSantirez }
50436e6637dSantirez 
50590b6337cSMatt Stancliff /*
50690b6337cSMatt Stancliff  * Packs all arguments as a stream for multiple upacking later.
50790b6337cSMatt Stancliff  * Returns error if no arguments provided.
50890b6337cSMatt Stancliff  */
50936e6637dSantirez static int mp_pack(lua_State *L) {
51090b6337cSMatt Stancliff     int nargs = lua_gettop(L);
51190b6337cSMatt Stancliff     int i;
51290b6337cSMatt Stancliff     mp_buf *buf;
51390b6337cSMatt Stancliff 
51490b6337cSMatt Stancliff     if (nargs == 0)
51590b6337cSMatt Stancliff         return luaL_argerror(L, 0, "MessagePack pack needs input.");
51690b6337cSMatt Stancliff 
51790b6337cSMatt Stancliff     buf = mp_buf_new(L);
51890b6337cSMatt Stancliff     for(i = 1; i <= nargs; i++) {
51990b6337cSMatt Stancliff         /* Copy argument i to top of stack for _encode processing;
52090b6337cSMatt Stancliff          * the encode function pops it from the stack when complete. */
52190b6337cSMatt Stancliff         lua_pushvalue(L, i);
52236e6637dSantirez 
52336e6637dSantirez         mp_encode_lua_type(L,buf,0);
52490b6337cSMatt Stancliff 
52536e6637dSantirez         lua_pushlstring(L,(char*)buf->b,buf->len);
52690b6337cSMatt Stancliff 
52790b6337cSMatt Stancliff         /* Reuse the buffer for the next operation by
52890b6337cSMatt Stancliff          * setting its free count to the total buffer size
52990b6337cSMatt Stancliff          * and the current position to zero. */
53090b6337cSMatt Stancliff         buf->free += buf->len;
53190b6337cSMatt Stancliff         buf->len = 0;
53290b6337cSMatt Stancliff     }
53336e6637dSantirez     mp_buf_free(buf);
53490b6337cSMatt Stancliff 
53590b6337cSMatt Stancliff     /* Concatenate all nargs buffers together */
53690b6337cSMatt Stancliff     lua_concat(L, nargs);
53736e6637dSantirez     return 1;
53836e6637dSantirez }
53936e6637dSantirez 
54090b6337cSMatt Stancliff /* ------------------------------- Decoding --------------------------------- */
54136e6637dSantirez 
54236e6637dSantirez void mp_decode_to_lua_type(lua_State *L, mp_cur *c);
54336e6637dSantirez 
54436e6637dSantirez void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) {
545*66e2bdf2Santirez     assert(len <= UINT_MAX);
54636e6637dSantirez     int index = 1;
54736e6637dSantirez 
54836e6637dSantirez     lua_newtable(L);
54936e6637dSantirez     while(len--) {
55036e6637dSantirez         lua_pushnumber(L,index++);
55136e6637dSantirez         mp_decode_to_lua_type(L,c);
55236e6637dSantirez         if (c->err) return;
55336e6637dSantirez         lua_settable(L,-3);
55436e6637dSantirez     }
55536e6637dSantirez }
55636e6637dSantirez 
55736e6637dSantirez void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) {
558*66e2bdf2Santirez     assert(len <= UINT_MAX);
55936e6637dSantirez     lua_newtable(L);
56036e6637dSantirez     while(len--) {
56136e6637dSantirez         mp_decode_to_lua_type(L,c); /* key */
56236e6637dSantirez         if (c->err) return;
56336e6637dSantirez         mp_decode_to_lua_type(L,c); /* value */
56436e6637dSantirez         if (c->err) return;
56536e6637dSantirez         lua_settable(L,-3);
56636e6637dSantirez     }
56736e6637dSantirez }
56836e6637dSantirez 
56936e6637dSantirez /* Decode a Message Pack raw object pointed by the string cursor 'c' to
57036e6637dSantirez  * a Lua type, that is left as the only result on the stack. */
57136e6637dSantirez void mp_decode_to_lua_type(lua_State *L, mp_cur *c) {
57236e6637dSantirez     mp_cur_need(c,1);
57390b6337cSMatt Stancliff 
57490b6337cSMatt Stancliff     /* If we return more than 18 elements, we must resize the stack to
57590b6337cSMatt Stancliff      * fit all our return values.  But, there is no way to
57690b6337cSMatt Stancliff      * determine how many objects a msgpack will unpack to up front, so
57790b6337cSMatt Stancliff      * we request a +1 larger stack on each iteration (noop if stack is
57890b6337cSMatt Stancliff      * big enough, and when stack does require resize it doubles in size) */
57990b6337cSMatt Stancliff     luaL_checkstack(L, 1,
58090b6337cSMatt Stancliff         "too many return values at once; "
58190b6337cSMatt Stancliff         "use unpack_one or unpack_limit instead.");
58290b6337cSMatt Stancliff 
58336e6637dSantirez     switch(c->p[0]) {
58436e6637dSantirez     case 0xcc:  /* uint 8 */
58536e6637dSantirez         mp_cur_need(c,2);
58690b6337cSMatt Stancliff         lua_pushunsigned(L,c->p[1]);
58736e6637dSantirez         mp_cur_consume(c,2);
58836e6637dSantirez         break;
58936e6637dSantirez     case 0xd0:  /* int 8 */
59036e6637dSantirez         mp_cur_need(c,2);
591*66e2bdf2Santirez         lua_pushinteger(L,(signed char)c->p[1]);
59236e6637dSantirez         mp_cur_consume(c,2);
59336e6637dSantirez         break;
59436e6637dSantirez     case 0xcd:  /* uint 16 */
59536e6637dSantirez         mp_cur_need(c,3);
59690b6337cSMatt Stancliff         lua_pushunsigned(L,
59736e6637dSantirez             (c->p[1] << 8) |
59836e6637dSantirez              c->p[2]);
59936e6637dSantirez         mp_cur_consume(c,3);
60036e6637dSantirez         break;
60136e6637dSantirez     case 0xd1:  /* int 16 */
60236e6637dSantirez         mp_cur_need(c,3);
60390b6337cSMatt Stancliff         lua_pushinteger(L,(int16_t)
60436e6637dSantirez             (c->p[1] << 8) |
60536e6637dSantirez              c->p[2]);
60636e6637dSantirez         mp_cur_consume(c,3);
60736e6637dSantirez         break;
60836e6637dSantirez     case 0xce:  /* uint 32 */
60936e6637dSantirez         mp_cur_need(c,5);
61090b6337cSMatt Stancliff         lua_pushunsigned(L,
61136e6637dSantirez             ((uint32_t)c->p[1] << 24) |
61236e6637dSantirez             ((uint32_t)c->p[2] << 16) |
61336e6637dSantirez             ((uint32_t)c->p[3] << 8) |
61436e6637dSantirez              (uint32_t)c->p[4]);
61536e6637dSantirez         mp_cur_consume(c,5);
61636e6637dSantirez         break;
61736e6637dSantirez     case 0xd2:  /* int 32 */
61836e6637dSantirez         mp_cur_need(c,5);
61990b6337cSMatt Stancliff         lua_pushinteger(L,
62036e6637dSantirez             ((int32_t)c->p[1] << 24) |
62136e6637dSantirez             ((int32_t)c->p[2] << 16) |
62236e6637dSantirez             ((int32_t)c->p[3] << 8) |
62336e6637dSantirez              (int32_t)c->p[4]);
62436e6637dSantirez         mp_cur_consume(c,5);
62536e6637dSantirez         break;
62636e6637dSantirez     case 0xcf:  /* uint 64 */
62736e6637dSantirez         mp_cur_need(c,9);
62890b6337cSMatt Stancliff         lua_pushunsigned(L,
62936e6637dSantirez             ((uint64_t)c->p[1] << 56) |
63036e6637dSantirez             ((uint64_t)c->p[2] << 48) |
63136e6637dSantirez             ((uint64_t)c->p[3] << 40) |
63236e6637dSantirez             ((uint64_t)c->p[4] << 32) |
63336e6637dSantirez             ((uint64_t)c->p[5] << 24) |
63436e6637dSantirez             ((uint64_t)c->p[6] << 16) |
63536e6637dSantirez             ((uint64_t)c->p[7] << 8) |
63636e6637dSantirez              (uint64_t)c->p[8]);
63736e6637dSantirez         mp_cur_consume(c,9);
63836e6637dSantirez         break;
63936e6637dSantirez     case 0xd3:  /* int 64 */
64036e6637dSantirez         mp_cur_need(c,9);
64160643710SMatt Stancliff #if LUA_VERSION_NUM < 503
64260643710SMatt Stancliff         lua_pushnumber(L,
64360643710SMatt Stancliff #else
64490b6337cSMatt Stancliff         lua_pushinteger(L,
64560643710SMatt Stancliff #endif
64636e6637dSantirez             ((int64_t)c->p[1] << 56) |
64736e6637dSantirez             ((int64_t)c->p[2] << 48) |
64836e6637dSantirez             ((int64_t)c->p[3] << 40) |
64936e6637dSantirez             ((int64_t)c->p[4] << 32) |
65036e6637dSantirez             ((int64_t)c->p[5] << 24) |
65136e6637dSantirez             ((int64_t)c->p[6] << 16) |
65236e6637dSantirez             ((int64_t)c->p[7] << 8) |
65336e6637dSantirez              (int64_t)c->p[8]);
65436e6637dSantirez         mp_cur_consume(c,9);
65536e6637dSantirez         break;
65636e6637dSantirez     case 0xc0:  /* nil */
65736e6637dSantirez         lua_pushnil(L);
65836e6637dSantirez         mp_cur_consume(c,1);
65936e6637dSantirez         break;
66036e6637dSantirez     case 0xc3:  /* true */
66136e6637dSantirez         lua_pushboolean(L,1);
66236e6637dSantirez         mp_cur_consume(c,1);
66336e6637dSantirez         break;
66436e6637dSantirez     case 0xc2:  /* false */
66536e6637dSantirez         lua_pushboolean(L,0);
66636e6637dSantirez         mp_cur_consume(c,1);
66736e6637dSantirez         break;
66836e6637dSantirez     case 0xca:  /* float */
66936e6637dSantirez         mp_cur_need(c,5);
67036e6637dSantirez         assert(sizeof(float) == 4);
67136e6637dSantirez         {
67236e6637dSantirez             float f;
67336e6637dSantirez             memcpy(&f,c->p+1,4);
67436e6637dSantirez             memrevifle(&f,4);
67536e6637dSantirez             lua_pushnumber(L,f);
67636e6637dSantirez             mp_cur_consume(c,5);
67736e6637dSantirez         }
67836e6637dSantirez         break;
67936e6637dSantirez     case 0xcb:  /* double */
68036e6637dSantirez         mp_cur_need(c,9);
68136e6637dSantirez         assert(sizeof(double) == 8);
68236e6637dSantirez         {
68336e6637dSantirez             double d;
68436e6637dSantirez             memcpy(&d,c->p+1,8);
68536e6637dSantirez             memrevifle(&d,8);
68636e6637dSantirez             lua_pushnumber(L,d);
68736e6637dSantirez             mp_cur_consume(c,9);
68836e6637dSantirez         }
68936e6637dSantirez         break;
69036e6637dSantirez     case 0xda:  /* raw 16 */
69136e6637dSantirez         mp_cur_need(c,3);
69236e6637dSantirez         {
69336e6637dSantirez             size_t l = (c->p[1] << 8) | c->p[2];
69436e6637dSantirez             mp_cur_need(c,3+l);
69536e6637dSantirez             lua_pushlstring(L,(char*)c->p+3,l);
69636e6637dSantirez             mp_cur_consume(c,3+l);
69736e6637dSantirez         }
69836e6637dSantirez         break;
69936e6637dSantirez     case 0xdb:  /* raw 32 */
70036e6637dSantirez         mp_cur_need(c,5);
70136e6637dSantirez         {
702*66e2bdf2Santirez             size_t l = ((size_t)c->p[1] << 24) |
703*66e2bdf2Santirez                        ((size_t)c->p[2] << 16) |
704*66e2bdf2Santirez                        ((size_t)c->p[3] << 8) |
705*66e2bdf2Santirez                        (size_t)c->p[4];
706*66e2bdf2Santirez             mp_cur_consume(c,5);
707*66e2bdf2Santirez             mp_cur_need(c,l);
708*66e2bdf2Santirez             lua_pushlstring(L,(char*)c->p,l);
709*66e2bdf2Santirez             mp_cur_consume(c,l);
71036e6637dSantirez         }
71136e6637dSantirez         break;
71236e6637dSantirez     case 0xdc:  /* array 16 */
71336e6637dSantirez         mp_cur_need(c,3);
71436e6637dSantirez         {
71536e6637dSantirez             size_t l = (c->p[1] << 8) | c->p[2];
71636e6637dSantirez             mp_cur_consume(c,3);
71736e6637dSantirez             mp_decode_to_lua_array(L,c,l);
71836e6637dSantirez         }
71936e6637dSantirez         break;
72036e6637dSantirez     case 0xdd:  /* array 32 */
72136e6637dSantirez         mp_cur_need(c,5);
72236e6637dSantirez         {
723*66e2bdf2Santirez             size_t l = ((size_t)c->p[1] << 24) |
724*66e2bdf2Santirez                        ((size_t)c->p[2] << 16) |
725*66e2bdf2Santirez                        ((size_t)c->p[3] << 8) |
726*66e2bdf2Santirez                        (size_t)c->p[4];
72736e6637dSantirez             mp_cur_consume(c,5);
72836e6637dSantirez             mp_decode_to_lua_array(L,c,l);
72936e6637dSantirez         }
73036e6637dSantirez         break;
73136e6637dSantirez     case 0xde:  /* map 16 */
73236e6637dSantirez         mp_cur_need(c,3);
73336e6637dSantirez         {
73436e6637dSantirez             size_t l = (c->p[1] << 8) | c->p[2];
73536e6637dSantirez             mp_cur_consume(c,3);
73636e6637dSantirez             mp_decode_to_lua_hash(L,c,l);
73736e6637dSantirez         }
73836e6637dSantirez         break;
73936e6637dSantirez     case 0xdf:  /* map 32 */
74036e6637dSantirez         mp_cur_need(c,5);
74136e6637dSantirez         {
742*66e2bdf2Santirez             size_t l = ((size_t)c->p[1] << 24) |
743*66e2bdf2Santirez                        ((size_t)c->p[2] << 16) |
744*66e2bdf2Santirez                        ((size_t)c->p[3] << 8) |
745*66e2bdf2Santirez                        (size_t)c->p[4];
74636e6637dSantirez             mp_cur_consume(c,5);
74736e6637dSantirez             mp_decode_to_lua_hash(L,c,l);
74836e6637dSantirez         }
74936e6637dSantirez         break;
75036e6637dSantirez     default:    /* types that can't be idenitified by first byte value. */
75136e6637dSantirez         if ((c->p[0] & 0x80) == 0) {   /* positive fixnum */
75290b6337cSMatt Stancliff             lua_pushunsigned(L,c->p[0]);
75336e6637dSantirez             mp_cur_consume(c,1);
75436e6637dSantirez         } else if ((c->p[0] & 0xe0) == 0xe0) {  /* negative fixnum */
75590b6337cSMatt Stancliff             lua_pushinteger(L,(signed char)c->p[0]);
75636e6637dSantirez             mp_cur_consume(c,1);
75736e6637dSantirez         } else if ((c->p[0] & 0xe0) == 0xa0) {  /* fix raw */
75836e6637dSantirez             size_t l = c->p[0] & 0x1f;
75936e6637dSantirez             mp_cur_need(c,1+l);
76036e6637dSantirez             lua_pushlstring(L,(char*)c->p+1,l);
76136e6637dSantirez             mp_cur_consume(c,1+l);
76236e6637dSantirez         } else if ((c->p[0] & 0xf0) == 0x90) {  /* fix map */
76336e6637dSantirez             size_t l = c->p[0] & 0xf;
76436e6637dSantirez             mp_cur_consume(c,1);
76536e6637dSantirez             mp_decode_to_lua_array(L,c,l);
76636e6637dSantirez         } else if ((c->p[0] & 0xf0) == 0x80) {  /* fix map */
76736e6637dSantirez             size_t l = c->p[0] & 0xf;
76836e6637dSantirez             mp_cur_consume(c,1);
76936e6637dSantirez             mp_decode_to_lua_hash(L,c,l);
77036e6637dSantirez         } else {
77136e6637dSantirez             c->err = MP_CUR_ERROR_BADFMT;
77236e6637dSantirez         }
77336e6637dSantirez     }
77436e6637dSantirez }
77536e6637dSantirez 
77690b6337cSMatt Stancliff static int mp_unpack_full(lua_State *L, int limit, int offset) {
77736e6637dSantirez     size_t len;
77890b6337cSMatt Stancliff     const char *s;
77990b6337cSMatt Stancliff     mp_cur c;
78090b6337cSMatt Stancliff     int cnt; /* Number of objects unpacked */
78190b6337cSMatt Stancliff     int decode_all = (!limit && !offset);
78236e6637dSantirez 
78390b6337cSMatt Stancliff     s = luaL_checklstring(L,1,&len); /* if no match, exits */
78490b6337cSMatt Stancliff 
78590b6337cSMatt Stancliff     if (offset < 0 || limit < 0) /* requesting negative off or lim is invalid */
78690b6337cSMatt Stancliff         return luaL_error(L,
78790b6337cSMatt Stancliff             "Invalid request to unpack with offset of %d and limit of %d.",
78890b6337cSMatt Stancliff             offset, len);
78990b6337cSMatt Stancliff     else if (offset > len)
79090b6337cSMatt Stancliff         return luaL_error(L,
79190b6337cSMatt Stancliff             "Start offset %d greater than input length %d.", offset, len);
79290b6337cSMatt Stancliff 
79390b6337cSMatt Stancliff     if (decode_all) limit = INT_MAX;
79490b6337cSMatt Stancliff 
79590b6337cSMatt Stancliff     mp_cur_init(&c,(const unsigned char *)s+offset,len-offset);
79690b6337cSMatt Stancliff 
79790b6337cSMatt Stancliff     /* We loop over the decode because this could be a stream
79890b6337cSMatt Stancliff      * of multiple top-level values serialized together */
79990b6337cSMatt Stancliff     for(cnt = 0; c.left > 0 && cnt < limit; cnt++) {
80090b6337cSMatt Stancliff         mp_decode_to_lua_type(L,&c);
80190b6337cSMatt Stancliff 
80290b6337cSMatt Stancliff         if (c.err == MP_CUR_ERROR_EOF) {
80390b6337cSMatt Stancliff             return luaL_error(L,"Missing bytes in input.");
80490b6337cSMatt Stancliff         } else if (c.err == MP_CUR_ERROR_BADFMT) {
80590b6337cSMatt Stancliff             return luaL_error(L,"Bad data format in input.");
80690b6337cSMatt Stancliff         }
80736e6637dSantirez     }
80836e6637dSantirez 
80990b6337cSMatt Stancliff     if (!decode_all) {
81090b6337cSMatt Stancliff         /* c->left is the remaining size of the input buffer.
81190b6337cSMatt Stancliff          * subtract the entire buffer size from the unprocessed size
81290b6337cSMatt Stancliff          * to get our next start offset */
81390b6337cSMatt Stancliff         int offset = len - c.left;
81490b6337cSMatt Stancliff         /* Return offset -1 when we have have processed the entire buffer. */
81590b6337cSMatt Stancliff         lua_pushinteger(L, c.left == 0 ? -1 : offset);
81690b6337cSMatt Stancliff         /* Results are returned with the arg elements still
81790b6337cSMatt Stancliff          * in place. Lua takes care of only returning
81890b6337cSMatt Stancliff          * elements above the args for us.
81990b6337cSMatt Stancliff          * In this case, we have one arg on the stack
82090b6337cSMatt Stancliff          * for this function, so we insert our first return
82190b6337cSMatt Stancliff          * value at position 2. */
82290b6337cSMatt Stancliff         lua_insert(L, 2);
82390b6337cSMatt Stancliff         cnt += 1; /* increase return count by one to make room for offset */
82436e6637dSantirez     }
82536e6637dSantirez 
82690b6337cSMatt Stancliff     return cnt;
82790b6337cSMatt Stancliff }
82836e6637dSantirez 
82990b6337cSMatt Stancliff static int mp_unpack(lua_State *L) {
83090b6337cSMatt Stancliff     return mp_unpack_full(L, 0, 0);
83190b6337cSMatt Stancliff }
83290b6337cSMatt Stancliff 
83390b6337cSMatt Stancliff static int mp_unpack_one(lua_State *L) {
834*66e2bdf2Santirez     int offset = luaL_optinteger(L, 2, 0);
83590b6337cSMatt Stancliff     /* Variable pop because offset may not exist */
83690b6337cSMatt Stancliff     lua_pop(L, lua_gettop(L)-1);
83790b6337cSMatt Stancliff     return mp_unpack_full(L, 1, offset);
83890b6337cSMatt Stancliff }
83990b6337cSMatt Stancliff 
84090b6337cSMatt Stancliff static int mp_unpack_limit(lua_State *L) {
841*66e2bdf2Santirez     int limit = luaL_checkinteger(L, 2);
842*66e2bdf2Santirez     int offset = luaL_optinteger(L, 3, 0);
84390b6337cSMatt Stancliff     /* Variable pop because offset may not exist */
84490b6337cSMatt Stancliff     lua_pop(L, lua_gettop(L)-1);
84590b6337cSMatt Stancliff 
84690b6337cSMatt Stancliff     return mp_unpack_full(L, limit, offset);
84790b6337cSMatt Stancliff }
84890b6337cSMatt Stancliff 
84990b6337cSMatt Stancliff static int mp_safe(lua_State *L) {
85090b6337cSMatt Stancliff     int argc, err, total_results;
85190b6337cSMatt Stancliff 
85290b6337cSMatt Stancliff     argc = lua_gettop(L);
85390b6337cSMatt Stancliff 
85490b6337cSMatt Stancliff     /* This adds our function to the bottom of the stack
85590b6337cSMatt Stancliff      * (the "call this function" position) */
85690b6337cSMatt Stancliff     lua_pushvalue(L, lua_upvalueindex(1));
85790b6337cSMatt Stancliff     lua_insert(L, 1);
85890b6337cSMatt Stancliff 
85990b6337cSMatt Stancliff     err = lua_pcall(L, argc, LUA_MULTRET, 0);
86090b6337cSMatt Stancliff     total_results = lua_gettop(L);
86190b6337cSMatt Stancliff 
86290b6337cSMatt Stancliff     if (!err) {
86390b6337cSMatt Stancliff         return total_results;
86490b6337cSMatt Stancliff     } else {
86590b6337cSMatt Stancliff         lua_pushnil(L);
86690b6337cSMatt Stancliff         lua_insert(L,-2);
86790b6337cSMatt Stancliff         return 2;
86890b6337cSMatt Stancliff     }
86990b6337cSMatt Stancliff }
87090b6337cSMatt Stancliff 
87190b6337cSMatt Stancliff /* -------------------------------------------------------------------------- */
87290b6337cSMatt Stancliff static const struct luaL_Reg cmds[] = {
87336e6637dSantirez     {"pack", mp_pack},
87436e6637dSantirez     {"unpack", mp_unpack},
87590b6337cSMatt Stancliff     {"unpack_one", mp_unpack_one},
87690b6337cSMatt Stancliff     {"unpack_limit", mp_unpack_limit},
87790b6337cSMatt Stancliff     {0}
87836e6637dSantirez };
87936e6637dSantirez 
88090b6337cSMatt Stancliff static int luaopen_create(lua_State *L) {
88190b6337cSMatt Stancliff     int i;
88290b6337cSMatt Stancliff     /* Manually construct our module table instead of
88390b6337cSMatt Stancliff      * relying on _register or _newlib */
88490b6337cSMatt Stancliff     lua_newtable(L);
88536e6637dSantirez 
88690b6337cSMatt Stancliff     for (i = 0; i < (sizeof(cmds)/sizeof(*cmds) - 1); i++) {
88790b6337cSMatt Stancliff         lua_pushcfunction(L, cmds[i].func);
88890b6337cSMatt Stancliff         lua_setfield(L, -2, cmds[i].name);
88990b6337cSMatt Stancliff     }
89090b6337cSMatt Stancliff 
89190b6337cSMatt Stancliff     /* Add metadata */
89290b6337cSMatt Stancliff     lua_pushliteral(L, LUACMSGPACK_NAME);
89390b6337cSMatt Stancliff     lua_setfield(L, -2, "_NAME");
89436e6637dSantirez     lua_pushliteral(L, LUACMSGPACK_VERSION);
89536e6637dSantirez     lua_setfield(L, -2, "_VERSION");
89636e6637dSantirez     lua_pushliteral(L, LUACMSGPACK_COPYRIGHT);
89736e6637dSantirez     lua_setfield(L, -2, "_COPYRIGHT");
89836e6637dSantirez     lua_pushliteral(L, LUACMSGPACK_DESCRIPTION);
89936e6637dSantirez     lua_setfield(L, -2, "_DESCRIPTION");
90036e6637dSantirez     return 1;
90136e6637dSantirez }
90236e6637dSantirez 
90390b6337cSMatt Stancliff LUALIB_API int luaopen_cmsgpack(lua_State *L) {
90490b6337cSMatt Stancliff     luaopen_create(L);
90590b6337cSMatt Stancliff 
90690b6337cSMatt Stancliff #if LUA_VERSION_NUM < 502
90790b6337cSMatt Stancliff     /* Register name globally for 5.1 */
90890b6337cSMatt Stancliff     lua_pushvalue(L, -1);
90990b6337cSMatt Stancliff     lua_setglobal(L, LUACMSGPACK_NAME);
91090b6337cSMatt Stancliff #endif
91190b6337cSMatt Stancliff 
91290b6337cSMatt Stancliff     return 1;
91390b6337cSMatt Stancliff }
91490b6337cSMatt Stancliff 
91590b6337cSMatt Stancliff LUALIB_API int luaopen_cmsgpack_safe(lua_State *L) {
91690b6337cSMatt Stancliff     int i;
91790b6337cSMatt Stancliff 
91890b6337cSMatt Stancliff     luaopen_cmsgpack(L);
91990b6337cSMatt Stancliff 
92090b6337cSMatt Stancliff     /* Wrap all functions in the safe handler */
92190b6337cSMatt Stancliff     for (i = 0; i < (sizeof(cmds)/sizeof(*cmds) - 1); i++) {
92290b6337cSMatt Stancliff         lua_getfield(L, -1, cmds[i].name);
92390b6337cSMatt Stancliff         lua_pushcclosure(L, mp_safe, 1);
92490b6337cSMatt Stancliff         lua_setfield(L, -2, cmds[i].name);
92590b6337cSMatt Stancliff     }
92690b6337cSMatt Stancliff 
92790b6337cSMatt Stancliff #if LUA_VERSION_NUM < 502
92890b6337cSMatt Stancliff     /* Register name globally for 5.1 */
92990b6337cSMatt Stancliff     lua_pushvalue(L, -1);
93090b6337cSMatt Stancliff     lua_setglobal(L, LUACMSGPACK_SAFE_NAME);
93190b6337cSMatt Stancliff #endif
93290b6337cSMatt Stancliff 
93390b6337cSMatt Stancliff     return 1;
93490b6337cSMatt Stancliff }
93590b6337cSMatt Stancliff 
93636e6637dSantirez /******************************************************************************
93736e6637dSantirez * Copyright (C) 2012 Salvatore Sanfilippo.  All rights reserved.
93836e6637dSantirez *
93936e6637dSantirez * Permission is hereby granted, free of charge, to any person obtaining
94036e6637dSantirez * a copy of this software and associated documentation files (the
94136e6637dSantirez * "Software"), to deal in the Software without restriction, including
94236e6637dSantirez * without limitation the rights to use, copy, modify, merge, publish,
94336e6637dSantirez * distribute, sublicense, and/or sell copies of the Software, and to
94436e6637dSantirez * permit persons to whom the Software is furnished to do so, subject to
94536e6637dSantirez * the following conditions:
94636e6637dSantirez *
94736e6637dSantirez * The above copyright notice and this permission notice shall be
94836e6637dSantirez * included in all copies or substantial portions of the Software.
94936e6637dSantirez *
95036e6637dSantirez * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
95136e6637dSantirez * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
95236e6637dSantirez * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
95336e6637dSantirez * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
95436e6637dSantirez * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
95536e6637dSantirez * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
95636e6637dSantirez * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
95736e6637dSantirez ******************************************************************************/
958