├── .gitignore ├── .travis.yml ├── .travis ├── platform.sh └── setup_lua.sh ├── CMakeLists.txt ├── README.md ├── lua_cmsgpack.c ├── rockspec ├── lua-cmsgpack-0.3-0.rockspec ├── lua-cmsgpack-0.3-1.rockspec ├── lua-cmsgpack-0.4.0-0.rockspec └── lua-cmsgpack-scm-1.rockspec └── test.lua /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .*~ 3 | \#*\# 4 | .\#*\# 5 | 6 | .DS_Store 7 | .project 8 | .settings 9 | 10 | *.o 11 | *.so 12 | 13 | build/ 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | 3 | env: 4 | global: 5 | - PLATFORM=linux 6 | - LUAROCKS_VER=2.2.0 7 | matrix: 8 | - LUA=lua5.1 LUA_SFX= 9 | - LUA=lua5.2 LUA_SFX= 10 | - LUA=luajit LUA_SFX=jit 11 | - LUA=lua5.3 LUA_SFX= 12 | 13 | before_install: 14 | - bash -x .travis/setup_lua.sh 15 | - sudo pip install cpp-coveralls 16 | 17 | install: 18 | - sudo luarocks make rockspec/lua-cmsgpack-scm-1.rockspec CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage" 19 | 20 | script: 21 | - lua$LUA_SFX test.lua 22 | 23 | after_success: 24 | - coveralls 25 | 26 | notifications: 27 | email: 28 | on_success: change 29 | on_failure: always 30 | -------------------------------------------------------------------------------- /.travis/platform.sh: -------------------------------------------------------------------------------- 1 | if [ -z "$PLATFORM" ]; then 2 | PLATFORM=$TRAVIS_OS_NAME; 3 | fi 4 | 5 | if [ "$PLATFORM" == "osx" ]; then 6 | PLATFORM="macosx"; 7 | fi 8 | 9 | if [ -z "$PLATFORM" ]; then 10 | if [ "$(uname)" == "Linux" ]; then 11 | PLATFORM="linux"; 12 | else 13 | PLATFORM="macosx"; 14 | fi; 15 | fi 16 | -------------------------------------------------------------------------------- /.travis/setup_lua.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # A script for setting up environment for travis-ci testing. 4 | # Sets up Lua and Luarocks. 5 | # LUA must be "lua5.1", "lua5.2" or "luajit". 6 | # luajit2.0 - master v2.0 7 | # luajit2.1 - master v2.1 8 | 9 | LUAJIT_BASE="LuaJIT-2.0.3" 10 | 11 | source .travis/platform.sh 12 | 13 | LUAJIT="no" 14 | 15 | if [ "$PLATFORM" == "macosx" ]; then 16 | if [ "$LUA" == "luajit" ]; then 17 | LUAJIT="yes"; 18 | fi 19 | if [ "$LUA" == "luajit2.0" ]; then 20 | LUAJIT="yes"; 21 | fi 22 | if [ "$LUA" == "luajit2.1" ]; then 23 | LUAJIT="yes"; 24 | fi; 25 | elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then 26 | LUAJIT="yes"; 27 | fi 28 | 29 | if [ "$LUAJIT" == "yes" ]; then 30 | 31 | if [ "$LUA" == "luajit" ]; then 32 | curl http://luajit.org/download/$LUAJIT_BASE.tar.gz | tar xz; 33 | else 34 | git clone http://luajit.org/git/luajit-2.0.git $LUAJIT_BASE; 35 | fi 36 | 37 | cd $LUAJIT_BASE 38 | 39 | if [ "$LUA" == "luajit2.1" ]; then 40 | git checkout v2.1; 41 | fi 42 | 43 | make && sudo make install 44 | 45 | if [ "$LUA" == "luajit2.1" ]; then 46 | sudo ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit 47 | sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua; 48 | else 49 | sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua; 50 | fi; 51 | 52 | else 53 | if [ "$LUA" == "lua5.1" ]; then 54 | curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz 55 | cd lua-5.1.5; 56 | elif [ "$LUA" == "lua5.2" ]; then 57 | curl http://www.lua.org/ftp/lua-5.2.3.tar.gz | tar xz 58 | cd lua-5.2.3; 59 | elif [ "$LUA" == "lua5.3" ]; then 60 | curl http://www.lua.org/work/lua-5.3.0-beta.tar.gz | tar xz 61 | cd lua-5.3.0-beta; 62 | fi 63 | sudo make $PLATFORM install; 64 | fi 65 | 66 | cd $TRAVIS_BUILD_DIR; 67 | 68 | LUAROCKS_BASE=luarocks-$LUAROCKS 69 | 70 | # curl http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz 71 | 72 | git clone https://github.com/keplerproject/luarocks.git $LUAROCKS_BASE 73 | cd $LUAROCKS_BASE 74 | 75 | git checkout v$LUAROCKS 76 | 77 | if [ "$LUA" == "luajit" ]; then 78 | ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0; 79 | elif [ "$LUA" == "luajit2.0" ]; then 80 | ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0; 81 | elif [ "$LUA" == "luajit2.1" ]; then 82 | ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.1; 83 | else 84 | ./configure; 85 | fi 86 | 87 | make build && sudo make install 88 | 89 | cd $TRAVIS_BUILD_DIR 90 | 91 | rm -rf $LUAROCKS_BASE 92 | 93 | if [ "$LUAJIT" == "yes" ]; then 94 | rm -rf $LUAJIT_BASE; 95 | elif [ "$LUA" == "lua5.1" ]; then 96 | rm -rf lua-5.1.5; 97 | elif [ "$LUA" == "lua5.2" ]; then 98 | rm -rf lua-5.2.3; 99 | elif [ "$LUA" == "lua5.3" ]; then 100 | rm -rf lua-5.3.0-beta; 101 | fi 102 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # If Lua is installed in a non-standard location, please set the LUA_DIR 2 | # environment variable to point to prefix for the install. Eg: 3 | # Unix: export LUA_DIR=/home/user/pkg 4 | # Windows: set LUA_DIR=c:\lua51 5 | 6 | project(lua-cmsgpack C) 7 | cmake_minimum_required(VERSION 2.6) 8 | 9 | if(NOT CMAKE_BUILD_TYPE) 10 | set(CMAKE_BUILD_TYPE Release CACHE STRING 11 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 12 | FORCE) 13 | endif() 14 | 15 | find_package(Lua51 REQUIRED) 16 | include_directories(${LUA_INCLUDE_DIR}) 17 | 18 | if(APPLE) 19 | set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS 20 | "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup") 21 | endif() 22 | 23 | if(WIN32) 24 | # Win32 modules need to be linked to the Lua library. 25 | set(_MODULE_LINK ${LUA_LIBRARY} ${_MODULE_LINK}) 26 | set(_lua_module_dir "${_lua_lib_dir}") 27 | else() 28 | set(_lua_module_dir "${_lua_lib_dir}/lua/5.1") 29 | endif() 30 | 31 | option(Build32Bit "Build 32-bit Library" OFF) 32 | 33 | set(CMAKE_C_FLAGS "-O2 -g -ggdb -Wall -pedantic -std=c99") 34 | add_library(cmsgpack MODULE lua_cmsgpack.c) 35 | set_target_properties(cmsgpack PROPERTIES PREFIX "") 36 | 37 | if(Build32Bit) 38 | set_target_properties(cmsgpack 39 | PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") 40 | endif() 41 | 42 | target_link_libraries(cmsgpack ${_MODULE_LINK}) 43 | install(TARGETS cmsgpack DESTINATION "${_lua_module_dir}") 44 | 45 | # vi:ai et sw=4 ts=4: 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | README for lua-cmsgpack.c 2 | === 3 | 4 | Lua-cmsgpack is a [MessagePack](http://msgpack.org) implementation and bindings for 5 | Lua 5.1/5.2/5.3 in a self contained C file without external dependencies. 6 | 7 | This library is open source software licensed under the BSD two-clause license. 8 | 9 | INSTALLATION 10 | --- 11 | 12 | Using LuaRocks (http://luarocks.org): 13 | 14 | * Install current stable release: 15 | 16 | sudo luarocks install lua-cmsgpack 17 | 18 | * Install current Git master head from GitHub: 19 | 20 | sudo luarocks install lua-cmsgpack --from=rocks-cvs 21 | 22 | * Install from current working copy 23 | 24 | cd lua-cmsgpack/ 25 | sudo luarocks make rockspec/lua-cmsgpack-scm-1.rockspec 26 | 27 | If you embed Lua and all modules into your C project, just add the 28 | `lua_cmsgpack.c` file and call the following function after creating the Lua 29 | interpreter: 30 | 31 | luaopen_cmsgpack(L); 32 | 33 | USAGE 34 | --- 35 | 36 | The exported API is very simple, consisting of four functions: 37 | 38 | Basic API: 39 | 40 | msgpack = cmsgpack.pack(lua_object1, lua_object2, ..., lua_objectN) 41 | lua_object1, lua_object2, ..., lua_objectN = cmsgpack.unpack(msgpack) 42 | 43 | Detailed API giving you more control over unpacking multiple values: 44 | 45 | resume_offset, lua_object1 = cmsgpack.unpack_one(msgpack) 46 | resume_offset1, lua_object2 = cmsgpack.unpack_one(msgpack, resume_offset) 47 | ... 48 | -1, lua_objectN = cmsgpack.unpack_one(msgpack, resume_offset_previous) 49 | 50 | resume_offset, lua_object1, lua_object2 = cmsgpack.unpack_limit(msgpack, 2) 51 | resume_offset2, lua_object3 = cmsgpack.unpack_limit(msgpack, 1, resume_offset1) 52 | 53 | Functions: 54 | 55 | - `pack(arg1, arg2, ..., argn)` - pack any number of lua objects into one msgpack stream. returns: msgpack 56 | - `unpack(msgpack)` - unpack all objects in msgpack to individual return values. returns: object1, object2, ..., objectN 57 | - `unpack_one(msgpack); unpack_one(msgpack, offset)` - unpacks the first object after offset. returns: offset, object 58 | - `unpack_limit(msgpack, limit); unpack_limit(msgpack, limit, offset)` - unpacks the first `limit` objects and returns: offset, object1, objet2, ..., objectN (up to limit, but may return fewer than limit if not that many objects remain to be unpacked) 59 | 60 | When you reach the end of your input stream with `unpack_one` or `unpack_limit`, an offset of `-1` is returned. 61 | 62 | You may `require "msgpack"` or you may `require "msgpack.safe"`. The safe version returns errors as (nil, errstring). 63 | 64 | However because of the nature of Lua numerical and table type a few behavior 65 | of the library must be well understood to avoid problems: 66 | 67 | * A table is converted into a MessagePack array type only if *all* the keys are 68 | composed of incrementing integers starting at 1 end ending at N, without holes, 69 | without additional non numerical keys. All the other tables are converted into 70 | maps. 71 | * An empty table is always converted into a MessagePack array, the rationale is that empty lists are much more common than empty maps (usually used to represent objects with fields). 72 | * A Lua number is converted into an integer type if floor(number) == number, otherwise it is converted into the MessagePack float or double value. 73 | * When a Lua number is converted to float or double, the former is preferred if there is no loss of precision compared to the double representation. 74 | * When a MessagePack big integer (64 bit) is converted to a Lua number it is possible that the resulting number will not represent the original number but just an approximation. This is unavoidable because the Lua numerical type is usually a double precision floating point type. 75 | 76 | TESTING 77 | --- 78 | 79 | Build and test: 80 | 81 | mkdir build; cd build 82 | cmake .. 83 | make 84 | lua ../test.lua 85 | 86 | You can build a 32-bit module on a 64-bit platform with: 87 | 88 | mkdir build; cd build 89 | cmake -DBuild32Bit=ON .. 90 | make 91 | lua ../test.lua 92 | 93 | NESTED TABLES 94 | --- 95 | Nested tables are handled correctly up to `LUACMSGPACK_MAX_NESTING` levels of 96 | nesting (that is set to 16 by default). 97 | Every table that is nested at a greater level than the maxium is encoded 98 | as MessagePack nil value. 99 | 100 | It is worth to note that in Lua it is possible to create tables that mutually 101 | refer to each other, creating a cycle. For example: 102 | 103 | a = {x=nil,y=5} 104 | b = {x=a} 105 | a['x'] = b 106 | 107 | This condition will simply make the encoder reach the max level of nesting, 108 | thus avoiding an infinite loop. 109 | 110 | CREDITS 111 | --- 112 | 113 | This library was written by Salvatore Sanfilippo for Redis, but is maintained as a separated project by the author. 114 | 115 | Some of the test vectors in "test.lua" are obtained from the Javascript [MessagePack-JS library](https://github.com/cuzic/MessagePack-JS). 116 | -------------------------------------------------------------------------------- /lua_cmsgpack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "lua.h" 8 | #include "lauxlib.h" 9 | 10 | #define LUACMSGPACK_NAME "cmsgpack" 11 | #define LUACMSGPACK_SAFE_NAME "cmsgpack_safe" 12 | #define LUACMSGPACK_VERSION "lua-cmsgpack 0.4.0" 13 | #define LUACMSGPACK_COPYRIGHT "Copyright (C) 2012, Salvatore Sanfilippo" 14 | #define LUACMSGPACK_DESCRIPTION "MessagePack C implementation for Lua" 15 | 16 | /* Allows a preprocessor directive to override MAX_NESTING */ 17 | #ifndef LUACMSGPACK_MAX_NESTING 18 | #define LUACMSGPACK_MAX_NESTING 16 /* Max tables nesting. */ 19 | #endif 20 | 21 | /* Check if float or double can be an integer without loss of precision */ 22 | #define IS_INT_TYPE_EQUIVALENT(x, T) (!isinf(x) && (T)(x) == (x)) 23 | 24 | #define IS_INT64_EQUIVALENT(x) IS_INT_TYPE_EQUIVALENT(x, int64_t) 25 | #define IS_INT_EQUIVALENT(x) IS_INT_TYPE_EQUIVALENT(x, int) 26 | 27 | /* If size of pointer is equal to a 4 byte integer, we're on 32 bits. */ 28 | #if UINTPTR_MAX == UINT_MAX 29 | #define BITS_32 1 30 | #else 31 | #define BITS_32 0 32 | #endif 33 | 34 | #if BITS_32 35 | #define lua_pushunsigned(L, n) lua_pushnumber(L, n) 36 | #else 37 | #define lua_pushunsigned(L, n) lua_pushinteger(L, n) 38 | #endif 39 | 40 | /* ============================================================================= 41 | * MessagePack implementation and bindings for Lua 5.1/5.2. 42 | * Copyright(C) 2012 Salvatore Sanfilippo 43 | * 44 | * http://github.com/antirez/lua-cmsgpack 45 | * 46 | * For MessagePack specification check the following web site: 47 | * http://wiki.msgpack.org/display/MSGPACK/Format+specification 48 | * 49 | * See Copyright Notice at the end of this file. 50 | * 51 | * CHANGELOG: 52 | * 19-Feb-2012 (ver 0.1.0): Initial release. 53 | * 20-Feb-2012 (ver 0.2.0): Tables encoding improved. 54 | * 20-Feb-2012 (ver 0.2.1): Minor bug fixing. 55 | * 20-Feb-2012 (ver 0.3.0): Module renamed lua-cmsgpack (was lua-msgpack). 56 | * 04-Apr-2014 (ver 0.3.1): Lua 5.2 support and minor bug fix. 57 | * 07-Apr-2014 (ver 0.4.0): Multiple pack/unpack, lua allocator, efficiency. 58 | * ========================================================================== */ 59 | 60 | /* -------------------------- Endian conversion -------------------------------- 61 | * We use it only for floats and doubles, all the other conversions performed 62 | * in an endian independent fashion. So the only thing we need is a function 63 | * that swaps a binary string if arch is little endian (and left it untouched 64 | * otherwise). */ 65 | 66 | /* Reverse memory bytes if arch is little endian. Given the conceptual 67 | * simplicity of the Lua build system we prefer check for endianess at runtime. 68 | * The performance difference should be acceptable. */ 69 | void memrevifle(void *ptr, size_t len) { 70 | unsigned char *p = (unsigned char *)ptr, 71 | *e = (unsigned char *)p+len-1, 72 | aux; 73 | int test = 1; 74 | unsigned char *testp = (unsigned char*) &test; 75 | 76 | if (testp[0] == 0) return; /* Big endian, nothing to do. */ 77 | len /= 2; 78 | while(len--) { 79 | aux = *p; 80 | *p = *e; 81 | *e = aux; 82 | p++; 83 | e--; 84 | } 85 | } 86 | 87 | /* ---------------------------- String buffer ---------------------------------- 88 | * This is a simple implementation of string buffers. The only operation 89 | * supported is creating empty buffers and appending bytes to it. 90 | * The string buffer uses 2x preallocation on every realloc for O(N) append 91 | * behavior. */ 92 | 93 | typedef struct mp_buf { 94 | unsigned char *b; 95 | size_t len, free; 96 | } mp_buf; 97 | 98 | void *mp_realloc(lua_State *L, void *target, size_t osize,size_t nsize) { 99 | void *(*local_realloc) (void *, void *, size_t osize, size_t nsize) = NULL; 100 | void *ud; 101 | 102 | local_realloc = lua_getallocf(L, &ud); 103 | 104 | return local_realloc(ud, target, osize, nsize); 105 | } 106 | 107 | mp_buf *mp_buf_new(lua_State *L) { 108 | mp_buf *buf = NULL; 109 | 110 | /* Old size = 0; new size = sizeof(*buf) */ 111 | buf = (mp_buf*)mp_realloc(L, NULL, 0, sizeof(*buf)); 112 | 113 | buf->b = NULL; 114 | buf->len = buf->free = 0; 115 | return buf; 116 | } 117 | 118 | void mp_buf_append(lua_State *L, mp_buf *buf, const unsigned char *s, size_t len) { 119 | if (buf->free < len) { 120 | size_t newsize = (buf->len+len)*2; 121 | 122 | buf->b = (unsigned char*)mp_realloc(L, buf->b, buf->len + buf->free, newsize); 123 | buf->free = newsize - buf->len; 124 | } 125 | memcpy(buf->b+buf->len,s,len); 126 | buf->len += len; 127 | buf->free -= len; 128 | } 129 | 130 | void mp_buf_free(lua_State *L, mp_buf *buf) { 131 | mp_realloc(L, buf->b, buf->len + buf->free, 0); /* realloc to 0 = free */ 132 | mp_realloc(L, buf, sizeof(*buf), 0); 133 | } 134 | 135 | /* ---------------------------- String cursor ---------------------------------- 136 | * This simple data structure is used for parsing. Basically you create a cursor 137 | * using a string pointer and a length, then it is possible to access the 138 | * current string position with cursor->p, check the remaining length 139 | * in cursor->left, and finally consume more string using 140 | * mp_cur_consume(cursor,len), to advance 'p' and subtract 'left'. 141 | * An additional field cursor->error is set to zero on initialization and can 142 | * be used to report errors. */ 143 | 144 | #define MP_CUR_ERROR_NONE 0 145 | #define MP_CUR_ERROR_EOF 1 /* Not enough data to complete operation. */ 146 | #define MP_CUR_ERROR_BADFMT 2 /* Bad data format */ 147 | 148 | typedef struct mp_cur { 149 | const unsigned char *p; 150 | size_t left; 151 | int err; 152 | } mp_cur; 153 | 154 | void mp_cur_init(mp_cur *cursor, const unsigned char *s, size_t len) { 155 | cursor->p = s; 156 | cursor->left = len; 157 | cursor->err = MP_CUR_ERROR_NONE; 158 | } 159 | 160 | #define mp_cur_consume(_c,_len) do { _c->p += _len; _c->left -= _len; } while(0) 161 | 162 | /* When there is not enough room we set an error in the cursor and return. This 163 | * is very common across the code so we have a macro to make the code look 164 | * a bit simpler. */ 165 | #define mp_cur_need(_c,_len) do { \ 166 | if (_c->left < _len) { \ 167 | _c->err = MP_CUR_ERROR_EOF; \ 168 | return; \ 169 | } \ 170 | } while(0) 171 | 172 | /* ------------------------- Low level MP encoding -------------------------- */ 173 | 174 | void mp_encode_bytes(lua_State *L, mp_buf *buf, const unsigned char *s, size_t len) { 175 | unsigned char hdr[5]; 176 | int hdrlen; 177 | 178 | if (len < 32) { 179 | hdr[0] = 0xa0 | (len&0xff); /* fix raw */ 180 | hdrlen = 1; 181 | } else if (len <= 0xff) { 182 | hdr[0] = 0xd9; 183 | hdr[1] = len; 184 | hdrlen = 2; 185 | } else if (len <= 0xffff) { 186 | hdr[0] = 0xda; 187 | hdr[1] = (len&0xff00)>>8; 188 | hdr[2] = len&0xff; 189 | hdrlen = 3; 190 | } else { 191 | hdr[0] = 0xdb; 192 | hdr[1] = (len&0xff000000)>>24; 193 | hdr[2] = (len&0xff0000)>>16; 194 | hdr[3] = (len&0xff00)>>8; 195 | hdr[4] = len&0xff; 196 | hdrlen = 5; 197 | } 198 | mp_buf_append(L,buf,hdr,hdrlen); 199 | mp_buf_append(L,buf,s,len); 200 | } 201 | 202 | /* we assume IEEE 754 internal format for single and double precision floats. */ 203 | void mp_encode_double(lua_State *L, mp_buf *buf, double d) { 204 | unsigned char b[9]; 205 | float f = d; 206 | 207 | assert(sizeof(f) == 4 && sizeof(d) == 8); 208 | if (d == (double)f) { 209 | b[0] = 0xca; /* float IEEE 754 */ 210 | memcpy(b+1,&f,4); 211 | memrevifle(b+1,4); 212 | mp_buf_append(L,buf,b,5); 213 | } else if (sizeof(d) == 8) { 214 | b[0] = 0xcb; /* double IEEE 754 */ 215 | memcpy(b+1,&d,8); 216 | memrevifle(b+1,8); 217 | mp_buf_append(L,buf,b,9); 218 | } 219 | } 220 | 221 | void mp_encode_int(lua_State *L, mp_buf *buf, int64_t n) { 222 | unsigned char b[9]; 223 | int enclen; 224 | 225 | if (n >= 0) { 226 | if (n <= 127) { 227 | b[0] = n & 0x7f; /* positive fixnum */ 228 | enclen = 1; 229 | } else if (n <= 0xff) { 230 | b[0] = 0xcc; /* uint 8 */ 231 | b[1] = n & 0xff; 232 | enclen = 2; 233 | } else if (n <= 0xffff) { 234 | b[0] = 0xcd; /* uint 16 */ 235 | b[1] = (n & 0xff00) >> 8; 236 | b[2] = n & 0xff; 237 | enclen = 3; 238 | } else if (n <= 0xffffffffLL) { 239 | b[0] = 0xce; /* uint 32 */ 240 | b[1] = (n & 0xff000000) >> 24; 241 | b[2] = (n & 0xff0000) >> 16; 242 | b[3] = (n & 0xff00) >> 8; 243 | b[4] = n & 0xff; 244 | enclen = 5; 245 | } else { 246 | b[0] = 0xcf; /* uint 64 */ 247 | b[1] = (n & 0xff00000000000000LL) >> 56; 248 | b[2] = (n & 0xff000000000000LL) >> 48; 249 | b[3] = (n & 0xff0000000000LL) >> 40; 250 | b[4] = (n & 0xff00000000LL) >> 32; 251 | b[5] = (n & 0xff000000) >> 24; 252 | b[6] = (n & 0xff0000) >> 16; 253 | b[7] = (n & 0xff00) >> 8; 254 | b[8] = n & 0xff; 255 | enclen = 9; 256 | } 257 | } else { 258 | if (n >= -32) { 259 | b[0] = ((signed char)n); /* negative fixnum */ 260 | enclen = 1; 261 | } else if (n >= -128) { 262 | b[0] = 0xd0; /* int 8 */ 263 | b[1] = n & 0xff; 264 | enclen = 2; 265 | } else if (n >= -32768) { 266 | b[0] = 0xd1; /* int 16 */ 267 | b[1] = (n & 0xff00) >> 8; 268 | b[2] = n & 0xff; 269 | enclen = 3; 270 | } else if (n >= -2147483648LL) { 271 | b[0] = 0xd2; /* int 32 */ 272 | b[1] = (n & 0xff000000) >> 24; 273 | b[2] = (n & 0xff0000) >> 16; 274 | b[3] = (n & 0xff00) >> 8; 275 | b[4] = n & 0xff; 276 | enclen = 5; 277 | } else { 278 | b[0] = 0xd3; /* int 64 */ 279 | b[1] = (n & 0xff00000000000000LL) >> 56; 280 | b[2] = (n & 0xff000000000000LL) >> 48; 281 | b[3] = (n & 0xff0000000000LL) >> 40; 282 | b[4] = (n & 0xff00000000LL) >> 32; 283 | b[5] = (n & 0xff000000) >> 24; 284 | b[6] = (n & 0xff0000) >> 16; 285 | b[7] = (n & 0xff00) >> 8; 286 | b[8] = n & 0xff; 287 | enclen = 9; 288 | } 289 | } 290 | mp_buf_append(L,buf,b,enclen); 291 | } 292 | 293 | void mp_encode_array(lua_State *L, mp_buf *buf, int64_t n) { 294 | unsigned char b[5]; 295 | int enclen; 296 | 297 | if (n <= 15) { 298 | b[0] = 0x90 | (n & 0xf); /* fix array */ 299 | enclen = 1; 300 | } else if (n <= 65535) { 301 | b[0] = 0xdc; /* array 16 */ 302 | b[1] = (n & 0xff00) >> 8; 303 | b[2] = n & 0xff; 304 | enclen = 3; 305 | } else { 306 | b[0] = 0xdd; /* array 32 */ 307 | b[1] = (n & 0xff000000) >> 24; 308 | b[2] = (n & 0xff0000) >> 16; 309 | b[3] = (n & 0xff00) >> 8; 310 | b[4] = n & 0xff; 311 | enclen = 5; 312 | } 313 | mp_buf_append(L,buf,b,enclen); 314 | } 315 | 316 | void mp_encode_map(lua_State *L, mp_buf *buf, int64_t n) { 317 | unsigned char b[5]; 318 | int enclen; 319 | 320 | if (n <= 15) { 321 | b[0] = 0x80 | (n & 0xf); /* fix map */ 322 | enclen = 1; 323 | } else if (n <= 65535) { 324 | b[0] = 0xde; /* map 16 */ 325 | b[1] = (n & 0xff00) >> 8; 326 | b[2] = n & 0xff; 327 | enclen = 3; 328 | } else { 329 | b[0] = 0xdf; /* map 32 */ 330 | b[1] = (n & 0xff000000) >> 24; 331 | b[2] = (n & 0xff0000) >> 16; 332 | b[3] = (n & 0xff00) >> 8; 333 | b[4] = n & 0xff; 334 | enclen = 5; 335 | } 336 | mp_buf_append(L,buf,b,enclen); 337 | } 338 | 339 | /* --------------------------- Lua types encoding --------------------------- */ 340 | 341 | void mp_encode_lua_string(lua_State *L, mp_buf *buf) { 342 | size_t len; 343 | const char *s; 344 | 345 | s = lua_tolstring(L,-1,&len); 346 | mp_encode_bytes(L,buf,(const unsigned char*)s,len); 347 | } 348 | 349 | void mp_encode_lua_bool(lua_State *L, mp_buf *buf) { 350 | unsigned char b = lua_toboolean(L,-1) ? 0xc3 : 0xc2; 351 | mp_buf_append(L,buf,&b,1); 352 | } 353 | 354 | /* Lua 5.3 has a built in 64-bit integer type */ 355 | void mp_encode_lua_integer(lua_State *L, mp_buf *buf) { 356 | #if (LUA_VERSION_NUM < 503) && BITS_32 357 | lua_Number i = lua_tonumber(L,-1); 358 | #else 359 | lua_Integer i = lua_tointeger(L,-1); 360 | #endif 361 | mp_encode_int(L, buf, (int64_t)i); 362 | } 363 | 364 | /* Lua 5.2 and lower only has 64-bit doubles, so we need to 365 | * detect if the double may be representable as an int 366 | * for Lua < 5.3 */ 367 | void mp_encode_lua_number(lua_State *L, mp_buf *buf) { 368 | lua_Number n = lua_tonumber(L,-1); 369 | 370 | if (IS_INT64_EQUIVALENT(n)) { 371 | mp_encode_lua_integer(L, buf); 372 | } else { 373 | mp_encode_double(L,buf,(double)n); 374 | } 375 | } 376 | 377 | void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level); 378 | 379 | /* Convert a lua table into a message pack list. */ 380 | void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) { 381 | #if LUA_VERSION_NUM < 502 382 | size_t len = lua_objlen(L,-1), j; 383 | #else 384 | size_t len = lua_rawlen(L,-1), j; 385 | #endif 386 | 387 | mp_encode_array(L,buf,len); 388 | luaL_checkstack(L, 1, "in function mp_encode_lua_table_as_array"); 389 | for (j = 1; j <= len; j++) { 390 | lua_pushnumber(L,j); 391 | lua_gettable(L,-2); 392 | mp_encode_lua_type(L,buf,level+1); 393 | } 394 | } 395 | 396 | /* Convert a lua table into a message pack key-value map. */ 397 | void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) { 398 | size_t len = 0; 399 | 400 | /* First step: count keys into table. No other way to do it with the 401 | * Lua API, we need to iterate a first time. Note that an alternative 402 | * would be to do a single run, and then hack the buffer to insert the 403 | * map opcodes for message pack. Too hackish for this lib. */ 404 | luaL_checkstack(L, 3, "in function mp_encode_lua_table_as_map"); 405 | lua_pushnil(L); 406 | while(lua_next(L,-2)) { 407 | lua_pop(L,1); /* remove value, keep key for next iteration. */ 408 | len++; 409 | } 410 | 411 | /* Step two: actually encoding of the map. */ 412 | mp_encode_map(L,buf,len); 413 | lua_pushnil(L); 414 | while(lua_next(L,-2)) { 415 | /* Stack: ... key value */ 416 | lua_pushvalue(L,-2); /* Stack: ... key value key */ 417 | mp_encode_lua_type(L,buf,level+1); /* encode key */ 418 | mp_encode_lua_type(L,buf,level+1); /* encode val */ 419 | } 420 | } 421 | 422 | /* Returns true if the Lua table on top of the stack is exclusively composed 423 | * of keys from numerical keys from 1 up to N, with N being the total number 424 | * of elements, without any hole in the middle. */ 425 | int table_is_an_array(lua_State *L) { 426 | int count = 0, max = 0; 427 | #if LUA_VERSION_NUM < 503 428 | lua_Number n; 429 | #else 430 | lua_Integer n; 431 | #endif 432 | 433 | /* Stack top on function entry */ 434 | int stacktop; 435 | 436 | stacktop = lua_gettop(L); 437 | 438 | lua_pushnil(L); 439 | while(lua_next(L,-2)) { 440 | /* Stack: ... key value */ 441 | lua_pop(L,1); /* Stack: ... key */ 442 | /* The <= 0 check is valid here because we're comparing indexes. */ 443 | #if LUA_VERSION_NUM < 503 444 | if ((LUA_TNUMBER != lua_type(L,-1)) || (n = lua_tonumber(L, -1)) <= 0 || 445 | !IS_INT_EQUIVALENT(n)) 446 | #else 447 | if (!lua_isinteger(L,-1) || (n = lua_tointeger(L, -1)) <= 0) 448 | #endif 449 | { 450 | lua_settop(L, stacktop); 451 | return 0; 452 | } 453 | max = (n > max ? n : max); 454 | count++; 455 | } 456 | /* We have the total number of elements in "count". Also we have 457 | * the max index encountered in "max". We can't reach this code 458 | * if there are indexes <= 0. If you also note that there can not be 459 | * repeated keys into a table, you have that if max==count you are sure 460 | * that there are all the keys form 1 to count (both included). */ 461 | lua_settop(L, stacktop); 462 | return max == count; 463 | } 464 | 465 | /* If the length operator returns non-zero, that is, there is at least 466 | * an object at key '1', we serialize to message pack list. Otherwise 467 | * we use a map. */ 468 | void mp_encode_lua_table(lua_State *L, mp_buf *buf, int level) { 469 | if (table_is_an_array(L)) 470 | mp_encode_lua_table_as_array(L,buf,level); 471 | else 472 | mp_encode_lua_table_as_map(L,buf,level); 473 | } 474 | 475 | void mp_encode_lua_null(lua_State *L, mp_buf *buf) { 476 | unsigned char b[1]; 477 | 478 | b[0] = 0xc0; 479 | mp_buf_append(L,buf,b,1); 480 | } 481 | 482 | void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level) { 483 | int t = lua_type(L,-1); 484 | 485 | /* Limit the encoding of nested tables to a specified maximum depth, so that 486 | * we survive when called against circular references in tables. */ 487 | if (t == LUA_TTABLE && level == LUACMSGPACK_MAX_NESTING) t = LUA_TNIL; 488 | switch(t) { 489 | case LUA_TSTRING: mp_encode_lua_string(L,buf); break; 490 | case LUA_TBOOLEAN: mp_encode_lua_bool(L,buf); break; 491 | case LUA_TNUMBER: 492 | #if LUA_VERSION_NUM < 503 493 | mp_encode_lua_number(L,buf); break; 494 | #else 495 | if (lua_isinteger(L, -1)) { 496 | mp_encode_lua_integer(L, buf); 497 | } else { 498 | mp_encode_lua_number(L, buf); 499 | } 500 | break; 501 | #endif 502 | case LUA_TTABLE: mp_encode_lua_table(L,buf,level); break; 503 | default: mp_encode_lua_null(L,buf); break; 504 | } 505 | lua_pop(L,1); 506 | } 507 | 508 | /* 509 | * Packs all arguments as a stream for multiple upacking later. 510 | * Returns error if no arguments provided. 511 | */ 512 | int mp_pack(lua_State *L) { 513 | int nargs = lua_gettop(L); 514 | int i; 515 | mp_buf *buf; 516 | 517 | if (nargs == 0) 518 | return luaL_argerror(L, 0, "MessagePack pack needs input."); 519 | 520 | if (!lua_checkstack(L, nargs)) 521 | return luaL_argerror(L, 0, "Too many arguments for MessagePack pack."); 522 | 523 | buf = mp_buf_new(L); 524 | for(i = 1; i <= nargs; i++) { 525 | /* Copy argument i to top of stack for _encode processing; 526 | * the encode function pops it from the stack when complete. */ 527 | luaL_checkstack(L, 1, "in function mp_check"); 528 | lua_pushvalue(L, i); 529 | 530 | mp_encode_lua_type(L,buf,0); 531 | 532 | lua_pushlstring(L,(char*)buf->b,buf->len); 533 | 534 | /* Reuse the buffer for the next operation by 535 | * setting its free count to the total buffer size 536 | * and the current position to zero. */ 537 | buf->free += buf->len; 538 | buf->len = 0; 539 | } 540 | mp_buf_free(L, buf); 541 | 542 | /* Concatenate all nargs buffers together */ 543 | lua_concat(L, nargs); 544 | return 1; 545 | } 546 | 547 | /* ------------------------------- Decoding --------------------------------- */ 548 | 549 | void mp_decode_to_lua_type(lua_State *L, mp_cur *c); 550 | 551 | void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) { 552 | assert(len <= UINT_MAX); 553 | int index = 1; 554 | 555 | lua_newtable(L); 556 | luaL_checkstack(L, 1, "in function mp_decode_to_lua_array"); 557 | while(len--) { 558 | lua_pushnumber(L,index++); 559 | mp_decode_to_lua_type(L,c); 560 | if (c->err) return; 561 | lua_settable(L,-3); 562 | } 563 | } 564 | 565 | void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) { 566 | assert(len <= UINT_MAX); 567 | lua_newtable(L); 568 | while(len--) { 569 | mp_decode_to_lua_type(L,c); /* key */ 570 | if (c->err) return; 571 | mp_decode_to_lua_type(L,c); /* value */ 572 | if (c->err) return; 573 | lua_settable(L,-3); 574 | } 575 | } 576 | 577 | /* Decode a Message Pack raw object pointed by the string cursor 'c' to 578 | * a Lua type, that is left as the only result on the stack. */ 579 | void mp_decode_to_lua_type(lua_State *L, mp_cur *c) { 580 | mp_cur_need(c,1); 581 | 582 | /* If we return more than 18 elements, we must resize the stack to 583 | * fit all our return values. But, there is no way to 584 | * determine how many objects a msgpack will unpack to up front, so 585 | * we request a +1 larger stack on each iteration (noop if stack is 586 | * big enough, and when stack does require resize it doubles in size) */ 587 | luaL_checkstack(L, 1, 588 | "too many return values at once; " 589 | "use unpack_one or unpack_limit instead."); 590 | 591 | switch(c->p[0]) { 592 | case 0xcc: /* uint 8 */ 593 | mp_cur_need(c,2); 594 | lua_pushunsigned(L,c->p[1]); 595 | mp_cur_consume(c,2); 596 | break; 597 | case 0xd0: /* int 8 */ 598 | mp_cur_need(c,2); 599 | lua_pushinteger(L,(signed char)c->p[1]); 600 | mp_cur_consume(c,2); 601 | break; 602 | case 0xcd: /* uint 16 */ 603 | mp_cur_need(c,3); 604 | lua_pushunsigned(L, 605 | (c->p[1] << 8) | 606 | c->p[2]); 607 | mp_cur_consume(c,3); 608 | break; 609 | case 0xd1: /* int 16 */ 610 | mp_cur_need(c,3); 611 | lua_pushinteger(L,(int16_t) 612 | (c->p[1] << 8) | 613 | c->p[2]); 614 | mp_cur_consume(c,3); 615 | break; 616 | case 0xce: /* uint 32 */ 617 | mp_cur_need(c,5); 618 | lua_pushunsigned(L, 619 | ((uint32_t)c->p[1] << 24) | 620 | ((uint32_t)c->p[2] << 16) | 621 | ((uint32_t)c->p[3] << 8) | 622 | (uint32_t)c->p[4]); 623 | mp_cur_consume(c,5); 624 | break; 625 | case 0xd2: /* int 32 */ 626 | mp_cur_need(c,5); 627 | lua_pushinteger(L, 628 | ((int32_t)c->p[1] << 24) | 629 | ((int32_t)c->p[2] << 16) | 630 | ((int32_t)c->p[3] << 8) | 631 | (int32_t)c->p[4]); 632 | mp_cur_consume(c,5); 633 | break; 634 | case 0xcf: /* uint 64 */ 635 | mp_cur_need(c,9); 636 | lua_pushunsigned(L, 637 | ((uint64_t)c->p[1] << 56) | 638 | ((uint64_t)c->p[2] << 48) | 639 | ((uint64_t)c->p[3] << 40) | 640 | ((uint64_t)c->p[4] << 32) | 641 | ((uint64_t)c->p[5] << 24) | 642 | ((uint64_t)c->p[6] << 16) | 643 | ((uint64_t)c->p[7] << 8) | 644 | (uint64_t)c->p[8]); 645 | mp_cur_consume(c,9); 646 | break; 647 | case 0xd3: /* int 64 */ 648 | mp_cur_need(c,9); 649 | #if LUA_VERSION_NUM < 503 650 | lua_pushnumber(L, 651 | #else 652 | lua_pushinteger(L, 653 | #endif 654 | ((int64_t)c->p[1] << 56) | 655 | ((int64_t)c->p[2] << 48) | 656 | ((int64_t)c->p[3] << 40) | 657 | ((int64_t)c->p[4] << 32) | 658 | ((int64_t)c->p[5] << 24) | 659 | ((int64_t)c->p[6] << 16) | 660 | ((int64_t)c->p[7] << 8) | 661 | (int64_t)c->p[8]); 662 | mp_cur_consume(c,9); 663 | break; 664 | case 0xc0: /* nil */ 665 | lua_pushnil(L); 666 | mp_cur_consume(c,1); 667 | break; 668 | case 0xc3: /* true */ 669 | lua_pushboolean(L,1); 670 | mp_cur_consume(c,1); 671 | break; 672 | case 0xc2: /* false */ 673 | lua_pushboolean(L,0); 674 | mp_cur_consume(c,1); 675 | break; 676 | case 0xca: /* float */ 677 | mp_cur_need(c,5); 678 | assert(sizeof(float) == 4); 679 | { 680 | float f; 681 | memcpy(&f,c->p+1,4); 682 | memrevifle(&f,4); 683 | lua_pushnumber(L,f); 684 | mp_cur_consume(c,5); 685 | } 686 | break; 687 | case 0xcb: /* double */ 688 | mp_cur_need(c,9); 689 | assert(sizeof(double) == 8); 690 | { 691 | double d; 692 | memcpy(&d,c->p+1,8); 693 | memrevifle(&d,8); 694 | lua_pushnumber(L,d); 695 | mp_cur_consume(c,9); 696 | } 697 | break; 698 | case 0xd9: /* raw 8 */ 699 | mp_cur_need(c,2); 700 | { 701 | size_t l = c->p[1]; 702 | mp_cur_need(c,2+l); 703 | lua_pushlstring(L,(char*)c->p+2,l); 704 | mp_cur_consume(c,2+l); 705 | } 706 | break; 707 | case 0xda: /* raw 16 */ 708 | mp_cur_need(c,3); 709 | { 710 | size_t l = (c->p[1] << 8) | c->p[2]; 711 | mp_cur_need(c,3+l); 712 | lua_pushlstring(L,(char*)c->p+3,l); 713 | mp_cur_consume(c,3+l); 714 | } 715 | break; 716 | case 0xdb: /* raw 32 */ 717 | mp_cur_need(c,5); 718 | { 719 | size_t l = ((size_t)c->p[1] << 24) | 720 | ((size_t)c->p[2] << 16) | 721 | ((size_t)c->p[3] << 8) | 722 | (size_t)c->p[4]; 723 | mp_cur_consume(c,5); 724 | mp_cur_need(c,l); 725 | lua_pushlstring(L,(char*)c->p,l); 726 | mp_cur_consume(c,l); 727 | } 728 | break; 729 | case 0xdc: /* array 16 */ 730 | mp_cur_need(c,3); 731 | { 732 | size_t l = (c->p[1] << 8) | c->p[2]; 733 | mp_cur_consume(c,3); 734 | mp_decode_to_lua_array(L,c,l); 735 | } 736 | break; 737 | case 0xdd: /* array 32 */ 738 | mp_cur_need(c,5); 739 | { 740 | size_t l = ((size_t)c->p[1] << 24) | 741 | ((size_t)c->p[2] << 16) | 742 | ((size_t)c->p[3] << 8) | 743 | (size_t)c->p[4]; 744 | mp_cur_consume(c,5); 745 | mp_decode_to_lua_array(L,c,l); 746 | } 747 | break; 748 | case 0xde: /* map 16 */ 749 | mp_cur_need(c,3); 750 | { 751 | size_t l = (c->p[1] << 8) | c->p[2]; 752 | mp_cur_consume(c,3); 753 | mp_decode_to_lua_hash(L,c,l); 754 | } 755 | break; 756 | case 0xdf: /* map 32 */ 757 | mp_cur_need(c,5); 758 | { 759 | size_t l = ((size_t)c->p[1] << 24) | 760 | ((size_t)c->p[2] << 16) | 761 | ((size_t)c->p[3] << 8) | 762 | (size_t)c->p[4]; 763 | mp_cur_consume(c,5); 764 | mp_decode_to_lua_hash(L,c,l); 765 | } 766 | break; 767 | default: /* types that can't be idenitified by first byte value. */ 768 | if ((c->p[0] & 0x80) == 0) { /* positive fixnum */ 769 | lua_pushunsigned(L,c->p[0]); 770 | mp_cur_consume(c,1); 771 | } else if ((c->p[0] & 0xe0) == 0xe0) { /* negative fixnum */ 772 | lua_pushinteger(L,(signed char)c->p[0]); 773 | mp_cur_consume(c,1); 774 | } else if ((c->p[0] & 0xe0) == 0xa0) { /* fix raw */ 775 | size_t l = c->p[0] & 0x1f; 776 | mp_cur_need(c,1+l); 777 | lua_pushlstring(L,(char*)c->p+1,l); 778 | mp_cur_consume(c,1+l); 779 | } else if ((c->p[0] & 0xf0) == 0x90) { /* fix map */ 780 | size_t l = c->p[0] & 0xf; 781 | mp_cur_consume(c,1); 782 | mp_decode_to_lua_array(L,c,l); 783 | } else if ((c->p[0] & 0xf0) == 0x80) { /* fix map */ 784 | size_t l = c->p[0] & 0xf; 785 | mp_cur_consume(c,1); 786 | mp_decode_to_lua_hash(L,c,l); 787 | } else { 788 | c->err = MP_CUR_ERROR_BADFMT; 789 | } 790 | } 791 | } 792 | 793 | int mp_unpack_full(lua_State *L, int limit, int offset) { 794 | size_t len; 795 | const char *s; 796 | mp_cur c; 797 | int cnt; /* Number of objects unpacked */ 798 | int decode_all = (!limit && !offset); 799 | 800 | s = luaL_checklstring(L,1,&len); /* if no match, exits */ 801 | 802 | if (offset < 0 || limit < 0) /* requesting negative off or lim is invalid */ 803 | return luaL_error(L, 804 | "Invalid request to unpack with offset of %d and limit of %d.", 805 | offset, len); 806 | else if (offset > len) 807 | return luaL_error(L, 808 | "Start offset %d greater than input length %d.", offset, len); 809 | 810 | if (decode_all) limit = INT_MAX; 811 | 812 | mp_cur_init(&c,(const unsigned char *)s+offset,len-offset); 813 | 814 | /* We loop over the decode because this could be a stream 815 | * of multiple top-level values serialized together */ 816 | for(cnt = 0; c.left > 0 && cnt < limit; cnt++) { 817 | mp_decode_to_lua_type(L,&c); 818 | 819 | if (c.err == MP_CUR_ERROR_EOF) { 820 | return luaL_error(L,"Missing bytes in input."); 821 | } else if (c.err == MP_CUR_ERROR_BADFMT) { 822 | return luaL_error(L,"Bad data format in input."); 823 | } 824 | } 825 | 826 | if (!decode_all) { 827 | /* c->left is the remaining size of the input buffer. 828 | * subtract the entire buffer size from the unprocessed size 829 | * to get our next start offset */ 830 | int offset = len - c.left; 831 | 832 | luaL_checkstack(L, 1, "in function mp_unpack_full"); 833 | 834 | /* Return offset -1 when we have have processed the entire buffer. */ 835 | lua_pushinteger(L, c.left == 0 ? -1 : offset); 836 | /* Results are returned with the arg elements still 837 | * in place. Lua takes care of only returning 838 | * elements above the args for us. 839 | * In this case, we have one arg on the stack 840 | * for this function, so we insert our first return 841 | * value at position 2. */ 842 | lua_insert(L, 2); 843 | cnt += 1; /* increase return count by one to make room for offset */ 844 | } 845 | 846 | return cnt; 847 | } 848 | 849 | int mp_unpack(lua_State *L) { 850 | return mp_unpack_full(L, 0, 0); 851 | } 852 | 853 | int mp_unpack_one(lua_State *L) { 854 | int offset = luaL_optinteger(L, 2, 0); 855 | /* Variable pop because offset may not exist */ 856 | lua_pop(L, lua_gettop(L)-1); 857 | return mp_unpack_full(L, 1, offset); 858 | } 859 | 860 | int mp_unpack_limit(lua_State *L) { 861 | int limit = luaL_checkinteger(L, 2); 862 | int offset = luaL_optinteger(L, 3, 0); 863 | /* Variable pop because offset may not exist */ 864 | lua_pop(L, lua_gettop(L)-1); 865 | 866 | return mp_unpack_full(L, limit, offset); 867 | } 868 | 869 | int mp_safe(lua_State *L) { 870 | int argc, err, total_results; 871 | 872 | argc = lua_gettop(L); 873 | 874 | /* This adds our function to the bottom of the stack 875 | * (the "call this function" position) */ 876 | lua_pushvalue(L, lua_upvalueindex(1)); 877 | lua_insert(L, 1); 878 | 879 | err = lua_pcall(L, argc, LUA_MULTRET, 0); 880 | total_results = lua_gettop(L); 881 | 882 | if (!err) { 883 | return total_results; 884 | } else { 885 | lua_pushnil(L); 886 | lua_insert(L,-2); 887 | return 2; 888 | } 889 | } 890 | 891 | /* -------------------------------------------------------------------------- */ 892 | const struct luaL_Reg cmds[] = { 893 | {"pack", mp_pack}, 894 | {"unpack", mp_unpack}, 895 | {"unpack_one", mp_unpack_one}, 896 | {"unpack_limit", mp_unpack_limit}, 897 | {0} 898 | }; 899 | 900 | int luaopen_create(lua_State *L) { 901 | int i; 902 | /* Manually construct our module table instead of 903 | * relying on _register or _newlib */ 904 | lua_newtable(L); 905 | 906 | for (i = 0; i < (sizeof(cmds)/sizeof(*cmds) - 1); i++) { 907 | lua_pushcfunction(L, cmds[i].func); 908 | lua_setfield(L, -2, cmds[i].name); 909 | } 910 | 911 | /* Add metadata */ 912 | lua_pushliteral(L, LUACMSGPACK_NAME); 913 | lua_setfield(L, -2, "_NAME"); 914 | lua_pushliteral(L, LUACMSGPACK_VERSION); 915 | lua_setfield(L, -2, "_VERSION"); 916 | lua_pushliteral(L, LUACMSGPACK_COPYRIGHT); 917 | lua_setfield(L, -2, "_COPYRIGHT"); 918 | lua_pushliteral(L, LUACMSGPACK_DESCRIPTION); 919 | lua_setfield(L, -2, "_DESCRIPTION"); 920 | return 1; 921 | } 922 | 923 | LUALIB_API int luaopen_cmsgpack(lua_State *L) { 924 | luaopen_create(L); 925 | 926 | #if LUA_VERSION_NUM < 502 927 | /* Register name globally for 5.1 */ 928 | lua_pushvalue(L, -1); 929 | lua_setglobal(L, LUACMSGPACK_NAME); 930 | #endif 931 | 932 | return 1; 933 | } 934 | 935 | LUALIB_API int luaopen_cmsgpack_safe(lua_State *L) { 936 | int i; 937 | 938 | luaopen_cmsgpack(L); 939 | 940 | /* Wrap all functions in the safe handler */ 941 | for (i = 0; i < (sizeof(cmds)/sizeof(*cmds) - 1); i++) { 942 | lua_getfield(L, -1, cmds[i].name); 943 | lua_pushcclosure(L, mp_safe, 1); 944 | lua_setfield(L, -2, cmds[i].name); 945 | } 946 | 947 | #if LUA_VERSION_NUM < 502 948 | /* Register name globally for 5.1 */ 949 | lua_pushvalue(L, -1); 950 | lua_setglobal(L, LUACMSGPACK_SAFE_NAME); 951 | #endif 952 | 953 | return 1; 954 | } 955 | 956 | /****************************************************************************** 957 | * Copyright (C) 2012 Salvatore Sanfilippo. All rights reserved. 958 | * 959 | * Permission is hereby granted, free of charge, to any person obtaining 960 | * a copy of this software and associated documentation files (the 961 | * "Software"), to deal in the Software without restriction, including 962 | * without limitation the rights to use, copy, modify, merge, publish, 963 | * distribute, sublicense, and/or sell copies of the Software, and to 964 | * permit persons to whom the Software is furnished to do so, subject to 965 | * the following conditions: 966 | * 967 | * The above copyright notice and this permission notice shall be 968 | * included in all copies or substantial portions of the Software. 969 | * 970 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 971 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 972 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 973 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 974 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 975 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 976 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 977 | ******************************************************************************/ 978 | -------------------------------------------------------------------------------- /rockspec/lua-cmsgpack-0.3-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-cmsgpack" 2 | version = "0.3-0" 3 | source = { 4 | url = "git://github.com/antirez/lua-cmsgpack.git", 5 | branch = "0.3.0" 6 | } 7 | description = { 8 | summary = "MessagePack C implementation and bindings for Lua 5.1", 9 | homepage = "http://github.com/antirez/lua-cmsgpack", 10 | license = "Two-clause BSD", 11 | maintainer = "Salvatore Sanfilippo " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | cmsgpack = { 20 | sources = { 21 | "lua_cmsgpack.c", 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rockspec/lua-cmsgpack-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-cmsgpack" 2 | version = "0.3.1-0" 3 | source = { 4 | url = "git://github.com/antirez/lua-cmsgpack.git", 5 | tag = "0.3.1" 6 | } 7 | description = { 8 | summary = "MessagePack C implementation and bindings for Lua 5.1/5.2", 9 | homepage = "http://github.com/antirez/lua-cmsgpack", 10 | license = "Two-clause BSD", 11 | maintainer = "Salvatore Sanfilippo " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | cmsgpack = { 20 | sources = { 21 | "lua_cmsgpack.c", 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rockspec/lua-cmsgpack-0.4.0-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-cmsgpack" 2 | version = "0.4.0-0" 3 | source = { 4 | url = "git://github.com/antirez/lua-cmsgpack.git", 5 | tag = "0.4.0" 6 | } 7 | description = { 8 | summary = "MessagePack C implementation and bindings for Lua 5.1/5.2/5.3", 9 | homepage = "http://github.com/antirez/lua-cmsgpack", 10 | license = "Two-clause BSD", 11 | maintainer = "Salvatore Sanfilippo " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | cmsgpack = { 20 | sources = { 21 | "lua_cmsgpack.c" 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rockspec/lua-cmsgpack-scm-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-cmsgpack" 2 | version = "scm-1" 3 | source = { 4 | url = "git://github.com/antirez/lua-cmsgpack.git", 5 | branch = "master" 6 | } 7 | description = { 8 | summary = "MessagePack C implementation and bindings for Lua 5.1", 9 | homepage = "http://github.com/antirez/lua-cmsgpack", 10 | license = "Two-clause BSD", 11 | maintainer = "Salvatore Sanfilippo " 12 | } 13 | dependencies = { 14 | "lua >= 5.1" 15 | } 16 | build = { 17 | type = "builtin", 18 | modules = { 19 | cmsgpack = { 20 | sources = { 21 | "lua_cmsgpack.c" 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | -- lua_cmsgpack.c lib tests 2 | -- Copyright(C) 2012 Salvatore Sanfilippo, All Rights Reserved. 3 | -- See the copyright notice at the end of lua_cmsgpack.c for more information. 4 | 5 | local cmsgpack = require "cmsgpack" 6 | local ok, cmsgpack_safe = pcall(require, 'cmsgpack.safe') 7 | if not ok then cmsgpack_safe = nil end 8 | 9 | print("------------------------------------") 10 | print("Lua version: " .. (_G.jit and _G.jit.version or _G._VERSION)) 11 | print("------------------------------------") 12 | 13 | local unpack = unpack or table.unpack 14 | 15 | passed = 0 16 | failed = 0 17 | skipped = 0 18 | 19 | function hex(s) 20 | local i 21 | local h = "" 22 | 23 | for i = 1, #s do 24 | h = h .. string.format("%02x",string.byte(s,i)) 25 | end 26 | return h 27 | end 28 | 29 | function ascii_to_num(c) 30 | if (c >= string.byte("0") and c <= string.byte("9")) then 31 | return c - string.byte("0") 32 | elseif (c >= string.byte("A") and c <= string.byte("F")) then 33 | return (c - string.byte("A"))+10 34 | elseif (c >= string.byte("a") and c <= string.byte("f")) then 35 | return (c - string.byte("a"))+10 36 | else 37 | error "Wrong input for ascii to num convertion." 38 | end 39 | end 40 | 41 | function unhex(h) 42 | local i 43 | local s = "" 44 | for i = 1, #h, 2 do 45 | high = ascii_to_num(string.byte(h,i)) 46 | low = ascii_to_num(string.byte(h,i+1)) 47 | s = s .. string.char((high*16)+low) 48 | end 49 | return s 50 | end 51 | 52 | function test_error(name, fn) 53 | io.write("Testing generate error '",name,"' ...") 54 | local ok, ret, err = pcall(fn) 55 | -- 'ok' is an error because we are testing for expicit *failure* 56 | if ok then 57 | print("ERROR: result ", ret, err) 58 | failed = failed+1 59 | else 60 | print("ok") 61 | passed = passed+1 62 | end 63 | end 64 | 65 | local function test_multiple(name, ...) 66 | io.write("Multiple test '",name,"' ...") 67 | if not compare_objects({...},{cmsgpack.unpack(cmsgpack.pack(...))}) then 68 | print("ERROR:", {...}, cmsgpack.unpack(cmsgpack.pack(...))) 69 | failed = failed+1 70 | else 71 | print("ok") 72 | passed = passed+1 73 | end 74 | end 75 | 76 | function test_noerror(name, fn) 77 | io.write("Testing safe calling '",name,"' ...") 78 | if not cmsgpack_safe then 79 | print("skip: no `cmsgpack.safe` module") 80 | skipped = skipped + 1 81 | return 82 | end 83 | local ok, ret, err = pcall(fn) 84 | if not ok then 85 | print("ERROR: result ", ret, err) 86 | failed = failed+1 87 | else 88 | print("ok") 89 | passed = passed+1 90 | end 91 | end 92 | 93 | function compare_objects(a,b,depth) 94 | if (type(a) == "table") then 95 | local count = 0 96 | if not depth then 97 | depth = 1 98 | elseif depth == 10 then 99 | return true -- assume if match down 10 levels, the rest is okay too 100 | end 101 | for k,v in pairs(a) do 102 | if not compare_objects(b[k],v, depth + 1) then return false end 103 | count = count + 1 104 | end 105 | -- All the 'a' keys are equal to their 'b' equivalents. 106 | -- Now we can check if there are extra fields in 'b'. 107 | for k,v in pairs(b) do count = count - 1 end 108 | if count == 0 then return true else return false end 109 | else 110 | return a == b 111 | end 112 | end 113 | 114 | function test_circular(name,obj) 115 | io.write("Circular test '",name,"' ...") 116 | if not compare_objects(obj,cmsgpack.unpack(cmsgpack.pack(obj))) then 117 | print("ERROR:", obj, cmsgpack.unpack(cmsgpack.pack(obj))) 118 | failed = failed+1 119 | else 120 | print("ok") 121 | passed = passed+1 122 | end 123 | end 124 | 125 | function test_stream(mod, name, ...) 126 | io.write("Stream test '", name, "' ...\n") 127 | if not mod then 128 | print("skip: no `cmsgpack.safe` module") 129 | skipped = skipped + 1 130 | return 131 | end 132 | local argc = select('#', ...) 133 | for i=1, argc do 134 | test_circular(name, select(i, ...)) 135 | end 136 | local ret = {mod.unpack(mod.pack(unpack({...})))} 137 | for i=1, argc do 138 | local origin = select(i, ...) 139 | if (type(origin) == "table") then 140 | for k,v in pairs(origin) do 141 | local fail = not compare_objects(v, ret[i][k]) 142 | if fail then 143 | print("ERRORa:", k, v, " not match ", ret[i][k]) 144 | failed = failed + 1 145 | elseif not fail then 146 | print("ok; matched stream table member") 147 | passed = passed + 1 148 | end 149 | end 150 | else 151 | local fail = not compare_objects(origin, ret[i]) 152 | if fail then 153 | print("ERRORc:", origin, " not match ", ret[i]) 154 | failed = failed + 1 155 | elseif not fail then 156 | print("ok; matched individual stream member") 157 | passed = passed + 1 158 | end 159 | end 160 | end 161 | 162 | end 163 | 164 | function test_partial_unpack(name, count, ...) 165 | io.write("Testing partial unpack '",name,"' ...\n") 166 | local first = select(1, ...) 167 | local pack, unpacked, args, offset, cargs, ok, err 168 | if (type(first) == "table") then 169 | pack = first.p 170 | args = first.remaining 171 | offset = first.o 172 | cargs = {pack, count, offset} 173 | else 174 | pack = cmsgpack.pack(unpack({...})) 175 | args = {...} 176 | cargs = {pack, count} 177 | end 178 | if offset and offset < 0 then 179 | ok, unpacked, err = pcall(function()return {cmsgpack.unpack_limit(unpack(cargs))} end) 180 | if not ok then 181 | print("ok; received error as expected") --, unpacked) 182 | passed = passed + 1 183 | return 184 | end 185 | else 186 | unpacked = {cmsgpack.unpack_limit(unpack(cargs))} 187 | -- print ("GOT RETURNED:", unpack(unpacked)) 188 | end 189 | 190 | if count == 0 and #unpacked == 1 then 191 | print("ok; received zero decodes as expected") 192 | passed = passed + 1 193 | return 194 | end 195 | 196 | if not (((#unpacked)-1) == count) then 197 | print(string.format("ERROR: received %d instead of %d objects:", (#unpacked)-1, count), 198 | unpack(select(1, unpacked))) 199 | failed = failed + 1 200 | return 201 | end 202 | 203 | for i=2, #unpacked do 204 | local origin = args[i-1] 205 | --print("Comparing ", origin, unpacked[i]) 206 | if not compare_objects(origin, unpacked[i]) then 207 | print("ERROR:", origin, " not match ", unpacked[i]) 208 | failed = failed + 1 209 | else 210 | print("ok; matched unpacked value to input") 211 | passed = passed + 1 212 | end 213 | end 214 | 215 | -- return the packed value and our continue offset 216 | return pack, unpacked[1] 217 | end 218 | 219 | function test_pack(name,obj,raw,optraw) 220 | io.write("Testing encoder '",name,"' ...") 221 | local result = hex(cmsgpack.pack(obj)) 222 | if optraw and (result == optraw) then 223 | print("ok") 224 | passed = passed + 1 225 | elseif result ~= raw then 226 | print("ERROR:", obj, hex(cmsgpack.pack(obj)), raw) 227 | failed = failed+1 228 | else 229 | print("ok") 230 | passed = passed+1 231 | end 232 | end 233 | 234 | function test_unpack_one(name, packed, check, offset) 235 | io.write("Testing one unpack '",name,"' ...") 236 | local unpacked = {cmsgpack.unpack_one(unpack({packed, offset}))} 237 | 238 | if #unpacked > 2 then 239 | print("ERROR: unpacked more than one object:", unpack(unpacked)) 240 | failed = failed + 1 241 | elseif not compare_objects(unpacked[2], check) then 242 | print("ERROR: unpacked unexpected result:", unpack(unpacked)) 243 | failed = failed + 1 244 | else 245 | print("ok") --; unpacked", unpacked[2]) 246 | passed = passed + 1 247 | end 248 | 249 | return unpacked[1] 250 | end 251 | 252 | function test_unpack(name,raw,obj) 253 | io.write("Testing decoder '",name,"' ...") 254 | if not compare_objects(cmsgpack.unpack(unhex(raw)),obj) then 255 | print("ERROR:", obj, raw, cmsgpack.unpack(unhex(raw))) 256 | failed = failed+1 257 | else 258 | print("ok") 259 | passed = passed+1 260 | end 261 | end 262 | 263 | function test_pack_and_unpack(name,obj,raw) 264 | test_pack(name,obj,raw) 265 | test_unpack(name,raw,obj) 266 | end 267 | 268 | local function test_global() 269 | io.write("Testing global variable ...") 270 | 271 | if _VERSION == "Lua 5.1" then 272 | if not _G.cmsgpack then 273 | print("ERROR: Lua 5.1 should set global") 274 | failed = failed+1 275 | else 276 | print("ok") 277 | passed = passed+1 278 | end 279 | else 280 | if _G.cmsgpack then 281 | print("ERROR: Lua 5.2 should not set global") 282 | failed = failed+1 283 | else 284 | print("ok") 285 | passed = passed+1 286 | end 287 | end 288 | end 289 | 290 | local function test_array() 291 | io.write("Testing array detection ...") 292 | 293 | local a = {a1 = 1, a2 = 1, a3 = 1, a4 = 1, a5 = 1, a6 = 1, a7 = 1, a8 = 1, a9 = 1} 294 | a[1] = 10 a[2] = 20 a[3] = 30 295 | a.a1,a.a2,a.a3,a.a4,a.a5,a.a6,a.a7,a.a8, a.a9 = nil 296 | 297 | local test_obj = {10,20,30} 298 | assert(compare_objects(test_obj, a)) 299 | 300 | local etalon = cmsgpack.pack(test_obj) 301 | local encode = cmsgpack.pack(a) 302 | 303 | if etalon ~= encode then 304 | print("ERROR:") 305 | print("", "expected: ", hex(etalon)) 306 | print("", " got: ", hex(encode)) 307 | failed = failed+1 308 | else 309 | print("ok") 310 | passed = passed+1 311 | end 312 | 313 | io.write("Testing array detection ...") 314 | 315 | a = {["1"] = 20, [2] = 30, [3] = 40} 316 | encode = cmsgpack.pack(a) 317 | if etalon == encode then 318 | print("ERROR:") 319 | print("", " incorrect: ", hex(etalon)) 320 | failed = failed+1 321 | else 322 | print("ok") 323 | passed = passed+1 324 | end 325 | end 326 | 327 | test_global() 328 | test_array() 329 | test_circular("positive fixnum",17); 330 | test_circular("negative fixnum",-1); 331 | test_circular("true boolean",true); 332 | test_circular("false boolean",false); 333 | test_circular("float",1.5); 334 | test_circular("positive uint8",101); 335 | test_circular("negative int8",-101); 336 | test_circular("positive uint16",20001); 337 | test_circular("negative int16",-20001); 338 | test_circular("positive uint32",20000001); 339 | test_circular("negative int32",-20000001); 340 | test_circular("positive uint64",200000000001); 341 | test_circular("negative int64",-200000000001); 342 | test_circular("uint8 max",0xff); 343 | test_circular("uint16 max",0xffff); 344 | test_circular("uint32 max",0xffffffff); 345 | test_circular("int8 min",-128); 346 | test_circular("int16 min",-32768); 347 | test_circular("int32 min",-2147483648); 348 | test_circular("nil",nil); 349 | test_circular("fix string","abc"); 350 | test_circular("string16","xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"); 351 | test_circular("fix array (1)",{1,2,3,"foo"}) 352 | test_circular("fix array (2)",{}) 353 | test_circular("fix array (3)",{1,{},{}}) 354 | test_circular("fix map",{a=5,b=10,c="string"}) 355 | test_circular("positive infinity", math.huge) 356 | test_circular("negative infinity", -math.huge) 357 | test_circular("high bits", 0xFFFFFFFF) 358 | test_circular("higher bits", 0xFFFFFFFFFFFFFFFF) 359 | test_circular("high bits", -0x7FFFFFFF) 360 | test_circular("higher bits", -0x7FFFFFFFFFFFFFFF) 361 | 362 | -- The following test vectors are taken from the Javascript lib at: 363 | -- https://github.com/cuzic/MessagePack-JS/blob/master/test/test_pack.html 364 | 365 | test_pack_and_unpack("positive fixnum",0,"00") 366 | test_pack_and_unpack("negative fixnum",-1,"ff") 367 | test_pack_and_unpack("uint8",255,"ccff") 368 | test_pack_and_unpack("fix raw","a","a161") 369 | test_pack_and_unpack("fix array",{0},"9100") 370 | test_pack_and_unpack("fix map",{a=64},"81a16140") 371 | test_pack_and_unpack("nil",nil,"c0") 372 | test_pack_and_unpack("true",true,"c3") 373 | test_pack_and_unpack("false",false,"c2") 374 | test_pack_and_unpack("double",0.1,"cb3fb999999999999a") 375 | test_pack_and_unpack("uint16",32768,"cd8000") 376 | test_pack_and_unpack("uint32",1048576,"ce00100000") 377 | test_pack_and_unpack("int8",-64,"d0c0") 378 | test_pack_and_unpack("int16",-1024,"d1fc00") 379 | test_pack_and_unpack("int32",-1048576,"d2fff00000") 380 | test_pack_and_unpack("int64",-1099511627776,"d3ffffff0000000000") 381 | test_pack_and_unpack("raw8"," ","d921202020202020202020202020202020202020202020202020202020202020202020") 382 | test_pack_and_unpack("raw16"," ","da01012020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020") 383 | test_pack_and_unpack("array 16",{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},"dc001000000000000000000000000000000000") 384 | 385 | -- Regression test for issue #4, cyclic references in tables. 386 | a = {x=nil,y=5} 387 | b = {x=a} 388 | a['x'] = b 389 | pack = cmsgpack.pack(a) 390 | -- Note: the generated result isn't stable because the order of traversal for 391 | -- a table isn't defined. So far we've only noticed two serializations of a 392 | -- (and the second serialization only happens on Lua 5.3 sometimes) 393 | test_pack("regression for issue #4 output matching",a,"82a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a178c0", "82a17881a17882a17881a17882a17881a17882a17881a17882a17881a17882a17881a17882a17881a17882a17881a178c0a17905a17905a17905a17905a17905a17905a17905a17905") 394 | test_circular("regression for issue #4 circular",a) 395 | 396 | -- test unpacking malformed input without crashing. This actually returns one integer value (the ASCII code) 397 | -- for each character in the string. We don't care about the return value, just that we don't segfault. 398 | cmsgpack.unpack("82a17881a17882a17881a17882a17881a17882a17881a17882a17881a17882a17881a17882a17881a17882a17881a17") 399 | 400 | -- Test unpacking input which may cause overflow memory access ("-1" for 32-bit size fields). 401 | -- These should cause a Lua error but not a segfault. 402 | test_error("unpack big string with missing input", function() cmsgpack.unpack("\219\255\255\255\255Z") end) 403 | test_error("unpack big array with missing input", function() cmsgpack.unpack("\221\255\255\255\255Z") end) 404 | test_error("unpack big map with missing input", function() cmsgpack.unpack("\223\255\255\255\255Z") end) 405 | 406 | -- Tests from github.com/moteus 407 | test_circular("map with number keys", {[1] = {1,2,3}}) 408 | test_circular("map with string keys", {["1"] = {1,2,3}}) 409 | test_circular("map with string keys", {["1"] = 20, [2] = 30, ["3"] = 40}) 410 | test_circular("map with float keys", {[1.5] = {1,2,3}}) 411 | test_error("unpack nil", function() cmsgpack.unpack(nil) end) 412 | test_error("unpack table", function() cmsgpack.unpack({}) end) 413 | test_error("unpack udata", function() cmsgpack.unpack(io.stdout) end) 414 | test_noerror("unpack nil", function() cmsgpack_safe.unpack(nil) end) 415 | test_noerror("unpack nil", function() cmsgpack_safe.unpack(nil) end) 416 | test_noerror("unpack table", function() cmsgpack_safe.unpack({}) end) 417 | test_noerror("unpack udata", function() cmsgpack_safe.unpack(io.stdout) end) 418 | test_multiple("two ints", 1, 2) 419 | test_multiple("holes", 1, nil, 2, nil, 4) 420 | 421 | -- Streaming/Multi-Input Tests 422 | test_stream(cmsgpack, "simple", {a=1}, {b=2}, {c=3}, 4, 5, 6, 7) 423 | test_stream(cmsgpack_safe, "safe simple", {a=1}, {b=2}, {c=3}, 4, 5, 6, 7) 424 | test_stream(cmsgpack, "oddities", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0}, {a=64}, math.huge, -math.huge) 425 | test_stream(cmsgpack_safe, "safe oddities", {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0}, {a=64}, math.huge, -math.huge) 426 | test_stream(cmsgpack, "strange things", nil, {}, {nil}, a, b, b, b, a, a, b, {c = a, d = b}) 427 | test_stream(cmsgpack_safe, "strange things", nil, {}, {nil}, a, b, b, b, a, a, b, {c = a, d = b}) 428 | test_error("pack nothing", function() cmsgpack.pack() end) 429 | test_noerror("pack nothing safe", function() cmsgpack_safe.pack() end) 430 | test_circular("large object test", 431 | {A=9483, a=9483, aa=9483, aal=9483, aalii=9483, aam=9483, Aani=9483, 432 | aardvark=9483, aardwolf=9483, Aaron=9483, Aaronic=9483, Aaronical=9483, 433 | Aaronite=9483, Aaronitic=9483, Aaru=9483, Ab=9483, aba=9483, Ababdeh=9483, 434 | Ababua=9483, abac=9483, abaca=9483, abacate=9483, abacay=9483, 435 | abacinate=9483, abacination=9483, abaciscus=9483, abacist=9483, 436 | aback=9483, abactinal=9483, abactinally=9483, abaction=9483, abactor=9483, 437 | abaculus=9483, abacus=9483, Abadite=9483, abaff=9483, abaft=9483, 438 | abaisance=9483, abaiser=9483, abaissed=9483, abalienate=9483, 439 | abalienation=9483, abalone=9483, Abama=9483, abampere=9483, abandon=9483, 440 | abandonable=9483, abandoned=9483, abandonedly=9483, abandonee=9483, 441 | abandoner=9483, abandonment=9483, Abanic=9483, Abantes=9483, 442 | abaptiston=9483, Abarambo=9483, Abaris=9483, abarthrosis=9483, 443 | abarticular=9483, abarticulation=9483, abas=9483, abase=9483, abased=9483, 444 | abasedly=9483, abasedness=9483, abasement=9483, abaser=9483, Abasgi=9483, 445 | abash=9483, abashed=9483, abashedly=9483, abashedness=9483, 446 | abashless=9483, abashlessly=9483, abashment=9483, abasia=9483, 447 | abasic=9483, abask=9483, Abassin=9483, abastardize=9483, abatable=9483, 448 | abate=9483, abatement=9483, abater=9483, abatis=9483, abatised=9483, 449 | abaton=9483, abator=9483, abattoir=9483, Abatua=9483, abature=9483, 450 | abave=9483, abaxial=9483, abaxile=9483, abaze=9483, abb=9483, Abba=9483, 451 | abbacomes=9483, abbacy=9483, Abbadide=9483, abbas=9483, abbasi=9483, 452 | abbassi=9483, Abbasside=9483, abbatial=9483, abbatical=9483, abbess=9483, 453 | abbey=9483, abbeystede=9483, Abbie=9483, abbot=9483, abbotcy=9483, 454 | abbotnullius=9483, abbotship=9483, abbreviate=9483, abbreviately=9483, 455 | abbreviation=9483, abbreviator=9483, abbreviatory=9483, abbreviature=9483, 456 | Abby=9483, abcoulomb=9483, abdal=9483, abdat=9483, Abderian=9483, 457 | Abderite=9483, abdest=9483, abdicable=9483, abdicant=9483, abdicate=9483, 458 | abdication=9483, abdicative=9483, abdicator=9483, Abdiel=9483, 459 | abditive=9483, abditory=9483, abdomen=9483, abdominal=9483, 460 | Abdominales=9483, abdominalian=9483, abdominally=9483, 461 | abdominoanterior=9483, abdominocardiac=9483, abdominocentesis=9483, 462 | abdominocystic=9483, abdominogenital=9483, abdominohysterectomy=9483, 463 | abdominohysterotomy=9483, abdominoposterior=9483, abdominoscope=9483, 464 | abdominoscopy=9483, abdominothoracic=9483, abdominous=9483, 465 | abdominovaginal=9483, abdominovesical=9483, abduce=9483, abducens=9483, 466 | abducent=9483, abduct=9483, abduction=9483, abductor=9483, Abe=9483, 467 | abeam=9483, abear=9483, abearance=9483, abecedarian=9483, 468 | abecedarium=9483, abecedary=9483, abed=9483, abeigh=9483, Abel=9483, 469 | abele=9483, Abelia=9483, Abelian=9483, Abelicea=9483, Abelite=9483, 470 | abelite=9483, Abelmoschus=9483, abelmosk=9483, Abelonian=9483, 471 | abeltree=9483, Abencerrages=9483, abenteric=9483, abepithymia=9483, 472 | Aberdeen=9483, aberdevine=9483, Aberdonian=9483, Aberia=9483, 473 | aberrance=9483, aberrancy=9483, aberrant=9483, aberrate=9483, 474 | aberration=9483, aberrational=9483, aberrator=9483, aberrometer=9483, 475 | aberroscope=9483, aberuncator=9483, abet=9483, abetment=9483, 476 | abettal=9483, abettor=9483, abevacuation=9483, abey=9483, abeyance=9483, 477 | abeyancy=9483, abeyant=9483, abfarad=9483, abhenry=9483, abhiseka=9483, 478 | abhominable=9483, abhor=9483, abhorrence=9483, abhorrency=9483, 479 | abhorrent=9483, abhorrently=9483, abhorrer=9483, abhorrible=9483, 480 | abhorring=9483, Abhorson=9483, abidal=9483, abidance=9483, abide=9483, 481 | abider=9483, abidi=9483, abiding=9483, abidingly=9483, abidingness=9483, 482 | Abie=9483, Abies=9483, abietate=9483, abietene=9483, abietic=9483, 483 | abietin=9483, Abietineae=9483, abietineous=9483, abietinic=9483, 484 | Abiezer=9483, Abigail=9483, abigail=9483, abigailship=9483, abigeat=9483, 485 | abigeus=9483, abilao=9483, ability=9483, abilla=9483, abilo=9483, 486 | abintestate=9483, abiogenesis=9483, abiogenesist=9483, abiogenetic=9483, 487 | abiogenetical=9483, abiogenetically=9483, abiogenist=9483, 488 | abiogenous=9483, abiogeny=9483, abiological=9483, abiologically=9483, 489 | abiology=9483, abiosis=9483, abiotic=9483, abiotrophic=9483, 490 | abiotrophy=9483, Abipon=9483, abir=9483, abirritant=9483, abirritate=9483, 491 | abirritation=9483, abirritative=9483, abiston=9483, Abitibi=9483, 492 | abiuret=9483, abject=9483, abjectedness=9483, abjection=9483, 493 | abjective=9483, abjectly=9483, abjectness=9483, abjoint=9483, 494 | abjudge=9483, abjudicate=9483, abjudication=9483, abjunction=9483, 495 | abjunctive=9483, abjuration=9483, abjuratory=9483, abjure=9483, 496 | abjurement=9483, abjurer=9483, abkar=9483, abkari=9483, Abkhas=9483, 497 | Abkhasian=9483, ablach=9483, ablactate=9483, ablactation=9483, 498 | ablare=9483, ablastemic=9483, ablastous=9483, ablate=9483, ablation=9483, 499 | ablatitious=9483, ablatival=9483, ablative=9483, ablator=9483, 500 | ablaut=9483, ablaze=9483, able=9483, ableeze=9483, ablegate=9483, 501 | ableness=9483, ablepharia=9483, ablepharon=9483, ablepharous=9483, 502 | Ablepharus=9483, ablepsia=9483, ableptical=9483, ableptically=9483, 503 | abler=9483, ablest=9483, ablewhackets=9483, ablins=9483, abloom=9483, 504 | ablow=9483, ablude=9483, abluent=9483, ablush=9483, ablution=9483, 505 | ablutionary=9483, abluvion=9483, ably=9483, abmho=9483, Abnaki=9483, 506 | abnegate=9483, abnegation=9483, abnegative=9483, abnegator=9483, 507 | Abner=9483, abnerval=9483, abnet=9483, abneural=9483, abnormal=9483, 508 | abnormalism=9483, abnormalist=9483, abnormality=9483, abnormalize=9483, 509 | abnormally=9483, abnormalness=9483, abnormity=9483, abnormous=9483, 510 | abnumerable=9483, Abo=9483, aboard=9483, Abobra=9483, abode=9483, 511 | abodement=9483, abody=9483, abohm=9483, aboil=9483, abolish=9483, 512 | abolisher=9483, abolishment=9483, abolition=9483, abolitionary=9483, 513 | abolitionism=9483, abolitionist=9483, abolitionize=9483, abolla=9483, 514 | aboma=9483, abomasum=9483, abomasus=9483, abominable=9483, 515 | abominableness=9483, abominably=9483, abominate=9483, abomination=9483, 516 | abominator=9483, abomine=9483, Abongo=9483, aboon=9483, aborad=9483, 517 | aboral=9483, aborally=9483, abord=9483, aboriginal=9483, 518 | aboriginality=9483, aboriginally=9483, aboriginary=9483, aborigine=9483, 519 | abort=9483, aborted=9483, aborticide=9483, abortient=9483, 520 | abortifacient=9483, abortin=9483, abortion=9483, abortional=9483, 521 | abortionist=9483, abortive=9483, abortively=9483, abortiveness=9483, 522 | abortus=9483, abouchement=9483, abound=9483, abounder=9483, 523 | abounding=9483, aboundingly=9483, about=9483, abouts=9483, above=9483, 524 | aboveboard=9483, abovedeck=9483, aboveground=9483, aboveproof=9483, 525 | abovestairs=9483, abox=9483, abracadabra=9483, abrachia=9483, 526 | abradant=9483, abrade=9483, abrader=9483, Abraham=9483, Abrahamic=9483, 527 | Abrahamidae=9483, Abrahamite=9483, Abrahamitic=9483, abraid=9483, 528 | Abram=9483, Abramis=9483, abranchial=9483, abranchialism=9483, 529 | abranchian=9483, Abranchiata=9483, abranchiate=9483, abranchious=9483, 530 | abrasax=9483, abrase=9483, abrash=9483, abrasiometer=9483, abrasion=9483, 531 | abrasive=9483, abrastol=9483, abraum=9483, abraxas=9483, abreact=9483, 532 | abreaction=9483, abreast=9483, abrenounce=9483, abret=9483, abrico=9483, 533 | abridge=9483, abridgeable=9483, abridged=9483, abridgedly=9483, 534 | abridger=9483, abridgment=9483, abrim=9483, abrin=9483, abristle=9483, 535 | abroach=9483, abroad=9483, Abrocoma=9483, abrocome=9483, abrogable=9483, 536 | abrogate=9483, abrogation=9483, abrogative=9483, abrogator=9483, 537 | Abroma=9483, Abronia=9483, abrook=9483, abrotanum=9483, abrotine=9483, 538 | abrupt=9483, abruptedly=9483, abruption=9483, abruptly=9483, 539 | abruptness=9483, Abrus=9483, Absalom=9483, absampere=9483, Absaroka=9483, 540 | absarokite=9483, abscess=9483, abscessed=9483, abscession=9483, 541 | abscessroot=9483, abscind=9483, abscise=9483, abscision=9483, 542 | absciss=9483, abscissa=9483, abscissae=9483, abscisse=9483, 543 | abscission=9483, absconce=9483, abscond=9483, absconded=9483, 544 | abscondedly=9483, abscondence=9483}) 545 | 546 | -- Test limited streaming 547 | packed, offset = test_partial_unpack("unpack 1a out of 7", 1, "a", "b", "c", "d", "e", "f", "g") 548 | packed, offset = test_partial_unpack("unpack 1b of remaining 7", 1, {p=packed,o=offset,remaining={"b"}}) 549 | packed, offset = test_partial_unpack("unpack 1c of remaining 7", 1, {p=packed,o=offset,remaining={"c"}}) 550 | packed, offset = test_partial_unpack("unpack 1d of remaining 7", 1, {p=packed,o=offset,remaining={"d"}}) 551 | packed, offset = test_partial_unpack("unpack 1e of remaining 7", 1, {p=packed,o=offset,remaining={"e"}}) 552 | packed, offset = test_partial_unpack("unpack 1f of remaining 7", 1, {p=packed,o=offset,remaining={"f"}}) 553 | packed, offset = test_partial_unpack("unpack 1g of remaining 7", 1, {p=packed,o=offset,remaining={"g"}}) 554 | packed, offset = test_partial_unpack("unpack 1nil of remaining 7", 0, {p=packed,o=offset}) 555 | 556 | packed, offset = test_partial_unpack("unpack 3 out of 7", 3, "a", "b", "c", "d", "e", "f", "g") 557 | test_partial_unpack("unpack remaining 4", 4, {p=packed,o=offset,remaining={"d", "e", "f", "g"}}) 558 | 559 | test_unpack_one("simple", packed, "a") 560 | offset = test_unpack_one("simple", cmsgpack.pack({f = 3, j = 2}, "m", "e", 7), {f = 3, j = 2}) 561 | test_unpack_one("simple", cmsgpack.pack({f = 3, j = 2}, "m", "e", 7), "m", offset) 562 | 563 | -- Final report 564 | print() 565 | print("TEST PASSED:",passed) 566 | print("TEST FAILED:",failed) 567 | print("TEST SKIPPED:",skipped) 568 | 569 | if failed > 0 then 570 | os.exit(1) 571 | end 572 | --------------------------------------------------------------------------------