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