├── Makefile ├── utils.lua ├── LICENSE ├── test.lua ├── README.md └── bson.c /Makefile: -------------------------------------------------------------------------------- 1 | LUAINCLUDE=-I/usr/local/include 2 | LUALIB=-L/usr/local/bin -llua53 3 | SOCKETLIB=-lws2_32 4 | 5 | .PHONY: all win linux 6 | 7 | all : 8 | @echo Please do \'make PLATFORM\' where PLATFORM is one of these: 9 | @echo win linux 10 | 11 | win: bson.dll 12 | 13 | linux: bson.so 14 | 15 | bson.dll : bson.c 16 | gcc --shared -Wall -O2 $^ -o$@ $(LUAINCLUDE) $(LUALIB) $(SOCKETLIB) 17 | 18 | bson.so : bson.c 19 | gcc --shared -Wall -fPIC -O2 $^ -o$@ $(LUAINCLUDE) -lm 20 | 21 | clean: 22 | rm -f bson.dll bson.so 23 | -------------------------------------------------------------------------------- /utils.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local tconcat = table.concat 4 | local tinsert = table.insert 5 | local srep = string.rep 6 | 7 | M.print_table = function(root) 8 | local cache = { [root] = "." } 9 | local function _dump(t,space,name) 10 | local temp = {} 11 | for k, v in next, t do 12 | local key = tostring(k) 13 | if cache[v] then 14 | tinsert(temp,"+" .. key .. " {" .. cache[v].."}") 15 | elseif type(v) == "table" then 16 | local new_key = name .. "." .. key 17 | cache[v] = new_key 18 | tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key)) 19 | else 20 | tinsert(temp,"+" .. key .. " [" .. tostring(v).."]") 21 | end 22 | end 23 | return tconcat(temp,"\n"..space) 24 | end 25 | 26 | print(_dump(root, "","")) 27 | end 28 | 29 | return M 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 codingnow.com 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | local bson = require "bson" 2 | local Utils = require "utils" 3 | 4 | sub = bson.encode_order( "hello", 1, "world", 2 ) 5 | 6 | local function tbl_next(...) 7 | print("--- next.a", ...) 8 | local k, v = next(...) 9 | print("--- next.b", k, v) 10 | return k, v 11 | end 12 | 13 | local function tbl_pairs(obj) 14 | return tbl_next, obj.__data, nil 15 | end 16 | 17 | local obj_a = { 18 | __data = { 19 | [1] = 2, 20 | [3] = 4, 21 | [5] = 6, 22 | } 23 | } 24 | 25 | setmetatable( 26 | obj_a, 27 | { 28 | __index = obj_a.__data, 29 | __pairs = tbl_pairs, 30 | } 31 | ) 32 | 33 | local obj_b = { 34 | __data = { 35 | [7] = 8, 36 | [9] = 10, 37 | [11] = obj_a, 38 | } 39 | } 40 | 41 | setmetatable( 42 | obj_b, 43 | { 44 | __index = obj_b.__data, 45 | __pairs = tbl_pairs, 46 | } 47 | ) 48 | 49 | b = bson.encode { 50 | a = 1, 51 | b = true, 52 | c = bson.null, 53 | d = { 1,2,3,4 }, 54 | e = bson.binary "hello", 55 | f = bson.regex ("*","i"), 56 | g = bson.regex "hello", 57 | h = bson.date (os.time()), 58 | i = bson.timestamp(os.time()), 59 | j = bson.objectid(), 60 | k = { a = false, b = true }, 61 | l = {}, 62 | m = bson.minkey, 63 | n = bson.maxkey, 64 | o = sub, 65 | p = 2^32-1, 66 | q = obj_b, 67 | } 68 | 69 | print "\n[before replace]" 70 | t = b:decode() 71 | 72 | for k,v in pairs(t) do 73 | local ty, val = bson.type(v) 74 | print("---", k, ty, val) 75 | if ty == 'table' then 76 | Utils.print_table(val) 77 | end 78 | end 79 | 80 | b:makeindex() 81 | b.a = 2 82 | b.b = false 83 | b.h = bson.date(os.time()) 84 | b.i = bson.timestamp(os.time()) 85 | b.j = bson.objectid() 86 | 87 | print "\n[after replace]" 88 | t = b:decode() 89 | 90 | for k,v in pairs(t) do 91 | local ty, val = bson.type(v) 92 | print("---", k, ty, val) 93 | if ty == 'table' then 94 | Utils.print_table(val) 95 | end 96 | end 97 | 98 | print("o.hello", bson.type(t.o.hello)) 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is a simple BSON library for Lua. 4 | 5 | ## Building 6 | 7 | ``` 8 | make win 9 | ``` 10 | or 11 | ``` 12 | make linux 13 | ``` 14 | 15 | ## Types 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
Lua TypeBSON TypeNotes
bson.nullNull
booleanBoolean
numberDouble
number32-bit integer
number64-bit integerprecision lost in lua 5.1/5.2
stringString
bson.binary(blob)Binary stringUse bson.type() to decode
tableBSON Document
tableBSON ArrayLua table must be a sequence. (Continuous number key base 1)
bson.date(os.time())UTC Datetimemilliseconds since epoch
bson.timestamp(os.time())Timestampspecial mongodb type, two 32-bit number
bson.regex(regex,option)Regular Expression
bson.objectid()ObjectIDMongoDB document ID
bson.minkeyMin Key
bson.maxkeyMax Key
37 | 38 | ## Convert a bson value to lua string 39 | 40 | A value with bson type Null,Binary,MinKey,Maxkey,etc would be encoded in lua, you can use bson.type(v) to convent back to normal lua string. 41 | ```Lua 42 | typestring, value = bson.type(bson.binary("Hello")) 43 | assert(typestring == "binary") 44 | assert(value == "Hello") 45 | ``` 46 | 47 | ## Replace field 48 | 49 | These bson types (fixed length) below can be replace by new value after encode to bson object. 50 | 51 | * int32 52 | * int64 53 | * double 54 | * boolean 55 | * date 56 | * timestamp 57 | * objectid 58 | 59 | You need call makeindex() before replace. 60 | 61 | ## Getting started 62 | 63 | See test.lua 64 | -------------------------------------------------------------------------------- /bson.c: -------------------------------------------------------------------------------- 1 | #define LUA_LIB 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(_WIN32) || defined(_WIN64) 15 | 16 | #include 17 | 18 | static void 19 | init_winsock() { 20 | WSADATA wsaData; 21 | WSAStartup(MAKEWORD(2,2), &wsaData); 22 | } 23 | 24 | #else 25 | 26 | static void 27 | init_winsock() { 28 | } 29 | 30 | #endif 31 | 32 | #define DEFAULT_CAP 64 33 | #define MAX_NUMBER 1024 34 | // avoid circular reference while encoding 35 | #define MAX_DEPTH 128 36 | 37 | #define BSON_REAL 1 38 | #define BSON_STRING 2 39 | #define BSON_DOCUMENT 3 40 | #define BSON_ARRAY 4 41 | #define BSON_BINARY 5 42 | #define BSON_UNDEFINED 6 43 | #define BSON_OBJECTID 7 44 | #define BSON_BOOLEAN 8 45 | #define BSON_DATE 9 46 | #define BSON_NULL 10 47 | #define BSON_REGEX 11 48 | #define BSON_DBPOINTER 12 49 | #define BSON_JSCODE 13 50 | #define BSON_SYMBOL 14 51 | #define BSON_CODEWS 15 52 | #define BSON_INT32 16 53 | #define BSON_TIMESTAMP 17 54 | #define BSON_INT64 18 55 | #define BSON_MINKEY 255 56 | #define BSON_MAXKEY 127 57 | 58 | #define BSON_TYPE_SHIFT 5 59 | 60 | static char bson_numstrs[MAX_NUMBER][4]; 61 | static int bson_numstr_len[MAX_NUMBER]; 62 | 63 | struct bson { 64 | int size; 65 | int cap; 66 | uint8_t *ptr; 67 | uint8_t buffer[DEFAULT_CAP]; 68 | }; 69 | 70 | struct bson_reader { 71 | const uint8_t * ptr; 72 | int size; 73 | }; 74 | 75 | static inline int32_t 76 | get_length(const uint8_t * data) { 77 | const uint8_t * b = (const uint8_t *)data; 78 | int32_t len = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; 79 | return len; 80 | } 81 | 82 | static inline void 83 | bson_destroy(struct bson *b) { 84 | if (b->ptr != b->buffer) { 85 | free(b->ptr); 86 | } 87 | } 88 | 89 | static inline void 90 | bson_create(struct bson *b) { 91 | b->size = 0; 92 | b->cap = DEFAULT_CAP; 93 | b->ptr = b->buffer; 94 | } 95 | 96 | static inline void 97 | bson_reserve(struct bson *b, int sz) { 98 | if (b->size + sz <= b->cap) 99 | return; 100 | do { 101 | b->cap *= 2; 102 | } while (b->cap <= b->size + sz); 103 | 104 | if (b->ptr == b->buffer) { 105 | b->ptr = malloc(b->cap); 106 | memcpy(b->ptr, b->buffer, b->size); 107 | } else { 108 | b->ptr = realloc(b->ptr, b->cap); 109 | } 110 | } 111 | 112 | static inline void 113 | check_reader(lua_State *L, struct bson_reader *br, int sz) { 114 | if (br->size < sz) { 115 | luaL_error(L, "Invalid bson block (%d:%d)", br->size, sz); 116 | } 117 | } 118 | 119 | static inline int 120 | read_byte(lua_State *L, struct bson_reader *br) { 121 | check_reader(L, br, 1); 122 | const uint8_t * b = br->ptr; 123 | int r = b[0]; 124 | ++br->ptr; 125 | --br->size; 126 | 127 | return r; 128 | } 129 | 130 | static inline int32_t 131 | read_int32(lua_State *L, struct bson_reader *br) { 132 | check_reader(L, br, 4); 133 | const uint8_t * b = br->ptr; 134 | uint32_t v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; 135 | br->ptr+=4; 136 | br->size-=4; 137 | return (int32_t)v; 138 | } 139 | 140 | static inline int64_t 141 | read_int64(lua_State *L, struct bson_reader *br) { 142 | check_reader(L, br, 8); 143 | const uint8_t * b = br->ptr; 144 | uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; 145 | uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; 146 | uint64_t v = (uint64_t)lo | (uint64_t)hi<<32; 147 | br->ptr+=8; 148 | br->size-=8; 149 | return (int64_t)v; 150 | } 151 | 152 | static inline lua_Number 153 | read_double(lua_State *L, struct bson_reader *br) { 154 | check_reader(L, br, 8); 155 | union { 156 | uint64_t i; 157 | double d; 158 | } v; 159 | const uint8_t * b = br->ptr; 160 | uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; 161 | uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; 162 | v.i = (uint64_t)lo | (uint64_t)hi<<32; 163 | br->ptr+=8; 164 | br->size-=8; 165 | return v.d; 166 | } 167 | 168 | static inline const void * 169 | read_bytes(lua_State *L, struct bson_reader *br, int sz) { 170 | const void * r = br->ptr; 171 | check_reader(L, br, sz); 172 | br->ptr+=sz; 173 | br->size-=sz; 174 | return r; 175 | } 176 | 177 | static inline const char * 178 | read_cstring(lua_State *L, struct bson_reader *br, size_t *sz) { 179 | int i; 180 | for (i=0;;i++) { 181 | if (i==br->size) { 182 | luaL_error(L, "Invalid bson block : cstring"); 183 | } 184 | if (br->ptr[i] == '\0') { 185 | break; 186 | } 187 | } 188 | *sz = i; 189 | const char * r = (const char *)br->ptr; 190 | br->ptr += i+1; 191 | br->size -= i+1; 192 | return r; 193 | } 194 | 195 | static inline void 196 | write_byte(struct bson *b, uint8_t v) { 197 | bson_reserve(b,1); 198 | b->ptr[b->size++] = v; 199 | } 200 | 201 | static inline void 202 | write_int32(struct bson *b, int32_t v) { 203 | uint32_t uv = (uint32_t)v; 204 | bson_reserve(b,4); 205 | b->ptr[b->size++] = uv & 0xff; 206 | b->ptr[b->size++] = (uv >> 8)&0xff; 207 | b->ptr[b->size++] = (uv >> 16)&0xff; 208 | b->ptr[b->size++] = (uv >> 24)&0xff; 209 | } 210 | 211 | static inline void 212 | write_length(struct bson *b, int32_t v, int off) { 213 | uint32_t uv = (uint32_t)v; 214 | b->ptr[off++] = uv & 0xff; 215 | b->ptr[off++] = (uv >> 8)&0xff; 216 | b->ptr[off++] = (uv >> 16)&0xff; 217 | b->ptr[off++] = (uv >> 24)&0xff; 218 | } 219 | 220 | static void 221 | write_string(struct bson *b, const char *key, size_t sz) { 222 | bson_reserve(b,sz+1); 223 | memcpy(b->ptr + b->size, key, sz); 224 | b->ptr[b->size+sz] = '\0'; 225 | b->size+=sz+1; 226 | } 227 | 228 | static inline int 229 | reserve_length(struct bson *b) { 230 | int sz = b->size; 231 | bson_reserve(b,4); 232 | b->size +=4; 233 | return sz; 234 | } 235 | 236 | static inline void 237 | write_int64(struct bson *b, int64_t v) { 238 | uint64_t uv = (uint64_t)v; 239 | int i; 240 | bson_reserve(b,8); 241 | for (i=0;i<64;i+=8) { 242 | b->ptr[b->size++] = (uv>>i) & 0xff; 243 | } 244 | } 245 | 246 | static inline void 247 | write_double(struct bson *b, lua_Number d) { 248 | union { 249 | double d; 250 | uint64_t i; 251 | } v; 252 | v.d = d; 253 | int i; 254 | bson_reserve(b,8); 255 | for (i=0;i<64;i+=8) { 256 | b->ptr[b->size++] = (v.i>>i) & 0xff; 257 | } 258 | } 259 | 260 | static void pack_dict(lua_State *L, struct bson *b, bool array, int depth); 261 | 262 | static inline void 263 | append_key(struct bson *bs, int type, const char *key, size_t sz) { 264 | write_byte(bs, type); 265 | write_string(bs, key, sz); 266 | } 267 | 268 | #if LUA_VERSION_NUM >= 503 269 | 270 | static inline int 271 | is_32bit(int64_t v) { 272 | return v >= INT32_MIN && v <= INT32_MAX; 273 | } 274 | 275 | static void 276 | append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { 277 | if (lua_isinteger(L, -1)) { 278 | int64_t i = lua_tointeger(L, -1); 279 | if (is_32bit(i)) { 280 | append_key(bs, BSON_INT32, key, sz); 281 | write_int32(bs, i); 282 | } else { 283 | append_key(bs, BSON_INT64, key, sz); 284 | write_int64(bs, i); 285 | } 286 | } else { 287 | lua_Number d = lua_tonumber(L,-1); 288 | append_key(bs, BSON_REAL, key, sz); 289 | write_double(bs, d); 290 | } 291 | } 292 | 293 | #else 294 | 295 | static void 296 | append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { 297 | int64_t i = lua_tointeger(L, -1); 298 | lua_Number d = lua_tonumber(L,-1); 299 | if (i != d) { 300 | append_key(bs, BSON_REAL, key, sz); 301 | write_double(bs, d); 302 | } else { 303 | if (is_32bit(i)) { 304 | append_key(bs, BSON_INT32, key, sz); 305 | write_int32(bs, i); 306 | } else { 307 | append_key(bs, BSON_INT64, key, sz); 308 | write_int64(bs, i); 309 | } 310 | } 311 | } 312 | #endif 313 | 314 | static void 315 | append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { 316 | size_t len = lua_rawlen(L, -1); 317 | bool isarray = false; 318 | if (len > 0) { 319 | lua_pushinteger(L, len); 320 | if (lua_next(L,-2) == 0) { 321 | isarray = true; 322 | } else { 323 | lua_pop(L,2); 324 | } 325 | } 326 | if (isarray) { 327 | append_key(bs, BSON_ARRAY, key, sz); 328 | } else { 329 | append_key(bs, BSON_DOCUMENT, key, sz); 330 | } 331 | pack_dict(L, bs, isarray, depth); 332 | } 333 | 334 | static void 335 | write_binary(struct bson *b, const void * buffer, size_t sz) { 336 | int length = reserve_length(b); 337 | bson_reserve(b,sz); 338 | memcpy(b->ptr + b->size, buffer, sz); // include sub type 339 | b->size+=sz; 340 | write_length(b, sz-1, length); // not include sub type 341 | } 342 | 343 | static void 344 | append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { 345 | int vt = lua_type(L,-1); 346 | switch(vt) { 347 | case LUA_TNUMBER: 348 | append_number(bs, L, key, sz); 349 | break; 350 | case LUA_TUSERDATA: { 351 | append_key(bs, BSON_DOCUMENT, key, sz); 352 | int32_t * doc = lua_touserdata(L,-1); 353 | int32_t sz = *doc; 354 | bson_reserve(bs,sz); 355 | memcpy(bs->ptr + bs->size, doc, sz); 356 | bs->size += sz; 357 | break; 358 | } 359 | case LUA_TSTRING: { 360 | size_t len; 361 | const char * str = lua_tolstring(L,-1,&len); 362 | if (len > 1 && str[0]==0) { 363 | int subt = (uint8_t)str[1]; 364 | append_key(bs, subt, key, sz); 365 | switch(subt) { 366 | case BSON_BINARY: 367 | write_binary(bs, str+2, len-2); 368 | break; 369 | case BSON_OBJECTID: 370 | if (len != 2+12) { 371 | luaL_error(L, "Invalid object id %s", str+2); 372 | } 373 | // go though 374 | case BSON_JSCODE: 375 | case BSON_DBPOINTER: 376 | case BSON_SYMBOL: 377 | case BSON_CODEWS: 378 | bson_reserve(bs,len-2); 379 | memcpy(bs->ptr + bs->size, str+2, len-2); 380 | bs->size += len-2; 381 | break; 382 | case BSON_DATE: { 383 | if (len != 2+4) { 384 | luaL_error(L, "Invalid date"); 385 | } 386 | const uint32_t * ts = (const uint32_t *)(str + 2); 387 | int64_t v = (int64_t)*ts * 1000; 388 | write_int64(bs, v); 389 | break; 390 | } 391 | case BSON_TIMESTAMP: { 392 | if (len != 2+8) { 393 | luaL_error(L, "Invalid timestamp"); 394 | } 395 | const uint32_t * inc = (const uint32_t *)(str + 2); 396 | const uint32_t * ts = (const uint32_t *)(str + 6); 397 | write_int32(bs, *inc); 398 | write_int32(bs, *ts); 399 | break; 400 | } 401 | case BSON_REGEX: { 402 | str+=2; 403 | len-=3; 404 | size_t i; 405 | for (i=0;i MAX_DEPTH) { 493 | luaL_error(L, "Too depth while encoding bson"); 494 | } 495 | luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table 496 | int length = reserve_length(b); 497 | lua_pushnil(L); 498 | while(lua_next(L,-2) != 0) { 499 | int kt = lua_type(L, -2); 500 | pack_dict_data(L, b, isarray, depth, kt); 501 | } 502 | write_byte(b,0); 503 | write_length(b, b->size - length, length); 504 | } 505 | 506 | 507 | static void 508 | pack_meta_dict(lua_State *L, struct bson *b, bool isarray, int depth) { 509 | if (depth > MAX_DEPTH) { 510 | luaL_error(L, "Too depth while encoding bson"); 511 | } 512 | luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table 513 | int length = reserve_length(b); 514 | 515 | lua_pushvalue(L, -2); // push meta_obj 516 | lua_call(L, 1, 3); // call __pairs_func => next_func, t_data, first_k 517 | for(;;) { 518 | lua_pushvalue(L, -2); // copy data 519 | lua_pushvalue(L, -2); // copy k 520 | lua_copy(L, -5, -3); // copy next_func replace old_k 521 | lua_call(L, 2, 2); // call next_func 522 | 523 | int kt = lua_type(L, -2); 524 | if (kt == LUA_TNIL) { 525 | lua_pop(L, 4); // pop all k, v, next_func, obj 526 | break; 527 | } 528 | pack_dict_data(L, b, isarray, depth, kt); 529 | } 530 | write_byte(b,0); 531 | write_length(b, b->size - length, length); 532 | } 533 | 534 | static void 535 | pack_dict(lua_State *L, struct bson *b, bool isarray, int depth) { 536 | if (luaL_getmetafield(L, -1, "__pairs") != LUA_TNIL) { 537 | pack_meta_dict(L, b, isarray, depth); 538 | } else { 539 | pack_simple_dict(L, b, isarray, depth); 540 | } 541 | } 542 | 543 | static void 544 | pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) { 545 | int length = reserve_length(b); 546 | int i; 547 | for (i=0;isize - length, length); 559 | } 560 | 561 | static int 562 | ltostring(lua_State *L) { 563 | size_t sz = lua_rawlen(L, 1); 564 | void * ud = lua_touserdata(L,1); 565 | lua_pushlstring(L, ud, sz); 566 | return 1; 567 | } 568 | 569 | static int 570 | llen(lua_State *L) { 571 | size_t sz = lua_rawlen(L, 1); 572 | lua_pushinteger(L, sz); 573 | return 1; 574 | } 575 | 576 | static void 577 | make_object(lua_State *L, int type, const void * ptr, size_t len) { 578 | luaL_Buffer b; 579 | luaL_buffinit(L, &b); 580 | luaL_addchar(&b, 0); 581 | luaL_addchar(&b, type); 582 | luaL_addlstring(&b, ptr, len); 583 | luaL_pushresult(&b); 584 | } 585 | 586 | static void 587 | unpack_dict(lua_State *L, struct bson_reader *br, bool array) { 588 | luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table 589 | int sz = read_int32(L, br); 590 | const void * bytes = read_bytes(L, br, sz-5); 591 | struct bson_reader t = { bytes, sz-5 }; 592 | int end = read_byte(L, br); 593 | if (end != '\0') { 594 | luaL_error(L, "Invalid document end"); 595 | } 596 | 597 | lua_newtable(L); 598 | 599 | for (;;) { 600 | if (t.size == 0) 601 | break; 602 | int bt = read_byte(L, &t); 603 | size_t klen = 0; 604 | const char * key = read_cstring(L, &t, &klen); 605 | if (array) { 606 | int id = strtol(key, NULL, 10) + 1; 607 | lua_pushinteger(L,id); 608 | } else { 609 | lua_pushlstring(L, key, klen); 610 | } 611 | switch (bt) { 612 | case BSON_REAL: 613 | lua_pushnumber(L, read_double(L, &t)); 614 | break; 615 | case BSON_BOOLEAN: 616 | lua_pushboolean(L, read_byte(L, &t)); 617 | break; 618 | case BSON_STRING: { 619 | int sz = read_int32(L, &t); 620 | if (sz <= 0) { 621 | luaL_error(L, "Invalid bson string , length = %d", sz); 622 | } 623 | lua_pushlstring(L, read_bytes(L, &t, sz), sz-1); 624 | break; 625 | } 626 | case BSON_DOCUMENT: 627 | unpack_dict(L, &t, false); 628 | break; 629 | case BSON_ARRAY: 630 | unpack_dict(L, &t, true); 631 | break; 632 | case BSON_BINARY: { 633 | int sz = read_int32(L, &t); 634 | int subtype = read_byte(L, &t); 635 | 636 | luaL_Buffer b; 637 | luaL_buffinit(L, &b); 638 | luaL_addchar(&b, 0); 639 | luaL_addchar(&b, BSON_BINARY); 640 | luaL_addchar(&b, subtype); 641 | luaL_addlstring(&b, read_bytes(L, &t, sz), sz); 642 | luaL_pushresult(&b); 643 | break; 644 | } 645 | case BSON_OBJECTID: 646 | make_object(L, BSON_OBJECTID, read_bytes(L, &t, 12), 12); 647 | break; 648 | case BSON_DATE: { 649 | int64_t date = read_int64(L, &t); 650 | uint32_t v = date / 1000; 651 | make_object(L, BSON_DATE, &v, 4); 652 | break; 653 | } 654 | case BSON_MINKEY: 655 | case BSON_MAXKEY: 656 | case BSON_NULL: { 657 | char key[] = { 0, bt }; 658 | lua_pushlstring(L, key, sizeof(key)); 659 | break; 660 | } 661 | case BSON_REGEX: { 662 | size_t rlen1=0; 663 | size_t rlen2=0; 664 | const char * r1 = read_cstring(L, &t, &rlen1); 665 | const char * r2 = read_cstring(L, &t, &rlen2); 666 | luaL_Buffer b; 667 | luaL_buffinit(L, &b); 668 | luaL_addchar(&b, 0); 669 | luaL_addchar(&b, BSON_REGEX); 670 | luaL_addlstring(&b, r1, rlen1); 671 | luaL_addchar(&b,0); 672 | luaL_addlstring(&b, r2, rlen2); 673 | luaL_addchar(&b,0); 674 | luaL_pushresult(&b); 675 | break; 676 | } 677 | case BSON_INT32: 678 | lua_pushinteger(L, read_int32(L, &t)); 679 | break; 680 | case BSON_TIMESTAMP: { 681 | int32_t inc = read_int32(L, &t); 682 | int32_t ts = read_int32(L, &t); 683 | 684 | luaL_Buffer b; 685 | luaL_buffinit(L, &b); 686 | luaL_addchar(&b, 0); 687 | luaL_addchar(&b, BSON_TIMESTAMP); 688 | luaL_addlstring(&b, (const char *)&inc, 4); 689 | luaL_addlstring(&b, (const char *)&ts, 4); 690 | luaL_pushresult(&b); 691 | break; 692 | } 693 | case BSON_INT64: 694 | lua_pushinteger(L, read_int64(L, &t)); 695 | break; 696 | case BSON_DBPOINTER: { 697 | const void * ptr = t.ptr; 698 | int sz = read_int32(L, &t); 699 | read_bytes(L, &t, sz+12); 700 | make_object(L, BSON_DBPOINTER, ptr, sz + 16); 701 | break; 702 | } 703 | case BSON_JSCODE: 704 | case BSON_SYMBOL: { 705 | const void * ptr = t.ptr; 706 | int sz = read_int32(L, &t); 707 | read_bytes(L, &t, sz); 708 | make_object(L, bt, ptr, sz + 4); 709 | break; 710 | } 711 | case BSON_CODEWS: { 712 | const void * ptr = t.ptr; 713 | int sz = read_int32(L, &t); 714 | read_bytes(L, &t, sz-4); 715 | make_object(L, bt, ptr, sz); 716 | break; 717 | } 718 | default: 719 | // unsupported 720 | luaL_error(L, "Invalid bson type : %d", bt); 721 | lua_pop(L,1); 722 | continue; 723 | } 724 | lua_rawset(L,-3); 725 | } 726 | } 727 | 728 | static int 729 | lmakeindex(lua_State *L) { 730 | int32_t *bson = luaL_checkudata(L,1,"bson"); 731 | const uint8_t * start = (const uint8_t *)bson; 732 | struct bson_reader br = { start+4, get_length(start) - 5 }; 733 | lua_newtable(L); 734 | 735 | for (;;) { 736 | if (br.size == 0) 737 | break; 738 | int bt = read_byte(L, &br); 739 | size_t klen = 0; 740 | const char * key = read_cstring(L, &br, &klen); 741 | int field_size = 0; 742 | switch (bt) { 743 | case BSON_INT64: 744 | case BSON_TIMESTAMP: 745 | case BSON_DATE: 746 | case BSON_REAL: 747 | field_size = 8; 748 | break; 749 | case BSON_BOOLEAN: 750 | field_size = 1; 751 | break; 752 | case BSON_JSCODE: 753 | case BSON_SYMBOL: 754 | case BSON_STRING: { 755 | int sz = read_int32(L, &br); 756 | read_bytes(L, &br, sz); 757 | break; 758 | } 759 | case BSON_CODEWS: 760 | case BSON_ARRAY: 761 | case BSON_DOCUMENT: { 762 | int sz = read_int32(L, &br); 763 | read_bytes(L, &br, sz-4); 764 | break; 765 | } 766 | case BSON_BINARY: { 767 | int sz = read_int32(L, &br); 768 | read_bytes(L, &br, sz+1); 769 | break; 770 | } 771 | case BSON_OBJECTID: 772 | field_size = 12; 773 | break; 774 | case BSON_MINKEY: 775 | case BSON_MAXKEY: 776 | case BSON_NULL: 777 | break; 778 | case BSON_REGEX: { 779 | size_t rlen1=0; 780 | size_t rlen2=0; 781 | read_cstring(L, &br, &rlen1); 782 | read_cstring(L, &br, &rlen2); 783 | break; 784 | } 785 | case BSON_INT32: 786 | field_size = 4; 787 | break; 788 | case BSON_DBPOINTER: { 789 | int sz = read_int32(L, &br); 790 | read_bytes(L, &br, sz+12); 791 | break; 792 | } 793 | default: 794 | // unsupported 795 | luaL_error(L, "Invalid bson type : %d", bt); 796 | lua_pop(L,1); 797 | continue; 798 | } 799 | if (field_size > 0) { 800 | int id = bt | (int)(br.ptr - start) << BSON_TYPE_SHIFT; 801 | read_bytes(L, &br, field_size); 802 | lua_pushlstring(L, key, klen); 803 | lua_pushinteger(L,id); 804 | lua_rawset(L,-3); 805 | } 806 | } 807 | lua_setuservalue(L,1); 808 | lua_settop(L,1); 809 | 810 | return 1; 811 | } 812 | 813 | static void 814 | replace_object(lua_State *L, int type, struct bson * bs) { 815 | size_t len = 0; 816 | const char * data = luaL_checklstring(L,3, &len); 817 | if (len < 6 || data[0] != 0 || data[1] != type) { 818 | luaL_error(L, "Type mismatch, need bson type %d", type); 819 | } 820 | switch (type) { 821 | case BSON_OBJECTID: 822 | if (len != 2+12) { 823 | luaL_error(L, "Invalid object id"); 824 | } 825 | memcpy(bs->ptr, data+2, 12); 826 | break; 827 | case BSON_DATE: { 828 | if (len != 2+4) { 829 | luaL_error(L, "Invalid date"); 830 | } 831 | const uint32_t * ts = (const uint32_t *)(data + 2); 832 | int64_t v = (int64_t)*ts * 1000; 833 | write_int64(bs, v); 834 | break; 835 | } 836 | case BSON_TIMESTAMP: { 837 | if (len != 2+8) { 838 | luaL_error(L, "Invalid timestamp"); 839 | } 840 | const uint32_t * inc = (const uint32_t *)(data + 2); 841 | const uint32_t * ts = (const uint32_t *)(data + 6); 842 | write_int32(bs, *inc); 843 | write_int32(bs, *ts); 844 | break; 845 | } 846 | } 847 | } 848 | 849 | static int 850 | lreplace(lua_State *L) { 851 | lua_getuservalue(L,1); 852 | if (!lua_istable(L,-1)) { 853 | return luaL_error(L, "call makeindex first"); 854 | } 855 | lua_pushvalue(L,2); 856 | lua_rawget(L, -2); 857 | if (!lua_isnumber(L,-1)) { 858 | return luaL_error(L, "Can't replace key : %s", lua_tostring(L,2)); 859 | } 860 | int id = lua_tointeger(L, -1); 861 | int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1); 862 | int offset = id >> BSON_TYPE_SHIFT; 863 | uint8_t * start = lua_touserdata(L,1); 864 | struct bson b = { 0,16, start + offset }; 865 | switch (type) { 866 | case BSON_REAL: 867 | write_double(&b, luaL_checknumber(L, 3)); 868 | break; 869 | case BSON_BOOLEAN: 870 | write_byte(&b, lua_toboolean(L,3)); 871 | break; 872 | case BSON_OBJECTID: 873 | case BSON_DATE: 874 | case BSON_TIMESTAMP: 875 | replace_object(L, type, &b); 876 | break; 877 | #if LUA_VERSION_NUM >= 503 878 | case BSON_INT32: { 879 | if (!lua_isinteger(L, 3)) { 880 | luaL_error(L, "%f must be a 32bit integer ", lua_tonumber(L, 3)); 881 | } 882 | int32_t i = lua_tointeger(L,3); 883 | write_int32(&b, i); 884 | break; 885 | } 886 | case BSON_INT64: { 887 | if (!lua_isinteger(L, 3)) { 888 | luaL_error(L, "%f must be a 64bit integer ", lua_tonumber(L, 3)); 889 | } 890 | int64_t i = lua_tointeger(L,3); 891 | write_int64(&b, i); 892 | break; 893 | } 894 | #else 895 | case BSON_INT32: { 896 | double d = luaL_checknumber(L,3); 897 | int32_t i = lua_tointeger(L,3); 898 | if ((int32_t)d != i) { 899 | luaL_error(L, "%f must be a 32bit integer ", d); 900 | } 901 | write_int32(&b, i); 902 | break; 903 | } 904 | case BSON_INT64: { 905 | double d = luaL_checknumber(L,3); 906 | lua_Integer i = lua_tointeger(L,3); 907 | if ((lua_Integer)d != i) { 908 | luaL_error(L, "%f must be a 64bit integer ", d); 909 | } 910 | write_int64(&b, i); 911 | break; 912 | } 913 | #endif 914 | default: 915 | luaL_error(L, "Can't replace type %d", type); 916 | break; 917 | } 918 | return 0; 919 | } 920 | 921 | static int 922 | ldecode(lua_State *L) { 923 | const int32_t * data = lua_touserdata(L,1); 924 | if (data == NULL) { 925 | return 0; 926 | } 927 | const uint8_t * b = (const uint8_t *)data; 928 | int32_t len = get_length(b); 929 | struct bson_reader br = { b , len }; 930 | 931 | unpack_dict(L, &br, false); 932 | 933 | return 1; 934 | } 935 | 936 | static void 937 | bson_meta(lua_State *L) { 938 | if (luaL_newmetatable(L, "bson")) { 939 | luaL_Reg l[] = { 940 | { "decode", ldecode }, 941 | { "makeindex", lmakeindex }, 942 | { NULL, NULL }, 943 | }; 944 | luaL_newlib(L,l); 945 | lua_setfield(L, -2, "__index"); 946 | lua_pushcfunction(L, ltostring); 947 | lua_setfield(L, -2, "__tostring"); 948 | lua_pushcfunction(L, llen); 949 | lua_setfield(L, -2, "__len"); 950 | lua_pushcfunction(L, lreplace); 951 | lua_setfield(L, -2, "__newindex"); 952 | } 953 | lua_setmetatable(L, -2); 954 | } 955 | 956 | static int 957 | encode_bson(lua_State *L) { 958 | struct bson *b = lua_touserdata(L, 2); 959 | lua_settop(L, 1); 960 | pack_dict(L, b, false, 0); 961 | void * ud = lua_newuserdata(L, b->size); 962 | memcpy(ud, b->ptr, b->size); 963 | return 1; 964 | } 965 | 966 | static int 967 | lencode(lua_State *L) { 968 | struct bson b; 969 | lua_settop(L,1); 970 | luaL_checktype(L, 1, LUA_TTABLE); 971 | bson_create(&b); 972 | lua_pushcfunction(L, encode_bson); 973 | lua_pushvalue(L, 1); 974 | lua_pushlightuserdata(L, &b); 975 | if (lua_pcall(L, 2, 1, 0) != LUA_OK) { 976 | bson_destroy(&b); 977 | return lua_error(L); 978 | } 979 | bson_destroy(&b); 980 | bson_meta(L); 981 | return 1; 982 | } 983 | 984 | static int 985 | encode_bson_byorder(lua_State *L) { 986 | int n = lua_gettop(L); 987 | struct bson *b = lua_touserdata(L, n); 988 | lua_settop(L, n-1); 989 | pack_ordered_dict(L, b, n-1, 0); 990 | lua_settop(L,0); 991 | void * ud = lua_newuserdata(L, b->size); 992 | memcpy(ud, b->ptr, b->size); 993 | return 1; 994 | } 995 | 996 | static int 997 | lencode_order(lua_State *L) { 998 | struct bson b; 999 | int n = lua_gettop(L); 1000 | if (n%2 != 0) { 1001 | return luaL_error(L, "Invalid ordered dict"); 1002 | } 1003 | bson_create(&b); 1004 | lua_pushcfunction(L, encode_bson_byorder); 1005 | lua_insert(L, 1); 1006 | lua_pushlightuserdata(L, &b); 1007 | if (lua_pcall(L, n+1, 1, 0) != LUA_OK) { 1008 | bson_destroy(&b); 1009 | return lua_error(L); 1010 | } 1011 | bson_destroy(&b); 1012 | bson_meta(L); 1013 | return 1; 1014 | } 1015 | 1016 | static int 1017 | ldate(lua_State *L) { 1018 | int d = luaL_checkinteger(L,1); 1019 | luaL_Buffer b; 1020 | luaL_buffinit(L, &b); 1021 | luaL_addchar(&b, 0); 1022 | luaL_addchar(&b, BSON_DATE); 1023 | luaL_addlstring(&b, (const char *)&d, sizeof(d)); 1024 | luaL_pushresult(&b); 1025 | 1026 | return 1; 1027 | } 1028 | 1029 | static int 1030 | ltimestamp(lua_State *L) { 1031 | int d = luaL_checkinteger(L,1); 1032 | luaL_Buffer b; 1033 | luaL_buffinit(L, &b); 1034 | luaL_addchar(&b, 0); 1035 | luaL_addchar(&b, BSON_TIMESTAMP); 1036 | if (lua_isnoneornil(L,2)) { 1037 | static uint32_t inc = 0; 1038 | luaL_addlstring(&b, (const char *)&inc, sizeof(inc)); 1039 | ++inc; 1040 | } else { 1041 | uint32_t i = (uint32_t)lua_tointeger(L,2); 1042 | luaL_addlstring(&b, (const char *)&i, sizeof(i)); 1043 | } 1044 | luaL_addlstring(&b, (const char *)&d, sizeof(d)); 1045 | luaL_pushresult(&b); 1046 | 1047 | return 1; 1048 | } 1049 | 1050 | static int 1051 | lregex(lua_State *L) { 1052 | luaL_checkstring(L,1); 1053 | if (lua_gettop(L) < 2) { 1054 | lua_pushliteral(L,""); 1055 | } 1056 | luaL_Buffer b; 1057 | luaL_buffinit(L, &b); 1058 | luaL_addchar(&b, 0); 1059 | luaL_addchar(&b, BSON_REGEX); 1060 | lua_pushvalue(L,1); 1061 | luaL_addvalue(&b); 1062 | luaL_addchar(&b,0); 1063 | lua_pushvalue(L,2); 1064 | luaL_addvalue(&b); 1065 | luaL_addchar(&b,0); 1066 | luaL_pushresult(&b); 1067 | 1068 | return 1; 1069 | } 1070 | 1071 | static int 1072 | lbinary(lua_State *L) { 1073 | lua_settop(L,1); 1074 | luaL_Buffer b; 1075 | luaL_buffinit(L, &b); 1076 | luaL_addchar(&b, 0); 1077 | luaL_addchar(&b, BSON_BINARY); 1078 | luaL_addchar(&b, 0); // sub type 1079 | lua_pushvalue(L, 1); 1080 | luaL_addvalue(&b); 1081 | luaL_pushresult(&b); 1082 | 1083 | return 1; 1084 | } 1085 | 1086 | static int 1087 | lsubtype(lua_State *L, int subtype, const uint8_t * buf, size_t sz) { 1088 | switch(subtype) { 1089 | case BSON_BINARY: 1090 | lua_pushvalue(L, lua_upvalueindex(6)); 1091 | lua_pushlstring(L, (const char *)buf+1, sz-1); 1092 | lua_pushinteger(L, buf[0]); 1093 | return 3; 1094 | case BSON_OBJECTID: { 1095 | if (sz != 12) { 1096 | return luaL_error(L, "Invalid object id"); 1097 | } 1098 | char oid[24]; 1099 | int i; 1100 | const uint8_t * id = buf; 1101 | static char *hex = "0123456789abcdef"; 1102 | for (i=0;i<12;i++) { 1103 | oid[i*2] = hex[id[i] >> 4]; 1104 | oid[i*2+1] = hex[id[i] & 0xf]; 1105 | } 1106 | lua_pushvalue(L, lua_upvalueindex(7)); 1107 | lua_pushlstring(L, oid, 24); 1108 | 1109 | return 2; 1110 | } 1111 | case BSON_DATE: { 1112 | if (sz != 4) { 1113 | return luaL_error(L, "Invalid date"); 1114 | } 1115 | int d = *(const int *)buf; 1116 | lua_pushvalue(L, lua_upvalueindex(9)); 1117 | lua_pushinteger(L, d); 1118 | return 2; 1119 | } 1120 | case BSON_TIMESTAMP: { 1121 | if (sz != 8) { 1122 | return luaL_error(L, "Invalid timestamp"); 1123 | } 1124 | const uint32_t * ts = (const uint32_t *)buf; 1125 | lua_pushvalue(L, lua_upvalueindex(8)); 1126 | lua_pushinteger(L, (lua_Integer)ts[1]); 1127 | lua_pushinteger(L, (lua_Integer)ts[0]); 1128 | return 3; 1129 | } 1130 | case BSON_REGEX: { 1131 | --sz; 1132 | size_t i; 1133 | const uint8_t *str = buf; 1134 | for (i=0;i= 2) { 1189 | return lsubtype(L, (uint8_t)str[1], (const uint8_t *)str+2, len-2); 1190 | } else { 1191 | type = 5; 1192 | break; 1193 | } 1194 | } 1195 | default: 1196 | return luaL_error(L, "Invalid type %s",lua_typename(L,t)); 1197 | } 1198 | lua_pushvalue(L, lua_upvalueindex(type)); 1199 | lua_pushvalue(L,1); 1200 | return 2; 1201 | } 1202 | 1203 | static void 1204 | typeclosure(lua_State *L) { 1205 | static const char * typename[] = { 1206 | "number", // 1 1207 | "boolean", // 2 1208 | "table", // 3 1209 | "nil", // 4 1210 | "string", // 5 1211 | "binary", // 6 1212 | "objectid", // 7 1213 | "timestamp",// 8 1214 | "date", // 9 1215 | "regex", // 10 1216 | "minkey", // 11 1217 | "maxkey", // 12 1218 | "unsupported", // 13 1219 | }; 1220 | int i; 1221 | int n = sizeof(typename)/sizeof(typename[0]); 1222 | for (i=0;i>2)+hostname[i]); 1241 | } 1242 | h ^= i; 1243 | } 1244 | oid_header[0] = h & 0xff; 1245 | oid_header[1] = (h>>8) & 0xff; 1246 | oid_header[2] = (h>>16) & 0xff; 1247 | oid_header[3] = pid & 0xff; 1248 | oid_header[4] = (pid >> 8) & 0xff; 1249 | 1250 | oid_counter = h ^ time(NULL) ^ (uintptr_t)&h; 1251 | } 1252 | 1253 | static inline int 1254 | hextoint(char c) { 1255 | if (c>='0' && c<='9') 1256 | return c-'0'; 1257 | if (c>='a' && c<='z') 1258 | return c-'a'+10; 1259 | if (c>='A' && c<='Z') 1260 | return c-'A'+10; 1261 | return 0; 1262 | } 1263 | 1264 | static int 1265 | lobjectid(lua_State *L) { 1266 | uint8_t oid[14] = { 0, BSON_OBJECTID }; 1267 | if (lua_isstring(L,1)) { 1268 | size_t len; 1269 | const char * str = lua_tolstring(L,1,&len); 1270 | if (len != 24) { 1271 | return luaL_error(L, "Invalid objectid %s", str); 1272 | } 1273 | int i; 1274 | for (i=0;i<12;i++) { 1275 | oid[i+2] = hextoint(str[i*2]) << 4 | hextoint(str[i*2+1]); 1276 | } 1277 | } else { 1278 | time_t ti = time(NULL); 1279 | oid[2] = (ti>>24) & 0xff; 1280 | oid[3] = (ti>>16) & 0xff; 1281 | oid[4] = (ti>>8) & 0xff; 1282 | oid[5] = ti & 0xff; 1283 | memcpy(oid+6 , oid_header, 5); 1284 | oid[11] = (oid_counter>>16) & 0xff; 1285 | oid[12] = (oid_counter>>8) & 0xff; 1286 | oid[13] = oid_counter & 0xff; 1287 | ++oid_counter; 1288 | } 1289 | lua_pushlstring( L, (const char *)oid, 14); 1290 | 1291 | return 1; 1292 | } 1293 | 1294 | LUAMOD_API int 1295 | luaopen_bson(lua_State *L) { 1296 | luaL_checkversion(L); 1297 | int i; 1298 | for (i=0;i