diff --git a/Makefile b/Makefile index aa031817a..f22184063 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,7 @@ luaclib/bson.so : lualib-src/lua-bson.c | luaclib gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ luaclib/mongo.so : lualib-src/lua-mongo.c | luaclib - gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ -Iskynet-src + gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ client : client-src/client.c gcc $(CFLAGS) $^ -o $@ -lpthread diff --git a/lualib-src/lua-bson.c b/lualib-src/lua-bson.c new file mode 100644 index 000000000..7070c8151 --- /dev/null +++ b/lualib-src/lua-bson.c @@ -0,0 +1,1135 @@ +#include +#include +#include "luacompat52.h" + +#include +#include + +#include +#include +#include +#include + +#if defined(_WIN32) || defined(_WIN64) + +#include + +static void +init_winsock() { + WSADATA wsaData; + WSAStartup(MAKEWORD(2,2), &wsaData); +} + +#else + +static void +init_winsock() { +} + +#endif + +#define DEFAULT_CAP 64 +#define MAX_NUMBER 1024 + +#define BSON_REAL 1 +#define BSON_STRING 2 +#define BSON_DOCUMENT 3 +#define BSON_ARRAY 4 +#define BSON_BINARY 5 +#define BSON_UNDEFINED 6 +#define BSON_OBJECTID 7 +#define BSON_BOOLEAN 8 +#define BSON_DATE 9 +#define BSON_NULL 10 +#define BSON_REGEX 11 +#define BSON_DBPOINTER 12 +#define BSON_JSCODE 13 +#define BSON_SYMBOL 14 +#define BSON_CODEWS 15 +#define BSON_INT32 16 +#define BSON_TIMESTAMP 17 +#define BSON_INT64 18 +#define BSON_MINKEY 255 +#define BSON_MAXKEY 127 + +#define BSON_TYPE_SHIFT 5 + +static char bson_numstrs[MAX_NUMBER][4]; +static int bson_numstr_len[MAX_NUMBER]; + +struct bson { + int size; + int cap; + uint8_t *ptr; + uint8_t buffer[DEFAULT_CAP]; +}; + +struct bson_reader { + const uint8_t * ptr; + int size; +}; + +static inline void +bson_destroy(struct bson *b) { + if (b->ptr != b->buffer) { + free(b->ptr); + } +} + +static inline void +bson_create(struct bson *b) { + b->size = 0; + b->cap = DEFAULT_CAP; + b->ptr = b->buffer; +} + +static inline void +bson_reserve(struct bson *b, int sz) { + if (b->size + sz <= b->cap) + return; + do { + b->cap *= 2; + } while (b->cap <= b->size + sz); + + if (b->ptr == b->buffer) { + b->ptr = malloc(b->cap); + memcpy(b->ptr, b->buffer, b->size); + } else { + b->ptr = realloc(b->ptr, b->cap); + } +} + +static inline void +check_reader(lua_State *L, struct bson_reader *br, int sz) { + if (br->size < sz) { + luaL_error(L, "Invalid bson block (%d:%d)", br->size, sz); + } +} + +static inline int +read_byte(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 1); + const uint8_t * b = br->ptr; + int r = b[0]; + ++br->ptr; + --br->size; + + return r; +} + +static inline int32_t +read_int32(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 4); + const uint8_t * b = br->ptr; + uint32_t v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + br->ptr+=4; + br->size-=4; + return (int32_t)v; +} + +static inline int64_t +read_int64(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 8); + const uint8_t * b = br->ptr; + uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; + uint64_t v = (uint64_t)lo | (uint64_t)hi<<32; + br->ptr+=8; + br->size-=8; + return (int64_t)v; +} + +static inline lua_Number +read_double(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 8); + union { + uint64_t i; + double d; + } v; + const uint8_t * b = br->ptr; + uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; + v.i = (uint64_t)lo | (uint64_t)hi<<32; + br->ptr+=8; + br->size-=8; + return v.d; +} + +static inline const void * +read_bytes(lua_State *L, struct bson_reader *br, int sz) { + const void * r = br->ptr; + check_reader(L, br, sz); + br->ptr+=sz; + br->size-=sz; + return r; +} + +static inline const char * +read_cstring(lua_State *L, struct bson_reader *br, size_t *sz) { + int i; + for (i=0;;i++) { + if (i==br->size) { + luaL_error(L, "Invalid bson block : cstring"); + } + if (br->ptr[i] == '\0') { + break; + } + } + *sz = i; + const char * r = (const char *)br->ptr; + br->ptr += i+1; + br->size -= i+1; + return r; +} + +static inline void +write_byte(struct bson *b, uint8_t v) { + bson_reserve(b,1); + b->ptr[b->size++] = v; +} + +static inline void +write_int32(struct bson *b, int32_t v) { + uint32_t uv = (uint32_t)v; + bson_reserve(b,4); + b->ptr[b->size++] = uv & 0xff; + b->ptr[b->size++] = (uv >> 8)&0xff; + b->ptr[b->size++] = (uv >> 16)&0xff; + b->ptr[b->size++] = (uv >> 24)&0xff; +} + +static inline void +write_length(struct bson *b, int32_t v, int off) { + uint32_t uv = (uint32_t)v; + b->ptr[off++] = uv & 0xff; + b->ptr[off++] = (uv >> 8)&0xff; + b->ptr[off++] = (uv >> 16)&0xff; + b->ptr[off++] = (uv >> 24)&0xff; +} + +static void +write_string(struct bson *b, const char *key, size_t sz) { + bson_reserve(b,sz+1); + memcpy(b->ptr + b->size, key, sz); + b->ptr[b->size+sz] = '\0'; + b->size+=sz+1; +} + +static inline int +reserve_length(struct bson *b) { + int sz = b->size; + bson_reserve(b,4); + b->size +=4; + return sz; +} + +static inline void +write_int64(struct bson *b, int64_t v) { + uint64_t uv = (uint64_t)v; + int i; + bson_reserve(b,8); + for (i=0;i<64;i+=8) { + b->ptr[b->size++] = (uv>>i) & 0xff; + } +} + +static inline void +write_double(struct bson *b, lua_Number d) { + union { + double d; + uint64_t i; + } v; + v.d = d; + int i; + bson_reserve(b,8); + for (i=0;i<64;i+=8) { + b->ptr[b->size++] = (v.i>>i) & 0xff; + } +} + +static void pack_dict(lua_State *L, struct bson *b); + +static inline void +append_key(struct bson *bs, int type, const char *key, size_t sz) { + write_byte(bs, type); + write_string(bs, key, sz); +} + +static void +append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { + lua_Integer i = lua_tointeger(L, -1); + lua_Number d = lua_tonumber(L,-1); + if (i != d) { + append_key(bs, BSON_REAL, key, sz); + write_double(bs, d); + } else { + int si = (int64_t)i >> 32; + if (si == 0 || si == -1) { + append_key(bs, BSON_INT32, key, sz); + write_int32(bs, i); + } else { + append_key(bs, BSON_INT64, key, sz); + write_int64(bs, i); + } + } +} + +static void +append_table(struct bson *bs, lua_State *L, const char *key, size_t sz) { + size_t len = lua_rawlen(L, -1); + bool isarray = false; + if (len > 0) { + lua_pushinteger(L, len); + if (lua_next(L,-2) == 0) { + isarray = true; + } else { + lua_pop(L,2); + } + } + if (isarray) { + append_key(bs, BSON_ARRAY, key, sz); + } else { + append_key(bs, BSON_DOCUMENT, key, sz); + } + pack_dict(L, bs); +} + +static void +write_binary(struct bson *b, const void * buffer, size_t sz) { + int length = reserve_length(b); + bson_reserve(b,sz); + memcpy(b->ptr + b->size, buffer, sz); // include sub type + b->size+=sz; + write_length(b, sz-1, length); // not include sub type +} + +static void +append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) { + int vt = lua_type(L,-1); + switch(vt) { + case LUA_TNUMBER: + append_number(bs, L, key, sz); + break; + case LUA_TUSERDATA: { + append_key(bs, BSON_DOCUMENT, key, sz); + int32_t * doc = lua_touserdata(L,-1); + int32_t sz = *doc; + bson_reserve(bs,sz); + memcpy(bs->ptr + bs->size, doc, sz); + bs->size += sz; + break; + } + case LUA_TSTRING: { + size_t len; + const char * str = lua_tolstring(L,-1,&len); + if (len > 1 && str[0]==0) { + int subt = (uint8_t)str[1]; + append_key(bs, subt, key, sz); + switch(subt) { + case BSON_BINARY: + write_binary(bs, str+2, len-2); + break; + case BSON_OBJECTID: + if (len != 2+12) { + luaL_error(L, "Invalid object id %s", str+2); + } + // go though + case BSON_JSCODE: + case BSON_DBPOINTER: + case BSON_SYMBOL: + case BSON_CODEWS: + bson_reserve(bs,len-2); + memcpy(bs->ptr + bs->size, str+2, len-2); + bs->size += len-2; + break; + case BSON_DATE: { + if (len != 2+4) { + luaL_error(L, "Invalid date"); + } + const uint32_t * ts = (const uint32_t *)(str + 2); + int64_t v = (int64_t)*ts * 1000; + write_int64(bs, v); + break; + } + case BSON_TIMESTAMP: { + if (len != 2+8) { + luaL_error(L, "Invalid timestamp"); + } + const uint32_t * inc = (const uint32_t *)(str + 2); + const uint32_t * ts = (const uint32_t *)(str + 6); + write_int32(bs, *inc); + write_int32(bs, *ts); + break; + } + case BSON_REGEX: { + str+=2; + len-=3; + size_t i; + for (i=0;isize - length, length); +} + +static int +ltostring(lua_State *L) { + size_t sz = lua_rawlen(L, 1); + void * ud = lua_touserdata(L,1); + lua_pushlstring(L, ud, sz); + return 1; +} + +static int +llen(lua_State *L) { + size_t sz = lua_rawlen(L, 1); + lua_pushinteger(L, sz); + return 1; +} + +static void +make_object(lua_State *L, int type, const void * ptr, size_t len) { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, type); + luaL_addlstring(&b, ptr, len); + luaL_pushresult(&b); +} + +static void +unpack_dict(lua_State *L, struct bson_reader *br, bool array) { + int sz = read_int32(L, br); + const void * bytes = read_bytes(L, br, sz-5); + struct bson_reader t = { bytes, sz-5 }; + int end = read_byte(L, br); + if (end != '\0') { + luaL_error(L, "Invalid document end"); + } + + lua_newtable(L); + + for (;;) { + if (t.size == 0) + break; + int bt = read_byte(L, &t); + size_t klen = 0; + const char * key = read_cstring(L, &t, &klen); + if (array) { + int id = strtol(key, NULL, 10) + 1; + lua_pushinteger(L,id); + } else { + lua_pushlstring(L, key, klen); + } + switch (bt) { + case BSON_REAL: + lua_pushnumber(L, read_double(L, &t)); + break; + case BSON_BOOLEAN: + lua_pushboolean(L, read_byte(L, &t)); + break; + case BSON_STRING: { + int sz = read_int32(L, &t); + lua_pushlstring(L, read_bytes(L, &t, sz), sz-1); + break; + } + case BSON_DOCUMENT: + unpack_dict(L, &t, false); + break; + case BSON_ARRAY: + unpack_dict(L, &t, true); + break; + case BSON_BINARY: { + int sz = read_int32(L, &t); + int subtype = read_byte(L, &t); + + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_BINARY); + luaL_addchar(&b, subtype); + luaL_addlstring(&b, read_bytes(L, &t, sz), sz); + luaL_pushresult(&b); + break; + } + case BSON_OBJECTID: + make_object(L, BSON_OBJECTID, read_bytes(L, &t, 12), 12); + break; + case BSON_DATE: { + int64_t date = read_int64(L, &t); + uint32_t v = date / 1000; + make_object(L, BSON_DATE, &v, 4); + break; + } + case BSON_MINKEY: + case BSON_MAXKEY: + case BSON_NULL: { + char key[] = { 0, bt }; + lua_pushlstring(L, key, sizeof(key)); + break; + } + case BSON_REGEX: { + size_t rlen1=0; + size_t rlen2=0; + const char * r1 = read_cstring(L, &t, &rlen1); + const char * r2 = read_cstring(L, &t, &rlen2); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_REGEX); + luaL_addlstring(&b, r1, rlen1); + luaL_addchar(&b,0); + luaL_addlstring(&b, r2, rlen2); + luaL_addchar(&b,0); + luaL_pushresult(&b); + break; + } + case BSON_INT32: + lua_pushinteger(L, read_int32(L, &t)); + break; + case BSON_TIMESTAMP: { + int32_t inc = read_int32(L, &t); + int32_t ts = read_int32(L, &t); + + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_TIMESTAMP); + luaL_addlstring(&b, (const char *)&inc, 4); + luaL_addlstring(&b, (const char *)&ts, 4); + luaL_pushresult(&b); + break; + } + case BSON_INT64: + lua_pushinteger(L, read_int64(L, &t)); + break; + case BSON_DBPOINTER: { + const void * ptr = t.ptr; + int sz = read_int32(L, &t); + read_bytes(L, &t, sz+12); + make_object(L, BSON_DBPOINTER, ptr, sz + 16); + break; + } + case BSON_JSCODE: + case BSON_SYMBOL: { + const void * ptr = t.ptr; + int sz = read_int32(L, &t); + read_bytes(L, &t, sz); + make_object(L, bt, ptr, sz + 4); + break; + } + case BSON_CODEWS: { + const void * ptr = t.ptr; + int sz = read_int32(L, &t); + read_bytes(L, &t, sz-4); + make_object(L, bt, ptr, sz); + break; + } + default: + // unsupported + luaL_error(L, "Invalid bson type : %d", bt); + lua_pop(L,1); + continue; + } + lua_rawset(L,-3); + } +} + +static int +lmakeindex(lua_State *L) { + int32_t *bson = luaL_checkudata(L,1,"bson"); + const uint8_t * start = (const uint8_t *)bson; + struct bson_reader br = { start+4, *bson - 5 }; + lua_newtable(L); + + for (;;) { + if (br.size == 0) + break; + int bt = read_byte(L, &br); + size_t klen = 0; + const char * key = read_cstring(L, &br, &klen); + int field_size = 0; + switch (bt) { + case BSON_INT64: + case BSON_TIMESTAMP: + case BSON_DATE: + case BSON_REAL: + field_size = 8; + break; + case BSON_BOOLEAN: + field_size = 1; + break; + case BSON_JSCODE: + case BSON_SYMBOL: + case BSON_STRING: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz); + break; + } + case BSON_CODEWS: + case BSON_ARRAY: + case BSON_DOCUMENT: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz-4); + break; + } + case BSON_BINARY: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz+1); + break; + } + case BSON_OBJECTID: + field_size = 12; + break; + case BSON_MINKEY: + case BSON_MAXKEY: + case BSON_NULL: + break; + case BSON_REGEX: { + size_t rlen1=0; + size_t rlen2=0; + read_cstring(L, &br, &rlen1); + read_cstring(L, &br, &rlen2); + break; + } + case BSON_INT32: + field_size = 4; + break; + case BSON_DBPOINTER: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz+12); + break; + } + default: + // unsupported + luaL_error(L, "Invalid bson type : %d", bt); + lua_pop(L,1); + continue; + } + if (field_size > 0) { + int id = bt | (int)(br.ptr - start) << BSON_TYPE_SHIFT; + read_bytes(L, &br, field_size); + lua_pushlstring(L, key, klen); + lua_pushinteger(L,id); + lua_rawset(L,-3); + } + } + lua_setuservalue(L,1); + lua_settop(L,1); + + return 1; +} + +static void +replace_object(lua_State *L, int type, struct bson * bs) { + size_t len = 0; + const char * data = luaL_checklstring(L,3, &len); + if (len < 6 || data[0] != 0 || data[1] != type) { + luaL_error(L, "Type mismatch, need bson type %d", type); + } + switch (type) { + case BSON_OBJECTID: + if (len != 2+12) { + luaL_error(L, "Invalid object id"); + } + memcpy(bs->ptr, data+2, 12); + break; + case BSON_DATE: { + if (len != 2+4) { + luaL_error(L, "Invalid date"); + } + const uint32_t * ts = (const uint32_t *)(data + 2); + int64_t v = (int64_t)*ts * 1000; + write_int64(bs, v); + break; + } + case BSON_TIMESTAMP: { + if (len != 2+8) { + luaL_error(L, "Invalid timestamp"); + } + const uint32_t * inc = (const uint32_t *)(data + 2); + const uint32_t * ts = (const uint32_t *)(data + 6); + write_int32(bs, *inc); + write_int32(bs, *ts); + break; + } + } +} + +static int +lreplace(lua_State *L) { + lua_getuservalue(L,1); + if (!lua_istable(L,-1)) { + return luaL_error(L, "call makeindex first"); + } + lua_pushvalue(L,2); + lua_rawget(L, -2); + if (!lua_isnumber(L,-1)) { + return luaL_error(L, "Can't replace key : %s", lua_tostring(L,2)); + } + int id = lua_tointeger(L, -1); + int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1); + int offset = id >> BSON_TYPE_SHIFT; + uint8_t * start = lua_touserdata(L,1); + struct bson b = { 0,16, start + offset }; + switch (type) { + case BSON_REAL: + write_double(&b, luaL_checknumber(L, 3)); + break; + case BSON_BOOLEAN: + write_byte(&b, lua_toboolean(L,3)); + break; + case BSON_OBJECTID: + case BSON_DATE: + case BSON_TIMESTAMP: + replace_object(L, type, &b); + break; + case BSON_INT32: { + double d = luaL_checknumber(L,3); + int32_t i = lua_tointeger(L,3); + if ((int32_t)d != i) { + luaL_error(L, "%f must be a 32bit integer ", d); + } + write_int32(&b, i); + break; + } + case BSON_INT64: { + double d = luaL_checknumber(L,3); + lua_Integer i = lua_tointeger(L,3); + if ((lua_Integer)d != i) { + luaL_error(L, "%f must be a 64bit integer ", d); + } + write_int64(&b, i); + break; + } + } + return 0; +} + +static int +ldecode(lua_State *L) { + const int32_t * data = lua_touserdata(L,1); + if (data == NULL) { + return 0; + } + struct bson_reader br = { (const uint8_t *)data , *data }; + + unpack_dict(L, &br, false); + + return 1; +} + +static int +lencode(lua_State *L) { + struct bson b; + bson_create(&b); + lua_settop(L,1); + luaL_checktype(L, 1, LUA_TTABLE); + pack_dict(L,&b); + void * ud = lua_newuserdata(L, b.size); + memcpy(ud, b.ptr, b.size); + bson_destroy(&b); + if (luaL_newmetatable(L, "bson")) { + luaL_Reg l[] = { + { "decode", ldecode }, + { "makeindex", lmakeindex }, + { NULL, NULL }, + }; + luaL_newlib(L,l); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, ltostring); + lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, llen); + lua_setfield(L, -2, "__len"); + lua_pushcfunction(L, lreplace); + lua_setfield(L, -2, "__newindex"); + } + lua_setmetatable(L, -2); + return 1; +} + +static int +ldate(lua_State *L) { + int d = luaL_checkinteger(L,1); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_DATE); + luaL_addlstring(&b, (const char *)&d, sizeof(d)); + luaL_pushresult(&b); + + return 1; +} + +static int +ltimestamp(lua_State *L) { + int d = luaL_checkinteger(L,1); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_TIMESTAMP); + if (lua_isnoneornil(L,2)) { + static uint32_t inc = 0; + luaL_addlstring(&b, (const char *)&inc, sizeof(inc)); + ++inc; + } else { + uint32_t i = lua_tounsigned(L,2); + luaL_addlstring(&b, (const char *)&i, sizeof(i)); + } + luaL_addlstring(&b, (const char *)&d, sizeof(d)); + luaL_pushresult(&b); + + return 1; +} + +static int +lregex(lua_State *L) { + luaL_checkstring(L,1); + if (lua_gettop(L) < 2) { + lua_pushliteral(L,""); + } + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_REGEX); + lua_pushvalue(L,1); + luaL_addvalue(&b); + luaL_addchar(&b,0); + lua_pushvalue(L,2); + luaL_addvalue(&b); + luaL_addchar(&b,0); + luaL_pushresult(&b); + + return 1; +} + +static int +lbinary(lua_State *L) { + lua_settop(L,1); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_BINARY); + luaL_addchar(&b, 0); // sub type + luaL_addvalue(&b); + luaL_pushresult(&b); + + return 1; +} + +static int +lsubtype(lua_State *L, int subtype, const uint8_t * buf, size_t sz) { + switch(subtype) { + case BSON_BINARY: + lua_pushvalue(L, lua_upvalueindex(6)); + lua_pushlstring(L, (const char *)buf+1, sz-1); + lua_pushinteger(L, buf[0]); + return 3; + case BSON_OBJECTID: { + if (sz != 12) { + return luaL_error(L, "Invalid object id"); + } + char oid[24]; + int i; + const uint8_t * id = buf; + static char *hex = "0123456789abcdef"; + for (i=0;i<12;i++) { + oid[i*2] = hex[id[i] >> 4]; + oid[i*2+1] = hex[id[i] & 0xf]; + } + lua_pushvalue(L, lua_upvalueindex(7)); + lua_pushlstring(L, oid, 24); + + return 2; + } + case BSON_DATE: { + if (sz != 4) { + return luaL_error(L, "Invalid date"); + } + int d = *(const int *)buf; + lua_pushvalue(L, lua_upvalueindex(9)); + lua_pushinteger(L, d); + return 2; + } + case BSON_TIMESTAMP: { + if (sz != 8) { + return luaL_error(L, "Invalid timestamp"); + } + const uint32_t * ts = (const uint32_t *)buf; + lua_pushvalue(L, lua_upvalueindex(8)); + lua_pushunsigned(L, ts[1]); + lua_pushunsigned(L, ts[0]); + return 3; + } + case BSON_REGEX: { + --sz; + size_t i; + const uint8_t *str = buf; + for (i=0;i= 2) { + return lsubtype(L, (uint8_t)str[1], (const uint8_t *)str+2, len-2); + } else { + type = 5; + break; + } + } + default: + return luaL_error(L, "Invalid type %s",lua_typename(L,t)); + } + lua_pushvalue(L, lua_upvalueindex(type)); + lua_pushvalue(L,1); + return 2; +} + +static void +typeclosure(lua_State *L) { + static const char * typename[] = { + "number", // 1 + "boolean", // 2 + "table", // 3 + "nil", // 4 + "string", // 5 + "binary", // 6 + "objectid", // 7 + "timestamp",// 8 + "date", // 9 + "regex", // 10 + "minkey", // 11 + "maxkey", // 12 + "unsupported", // 13 + }; + int i; + int n = sizeof(typename)/sizeof(typename[0]); + for (i=0;i>2)+hostname[i]); + } + h ^= i; + } + oid_header[0] = h & 0xff; + oid_header[1] = (h>>8) & 0xff; + oid_header[2] = (h>>16) & 0xff; + oid_header[3] = pid & 0xff; + oid_header[4] = (pid >> 8) & 0xff; + + oid_counter = h ^ time(NULL) ^ (uintptr_t)&h; +} + +static inline int +hextoint(char c) { + if (c>='0' && c<='9') + return c-'0'; + if (c>='a' && c<='z') + return c-'a'+10; + if (c>='A' && c<='Z') + return c-'A'+10; + return 0; +} + +static int +lobjectid(lua_State *L) { + uint8_t oid[14] = { 0, BSON_OBJECTID }; + if (lua_isstring(L,1)) { + size_t len; + const char * str = lua_tolstring(L,1,&len); + if (len != 24) { + return luaL_error(L, "Invalid objectid %s", str); + } + int i; + for (i=0;i<12;i++) { + oid[i+2] = hextoint(str[i*2]) << 4 | hextoint(str[i*2+1]); + } + } else { + time_t ti = time(NULL); + oid[2] = ti & 0xff; + oid[3] = (ti>>8) & 0xff; + oid[4] = (ti>>16) & 0xff; + oid[5] = (ti>>24) & 0xff; + memcpy(oid+6 , oid_header, 5); + oid[11] = oid_counter & 0xff; + oid[12] = (oid_counter>>8) & 0xff; + oid[13] = (oid_counter>>16) & 0xff; + ++oid_counter; + } + lua_pushlstring( L, (const char *)oid, 14); + + return 1; +} + +int +luaopen_bson(lua_State *L) { + luaL_checkversion(L); + int i; + for (i=0;i #include +#include "luacompat52.h" #include #include