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. */
memrevifle(void * ptr,size_t len)69357a40c4Santirez 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 {
9436e6637dSantirez unsigned char *b;
9536e6637dSantirez size_t len, free;
9636e6637dSantirez } mp_buf;
9736e6637dSantirez
mp_realloc(lua_State * L,void * target,size_t osize,size_t nsize)98357a40c4Santirez void *mp_realloc(lua_State *L, void *target, size_t osize,size_t nsize) {
9990b6337cSMatt Stancliff void *(*local_realloc) (void *, void *, size_t osize, size_t nsize) = NULL;
10090b6337cSMatt Stancliff void *ud;
10136e6637dSantirez
10290b6337cSMatt Stancliff local_realloc = lua_getallocf(L, &ud);
10390b6337cSMatt Stancliff
10490b6337cSMatt Stancliff return local_realloc(ud, target, osize, nsize);
10590b6337cSMatt Stancliff }
10690b6337cSMatt Stancliff
mp_buf_new(lua_State * L)107357a40c4Santirez mp_buf *mp_buf_new(lua_State *L) {
10890b6337cSMatt Stancliff mp_buf *buf = NULL;
10990b6337cSMatt Stancliff
11090b6337cSMatt Stancliff /* Old size = 0; new size = sizeof(*buf) */
11160643710SMatt Stancliff buf = (mp_buf*)mp_realloc(L, NULL, 0, sizeof(*buf));
11290b6337cSMatt Stancliff
11336e6637dSantirez buf->b = NULL;
11436e6637dSantirez buf->len = buf->free = 0;
11536e6637dSantirez return buf;
11636e6637dSantirez }
11736e6637dSantirez
mp_buf_append(lua_State * L,mp_buf * buf,const unsigned char * s,size_t len)118*0b4a628fSantirez void mp_buf_append(lua_State *L, mp_buf *buf, const unsigned char *s, size_t len) {
11936e6637dSantirez if (buf->free < len) {
12043509f68S[email protected] size_t newsize = (buf->len+len)*2;
12136e6637dSantirez
122*0b4a628fSantirez buf->b = (unsigned char*)mp_realloc(L, buf->b, buf->len + buf->free, newsize);
12343509f68S[email protected] buf->free = newsize - buf->len;
12436e6637dSantirez }
12536e6637dSantirez memcpy(buf->b+buf->len,s,len);
12636e6637dSantirez buf->len += len;
12736e6637dSantirez buf->free -= len;
12836e6637dSantirez }
12936e6637dSantirez
mp_buf_free(lua_State * L,mp_buf * buf)130*0b4a628fSantirez void mp_buf_free(lua_State *L, mp_buf *buf) {
131*0b4a628fSantirez mp_realloc(L, buf->b, buf->len + buf->free, 0); /* realloc to 0 = free */
132*0b4a628fSantirez mp_realloc(L, buf, sizeof(*buf), 0);
13336e6637dSantirez }
13436e6637dSantirez
13590b6337cSMatt Stancliff /* ---------------------------- String cursor ----------------------------------
13636e6637dSantirez * This simple data structure is used for parsing. Basically you create a cursor
13736e6637dSantirez * using a string pointer and a length, then it is possible to access the
13836e6637dSantirez * current string position with cursor->p, check the remaining length
13936e6637dSantirez * in cursor->left, and finally consume more string using
14036e6637dSantirez * mp_cur_consume(cursor,len), to advance 'p' and subtract 'left'.
14136e6637dSantirez * An additional field cursor->error is set to zero on initialization and can
14236e6637dSantirez * be used to report errors. */
14336e6637dSantirez
14436e6637dSantirez #define MP_CUR_ERROR_NONE 0
14560643710SMatt Stancliff #define MP_CUR_ERROR_EOF 1 /* Not enough data to complete operation. */
14636e6637dSantirez #define MP_CUR_ERROR_BADFMT 2 /* Bad data format */
14736e6637dSantirez
14836e6637dSantirez typedef struct mp_cur {
14936e6637dSantirez const unsigned char *p;
15036e6637dSantirez size_t left;
15136e6637dSantirez int err;
15236e6637dSantirez } mp_cur;
15336e6637dSantirez
mp_cur_init(mp_cur * cursor,const unsigned char * s,size_t len)154357a40c4Santirez void mp_cur_init(mp_cur *cursor, const unsigned char *s, size_t len) {
15536e6637dSantirez cursor->p = s;
15636e6637dSantirez cursor->left = len;
15736e6637dSantirez cursor->err = MP_CUR_ERROR_NONE;
15836e6637dSantirez }
15936e6637dSantirez
16036e6637dSantirez #define mp_cur_consume(_c,_len) do { _c->p += _len; _c->left -= _len; } while(0)
16136e6637dSantirez
16260643710SMatt Stancliff /* When there is not enough room we set an error in the cursor and return. This
16336e6637dSantirez * is very common across the code so we have a macro to make the code look
16436e6637dSantirez * a bit simpler. */
16536e6637dSantirez #define mp_cur_need(_c,_len) do { \
16636e6637dSantirez if (_c->left < _len) { \
16736e6637dSantirez _c->err = MP_CUR_ERROR_EOF; \
16836e6637dSantirez return; \
16936e6637dSantirez } \
17036e6637dSantirez } while(0)
17136e6637dSantirez
17290b6337cSMatt Stancliff /* ------------------------- Low level MP encoding -------------------------- */
17336e6637dSantirez
mp_encode_bytes(lua_State * L,mp_buf * buf,const unsigned char * s,size_t len)174*0b4a628fSantirez void mp_encode_bytes(lua_State *L, mp_buf *buf, const unsigned char *s, size_t len) {
17536e6637dSantirez unsigned char hdr[5];
17636e6637dSantirez int hdrlen;
17736e6637dSantirez
17836e6637dSantirez if (len < 32) {
17936e6637dSantirez hdr[0] = 0xa0 | (len&0xff); /* fix raw */
18036e6637dSantirez hdrlen = 1;
181357a40c4Santirez } else if (len <= 0xff) {
182357a40c4Santirez hdr[0] = 0xd9;
183357a40c4Santirez hdr[1] = len;
184357a40c4Santirez hdrlen = 2;
18536e6637dSantirez } else if (len <= 0xffff) {
18636e6637dSantirez hdr[0] = 0xda;
18736e6637dSantirez hdr[1] = (len&0xff00)>>8;
18836e6637dSantirez hdr[2] = len&0xff;
18936e6637dSantirez hdrlen = 3;
19036e6637dSantirez } else {
19136e6637dSantirez hdr[0] = 0xdb;
19236e6637dSantirez hdr[1] = (len&0xff000000)>>24;
19336e6637dSantirez hdr[2] = (len&0xff0000)>>16;
19436e6637dSantirez hdr[3] = (len&0xff00)>>8;
19536e6637dSantirez hdr[4] = len&0xff;
19636e6637dSantirez hdrlen = 5;
19736e6637dSantirez }
198*0b4a628fSantirez mp_buf_append(L,buf,hdr,hdrlen);
199*0b4a628fSantirez mp_buf_append(L,buf,s,len);
20036e6637dSantirez }
20136e6637dSantirez
20236e6637dSantirez /* we assume IEEE 754 internal format for single and double precision floats. */
mp_encode_double(lua_State * L,mp_buf * buf,double d)203*0b4a628fSantirez void mp_encode_double(lua_State *L, mp_buf *buf, double d) {
20436e6637dSantirez unsigned char b[9];
20536e6637dSantirez float f = d;
20636e6637dSantirez
20736e6637dSantirez assert(sizeof(f) == 4 && sizeof(d) == 8);
20836e6637dSantirez if (d == (double)f) {
20936e6637dSantirez b[0] = 0xca; /* float IEEE 754 */
21036e6637dSantirez memcpy(b+1,&f,4);
21136e6637dSantirez memrevifle(b+1,4);
212*0b4a628fSantirez mp_buf_append(L,buf,b,5);
21336e6637dSantirez } else if (sizeof(d) == 8) {
21436e6637dSantirez b[0] = 0xcb; /* double IEEE 754 */
21536e6637dSantirez memcpy(b+1,&d,8);
21636e6637dSantirez memrevifle(b+1,8);
217*0b4a628fSantirez mp_buf_append(L,buf,b,9);
21836e6637dSantirez }
21936e6637dSantirez }
22036e6637dSantirez
mp_encode_int(lua_State * L,mp_buf * buf,int64_t n)221*0b4a628fSantirez void mp_encode_int(lua_State *L, mp_buf *buf, int64_t n) {
22236e6637dSantirez unsigned char b[9];
22336e6637dSantirez int enclen;
22436e6637dSantirez
22536e6637dSantirez if (n >= 0) {
22636e6637dSantirez if (n <= 127) {
22736e6637dSantirez b[0] = n & 0x7f; /* positive fixnum */
22836e6637dSantirez enclen = 1;
22936e6637dSantirez } else if (n <= 0xff) {
23036e6637dSantirez b[0] = 0xcc; /* uint 8 */
23136e6637dSantirez b[1] = n & 0xff;
23236e6637dSantirez enclen = 2;
23336e6637dSantirez } else if (n <= 0xffff) {
23436e6637dSantirez b[0] = 0xcd; /* uint 16 */
23536e6637dSantirez b[1] = (n & 0xff00) >> 8;
23636e6637dSantirez b[2] = n & 0xff;
23736e6637dSantirez enclen = 3;
23836e6637dSantirez } else if (n <= 0xffffffffLL) {
23936e6637dSantirez b[0] = 0xce; /* uint 32 */
24036e6637dSantirez b[1] = (n & 0xff000000) >> 24;
24136e6637dSantirez b[2] = (n & 0xff0000) >> 16;
24236e6637dSantirez b[3] = (n & 0xff00) >> 8;
24336e6637dSantirez b[4] = n & 0xff;
24436e6637dSantirez enclen = 5;
24536e6637dSantirez } else {
24636e6637dSantirez b[0] = 0xcf; /* uint 64 */
24736e6637dSantirez b[1] = (n & 0xff00000000000000LL) >> 56;
24836e6637dSantirez b[2] = (n & 0xff000000000000LL) >> 48;
24936e6637dSantirez b[3] = (n & 0xff0000000000LL) >> 40;
25036e6637dSantirez b[4] = (n & 0xff00000000LL) >> 32;
25136e6637dSantirez b[5] = (n & 0xff000000) >> 24;
25236e6637dSantirez b[6] = (n & 0xff0000) >> 16;
25336e6637dSantirez b[7] = (n & 0xff00) >> 8;
25436e6637dSantirez b[8] = n & 0xff;
25536e6637dSantirez enclen = 9;
25636e6637dSantirez }
25736e6637dSantirez } else {
25836e6637dSantirez if (n >= -32) {
25966e2bdf2Santirez b[0] = ((signed char)n); /* negative fixnum */
26036e6637dSantirez enclen = 1;
26136e6637dSantirez } else if (n >= -128) {
26236e6637dSantirez b[0] = 0xd0; /* int 8 */
26336e6637dSantirez b[1] = n & 0xff;
26436e6637dSantirez enclen = 2;
26536e6637dSantirez } else if (n >= -32768) {
26636e6637dSantirez b[0] = 0xd1; /* int 16 */
26736e6637dSantirez b[1] = (n & 0xff00) >> 8;
26836e6637dSantirez b[2] = n & 0xff;
26936e6637dSantirez enclen = 3;
27036e6637dSantirez } else if (n >= -2147483648LL) {
27136e6637dSantirez b[0] = 0xd2; /* int 32 */
27236e6637dSantirez b[1] = (n & 0xff000000) >> 24;
27336e6637dSantirez b[2] = (n & 0xff0000) >> 16;
27436e6637dSantirez b[3] = (n & 0xff00) >> 8;
27536e6637dSantirez b[4] = n & 0xff;
27636e6637dSantirez enclen = 5;
27736e6637dSantirez } else {
27836e6637dSantirez b[0] = 0xd3; /* int 64 */
27936e6637dSantirez b[1] = (n & 0xff00000000000000LL) >> 56;
28036e6637dSantirez b[2] = (n & 0xff000000000000LL) >> 48;
28136e6637dSantirez b[3] = (n & 0xff0000000000LL) >> 40;
28236e6637dSantirez b[4] = (n & 0xff00000000LL) >> 32;
28336e6637dSantirez b[5] = (n & 0xff000000) >> 24;
28436e6637dSantirez b[6] = (n & 0xff0000) >> 16;
28536e6637dSantirez b[7] = (n & 0xff00) >> 8;
28636e6637dSantirez b[8] = n & 0xff;
28736e6637dSantirez enclen = 9;
28836e6637dSantirez }
28936e6637dSantirez }
290*0b4a628fSantirez mp_buf_append(L,buf,b,enclen);
29136e6637dSantirez }
29236e6637dSantirez
mp_encode_array(lua_State * L,mp_buf * buf,int64_t n)293*0b4a628fSantirez void mp_encode_array(lua_State *L, mp_buf *buf, int64_t n) {
29436e6637dSantirez unsigned char b[5];
29536e6637dSantirez int enclen;
29636e6637dSantirez
29736e6637dSantirez if (n <= 15) {
29836e6637dSantirez b[0] = 0x90 | (n & 0xf); /* fix array */
29936e6637dSantirez enclen = 1;
30036e6637dSantirez } else if (n <= 65535) {
30136e6637dSantirez b[0] = 0xdc; /* array 16 */
30236e6637dSantirez b[1] = (n & 0xff00) >> 8;
30336e6637dSantirez b[2] = n & 0xff;
30436e6637dSantirez enclen = 3;
30536e6637dSantirez } else {
30636e6637dSantirez b[0] = 0xdd; /* array 32 */
30736e6637dSantirez b[1] = (n & 0xff000000) >> 24;
30836e6637dSantirez b[2] = (n & 0xff0000) >> 16;
30936e6637dSantirez b[3] = (n & 0xff00) >> 8;
31036e6637dSantirez b[4] = n & 0xff;
31136e6637dSantirez enclen = 5;
31236e6637dSantirez }
313*0b4a628fSantirez mp_buf_append(L,buf,b,enclen);
31436e6637dSantirez }
31536e6637dSantirez
mp_encode_map(lua_State * L,mp_buf * buf,int64_t n)316*0b4a628fSantirez void mp_encode_map(lua_State *L, mp_buf *buf, int64_t n) {
31736e6637dSantirez unsigned char b[5];
31836e6637dSantirez int enclen;
31936e6637dSantirez
32036e6637dSantirez if (n <= 15) {
32136e6637dSantirez b[0] = 0x80 | (n & 0xf); /* fix map */
32236e6637dSantirez enclen = 1;
32336e6637dSantirez } else if (n <= 65535) {
32436e6637dSantirez b[0] = 0xde; /* map 16 */
32536e6637dSantirez b[1] = (n & 0xff00) >> 8;
32636e6637dSantirez b[2] = n & 0xff;
32736e6637dSantirez enclen = 3;
32836e6637dSantirez } else {
32936e6637dSantirez b[0] = 0xdf; /* map 32 */
33036e6637dSantirez b[1] = (n & 0xff000000) >> 24;
33136e6637dSantirez b[2] = (n & 0xff0000) >> 16;
33236e6637dSantirez b[3] = (n & 0xff00) >> 8;
33336e6637dSantirez b[4] = n & 0xff;
33436e6637dSantirez enclen = 5;
33536e6637dSantirez }
336*0b4a628fSantirez mp_buf_append(L,buf,b,enclen);
33736e6637dSantirez }
33836e6637dSantirez
33990b6337cSMatt Stancliff /* --------------------------- Lua types encoding --------------------------- */
34036e6637dSantirez
mp_encode_lua_string(lua_State * L,mp_buf * buf)341357a40c4Santirez void mp_encode_lua_string(lua_State *L, mp_buf *buf) {
34236e6637dSantirez size_t len;
34336e6637dSantirez const char *s;
34436e6637dSantirez
34536e6637dSantirez s = lua_tolstring(L,-1,&len);
346*0b4a628fSantirez mp_encode_bytes(L,buf,(const unsigned char*)s,len);
34736e6637dSantirez }
34836e6637dSantirez
mp_encode_lua_bool(lua_State * L,mp_buf * buf)349357a40c4Santirez void mp_encode_lua_bool(lua_State *L, mp_buf *buf) {
35036e6637dSantirez unsigned char b = lua_toboolean(L,-1) ? 0xc3 : 0xc2;
351*0b4a628fSantirez mp_buf_append(L,buf,&b,1);
35236e6637dSantirez }
35336e6637dSantirez
35490b6337cSMatt Stancliff /* Lua 5.3 has a built in 64-bit integer type */
mp_encode_lua_integer(lua_State * L,mp_buf * buf)355357a40c4Santirez void mp_encode_lua_integer(lua_State *L, mp_buf *buf) {
35660643710SMatt Stancliff #if (LUA_VERSION_NUM < 503) && BITS_32
35760643710SMatt Stancliff lua_Number i = lua_tonumber(L,-1);
35860643710SMatt Stancliff #else
35990b6337cSMatt Stancliff lua_Integer i = lua_tointeger(L,-1);
36060643710SMatt Stancliff #endif
361*0b4a628fSantirez mp_encode_int(L, buf, (int64_t)i);
36290b6337cSMatt Stancliff }
36390b6337cSMatt Stancliff
36490b6337cSMatt Stancliff /* Lua 5.2 and lower only has 64-bit doubles, so we need to
36590b6337cSMatt Stancliff * detect if the double may be representable as an int
36690b6337cSMatt Stancliff * for Lua < 5.3 */
mp_encode_lua_number(lua_State * L,mp_buf * buf)367357a40c4Santirez void mp_encode_lua_number(lua_State *L, mp_buf *buf) {
36836e6637dSantirez lua_Number n = lua_tonumber(L,-1);
36936e6637dSantirez
37090b6337cSMatt Stancliff if (IS_INT64_EQUIVALENT(n)) {
37190b6337cSMatt Stancliff mp_encode_lua_integer(L, buf);
37236e6637dSantirez } else {
373*0b4a628fSantirez mp_encode_double(L,buf,(double)n);
37436e6637dSantirez }
37536e6637dSantirez }
37636e6637dSantirez
377357a40c4Santirez void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level);
37836e6637dSantirez
37936e6637dSantirez /* Convert a lua table into a message pack list. */
mp_encode_lua_table_as_array(lua_State * L,mp_buf * buf,int level)380357a40c4Santirez void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) {
38190b6337cSMatt Stancliff #if LUA_VERSION_NUM < 502
38236e6637dSantirez size_t len = lua_objlen(L,-1), j;
38390b6337cSMatt Stancliff #else
38490b6337cSMatt Stancliff size_t len = lua_rawlen(L,-1), j;
38590b6337cSMatt Stancliff #endif
38636e6637dSantirez
387*0b4a628fSantirez mp_encode_array(L,buf,len);
38836e6637dSantirez for (j = 1; j <= len; j++) {
38936e6637dSantirez lua_pushnumber(L,j);
39036e6637dSantirez lua_gettable(L,-2);
39136e6637dSantirez mp_encode_lua_type(L,buf,level+1);
39236e6637dSantirez }
39336e6637dSantirez }
39436e6637dSantirez
39536e6637dSantirez /* Convert a lua table into a message pack key-value map. */
mp_encode_lua_table_as_map(lua_State * L,mp_buf * buf,int level)396357a40c4Santirez void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) {
39736e6637dSantirez size_t len = 0;
39836e6637dSantirez
39936e6637dSantirez /* First step: count keys into table. No other way to do it with the
40036e6637dSantirez * Lua API, we need to iterate a first time. Note that an alternative
40136e6637dSantirez * would be to do a single run, and then hack the buffer to insert the
40260643710SMatt Stancliff * map opcodes for message pack. Too hackish for this lib. */
40336e6637dSantirez lua_pushnil(L);
40436e6637dSantirez while(lua_next(L,-2)) {
40536e6637dSantirez lua_pop(L,1); /* remove value, keep key for next iteration. */
40636e6637dSantirez len++;
40736e6637dSantirez }
40836e6637dSantirez
40936e6637dSantirez /* Step two: actually encoding of the map. */
410*0b4a628fSantirez mp_encode_map(L,buf,len);
41136e6637dSantirez lua_pushnil(L);
41236e6637dSantirez while(lua_next(L,-2)) {
41336e6637dSantirez /* Stack: ... key value */
41436e6637dSantirez lua_pushvalue(L,-2); /* Stack: ... key value key */
41536e6637dSantirez mp_encode_lua_type(L,buf,level+1); /* encode key */
41636e6637dSantirez mp_encode_lua_type(L,buf,level+1); /* encode val */
41736e6637dSantirez }
41836e6637dSantirez }
41936e6637dSantirez
42036e6637dSantirez /* Returns true if the Lua table on top of the stack is exclusively composed
42136e6637dSantirez * of keys from numerical keys from 1 up to N, with N being the total number
42236e6637dSantirez * of elements, without any hole in the middle. */
table_is_an_array(lua_State * L)423357a40c4Santirez int table_is_an_array(lua_State *L) {
42490b6337cSMatt Stancliff int count = 0, max = 0;
42590b6337cSMatt Stancliff #if LUA_VERSION_NUM < 503
42636e6637dSantirez lua_Number n;
42790b6337cSMatt Stancliff #else
42890b6337cSMatt Stancliff lua_Integer n;
42990b6337cSMatt Stancliff #endif
43090b6337cSMatt Stancliff
43190b6337cSMatt Stancliff /* Stack top on function entry */
43290b6337cSMatt Stancliff int stacktop;
43390b6337cSMatt Stancliff
43490b6337cSMatt Stancliff stacktop = lua_gettop(L);
43536e6637dSantirez
43636e6637dSantirez lua_pushnil(L);
43736e6637dSantirez while(lua_next(L,-2)) {
43836e6637dSantirez /* Stack: ... key value */
43936e6637dSantirez lua_pop(L,1); /* Stack: ... key */
44090b6337cSMatt Stancliff /* The <= 0 check is valid here because we're comparing indexes. */
44190b6337cSMatt Stancliff #if LUA_VERSION_NUM < 503
44260643710SMatt Stancliff if ((LUA_TNUMBER != lua_type(L,-1)) || (n = lua_tonumber(L, -1)) <= 0 ||
44360643710SMatt Stancliff !IS_INT_EQUIVALENT(n))
44490b6337cSMatt Stancliff #else
44560643710SMatt Stancliff if (!lua_isinteger(L,-1) || (n = lua_tointeger(L, -1)) <= 0)
44690b6337cSMatt Stancliff #endif
44760643710SMatt Stancliff {
44890b6337cSMatt Stancliff lua_settop(L, stacktop);
44990b6337cSMatt Stancliff return 0;
45090b6337cSMatt Stancliff }
45190b6337cSMatt Stancliff max = (n > max ? n : max);
45236e6637dSantirez count++;
45336e6637dSantirez }
45436e6637dSantirez /* We have the total number of elements in "count". Also we have
45590b6337cSMatt Stancliff * the max index encountered in "max". We can't reach this code
45636e6637dSantirez * if there are indexes <= 0. If you also note that there can not be
45790b6337cSMatt Stancliff * repeated keys into a table, you have that if max==count you are sure
45836e6637dSantirez * that there are all the keys form 1 to count (both included). */
45990b6337cSMatt Stancliff lua_settop(L, stacktop);
46090b6337cSMatt Stancliff return max == count;
46136e6637dSantirez }
46236e6637dSantirez
46336e6637dSantirez /* If the length operator returns non-zero, that is, there is at least
46436e6637dSantirez * an object at key '1', we serialize to message pack list. Otherwise
46536e6637dSantirez * we use a map. */
mp_encode_lua_table(lua_State * L,mp_buf * buf,int level)466357a40c4Santirez void mp_encode_lua_table(lua_State *L, mp_buf *buf, int level) {
46736e6637dSantirez if (table_is_an_array(L))
46836e6637dSantirez mp_encode_lua_table_as_array(L,buf,level);
46936e6637dSantirez else
47036e6637dSantirez mp_encode_lua_table_as_map(L,buf,level);
47136e6637dSantirez }
47236e6637dSantirez
mp_encode_lua_null(lua_State * L,mp_buf * buf)473357a40c4Santirez void mp_encode_lua_null(lua_State *L, mp_buf *buf) {
47436e6637dSantirez unsigned char b[1];
47536e6637dSantirez
47636e6637dSantirez b[0] = 0xc0;
477*0b4a628fSantirez mp_buf_append(L,buf,b,1);
47836e6637dSantirez }
47936e6637dSantirez
mp_encode_lua_type(lua_State * L,mp_buf * buf,int level)480357a40c4Santirez void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level) {
48136e6637dSantirez int t = lua_type(L,-1);
48236e6637dSantirez
48360643710SMatt Stancliff /* Limit the encoding of nested tables to a specified maximum depth, so that
48436e6637dSantirez * we survive when called against circular references in tables. */
48536e6637dSantirez if (t == LUA_TTABLE && level == LUACMSGPACK_MAX_NESTING) t = LUA_TNIL;
48636e6637dSantirez switch(t) {
48736e6637dSantirez case LUA_TSTRING: mp_encode_lua_string(L,buf); break;
48836e6637dSantirez case LUA_TBOOLEAN: mp_encode_lua_bool(L,buf); break;
48990b6337cSMatt Stancliff case LUA_TNUMBER:
49090b6337cSMatt Stancliff #if LUA_VERSION_NUM < 503
49190b6337cSMatt Stancliff mp_encode_lua_number(L,buf); break;
49290b6337cSMatt Stancliff #else
49390b6337cSMatt Stancliff if (lua_isinteger(L, -1)) {
49490b6337cSMatt Stancliff mp_encode_lua_integer(L, buf);
49590b6337cSMatt Stancliff } else {
49690b6337cSMatt Stancliff mp_encode_lua_number(L, buf);
49790b6337cSMatt Stancliff }
49890b6337cSMatt Stancliff break;
49990b6337cSMatt Stancliff #endif
50036e6637dSantirez case LUA_TTABLE: mp_encode_lua_table(L,buf,level); break;
50136e6637dSantirez default: mp_encode_lua_null(L,buf); break;
50236e6637dSantirez }
50336e6637dSantirez lua_pop(L,1);
50436e6637dSantirez }
50536e6637dSantirez
50690b6337cSMatt Stancliff /*
50790b6337cSMatt Stancliff * Packs all arguments as a stream for multiple upacking later.
50890b6337cSMatt Stancliff * Returns error if no arguments provided.
50990b6337cSMatt Stancliff */
mp_pack(lua_State * L)510357a40c4Santirez int mp_pack(lua_State *L) {
51190b6337cSMatt Stancliff int nargs = lua_gettop(L);
51290b6337cSMatt Stancliff int i;
51390b6337cSMatt Stancliff mp_buf *buf;
51490b6337cSMatt Stancliff
51590b6337cSMatt Stancliff if (nargs == 0)
51690b6337cSMatt Stancliff return luaL_argerror(L, 0, "MessagePack pack needs input.");
51790b6337cSMatt Stancliff
51890b6337cSMatt Stancliff buf = mp_buf_new(L);
51990b6337cSMatt Stancliff for(i = 1; i <= nargs; i++) {
52090b6337cSMatt Stancliff /* Copy argument i to top of stack for _encode processing;
52190b6337cSMatt Stancliff * the encode function pops it from the stack when complete. */
52290b6337cSMatt Stancliff lua_pushvalue(L, i);
52336e6637dSantirez
52436e6637dSantirez mp_encode_lua_type(L,buf,0);
52590b6337cSMatt Stancliff
52636e6637dSantirez lua_pushlstring(L,(char*)buf->b,buf->len);
52790b6337cSMatt Stancliff
52890b6337cSMatt Stancliff /* Reuse the buffer for the next operation by
52990b6337cSMatt Stancliff * setting its free count to the total buffer size
53090b6337cSMatt Stancliff * and the current position to zero. */
53190b6337cSMatt Stancliff buf->free += buf->len;
53290b6337cSMatt Stancliff buf->len = 0;
53390b6337cSMatt Stancliff }
534*0b4a628fSantirez mp_buf_free(L, buf);
53590b6337cSMatt Stancliff
53690b6337cSMatt Stancliff /* Concatenate all nargs buffers together */
53790b6337cSMatt Stancliff lua_concat(L, nargs);
53836e6637dSantirez return 1;
53936e6637dSantirez }
54036e6637dSantirez
54190b6337cSMatt Stancliff /* ------------------------------- Decoding --------------------------------- */
54236e6637dSantirez
54336e6637dSantirez void mp_decode_to_lua_type(lua_State *L, mp_cur *c);
54436e6637dSantirez
mp_decode_to_lua_array(lua_State * L,mp_cur * c,size_t len)54536e6637dSantirez void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) {
54666e2bdf2Santirez assert(len <= UINT_MAX);
54736e6637dSantirez int index = 1;
54836e6637dSantirez
54936e6637dSantirez lua_newtable(L);
55036e6637dSantirez while(len--) {
55136e6637dSantirez lua_pushnumber(L,index++);
55236e6637dSantirez mp_decode_to_lua_type(L,c);
55336e6637dSantirez if (c->err) return;
55436e6637dSantirez lua_settable(L,-3);
55536e6637dSantirez }
55636e6637dSantirez }
55736e6637dSantirez
mp_decode_to_lua_hash(lua_State * L,mp_cur * c,size_t len)55836e6637dSantirez void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) {
55966e2bdf2Santirez assert(len <= UINT_MAX);
56036e6637dSantirez lua_newtable(L);
56136e6637dSantirez while(len--) {
56236e6637dSantirez mp_decode_to_lua_type(L,c); /* key */
56336e6637dSantirez if (c->err) return;
56436e6637dSantirez mp_decode_to_lua_type(L,c); /* value */
56536e6637dSantirez if (c->err) return;
56636e6637dSantirez lua_settable(L,-3);
56736e6637dSantirez }
56836e6637dSantirez }
56936e6637dSantirez
57036e6637dSantirez /* Decode a Message Pack raw object pointed by the string cursor 'c' to
57136e6637dSantirez * a Lua type, that is left as the only result on the stack. */
mp_decode_to_lua_type(lua_State * L,mp_cur * c)57236e6637dSantirez void mp_decode_to_lua_type(lua_State *L, mp_cur *c) {
57336e6637dSantirez mp_cur_need(c,1);
57490b6337cSMatt Stancliff
57590b6337cSMatt Stancliff /* If we return more than 18 elements, we must resize the stack to
57690b6337cSMatt Stancliff * fit all our return values. But, there is no way to
57790b6337cSMatt Stancliff * determine how many objects a msgpack will unpack to up front, so
57890b6337cSMatt Stancliff * we request a +1 larger stack on each iteration (noop if stack is
57990b6337cSMatt Stancliff * big enough, and when stack does require resize it doubles in size) */
58090b6337cSMatt Stancliff luaL_checkstack(L, 1,
58190b6337cSMatt Stancliff "too many return values at once; "
58290b6337cSMatt Stancliff "use unpack_one or unpack_limit instead.");
58390b6337cSMatt Stancliff
58436e6637dSantirez switch(c->p[0]) {
58536e6637dSantirez case 0xcc: /* uint 8 */
58636e6637dSantirez mp_cur_need(c,2);
58790b6337cSMatt Stancliff lua_pushunsigned(L,c->p[1]);
58836e6637dSantirez mp_cur_consume(c,2);
58936e6637dSantirez break;
59036e6637dSantirez case 0xd0: /* int 8 */
59136e6637dSantirez mp_cur_need(c,2);
59266e2bdf2Santirez lua_pushinteger(L,(signed char)c->p[1]);
59336e6637dSantirez mp_cur_consume(c,2);
59436e6637dSantirez break;
59536e6637dSantirez case 0xcd: /* uint 16 */
59636e6637dSantirez mp_cur_need(c,3);
59790b6337cSMatt Stancliff lua_pushunsigned(L,
59836e6637dSantirez (c->p[1] << 8) |
59936e6637dSantirez c->p[2]);
60036e6637dSantirez mp_cur_consume(c,3);
60136e6637dSantirez break;
60236e6637dSantirez case 0xd1: /* int 16 */
60336e6637dSantirez mp_cur_need(c,3);
60490b6337cSMatt Stancliff lua_pushinteger(L,(int16_t)
60536e6637dSantirez (c->p[1] << 8) |
60636e6637dSantirez c->p[2]);
60736e6637dSantirez mp_cur_consume(c,3);
60836e6637dSantirez break;
60936e6637dSantirez case 0xce: /* uint 32 */
61036e6637dSantirez mp_cur_need(c,5);
61190b6337cSMatt Stancliff lua_pushunsigned(L,
61236e6637dSantirez ((uint32_t)c->p[1] << 24) |
61336e6637dSantirez ((uint32_t)c->p[2] << 16) |
61436e6637dSantirez ((uint32_t)c->p[3] << 8) |
61536e6637dSantirez (uint32_t)c->p[4]);
61636e6637dSantirez mp_cur_consume(c,5);
61736e6637dSantirez break;
61836e6637dSantirez case 0xd2: /* int 32 */
61936e6637dSantirez mp_cur_need(c,5);
62090b6337cSMatt Stancliff lua_pushinteger(L,
62136e6637dSantirez ((int32_t)c->p[1] << 24) |
62236e6637dSantirez ((int32_t)c->p[2] << 16) |
62336e6637dSantirez ((int32_t)c->p[3] << 8) |
62436e6637dSantirez (int32_t)c->p[4]);
62536e6637dSantirez mp_cur_consume(c,5);
62636e6637dSantirez break;
62736e6637dSantirez case 0xcf: /* uint 64 */
62836e6637dSantirez mp_cur_need(c,9);
62990b6337cSMatt Stancliff lua_pushunsigned(L,
63036e6637dSantirez ((uint64_t)c->p[1] << 56) |
63136e6637dSantirez ((uint64_t)c->p[2] << 48) |
63236e6637dSantirez ((uint64_t)c->p[3] << 40) |
63336e6637dSantirez ((uint64_t)c->p[4] << 32) |
63436e6637dSantirez ((uint64_t)c->p[5] << 24) |
63536e6637dSantirez ((uint64_t)c->p[6] << 16) |
63636e6637dSantirez ((uint64_t)c->p[7] << 8) |
63736e6637dSantirez (uint64_t)c->p[8]);
63836e6637dSantirez mp_cur_consume(c,9);
63936e6637dSantirez break;
64036e6637dSantirez case 0xd3: /* int 64 */
64136e6637dSantirez mp_cur_need(c,9);
64260643710SMatt Stancliff #if LUA_VERSION_NUM < 503
64360643710SMatt Stancliff lua_pushnumber(L,
64460643710SMatt Stancliff #else
64590b6337cSMatt Stancliff lua_pushinteger(L,
64660643710SMatt Stancliff #endif
64736e6637dSantirez ((int64_t)c->p[1] << 56) |
64836e6637dSantirez ((int64_t)c->p[2] << 48) |
64936e6637dSantirez ((int64_t)c->p[3] << 40) |
65036e6637dSantirez ((int64_t)c->p[4] << 32) |
65136e6637dSantirez ((int64_t)c->p[5] << 24) |
65236e6637dSantirez ((int64_t)c->p[6] << 16) |
65336e6637dSantirez ((int64_t)c->p[7] << 8) |
65436e6637dSantirez (int64_t)c->p[8]);
65536e6637dSantirez mp_cur_consume(c,9);
65636e6637dSantirez break;
65736e6637dSantirez case 0xc0: /* nil */
65836e6637dSantirez lua_pushnil(L);
65936e6637dSantirez mp_cur_consume(c,1);
66036e6637dSantirez break;
66136e6637dSantirez case 0xc3: /* true */
66236e6637dSantirez lua_pushboolean(L,1);
66336e6637dSantirez mp_cur_consume(c,1);
66436e6637dSantirez break;
66536e6637dSantirez case 0xc2: /* false */
66636e6637dSantirez lua_pushboolean(L,0);
66736e6637dSantirez mp_cur_consume(c,1);
66836e6637dSantirez break;
66936e6637dSantirez case 0xca: /* float */
67036e6637dSantirez mp_cur_need(c,5);
67136e6637dSantirez assert(sizeof(float) == 4);
67236e6637dSantirez {
67336e6637dSantirez float f;
67436e6637dSantirez memcpy(&f,c->p+1,4);
67536e6637dSantirez memrevifle(&f,4);
67636e6637dSantirez lua_pushnumber(L,f);
67736e6637dSantirez mp_cur_consume(c,5);
67836e6637dSantirez }
67936e6637dSantirez break;
68036e6637dSantirez case 0xcb: /* double */
68136e6637dSantirez mp_cur_need(c,9);
68236e6637dSantirez assert(sizeof(double) == 8);
68336e6637dSantirez {
68436e6637dSantirez double d;
68536e6637dSantirez memcpy(&d,c->p+1,8);
68636e6637dSantirez memrevifle(&d,8);
68736e6637dSantirez lua_pushnumber(L,d);
68836e6637dSantirez mp_cur_consume(c,9);
68936e6637dSantirez }
69036e6637dSantirez break;
691357a40c4Santirez case 0xd9: /* raw 8 */
692357a40c4Santirez mp_cur_need(c,2);
693357a40c4Santirez {
694357a40c4Santirez size_t l = c->p[1];
695357a40c4Santirez mp_cur_need(c,2+l);
696357a40c4Santirez lua_pushlstring(L,(char*)c->p+2,l);
697357a40c4Santirez mp_cur_consume(c,2+l);
698357a40c4Santirez }
699357a40c4Santirez break;
70036e6637dSantirez case 0xda: /* raw 16 */
70136e6637dSantirez mp_cur_need(c,3);
70236e6637dSantirez {
70336e6637dSantirez size_t l = (c->p[1] << 8) | c->p[2];
70436e6637dSantirez mp_cur_need(c,3+l);
70536e6637dSantirez lua_pushlstring(L,(char*)c->p+3,l);
70636e6637dSantirez mp_cur_consume(c,3+l);
70736e6637dSantirez }
70836e6637dSantirez break;
70936e6637dSantirez case 0xdb: /* raw 32 */
71036e6637dSantirez mp_cur_need(c,5);
71136e6637dSantirez {
71266e2bdf2Santirez size_t l = ((size_t)c->p[1] << 24) |
71366e2bdf2Santirez ((size_t)c->p[2] << 16) |
71466e2bdf2Santirez ((size_t)c->p[3] << 8) |
71566e2bdf2Santirez (size_t)c->p[4];
71666e2bdf2Santirez mp_cur_consume(c,5);
71766e2bdf2Santirez mp_cur_need(c,l);
71866e2bdf2Santirez lua_pushlstring(L,(char*)c->p,l);
71966e2bdf2Santirez mp_cur_consume(c,l);
72036e6637dSantirez }
72136e6637dSantirez break;
72236e6637dSantirez case 0xdc: /* array 16 */
72336e6637dSantirez mp_cur_need(c,3);
72436e6637dSantirez {
72536e6637dSantirez size_t l = (c->p[1] << 8) | c->p[2];
72636e6637dSantirez mp_cur_consume(c,3);
72736e6637dSantirez mp_decode_to_lua_array(L,c,l);
72836e6637dSantirez }
72936e6637dSantirez break;
73036e6637dSantirez case 0xdd: /* array 32 */
73136e6637dSantirez mp_cur_need(c,5);
73236e6637dSantirez {
73366e2bdf2Santirez size_t l = ((size_t)c->p[1] << 24) |
73466e2bdf2Santirez ((size_t)c->p[2] << 16) |
73566e2bdf2Santirez ((size_t)c->p[3] << 8) |
73666e2bdf2Santirez (size_t)c->p[4];
73736e6637dSantirez mp_cur_consume(c,5);
73836e6637dSantirez mp_decode_to_lua_array(L,c,l);
73936e6637dSantirez }
74036e6637dSantirez break;
74136e6637dSantirez case 0xde: /* map 16 */
74236e6637dSantirez mp_cur_need(c,3);
74336e6637dSantirez {
74436e6637dSantirez size_t l = (c->p[1] << 8) | c->p[2];
74536e6637dSantirez mp_cur_consume(c,3);
74636e6637dSantirez mp_decode_to_lua_hash(L,c,l);
74736e6637dSantirez }
74836e6637dSantirez break;
74936e6637dSantirez case 0xdf: /* map 32 */
75036e6637dSantirez mp_cur_need(c,5);
75136e6637dSantirez {
75266e2bdf2Santirez size_t l = ((size_t)c->p[1] << 24) |
75366e2bdf2Santirez ((size_t)c->p[2] << 16) |
75466e2bdf2Santirez ((size_t)c->p[3] << 8) |
75566e2bdf2Santirez (size_t)c->p[4];
75636e6637dSantirez mp_cur_consume(c,5);
75736e6637dSantirez mp_decode_to_lua_hash(L,c,l);
75836e6637dSantirez }
75936e6637dSantirez break;
76036e6637dSantirez default: /* types that can't be idenitified by first byte value. */
76136e6637dSantirez if ((c->p[0] & 0x80) == 0) { /* positive fixnum */
76290b6337cSMatt Stancliff lua_pushunsigned(L,c->p[0]);
76336e6637dSantirez mp_cur_consume(c,1);
76436e6637dSantirez } else if ((c->p[0] & 0xe0) == 0xe0) { /* negative fixnum */
76590b6337cSMatt Stancliff lua_pushinteger(L,(signed char)c->p[0]);
76636e6637dSantirez mp_cur_consume(c,1);
76736e6637dSantirez } else if ((c->p[0] & 0xe0) == 0xa0) { /* fix raw */
76836e6637dSantirez size_t l = c->p[0] & 0x1f;
76936e6637dSantirez mp_cur_need(c,1+l);
77036e6637dSantirez lua_pushlstring(L,(char*)c->p+1,l);
77136e6637dSantirez mp_cur_consume(c,1+l);
77236e6637dSantirez } else if ((c->p[0] & 0xf0) == 0x90) { /* fix map */
77336e6637dSantirez size_t l = c->p[0] & 0xf;
77436e6637dSantirez mp_cur_consume(c,1);
77536e6637dSantirez mp_decode_to_lua_array(L,c,l);
77636e6637dSantirez } else if ((c->p[0] & 0xf0) == 0x80) { /* fix map */
77736e6637dSantirez size_t l = c->p[0] & 0xf;
77836e6637dSantirez mp_cur_consume(c,1);
77936e6637dSantirez mp_decode_to_lua_hash(L,c,l);
78036e6637dSantirez } else {
78136e6637dSantirez c->err = MP_CUR_ERROR_BADFMT;
78236e6637dSantirez }
78336e6637dSantirez }
78436e6637dSantirez }
78536e6637dSantirez
mp_unpack_full(lua_State * L,int limit,int offset)786357a40c4Santirez int mp_unpack_full(lua_State *L, int limit, int offset) {
78736e6637dSantirez size_t len;
78890b6337cSMatt Stancliff const char *s;
78990b6337cSMatt Stancliff mp_cur c;
79090b6337cSMatt Stancliff int cnt; /* Number of objects unpacked */
79190b6337cSMatt Stancliff int decode_all = (!limit && !offset);
79236e6637dSantirez
79390b6337cSMatt Stancliff s = luaL_checklstring(L,1,&len); /* if no match, exits */
79490b6337cSMatt Stancliff
79590b6337cSMatt Stancliff if (offset < 0 || limit < 0) /* requesting negative off or lim is invalid */
79690b6337cSMatt Stancliff return luaL_error(L,
79790b6337cSMatt Stancliff "Invalid request to unpack with offset of %d and limit of %d.",
79890b6337cSMatt Stancliff offset, len);
79990b6337cSMatt Stancliff else if (offset > len)
80090b6337cSMatt Stancliff return luaL_error(L,
80190b6337cSMatt Stancliff "Start offset %d greater than input length %d.", offset, len);
80290b6337cSMatt Stancliff
80390b6337cSMatt Stancliff if (decode_all) limit = INT_MAX;
80490b6337cSMatt Stancliff
80590b6337cSMatt Stancliff mp_cur_init(&c,(const unsigned char *)s+offset,len-offset);
80690b6337cSMatt Stancliff
80790b6337cSMatt Stancliff /* We loop over the decode because this could be a stream
80890b6337cSMatt Stancliff * of multiple top-level values serialized together */
80990b6337cSMatt Stancliff for(cnt = 0; c.left > 0 && cnt < limit; cnt++) {
81090b6337cSMatt Stancliff mp_decode_to_lua_type(L,&c);
81190b6337cSMatt Stancliff
81290b6337cSMatt Stancliff if (c.err == MP_CUR_ERROR_EOF) {
81390b6337cSMatt Stancliff return luaL_error(L,"Missing bytes in input.");
81490b6337cSMatt Stancliff } else if (c.err == MP_CUR_ERROR_BADFMT) {
81590b6337cSMatt Stancliff return luaL_error(L,"Bad data format in input.");
81690b6337cSMatt Stancliff }
81736e6637dSantirez }
81836e6637dSantirez
81990b6337cSMatt Stancliff if (!decode_all) {
82090b6337cSMatt Stancliff /* c->left is the remaining size of the input buffer.
82190b6337cSMatt Stancliff * subtract the entire buffer size from the unprocessed size
82290b6337cSMatt Stancliff * to get our next start offset */
82390b6337cSMatt Stancliff int offset = len - c.left;
82490b6337cSMatt Stancliff /* Return offset -1 when we have have processed the entire buffer. */
82590b6337cSMatt Stancliff lua_pushinteger(L, c.left == 0 ? -1 : offset);
82690b6337cSMatt Stancliff /* Results are returned with the arg elements still
82790b6337cSMatt Stancliff * in place. Lua takes care of only returning
82890b6337cSMatt Stancliff * elements above the args for us.
82990b6337cSMatt Stancliff * In this case, we have one arg on the stack
83090b6337cSMatt Stancliff * for this function, so we insert our first return
83190b6337cSMatt Stancliff * value at position 2. */
83290b6337cSMatt Stancliff lua_insert(L, 2);
83390b6337cSMatt Stancliff cnt += 1; /* increase return count by one to make room for offset */
83436e6637dSantirez }
83536e6637dSantirez
83690b6337cSMatt Stancliff return cnt;
83790b6337cSMatt Stancliff }
83836e6637dSantirez
mp_unpack(lua_State * L)839357a40c4Santirez int mp_unpack(lua_State *L) {
84090b6337cSMatt Stancliff return mp_unpack_full(L, 0, 0);
84190b6337cSMatt Stancliff }
84290b6337cSMatt Stancliff
mp_unpack_one(lua_State * L)843357a40c4Santirez int mp_unpack_one(lua_State *L) {
84466e2bdf2Santirez int offset = luaL_optinteger(L, 2, 0);
84590b6337cSMatt Stancliff /* Variable pop because offset may not exist */
84690b6337cSMatt Stancliff lua_pop(L, lua_gettop(L)-1);
84790b6337cSMatt Stancliff return mp_unpack_full(L, 1, offset);
84890b6337cSMatt Stancliff }
84990b6337cSMatt Stancliff
mp_unpack_limit(lua_State * L)850357a40c4Santirez int mp_unpack_limit(lua_State *L) {
85166e2bdf2Santirez int limit = luaL_checkinteger(L, 2);
85266e2bdf2Santirez int offset = luaL_optinteger(L, 3, 0);
85390b6337cSMatt Stancliff /* Variable pop because offset may not exist */
85490b6337cSMatt Stancliff lua_pop(L, lua_gettop(L)-1);
85590b6337cSMatt Stancliff
85690b6337cSMatt Stancliff return mp_unpack_full(L, limit, offset);
85790b6337cSMatt Stancliff }
85890b6337cSMatt Stancliff
mp_safe(lua_State * L)859357a40c4Santirez int mp_safe(lua_State *L) {
86090b6337cSMatt Stancliff int argc, err, total_results;
86190b6337cSMatt Stancliff
86290b6337cSMatt Stancliff argc = lua_gettop(L);
86390b6337cSMatt Stancliff
86490b6337cSMatt Stancliff /* This adds our function to the bottom of the stack
86590b6337cSMatt Stancliff * (the "call this function" position) */
86690b6337cSMatt Stancliff lua_pushvalue(L, lua_upvalueindex(1));
86790b6337cSMatt Stancliff lua_insert(L, 1);
86890b6337cSMatt Stancliff
86990b6337cSMatt Stancliff err = lua_pcall(L, argc, LUA_MULTRET, 0);
87090b6337cSMatt Stancliff total_results = lua_gettop(L);
87190b6337cSMatt Stancliff
87290b6337cSMatt Stancliff if (!err) {
87390b6337cSMatt Stancliff return total_results;
87490b6337cSMatt Stancliff } else {
87590b6337cSMatt Stancliff lua_pushnil(L);
87690b6337cSMatt Stancliff lua_insert(L,-2);
87790b6337cSMatt Stancliff return 2;
87890b6337cSMatt Stancliff }
87990b6337cSMatt Stancliff }
88090b6337cSMatt Stancliff
88190b6337cSMatt Stancliff /* -------------------------------------------------------------------------- */
882357a40c4Santirez const struct luaL_Reg cmds[] = {
88336e6637dSantirez {"pack", mp_pack},
88436e6637dSantirez {"unpack", mp_unpack},
88590b6337cSMatt Stancliff {"unpack_one", mp_unpack_one},
88690b6337cSMatt Stancliff {"unpack_limit", mp_unpack_limit},
88790b6337cSMatt Stancliff {0}
88836e6637dSantirez };
88936e6637dSantirez
luaopen_create(lua_State * L)890357a40c4Santirez int luaopen_create(lua_State *L) {
89190b6337cSMatt Stancliff int i;
89290b6337cSMatt Stancliff /* Manually construct our module table instead of
89390b6337cSMatt Stancliff * relying on _register or _newlib */
89490b6337cSMatt Stancliff lua_newtable(L);
89536e6637dSantirez
89690b6337cSMatt Stancliff for (i = 0; i < (sizeof(cmds)/sizeof(*cmds) - 1); i++) {
89790b6337cSMatt Stancliff lua_pushcfunction(L, cmds[i].func);
89890b6337cSMatt Stancliff lua_setfield(L, -2, cmds[i].name);
89990b6337cSMatt Stancliff }
90090b6337cSMatt Stancliff
90190b6337cSMatt Stancliff /* Add metadata */
90290b6337cSMatt Stancliff lua_pushliteral(L, LUACMSGPACK_NAME);
90390b6337cSMatt Stancliff lua_setfield(L, -2, "_NAME");
90436e6637dSantirez lua_pushliteral(L, LUACMSGPACK_VERSION);
90536e6637dSantirez lua_setfield(L, -2, "_VERSION");
90636e6637dSantirez lua_pushliteral(L, LUACMSGPACK_COPYRIGHT);
90736e6637dSantirez lua_setfield(L, -2, "_COPYRIGHT");
90836e6637dSantirez lua_pushliteral(L, LUACMSGPACK_DESCRIPTION);
90936e6637dSantirez lua_setfield(L, -2, "_DESCRIPTION");
91036e6637dSantirez return 1;
91136e6637dSantirez }
91236e6637dSantirez
luaopen_cmsgpack(lua_State * L)91390b6337cSMatt Stancliff LUALIB_API int luaopen_cmsgpack(lua_State *L) {
91490b6337cSMatt Stancliff luaopen_create(L);
91590b6337cSMatt Stancliff
91690b6337cSMatt Stancliff #if LUA_VERSION_NUM < 502
91790b6337cSMatt Stancliff /* Register name globally for 5.1 */
91890b6337cSMatt Stancliff lua_pushvalue(L, -1);
91990b6337cSMatt Stancliff lua_setglobal(L, LUACMSGPACK_NAME);
92090b6337cSMatt Stancliff #endif
92190b6337cSMatt Stancliff
92290b6337cSMatt Stancliff return 1;
92390b6337cSMatt Stancliff }
92490b6337cSMatt Stancliff
luaopen_cmsgpack_safe(lua_State * L)92590b6337cSMatt Stancliff LUALIB_API int luaopen_cmsgpack_safe(lua_State *L) {
92690b6337cSMatt Stancliff int i;
92790b6337cSMatt Stancliff
92890b6337cSMatt Stancliff luaopen_cmsgpack(L);
92990b6337cSMatt Stancliff
93090b6337cSMatt Stancliff /* Wrap all functions in the safe handler */
93190b6337cSMatt Stancliff for (i = 0; i < (sizeof(cmds)/sizeof(*cmds) - 1); i++) {
93290b6337cSMatt Stancliff lua_getfield(L, -1, cmds[i].name);
93390b6337cSMatt Stancliff lua_pushcclosure(L, mp_safe, 1);
93490b6337cSMatt Stancliff lua_setfield(L, -2, cmds[i].name);
93590b6337cSMatt Stancliff }
93690b6337cSMatt Stancliff
93790b6337cSMatt Stancliff #if LUA_VERSION_NUM < 502
93890b6337cSMatt Stancliff /* Register name globally for 5.1 */
93990b6337cSMatt Stancliff lua_pushvalue(L, -1);
94090b6337cSMatt Stancliff lua_setglobal(L, LUACMSGPACK_SAFE_NAME);
94190b6337cSMatt Stancliff #endif
94290b6337cSMatt Stancliff
94390b6337cSMatt Stancliff return 1;
94490b6337cSMatt Stancliff }
94590b6337cSMatt Stancliff
94636e6637dSantirez /******************************************************************************
94736e6637dSantirez * Copyright (C) 2012 Salvatore Sanfilippo. All rights reserved.
94836e6637dSantirez *
94936e6637dSantirez * Permission is hereby granted, free of charge, to any person obtaining
95036e6637dSantirez * a copy of this software and associated documentation files (the
95136e6637dSantirez * "Software"), to deal in the Software without restriction, including
95236e6637dSantirez * without limitation the rights to use, copy, modify, merge, publish,
95336e6637dSantirez * distribute, sublicense, and/or sell copies of the Software, and to
95436e6637dSantirez * permit persons to whom the Software is furnished to do so, subject to
95536e6637dSantirez * the following conditions:
95636e6637dSantirez *
95736e6637dSantirez * The above copyright notice and this permission notice shall be
95836e6637dSantirez * included in all copies or substantial portions of the Software.
95936e6637dSantirez *
96036e6637dSantirez * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
96136e6637dSantirez * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
96236e6637dSantirez * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
96336e6637dSantirez * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
96436e6637dSantirez * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
96536e6637dSantirez * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
96636e6637dSantirez * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
96736e6637dSantirez ******************************************************************************/
968