diff options
author | Noah Watkins <noahwatkins@gmail.com> | 2013-02-15 15:38:06 -0800 |
---|---|---|
committer | Noah Watkins <noahwatkins@gmail.com> | 2013-08-25 08:58:26 -0700 |
commit | eec2f0f51f88ca571d1675ba9e249f2a0774ea4c (patch) | |
tree | da25f51ff45c131f7ea09cfc3065d9f055629998 | |
parent | f1ee58bef3d40601133f1477cb65cec00e0c75f6 (diff) | |
download | ceph-eec2f0f51f88ca571d1675ba9e249f2a0774ea4c.tar.gz |
lua: adds bufferlist and msgpack libraries
Adds basic Lua wrappers around ceph::bufferlist, the cmsgpack Lua
library, and builds Lua as a noinst shared library.
Signed-off-by: Noah Watkins <noahwatkins@gmail.com>
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/liblua/Makefile.am | 59 | ||||
-rw-r--r-- | src/liblua/lua.hpp | 21 | ||||
-rw-r--r-- | src/liblua/src/lua_bufferlist.cc | 129 | ||||
-rw-r--r-- | src/liblua/src/lua_cmsgpack.c | 730 |
6 files changed, 942 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 38b6782a46a..b95d136fc9b 100644 --- a/configure.ac +++ b/configure.ac @@ -602,6 +602,7 @@ AC_CONFIG_FILES([Makefile src/ocf/ceph src/ocf/rbd src/java/Makefile + src/liblua/Makefile man/Makefile ceph.spec]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 4b09c23e872..421179eda72 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = gnu -SUBDIRS = ocf java -DIST_SUBDIRS = gtest ocf libs3 java +SUBDIRS = ocf java liblua +DIST_SUBDIRS = gtest ocf libs3 java liblua EXTRA_DIST = \ libs3/COPYING \ diff --git a/src/liblua/Makefile.am b/src/liblua/Makefile.am new file mode 100644 index 00000000000..04c47ad6f29 --- /dev/null +++ b/src/liblua/Makefile.am @@ -0,0 +1,59 @@ +noinst_LTLIBRARIES = liblua.la + +liblua_la_SOURCES = \ + src/print.c \ + src/lmem.c \ + src/lbaselib.c \ + src/lauxlib.c \ + src/ltm.c \ + src/loadlib.c \ + src/lobject.c \ + src/lzio.c \ + src/ldebug.c \ + src/lundump.c \ + src/lcode.c \ + src/liolib.c \ + src/loslib.c \ + src/ldblib.c \ + src/llex.c \ + src/lopcodes.c \ + src/lstate.c \ + src/lstring.c \ + src/ldo.c \ + src/ltable.c \ + src/linit.c \ + src/lapi.c \ + src/ldump.c \ + src/lparser.c \ + src/lstrlib.c \ + src/ltablib.c \ + src/lvm.c \ + src/lmathlib.c \ + src/lgc.c \ + src/lfunc.c \ + src/lua_cmsgpack.c \ + src/lua_bufferlist.cc \ + src/lualib.h \ + src/luaconf.h \ + src/llimits.h \ + src/lua.h \ + src/ltm.h \ + src/lvm.h \ + src/lapi.h \ + src/lauxlib.h \ + src/lparser.h \ + src/lstring.h \ + src/lobject.h \ + src/ldebug.h \ + src/lundump.h \ + src/ltable.h \ + src/lstate.h \ + src/lfunc.h \ + src/lzio.h \ + src/lmem.h \ + src/lgc.h \ + src/lcode.h \ + src/ldo.h \ + src/lopcodes.h \ + src/llex.h \ + lua.hpp diff --git a/src/liblua/lua.hpp b/src/liblua/lua.hpp new file mode 100644 index 00000000000..aaf079a22b1 --- /dev/null +++ b/src/liblua/lua.hpp @@ -0,0 +1,21 @@ +#ifndef LIB_LUA_LUA_HPP +#define LIB_LUA_LUA_HPP + +#include "include/types.h" + +extern "C" { +#include "liblua/src/lua.h" +#include "liblua/src/lualib.h" +#include "liblua/src/lauxlib.h" +} + +extern "C" { + LUALIB_API int luaopen_cmsgpack(lua_State *L); +} + +LUALIB_API int luaopen_bufferlist(lua_State *L); + +extern bufferlist *clslua_checkbufferlist(lua_State *L, int pos = 1); +extern bufferlist *clslua_pushbufferlist(lua_State *L, bufferlist *set); + +#endif diff --git a/src/liblua/src/lua_bufferlist.cc b/src/liblua/src/lua_bufferlist.cc new file mode 100644 index 00000000000..bb2b6084633 --- /dev/null +++ b/src/liblua/src/lua_bufferlist.cc @@ -0,0 +1,129 @@ +/* + * Lua module wrapping librados::bufferlist + */ +#include <errno.h> +#include <string> +#include <sstream> +#include <math.h> +#include "liblua/lua.hpp" +#include "include/types.h" +#include "include/buffer.h" +#include "objclass/objclass.h" +#include "cls/lua/cls_lua.h" + +#define LUA_BUFFERLIST "ClsLua.Bufferlist" + +struct bufferlist_wrap { + bufferlist *bl; + int gc; /* do garbage collect? */ +}; + +static inline struct bufferlist_wrap *to_blwrap(lua_State *L, int pos = 1) +{ + return (bufferlist_wrap *)luaL_checkudata(L, pos, LUA_BUFFERLIST); +} + +bufferlist *clslua_checkbufferlist(lua_State *L, int pos) +{ + struct bufferlist_wrap *blw = to_blwrap(L, pos); + return blw->bl; +} + +/* + * Pushes a new bufferlist userdata object onto the stack. If @set is non-null + * it is assumed to be a bufferlist that should not be garbage collected. + */ +bufferlist *clslua_pushbufferlist(lua_State *L, bufferlist *set) +{ + bufferlist_wrap *blw = (bufferlist_wrap *)lua_newuserdata(L, sizeof(*blw)); + blw->bl = set ? set : new bufferlist(); + blw->gc = set ? 0 : 1; + luaL_getmetatable(L, LUA_BUFFERLIST); + lua_setmetatable(L, -2); + return blw->bl; +} + +/* + * Create a new bufferlist + */ +static int bl_new(lua_State *L) +{ + clslua_pushbufferlist(L, NULL); + return 1; +} + +/* + * Convert bufferlist to Lua string + */ +static int bl_str(lua_State *L) +{ + bufferlist *bl = clslua_checkbufferlist(L); + lua_pushlstring(L, bl->c_str(), bl->length()); + return 1; +} + +/* + * Append a Lua string to bufferlist + */ +static int bl_append(lua_State *L) +{ + bufferlist *bl = clslua_checkbufferlist(L); + luaL_checktype(L, 2, LUA_TSTRING); + + size_t len; + const char *data = lua_tolstring(L, 2, &len); + bl->append(data, len); + + return 0; +} + +/* + * Perform byte-for-byte bufferlist equality test + */ +static int bl_eq(lua_State *L) +{ + bufferlist *bl1 = clslua_checkbufferlist(L, 1); + bufferlist *bl2 = clslua_checkbufferlist(L, 2); + lua_pushboolean(L, *bl1 == *bl2 ? 1 : 0); + return 1; +} + +/* + * Garbage collect bufferlist + */ +static int bl_gc(lua_State *L) +{ + struct bufferlist_wrap *blw = to_blwrap(L); + assert(blw); + assert(blw->bl); + if (blw->gc) + delete blw->bl; + return 0; +} + +static const struct luaL_Reg bufferlist_methods[] = { + {"str", bl_str}, + {"append", bl_append}, + {"__gc", bl_gc}, + {"__eq", bl_eq}, + {NULL, NULL} +}; + +static const struct luaL_Reg bllib_f[] = { + {"new", bl_new}, + {NULL, NULL} +}; + +LUALIB_API int luaopen_bufferlist(lua_State *L) +{ + /* Setup bufferlist user-data type */ + luaL_newmetatable(L, LUA_BUFFERLIST); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_register(L, NULL, bufferlist_methods); + lua_pop(L, 1); + + luaL_register(L, "bufferlist", bllib_f); + + return 1; +} diff --git a/src/liblua/src/lua_cmsgpack.c b/src/liblua/src/lua_cmsgpack.c new file mode 100644 index 00000000000..1994862e90a --- /dev/null +++ b/src/liblua/src/lua_cmsgpack.c @@ -0,0 +1,730 @@ +#include <math.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include "liblua/src/lua.h" +#include "liblua/src/lauxlib.h" + +#define LUACMSGPACK_VERSION "lua-cmsgpack 0.3.0" +#define LUACMSGPACK_COPYRIGHT "Copyright (C) 2012, Salvatore Sanfilippo" +#define LUACMSGPACK_DESCRIPTION "MessagePack C implementation for Lua" + +#define LUACMSGPACK_MAX_NESTING 16 /* Max tables nesting. */ + +/* ============================================================================== + * MessagePack implementation and bindings for Lua 5.1. + * Copyright(C) 2012 Salvatore Sanfilippo <antirez@gmail.com> + * + * http://github.com/antirez/lua-cmsgpack + * + * For MessagePack specification check the following web site: + * http://wiki.msgpack.org/display/MSGPACK/Format+specification + * + * See Copyright Notice at the end of this file. + * + * CHANGELOG: + * 19-Feb-2012 (ver 0.1.0): Initial release. + * 20-Feb-2012 (ver 0.2.0): Tables encoding improved. + * 20-Feb-2012 (ver 0.2.1): Minor bug fixing. + * 20-Feb-2012 (ver 0.3.0): Module renamed lua-cmsgpack (was lua-msgpack). + * ============================================================================ */ + +/* --------------------------- Endian conversion -------------------------------- + * We use it only for floats and doubles, all the other conversions are performed + * in an endian independent fashion. So the only thing we need is a function + * that swaps a binary string if the arch is little endian (and left it untouched + * otherwise). */ + +/* Reverse memory bytes if arch is little endian. Given the conceptual + * simplicity of the Lua build system we prefer to check for endianess at runtime. + * The performance difference should be acceptable. */ +static void memrevifle(void *ptr, size_t len) { + unsigned char *p = ptr, *e = p+len-1, aux; + int test = 1; + unsigned char *testp = (unsigned char*) &test; + + if (testp[0] == 0) return; /* Big endian, nothign to do. */ + len /= 2; + while(len--) { + aux = *p; + *p = *e; + *e = aux; + p++; + e--; + } +} + +/* ----------------------------- String buffer ---------------------------------- + * This is a simple implementation of string buffers. The only opereation + * supported is creating empty buffers and appending bytes to it. + * The string buffer uses 2x preallocation on every realloc for O(N) append + * behavior. */ + +typedef struct mp_buf { + unsigned char *b; + size_t len, free; +} mp_buf; + +static mp_buf *mp_buf_new(void) { + mp_buf *buf = malloc(sizeof(*buf)); + + buf->b = NULL; + buf->len = buf->free = 0; + return buf; +} + +void mp_buf_append(mp_buf *buf, const unsigned char *s, size_t len) { + if (buf->free < len) { + size_t newlen = buf->len+len; + + buf->b = realloc(buf->b,newlen*2); + buf->free = newlen; + } + memcpy(buf->b+buf->len,s,len); + buf->len += len; + buf->free -= len; +} + +void mp_buf_free(mp_buf *buf) { + free(buf->b); + free(buf); +} + +/* ------------------------------ String cursor ---------------------------------- + * This simple data structure is used for parsing. Basically you create a cursor + * using a string pointer and a length, then it is possible to access the + * current string position with cursor->p, check the remaining length + * in cursor->left, and finally consume more string using + * mp_cur_consume(cursor,len), to advance 'p' and subtract 'left'. + * An additional field cursor->error is set to zero on initialization and can + * be used to report errors. */ + +#define MP_CUR_ERROR_NONE 0 +#define MP_CUR_ERROR_EOF 1 /* Not enough data to complete the opereation. */ +#define MP_CUR_ERROR_BADFMT 2 /* Bad data format */ + +typedef struct mp_cur { + const unsigned char *p; + size_t left; + int err; +} mp_cur; + +static mp_cur *mp_cur_new(const unsigned char *s, size_t len) { + mp_cur *cursor = malloc(sizeof(*cursor)); + + cursor->p = s; + cursor->left = len; + cursor->err = MP_CUR_ERROR_NONE; + return cursor; +} + +static void mp_cur_free(mp_cur *cursor) { + free(cursor); +} + +#define mp_cur_consume(_c,_len) do { _c->p += _len; _c->left -= _len; } while(0) + +/* When there is not enough room we set an error in the cursor and return, this + * is very common across the code so we have a macro to make the code look + * a bit simpler. */ +#define mp_cur_need(_c,_len) do { \ + if (_c->left < _len) { \ + _c->err = MP_CUR_ERROR_EOF; \ + return; \ + } \ +} while(0) + +/* --------------------------- Low level MP encoding -------------------------- */ + +static void mp_encode_bytes(mp_buf *buf, const unsigned char *s, size_t len) { + unsigned char hdr[5]; + int hdrlen; + + if (len < 32) { + hdr[0] = 0xa0 | (len&0xff); /* fix raw */ + hdrlen = 1; + } else if (len <= 0xffff) { + hdr[0] = 0xda; + hdr[1] = (len&0xff00)>>8; + hdr[2] = len&0xff; + hdrlen = 3; + } else { + hdr[0] = 0xdb; + hdr[1] = (len&0xff000000)>>24; + hdr[2] = (len&0xff0000)>>16; + hdr[3] = (len&0xff00)>>8; + hdr[4] = len&0xff; + hdrlen = 5; + } + mp_buf_append(buf,hdr,hdrlen); + mp_buf_append(buf,s,len); +} + +/* we assume IEEE 754 internal format for single and double precision floats. */ +static void mp_encode_double(mp_buf *buf, double d) { + unsigned char b[9]; + float f = d; + + assert(sizeof(f) == 4 && sizeof(d) == 8); + if (d == (double)f) { + b[0] = 0xca; /* float IEEE 754 */ + memcpy(b+1,&f,4); + memrevifle(b+1,4); + mp_buf_append(buf,b,5); + } else if (sizeof(d) == 8) { + b[0] = 0xcb; /* double IEEE 754 */ + memcpy(b+1,&d,8); + memrevifle(b+1,8); + mp_buf_append(buf,b,9); + } +} + +static void mp_encode_int(mp_buf *buf, int64_t n) { + unsigned char b[9]; + int enclen; + + if (n >= 0) { + if (n <= 127) { + b[0] = n & 0x7f; /* positive fixnum */ + enclen = 1; + } else if (n <= 0xff) { + b[0] = 0xcc; /* uint 8 */ + b[1] = n & 0xff; + enclen = 2; + } else if (n <= 0xffff) { + b[0] = 0xcd; /* uint 16 */ + b[1] = (n & 0xff00) >> 8; + b[2] = n & 0xff; + enclen = 3; + } else if (n <= 0xffffffffLL) { + b[0] = 0xce; /* uint 32 */ + b[1] = (n & 0xff000000) >> 24; + b[2] = (n & 0xff0000) >> 16; + b[3] = (n & 0xff00) >> 8; + b[4] = n & 0xff; + enclen = 5; + } else { + b[0] = 0xcf; /* uint 64 */ + b[1] = (n & 0xff00000000000000LL) >> 56; + b[2] = (n & 0xff000000000000LL) >> 48; + b[3] = (n & 0xff0000000000LL) >> 40; + b[4] = (n & 0xff00000000LL) >> 32; + b[5] = (n & 0xff000000) >> 24; + b[6] = (n & 0xff0000) >> 16; + b[7] = (n & 0xff00) >> 8; + b[8] = n & 0xff; + enclen = 9; + } + } else { + if (n >= -32) { + b[0] = ((char)n); /* negative fixnum */ + enclen = 1; + } else if (n >= -128) { + b[0] = 0xd0; /* int 8 */ + b[1] = n & 0xff; + enclen = 2; + } else if (n >= -32768) { + b[0] = 0xd1; /* int 16 */ + b[1] = (n & 0xff00) >> 8; + b[2] = n & 0xff; + enclen = 3; + } else if (n >= -2147483648LL) { + b[0] = 0xd2; /* int 32 */ + b[1] = (n & 0xff000000) >> 24; + b[2] = (n & 0xff0000) >> 16; + b[3] = (n & 0xff00) >> 8; + b[4] = n & 0xff; + enclen = 5; + } else { + b[0] = 0xd3; /* int 64 */ + b[1] = (n & 0xff00000000000000LL) >> 56; + b[2] = (n & 0xff000000000000LL) >> 48; + b[3] = (n & 0xff0000000000LL) >> 40; + b[4] = (n & 0xff00000000LL) >> 32; + b[5] = (n & 0xff000000) >> 24; + b[6] = (n & 0xff0000) >> 16; + b[7] = (n & 0xff00) >> 8; + b[8] = n & 0xff; + enclen = 9; + } + } + mp_buf_append(buf,b,enclen); +} + +static void mp_encode_array(mp_buf *buf, int64_t n) { + unsigned char b[5]; + int enclen; + + if (n <= 15) { + b[0] = 0x90 | (n & 0xf); /* fix array */ + enclen = 1; + } else if (n <= 65535) { + b[0] = 0xdc; /* array 16 */ + b[1] = (n & 0xff00) >> 8; + b[2] = n & 0xff; + enclen = 3; + } else { + b[0] = 0xdd; /* array 32 */ + b[1] = (n & 0xff000000) >> 24; + b[2] = (n & 0xff0000) >> 16; + b[3] = (n & 0xff00) >> 8; + b[4] = n & 0xff; + enclen = 5; + } + mp_buf_append(buf,b,enclen); +} + +static void mp_encode_map(mp_buf *buf, int64_t n) { + unsigned char b[5]; + int enclen; + + if (n <= 15) { + b[0] = 0x80 | (n & 0xf); /* fix map */ + enclen = 1; + } else if (n <= 65535) { + b[0] = 0xde; /* map 16 */ + b[1] = (n & 0xff00) >> 8; + b[2] = n & 0xff; + enclen = 3; + } else { + b[0] = 0xdf; /* map 32 */ + b[1] = (n & 0xff000000) >> 24; + b[2] = (n & 0xff0000) >> 16; + b[3] = (n & 0xff00) >> 8; + b[4] = n & 0xff; + enclen = 5; + } + mp_buf_append(buf,b,enclen); +} + +/* ----------------------------- Lua types encoding --------------------------- */ + +static void mp_encode_lua_string(lua_State *L, mp_buf *buf) { + size_t len; + const char *s; + + s = lua_tolstring(L,-1,&len); + mp_encode_bytes(buf,(const unsigned char*)s,len); +} + +static void mp_encode_lua_bool(lua_State *L, mp_buf *buf) { + unsigned char b = lua_toboolean(L,-1) ? 0xc3 : 0xc2; + mp_buf_append(buf,&b,1); +} + +static void mp_encode_lua_number(lua_State *L, mp_buf *buf) { + lua_Number n = lua_tonumber(L,-1); + + if (floor(n) != n) { + mp_encode_double(buf,(double)n); + } else { + mp_encode_int(buf,(int64_t)n); + } +} + +static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level); + +/* Convert a lua table into a message pack list. */ +static void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) { + size_t len = lua_objlen(L,-1), j; + + mp_encode_array(buf,len); + for (j = 1; j <= len; j++) { + lua_pushnumber(L,j); + lua_gettable(L,-2); + mp_encode_lua_type(L,buf,level+1); + } +} + +/* Convert a lua table into a message pack key-value map. */ +static void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) { + size_t len = 0; + + /* First step: count keys into table. No other way to do it with the + * Lua API, we need to iterate a first time. Note that an alternative + * would be to do a single run, and then hack the buffer to insert the + * map opcodes for message pack. Too hachish for this lib. */ + lua_pushnil(L); + while(lua_next(L,-2)) { + lua_pop(L,1); /* remove value, keep key for next iteration. */ + len++; + } + + /* Step two: actually encoding of the map. */ + mp_encode_map(buf,len); + lua_pushnil(L); + while(lua_next(L,-2)) { + /* Stack: ... key value */ + lua_pushvalue(L,-2); /* Stack: ... key value key */ + mp_encode_lua_type(L,buf,level+1); /* encode key */ + mp_encode_lua_type(L,buf,level+1); /* encode val */ + } +} + +/* Returns true if the Lua table on top of the stack is exclusively composed + * of keys from numerical keys from 1 up to N, with N being the total number + * of elements, without any hole in the middle. */ +static int table_is_an_array(lua_State *L) { + //long count = 0, max = 0, idx = 0; + long count = 0, idx = 0; + lua_Number n; + + lua_pushnil(L); + while(lua_next(L,-2)) { + /* Stack: ... key value */ + lua_pop(L,1); /* Stack: ... key */ + if (!lua_isnumber(L,-1)) goto not_array; + n = lua_tonumber(L,-1); + idx = n; + if (idx != n || idx < 1) goto not_array; + count++; + //max = idx; + } + /* We have the total number of elements in "count". Also we have + * the max index encountered in "idx". We can't reach this code + * if there are indexes <= 0. If you also note that there can not be + * repeated keys into a table, you have that if idx==count you are sure + * that there are all the keys form 1 to count (both included). */ + return idx == count; + +not_array: + lua_pop(L,1); + return 0; +} + +/* If the length operator returns non-zero, that is, there is at least + * an object at key '1', we serialize to message pack list. Otherwise + * we use a map. */ +static void mp_encode_lua_table(lua_State *L, mp_buf *buf, int level) { + if (table_is_an_array(L)) + mp_encode_lua_table_as_array(L,buf,level); + else + mp_encode_lua_table_as_map(L,buf,level); +} + +static void mp_encode_lua_null(lua_State *L, mp_buf *buf) { + unsigned char b[1]; + + b[0] = 0xc0; + mp_buf_append(buf,b,1); +} + +static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level) { + int t = lua_type(L,-1); + + /* Limit the encoding of nested tables to a specfiied maximum depth, so that + * we survive when called against circular references in tables. */ + if (t == LUA_TTABLE && level == LUACMSGPACK_MAX_NESTING) t = LUA_TNIL; + switch(t) { + case LUA_TSTRING: mp_encode_lua_string(L,buf); break; + case LUA_TBOOLEAN: mp_encode_lua_bool(L,buf); break; + case LUA_TNUMBER: mp_encode_lua_number(L,buf); break; + case LUA_TTABLE: mp_encode_lua_table(L,buf,level); break; + default: mp_encode_lua_null(L,buf); break; + } + lua_pop(L,1); +} + +static int mp_pack(lua_State *L) { + mp_buf *buf = mp_buf_new(); + + mp_encode_lua_type(L,buf,0); + lua_pushlstring(L,(char*)buf->b,buf->len); + mp_buf_free(buf); + return 1; +} + +/* --------------------------------- Decoding --------------------------------- */ + +void mp_decode_to_lua_type(lua_State *L, mp_cur *c); + +void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) { + int index = 1; + + lua_newtable(L); + while(len--) { + lua_pushnumber(L,index++); + mp_decode_to_lua_type(L,c); + if (c->err) return; + lua_settable(L,-3); + } +} + +void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) { + lua_newtable(L); + while(len--) { + mp_decode_to_lua_type(L,c); /* key */ + if (c->err) return; + mp_decode_to_lua_type(L,c); /* value */ + if (c->err) return; + lua_settable(L,-3); + } +} + +/* Decode a Message Pack raw object pointed by the string cursor 'c' to + * a Lua type, that is left as the only result on the stack. */ +void mp_decode_to_lua_type(lua_State *L, mp_cur *c) { + mp_cur_need(c,1); + switch(c->p[0]) { + case 0xcc: /* uint 8 */ + mp_cur_need(c,2); + lua_pushnumber(L,c->p[1]); + mp_cur_consume(c,2); + break; + case 0xd0: /* int 8 */ + mp_cur_need(c,2); + lua_pushnumber(L,(char)c->p[1]); + mp_cur_consume(c,2); + break; + case 0xcd: /* uint 16 */ + mp_cur_need(c,3); + lua_pushnumber(L, + (c->p[1] << 8) | + c->p[2]); + mp_cur_consume(c,3); + break; + case 0xd1: /* int 16 */ + mp_cur_need(c,3); + lua_pushnumber(L,(int16_t) + (c->p[1] << 8) | + c->p[2]); + mp_cur_consume(c,3); + break; + case 0xce: /* uint 32 */ + mp_cur_need(c,5); + lua_pushnumber(L, + ((uint32_t)c->p[1] << 24) | + ((uint32_t)c->p[2] << 16) | + ((uint32_t)c->p[3] << 8) | + (uint32_t)c->p[4]); + mp_cur_consume(c,5); + break; + case 0xd2: /* int 32 */ + mp_cur_need(c,5); + lua_pushnumber(L, + ((int32_t)c->p[1] << 24) | + ((int32_t)c->p[2] << 16) | + ((int32_t)c->p[3] << 8) | + (int32_t)c->p[4]); + mp_cur_consume(c,5); + break; + case 0xcf: /* uint 64 */ + mp_cur_need(c,9); + lua_pushnumber(L, + ((uint64_t)c->p[1] << 56) | + ((uint64_t)c->p[2] << 48) | + ((uint64_t)c->p[3] << 40) | + ((uint64_t)c->p[4] << 32) | + ((uint64_t)c->p[5] << 24) | + ((uint64_t)c->p[6] << 16) | + ((uint64_t)c->p[7] << 8) | + (uint64_t)c->p[8]); + mp_cur_consume(c,9); + break; + case 0xd3: /* int 64 */ + mp_cur_need(c,9); + lua_pushnumber(L, + ((int64_t)c->p[1] << 56) | + ((int64_t)c->p[2] << 48) | + ((int64_t)c->p[3] << 40) | + ((int64_t)c->p[4] << 32) | + ((int64_t)c->p[5] << 24) | + ((int64_t)c->p[6] << 16) | + ((int64_t)c->p[7] << 8) | + (int64_t)c->p[8]); + mp_cur_consume(c,9); + break; + case 0xc0: /* nil */ + lua_pushnil(L); + mp_cur_consume(c,1); + break; + case 0xc3: /* true */ + lua_pushboolean(L,1); + mp_cur_consume(c,1); + break; + case 0xc2: /* false */ + lua_pushboolean(L,0); + mp_cur_consume(c,1); + break; + case 0xca: /* float */ + mp_cur_need(c,5); + assert(sizeof(float) == 4); + { + float f; + memcpy(&f,c->p+1,4); + memrevifle(&f,4); + lua_pushnumber(L,f); + mp_cur_consume(c,5); + } + break; + case 0xcb: /* double */ + mp_cur_need(c,9); + assert(sizeof(double) == 8); + { + double d; + memcpy(&d,c->p+1,8); + memrevifle(&d,8); + lua_pushnumber(L,d); + mp_cur_consume(c,9); + } + break; + case 0xda: /* raw 16 */ + mp_cur_need(c,3); + { + size_t l = (c->p[1] << 8) | c->p[2]; + mp_cur_need(c,3+l); + lua_pushlstring(L,(char*)c->p+3,l); + mp_cur_consume(c,3+l); + } + break; + case 0xdb: /* raw 32 */ + mp_cur_need(c,5); + { + size_t l = (c->p[1] << 24) | + (c->p[2] << 16) | + (c->p[3] << 8) | + c->p[4]; + mp_cur_need(c,5+l); + lua_pushlstring(L,(char*)c->p+5,l); + mp_cur_consume(c,5+l); + } + break; + case 0xdc: /* array 16 */ + mp_cur_need(c,3); + { + size_t l = (c->p[1] << 8) | c->p[2]; + mp_cur_consume(c,3); + mp_decode_to_lua_array(L,c,l); + } + break; + case 0xdd: /* array 32 */ + mp_cur_need(c,5); + { + size_t l = (c->p[1] << 24) | + (c->p[2] << 16) | + (c->p[3] << 8) | + c->p[4]; + mp_cur_consume(c,5); + mp_decode_to_lua_array(L,c,l); + } + break; + case 0xde: /* map 16 */ + mp_cur_need(c,3); + { + size_t l = (c->p[1] << 8) | c->p[2]; + mp_cur_consume(c,3); + mp_decode_to_lua_hash(L,c,l); + } + break; + case 0xdf: /* map 32 */ + mp_cur_need(c,5); + { + size_t l = (c->p[1] << 24) | + (c->p[2] << 16) | + (c->p[3] << 8) | + c->p[4]; + mp_cur_consume(c,5); + mp_decode_to_lua_hash(L,c,l); + } + break; + default: /* types that can't be idenitified by first byte value. */ + if ((c->p[0] & 0x80) == 0) { /* positive fixnum */ + lua_pushnumber(L,c->p[0]); + mp_cur_consume(c,1); + } else if ((c->p[0] & 0xe0) == 0xe0) { /* negative fixnum */ + lua_pushnumber(L,(signed char)c->p[0]); + mp_cur_consume(c,1); + } else if ((c->p[0] & 0xe0) == 0xa0) { /* fix raw */ + size_t l = c->p[0] & 0x1f; + mp_cur_need(c,1+l); + lua_pushlstring(L,(char*)c->p+1,l); + mp_cur_consume(c,1+l); + } else if ((c->p[0] & 0xf0) == 0x90) { /* fix map */ + size_t l = c->p[0] & 0xf; + mp_cur_consume(c,1); + mp_decode_to_lua_array(L,c,l); + } else if ((c->p[0] & 0xf0) == 0x80) { /* fix map */ + size_t l = c->p[0] & 0xf; + mp_cur_consume(c,1); + mp_decode_to_lua_hash(L,c,l); + } else { + c->err = MP_CUR_ERROR_BADFMT; + } + } +} + +static int mp_unpack(lua_State *L) { + size_t len; + const unsigned char *s; + mp_cur *c; + + if (!lua_isstring(L,-1)) { + lua_pushstring(L,"MessagePack decoding needs a string as input."); + lua_error(L); + } + + s = (const unsigned char*) lua_tolstring(L,-1,&len); + c = mp_cur_new(s,len); + mp_decode_to_lua_type(L,c); + + if (c->err == MP_CUR_ERROR_EOF) { + mp_cur_free(c); + lua_pushstring(L,"Missing bytes in input."); + lua_error(L); + } else if (c->err == MP_CUR_ERROR_BADFMT) { + mp_cur_free(c); + lua_pushstring(L,"Bad data format in input."); + lua_error(L); + } else if (c->left != 0) { + mp_cur_free(c); + lua_pushstring(L,"Extra bytes in input."); + lua_error(L); + } + mp_cur_free(c); + return 1; +} + +/* ---------------------------------------------------------------------------- */ + +static const struct luaL_reg thislib[] = { + {"pack", mp_pack}, + {"unpack", mp_unpack}, + {NULL, NULL} +}; + +LUALIB_API int luaopen_cmsgpack (lua_State *L) { + luaL_register(L, "cmsgpack", thislib); + + lua_pushliteral(L, LUACMSGPACK_VERSION); + lua_setfield(L, -2, "_VERSION"); + lua_pushliteral(L, LUACMSGPACK_COPYRIGHT); + lua_setfield(L, -2, "_COPYRIGHT"); + lua_pushliteral(L, LUACMSGPACK_DESCRIPTION); + lua_setfield(L, -2, "_DESCRIPTION"); + return 1; +} + +/****************************************************************************** +* Copyright (C) 2012 Salvatore Sanfilippo. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ |