├── 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 | | Lua Type | BSON Type | Notes |
19 |
20 | | bson.null | Null | |
21 | | boolean | Boolean | |
22 | | number | Double | |
23 | | number | 32-bit integer | |
24 | | number | 64-bit integer | precision lost in lua 5.1/5.2 |
25 | | string | String | |
26 | | bson.binary(blob) | Binary string | Use bson.type() to decode |
27 | | table | BSON Document | |
28 | | table | BSON Array | Lua table must be a sequence. (Continuous number key base 1) |
29 | | bson.date(os.time()) | UTC Datetime | milliseconds since epoch |
30 | | bson.timestamp(os.time()) | Timestamp | special mongodb type, two 32-bit number |
31 | | bson.regex(regex,option) | Regular Expression | |
32 | | bson.objectid() | ObjectID | MongoDB document ID |
33 | | bson.minkey | Min Key | |
34 | | bson.maxkey | Max Key | |
35 |
36 |
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