webmcp

view libraries/json/json.c @ 169:681367a16657

json.array and json.object functions create a new container rather than marking a table
author jbe
date Fri Aug 01 05:12:21 2014 +0200 (2014-08-01)
parents e618ccd017a3
children c055d6d64586
line source
1 #include <lua.h>
2 #include <lauxlib.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
7 // maximum number of nested JSON values (objects and arrays):
8 // NOTE: The Lua reference states that the stack may typically contain at least
9 // "a few thousand elements". Since every nested level consumes
10 // 3 elements on the Lua stack (the object/array, its shadow table,
11 // a string key or a placeholder), we limit the number of nested levels
12 // to 500. If a stack overflow would still happen in the import function,
13 // this is detected nevertheless and an error is thrown (instead of
14 // returning nil and an error string).
15 #define JSON_MAXDEPTH 500
17 // generate dummy memory addresses that represents null values:
18 char json_nullmark;
19 #define json_isnullmark(L, i) (lua_touserdata((L), (i)) == &json_nullmark)
20 #define json_pushnullmark(L) lua_pushlightuserdata((L), &json_nullmark)
22 // macros for usage of Lua registry:
23 #define JSON_REGENT char
24 #define JSON_REGPOINTER void *
25 #define json_regpointer(x) (&json_registry.x)
26 #define json_regfetchpointer(L, x) lua_rawgetp((L), LUA_REGISTRYINDEX, (x))
27 #define json_regfetch(L, x) json_regfetchpointer(L, json_regpointer(x))
28 #define json_regstore(L, x) lua_rawsetp(L, LUA_REGISTRYINDEX, json_regpointer(x))
30 // generate dummy memory addresses that represent Lua objects
31 // via lightuserdata keys and LUA_REGISTRYINDEX:
32 static struct {
33 JSON_REGENT shadowtbl; // ephemeron table that maps tables to their corresponding shadow table
34 JSON_REGENT objectmt; // metatable for JSON objects
35 JSON_REGENT arraymt; // metatable for JSON arrays
36 } json_registry;
38 // returns the string "<JSON null marker>":
39 static int json_nullmark_tostring(lua_State *L) {
40 lua_pushliteral(L, "<JSON null marker>");
41 return 1;
42 }
44 #define json_convert_source_idx 1
45 #define json_convert_iterator_idx 2
46 #define json_convert_output_idx 3
47 #define json_convert_shadow_idx 4
49 // converts a Lua table to a JSON object or JSON array:
50 // (does never modify the argument, returns an empty object or array if argument is nil)
51 static int json_convert(lua_State *L, int array) {
52 lua_settop(L, 1);
53 if (lua_isnoneornil(L, json_convert_source_idx)) {
54 json_regfetch(L, shadowtbl);
55 lua_newtable(L);
56 lua_pushvalue(L, -1);
57 lua_newtable(L);
58 lua_rawset(L, -4);
59 } else {
60 // push iterator function on stack position 2 if existent,
61 // else push null for normal tables:
62 if (lua_getmetatable(L, json_convert_source_idx)) {
63 lua_getfield(L, -1, array ? "__ipairs" : "__pairs");
64 if (lua_isnil(L, -1)) luaL_checktype(L, 1, LUA_TTABLE);
65 else if (lua_type(L, -1) != LUA_TFUNCTION)
66 return luaL_error(L, "%s metamethod is not a function", array ? "__ipairs" : "__pairs");
67 lua_replace(L, -2);
68 } else {
69 lua_pushnil(L);
70 }
71 // create table on stack position 3:
72 lua_newtable(L);
73 // create shadow table on stack position 4:
74 json_regfetch(L, shadowtbl);
75 lua_newtable(L);
76 lua_pushvalue(L, json_convert_output_idx);
77 lua_pushvalue(L, -2);
78 lua_rawset(L, -4);
79 lua_replace(L, -2);
80 if (lua_isnil(L, json_convert_iterator_idx)) {
81 for (lua_pushnil(L); lua_next(L, json_convert_source_idx); lua_pop(L, 1)) {
82 lua_pushvalue(L, -2);
83 lua_pushvalue(L, -2);
84 lua_rawset(L, json_convert_shadow_idx);
85 }
86 } else {
87 return luaL_error(L, "Using %s metamethod not implemented yet", array ? "__ipairs" : "__pairs");
88 }
89 lua_settop(L, json_convert_output_idx);
90 }
91 // set metatable:
92 if (array) json_regfetch(L, arraymt);
93 else json_regfetch(L, objectmt);
94 lua_setmetatable(L, -2);
95 // return table:
96 return 1;
97 }
99 static int json_object(lua_State *L) {
100 return json_convert(L, 0);
101 }
103 static int json_array(lua_State *L) {
104 return json_convert(L, 1);
105 }
107 // internal states of JSON parser:
108 #define JSON_STATE_VALUE 0
109 #define JSON_STATE_OBJECT_KEY 1
110 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2
111 #define JSON_STATE_OBJECT_VALUE 3
112 #define JSON_STATE_OBJECT_SEPARATOR 4
113 #define JSON_STATE_ARRAY_VALUE 5
114 #define JSON_STATE_ARRAY_SEPARATOR 6
115 #define JSON_STATE_END 7
117 // special Lua stack indicies for json_import function:
118 #define json_import_objectmt_idx 2
119 #define json_import_arraymt_idx 3
120 #define json_import_shadowtbl_idx 4
122 // macros for hex decoding:
123 #define json_utf16_surrogate(x) ((x) >= 0xD800 && (x) <= 0xDFFF)
124 #define json_utf16_lead(x) ((x) >= 0xD800 && (x) <= 0xDBFF)
125 #define json_utf16_tail(x) ((x) >= 0xDC00 && (x) <= 0xDFFF)
126 #define json_import_readhex(x) \
127 do { \
128 x = 0; \
129 for (i=0; i<4; i++) { \
130 x <<= 4; \
131 c = str[pos++]; \
132 if (c >= '0' && c <= '9') x += c - '0'; \
133 else if (c >= 'A' && c <= 'F') x += c - 'A' + 10; \
134 else if (c >= 'a' && c <= 'f') x += c - 'a' + 10; \
135 else if (c == 0) goto json_import_unexpected_eof; \
136 else goto json_import_unexpected_escape; \
137 } \
138 } while (0)
140 // decodes a JSON document:
141 static int json_import(lua_State *L) {
142 int i; // loop variable
143 const char *str; // string to parse
144 size_t total; // total length of string to parse
145 size_t pos = 0; // current position in string to parse
146 size_t level = 0; // nested levels of objects/arrays currently being processed
147 int mode = JSON_STATE_VALUE; // state of parser (i.e. "what's expected next?")
148 char c; // variable to store a single character to be processed
149 luaL_Buffer luabuf; // Lua buffer to decode JSON string values
150 char *cbuf; // C buffer to decode JSON string values
151 size_t outlen; // maximum length or write position of C buffer
152 long codepoint; // decoded UTF-16 character or higher codepoint
153 long utf16tail; // second decoded UTF-16 character (surrogate tail)
154 size_t arraylen; // variable to temporarily store the array length
155 // require string as argument and convert to C string with length information:
156 str = luaL_checklstring(L, 1, &total);
157 // if string contains a NULL byte, this is a syntax error
158 if (strlen(str) != total) goto json_import_syntax_error;
159 // stack shall contain one function argument:
160 lua_settop(L, 1);
161 // push objectmt onto stack position 2:
162 json_regfetch(L, objectmt);
163 // push arraymt onto stack position 3:
164 json_regfetch(L, arraymt);
165 // push shadowtbl onto stack position 4:
166 json_regfetch(L, shadowtbl);
167 // main loop of parser:
168 json_import_loop:
169 // skip whitespace and store next character in variable 'c':
170 while (c = str[pos],
171 c == ' ' ||
172 c == '\f' ||
173 c == '\n' ||
174 c == '\r' ||
175 c == '\t' ||
176 c == '\v'
177 ) pos++;
178 // switch statement to handle certain (single) characters:
179 switch (c) {
180 // handle end of JSON document:
181 case 0:
182 // if end of JSON document was expected, then return top element of stack as result:
183 if (mode == JSON_STATE_END) return 1;
184 // otherwise, the JSON document was malformed:
185 if (level == 0) {
186 lua_pushnil(L);
187 lua_pushliteral(L, "Empty string");
188 } else {
189 json_import_unexpected_eof:
190 lua_pushnil(L);
191 lua_pushliteral(L, "Unexpected end of JSON document");
192 }
193 return 2;
194 // new JSON object:
195 case '{':
196 // if a JSON object is not expected here, then return an error:
197 if (
198 mode != JSON_STATE_VALUE &&
199 mode != JSON_STATE_OBJECT_VALUE &&
200 mode != JSON_STATE_ARRAY_VALUE
201 ) goto json_import_syntax_error;
202 // create JSON object on stack:
203 lua_newtable(L);
204 // set metatable of JSON object:
205 lua_pushvalue(L, json_import_objectmt_idx);
206 lua_setmetatable(L, -2);
207 // create internal shadow table on stack:
208 lua_newtable(L);
209 // register internal shadow table:
210 lua_pushvalue(L, -2);
211 lua_pushvalue(L, -2);
212 lua_rawset(L, json_import_shadowtbl_idx);
213 // expect object key (or end of object) to follow:
214 mode = JSON_STATE_OBJECT_KEY;
215 // jump to common code for opening JSON object and JSON array:
216 goto json_import_open;
217 // new JSON array:
218 case '[':
219 // if a JSON array is not expected here, then return an error:
220 if (
221 mode != JSON_STATE_VALUE &&
222 mode != JSON_STATE_OBJECT_VALUE &&
223 mode != JSON_STATE_ARRAY_VALUE
224 ) goto json_import_syntax_error;
225 // create JSON array on stack:
226 lua_newtable(L);
227 // set metatable of JSON array:
228 lua_pushvalue(L, json_import_arraymt_idx);
229 lua_setmetatable(L, -2);
230 // create internal shadow table on stack:
231 lua_newtable(L);
232 // register internal shadow table:
233 lua_pushvalue(L, -2);
234 lua_pushvalue(L, -2);
235 lua_rawset(L, json_import_shadowtbl_idx);
236 // add nil as key (needed to keep stack balance) and as magic to detect arrays:
237 lua_pushnil(L);
238 // expect array value (or end of array) to follow:
239 mode = JSON_STATE_ARRAY_VALUE;
240 // continue with common code for opening JSON object and JSON array:
241 // common code for opening JSON object or JSON array:
242 json_import_open:
243 // limit nested levels:
244 if (level >= JSON_MAXDEPTH) {
245 lua_pushnil(L);
246 lua_pushfstring(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
247 return 2;
248 }
249 // additional buffer overflow protection:
250 if (!lua_checkstack(L, LUA_MINSTACK))
251 return luaL_error(L, "Caught stack overflow in JSON import function (too many nested levels and stack size too small)");
252 // increment level:
253 level++;
254 // consume input character:
255 pos++;
256 goto json_import_loop;
257 // end of JSON object:
258 case '}':
259 // if end of JSON object is not expected here, then return an error:
260 if (
261 mode != JSON_STATE_OBJECT_KEY &&
262 mode != JSON_STATE_OBJECT_SEPARATOR
263 ) goto json_import_syntax_error;
264 // jump to common code for end of JSON object and JSON array:
265 goto json_import_close;
266 // end of JSON array:
267 case ']':
268 // if end of JSON array is not expected here, then return an error:
269 if (
270 mode != JSON_STATE_ARRAY_VALUE &&
271 mode != JSON_STATE_ARRAY_SEPARATOR
272 ) goto json_import_syntax_error;
273 // pop nil key/magic (that was needed to keep stack balance):
274 lua_pop(L, 1);
275 // continue with common code for end of JSON object and JSON array:
276 // common code for end of JSON object or JSON array:
277 json_import_close:
278 // consume input character:
279 pos++;
280 // pop shadow table:
281 lua_pop(L, 1);
282 // check if nested:
283 if (--level) {
284 // if nested,
285 // check if outer(!) structure is an array or object:
286 if (lua_isnil(L, -2)) {
287 // select array value processing:
288 mode = JSON_STATE_ARRAY_VALUE;
289 } else {
290 // select object value processing:
291 mode = JSON_STATE_OBJECT_VALUE;
292 }
293 // store value in outer structure:
294 goto json_import_process_value;
295 }
296 // if not nested, then expect end of JSON document and continue with loop:
297 mode = JSON_STATE_END;
298 goto json_import_loop;
299 // key terminator:
300 case ':':
301 // if key terminator is not expected here, then return an error:
302 if (mode != JSON_STATE_OBJECT_KEY_TERMINATOR)
303 goto json_import_syntax_error;
304 // consume input character:
305 pos++;
306 // expect object value to follow:
307 mode = JSON_STATE_OBJECT_VALUE;
308 // continue with loop:
309 goto json_import_loop;
310 // value terminator (NOTE: trailing comma at end of value or key-value list is tolerated by this parser)
311 case ',':
312 // branch according to parser state:
313 if (mode == JSON_STATE_OBJECT_SEPARATOR) {
314 // expect an object key to follow:
315 mode = JSON_STATE_OBJECT_KEY;
316 } else if (mode == JSON_STATE_ARRAY_SEPARATOR) {
317 // expect an array value to follow:
318 mode = JSON_STATE_ARRAY_VALUE;
319 } else {
320 // if value terminator is not expected here, then return an error:
321 goto json_import_syntax_error;
322 }
323 // consume input character:
324 pos++;
325 // continue with loop:
326 goto json_import_loop;
327 // string literal:
328 case '"':
329 // consume quote character:
330 pos++;
331 // find last character in input string:
332 outlen = pos;
333 while ((c = str[outlen]) != '"') {
334 // consume one character:
335 outlen++;
336 // handle unexpected end of JSON document:
337 if (c == 0) goto json_import_unexpected_eof;
338 // consume one extra character when encountering an escaped quote:
339 else if (c == '\\' && str[outlen] == '"') outlen++;
340 }
341 // determine buffer length:
342 outlen -= pos;
343 // check if string is non empty:
344 if (outlen) {
345 // prepare buffer to decode string (with maximum possible length) and set write position to zero:
346 cbuf = luaL_buffinitsize(L, &luabuf, outlen);
347 outlen = 0;
348 // loop through the characters until encountering end quote:
349 while ((c = str[pos++]) != '"') {
350 // NOTE: unexpected end cannot happen anymore
351 if (c < 32 || c == 127) {
352 // do not allow ASCII control characters:
353 // NOTE: illegal UTF-8 sequences and extended control characters are not sanitized
354 // by this parser to allow different encodings than Unicode
355 lua_pushnil(L);
356 lua_pushliteral(L, "Unexpected control character in JSON string");
357 return 2;
358 } else if (c == '\\') {
359 // read next char after backslash escape:
360 c = str[pos++];
361 switch (c) {
362 // unexpected end-of-string:
363 case 0:
364 goto json_import_unexpected_eof;
365 // unescaping of quotation mark, slash, and backslash:
366 case '"':
367 case '/':
368 case '\\':
369 cbuf[outlen++] = c;
370 break;
371 // unescaping of backspace:
372 case 'b': cbuf[outlen++] = '\b'; break;
373 // unescaping of form-feed:
374 case 'f': cbuf[outlen++] = '\f'; break;
375 // unescaping of new-line:
376 case 'n': cbuf[outlen++] = '\n'; break;
377 // unescaping of carriage-return:
378 case 'r': cbuf[outlen++] = '\r'; break;
379 // unescaping of tabulator:
380 case 't': cbuf[outlen++] = '\t'; break;
381 // unescaping of UTF-16 characters
382 case 'u':
383 // decode 4 hex nibbles:
384 json_import_readhex(codepoint);
385 // handle surrogate character:
386 if (json_utf16_surrogate(codepoint)) {
387 // check if first surrogate is in valid range:
388 if (json_utf16_lead(codepoint)) {
389 // require second surrogate:
390 if ((c = str[pos++]) != '\\' || (c = str[pos++]) != 'u') {
391 if (c == 0) goto json_import_unexpected_eof;
392 else goto json_import_wrong_surrogate;
393 }
394 // read 4 hex nibbles of second surrogate character:
395 json_import_readhex(utf16tail);
396 // check if second surrogate is in valid range:
397 if (!json_utf16_tail(utf16tail)) goto json_import_wrong_surrogate;
398 // calculate codepoint:
399 codepoint = 0x10000 + (utf16tail - 0xDC00) + (codepoint - 0xD800) * 0x400;
400 } else {
401 // throw error for wrong surrogates:
402 json_import_wrong_surrogate:
403 lua_pushnil(L);
404 lua_pushliteral(L, "Illegal UTF-16 surrogate in JSON string escape sequence");
405 return 2;
406 }
407 }
408 // encode as UTF-8:
409 if (codepoint < 0x80) {
410 cbuf[outlen++] = (char)codepoint;
411 } else if (codepoint < 0x800) {
412 cbuf[outlen++] = (char)(0xc0 | (codepoint >> 6));
413 cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
414 } else if (codepoint < 0x10000) {
415 cbuf[outlen++] = (char)(0xe0 | (codepoint >> 12));
416 cbuf[outlen++] = (char)(0x80 | ((codepoint >> 6) & 0x3f));
417 cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
418 } else {
419 cbuf[outlen++] = (char)(0xf0 | (codepoint >> 18));
420 cbuf[outlen++] = (char)(0x80 | ((codepoint >> 12) & 0x3f));
421 cbuf[outlen++] = (char)(0x80 | ((codepoint >> 6) & 0x3f));
422 cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
423 }
424 break;
425 // unexpected escape sequence:
426 default:
427 json_import_unexpected_escape:
428 lua_pushnil(L);
429 lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
430 return 2;
431 }
432 } else {
433 // normal character:
434 cbuf[outlen++] = c;
435 }
436 }
437 // process buffer to Lua string:
438 luaL_pushresultsize(&luabuf, outlen);
439 } else {
440 // if JSON string is empty,
441 // push empty Lua string:
442 lua_pushliteral(L, "");
443 // consume closing quote:
444 pos++;
445 }
446 // continue with processing of decoded string:
447 goto json_import_process_value;
448 }
449 // process values whose type is is not deducible from a single character:
450 if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
451 // for numbers,
452 // use strtod() call to parse a (double precision) floating point number:
453 double numval;
454 char *endptr;
455 numval = strtod(str+pos, &endptr);
456 // catch parsing errors:
457 if (endptr == str+pos) goto json_import_syntax_error;
458 // consume characters that were parsed:
459 pos += endptr - (str+pos);
460 // push parsed (double precision) floating point number on Lua stack:
461 lua_pushnumber(L, numval);
462 } else if (!strncmp(str+pos, "true", 4)) {
463 // consume 4 input characters for "true":
464 pos += 4;
465 // put Lua true value onto stack:
466 lua_pushboolean(L, 1);
467 } else if (!strncmp(str+pos, "false", 5)) {
468 // consume 5 input characters for "false":
469 pos += 5;
470 // put Lua false value onto stack:
471 lua_pushboolean(L, 0);
472 } else if (!strncmp(str+pos, "null", 4)) {
473 // consume 4 input characters for "null":
474 pos += 4;
475 // different behavor for top-level and sub-levels:
476 if (level) {
477 // if sub-level,
478 // push special null-marker onto stack:
479 json_pushnullmark(L);
480 } else {
481 // if top-level,
482 // push nil onto stack:
483 lua_pushnil(L);
484 }
485 } else {
486 // all other cases are a syntax error:
487 goto json_import_syntax_error;
488 }
489 // process a decoded value or key value pair (expected on top of Lua stack):
490 json_import_process_value:
491 switch (mode) {
492 // an object key has been read:
493 case JSON_STATE_OBJECT_KEY:
494 // if an object key is not a string, then this is a syntax error:
495 if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
496 // expect key terminator to follow:
497 mode = JSON_STATE_OBJECT_KEY_TERMINATOR;
498 // continue with loop:
499 goto json_import_loop;
500 // a key value pair has been read:
501 case JSON_STATE_OBJECT_VALUE:
502 // store key value pair in outer shadow table:
503 lua_rawset(L, -3);
504 // expect value terminator (or end of object) to follow:
505 mode = JSON_STATE_OBJECT_SEPARATOR;
506 // continue with loop:
507 goto json_import_loop;
508 // an array value has been read:
509 case JSON_STATE_ARRAY_VALUE:
510 // get current array length:
511 arraylen = lua_rawlen(L, -3);
512 // throw error if array would exceed INT_MAX elements:
513 // TODO: Lua 5.3 may support more elements
514 if (arraylen >= INT_MAX) {
515 lua_pushnil(L);
516 lua_pushfstring(L, "Array exceeded length of %d elements", INT_MAX);
517 }
518 // store value in outer shadow table:
519 lua_rawseti(L, -3, arraylen + 1);
520 // expect value terminator (or end of object) to follow:
521 mode = JSON_STATE_ARRAY_SEPARATOR;
522 // continue with loop
523 goto json_import_loop;
524 // a single value has been read:
525 case JSON_STATE_VALUE:
526 // leave value on top of stack, expect end of JSON document, and continue with loop:
527 mode = JSON_STATE_END;
528 goto json_import_loop;
529 }
530 // syntax error handling (reachable by goto statement):
531 json_import_syntax_error:
532 lua_pushnil(L);
533 lua_pushliteral(L, "Syntax error in JSON document");
534 return 2;
535 }
537 // special Lua stack indicies for json_path function:
538 #define json_path_shadowtbl_idx 1
540 // stack offset of arguments to json_path function:
541 #define json_path_idxshift 1
543 // gets a value or its type from a JSON document (passed as first argument)
544 // using a path (passed as variable number of keys after first argument):
545 static int json_path(lua_State *L, int type_mode) {
546 int stacktop; // stack index of top of stack (after shifting)
547 int idx = 2 + json_path_idxshift; // stack index of current argument to process
548 // insert shadowtbl into stack at position 1 (shifting the arguments):
549 json_regfetch(L, shadowtbl);
550 lua_insert(L, 1);
551 // store stack index of top of stack:
552 stacktop = lua_gettop(L);
553 // use first argument as "current value" (stored on top of stack):
554 lua_pushvalue(L, 1 + json_path_idxshift);
555 // process each "path key" (2nd argument and following arguments):
556 while (idx <= stacktop) {
557 // if "current value" (on top of stack) is nil, then the path cannot be walked and nil is returned:
558 if (lua_isnil(L, -1)) return 1;
559 // try to get shadow table of "current value":
560 lua_pushvalue(L, -1);
561 lua_rawget(L, json_path_shadowtbl_idx);
562 if (lua_isnil(L, -1)) {
563 // if no shadow table is found,
564 if (lua_type(L, -1) == LUA_TTABLE) {
565 // and if "current value" is a table,
566 // drop nil from stack:
567 lua_pop(L, 1);
568 // get "next value" using the "path key":
569 lua_pushvalue(L, idx++);
570 lua_gettable(L, -2);
571 } else {
572 // if "current value" is not a table,
573 // then the path cannot be walked and nil (already on top of stack) is returned:
574 return 1;
575 }
576 } else {
577 // if a shadow table is found,
578 // set "current value" to its shadow table:
579 lua_replace(L, -2);
580 // get "next value" using the "path key":
581 lua_pushvalue(L, idx++);
582 lua_rawget(L, -2);
583 }
584 // the "next value" replaces the "current value":
585 lua_replace(L, -2);
586 }
587 if (!type_mode) {
588 // if a value (and not its type) was requested,
589 // check if value is the null-marker, and store nil on top of Lua stack in that case:
590 if (json_isnullmark(L, -1)) lua_pushnil(L);
591 } else {
592 // if the type was requested,
593 // check if value is the null-marker:
594 if (json_isnullmark(L, -1)) {
595 // if yes, store string "null" on top of Lua stack:
596 lua_pushliteral(L, "null");
597 } else {
598 // otherwise,
599 // check if metatable indicates "object" or "array":
600 if (lua_getmetatable(L, -1)) {
601 json_regfetch(L, objectmt);
602 if (lua_rawequal(L, -2, -1)) {
603 // if value has metatable for JSON objects,
604 // return string "object":
605 lua_pushliteral(L, "object");
606 return 1;
607 }
608 json_regfetch(L, arraymt);
609 if (lua_rawequal(L, -3, -1)) {
610 // if value has metatable for JSON arrays,
611 // return string "object":
612 lua_pushliteral(L, "array");
613 return 1;
614 }
615 // remove 3 metatables (one of the value, two for comparison) from stack:
616 lua_pop(L, 3);
617 }
618 // otherwise, get the Lua type:
619 lua_pushstring(L, lua_typename(L, lua_type(L, -1)));
620 }
621 }
622 // return the top most value on the Lua stack:
623 return 1;
624 }
626 // gets a value from a JSON document (passed as first argument)
627 // using a path (passed as variable number of keys after first argument):
628 static int json_get(lua_State *L) {
629 return json_path(L, 0);
630 }
632 // gets a value's type from a JSON document (passed as first argument)
633 // using a path (variable number of keys after first argument):
634 static int json_type(lua_State *L) {
635 return json_path(L, 1);
636 }
638 // returns the length of a JSON array (or zero for a table without numeric keys):
639 static int json_len(lua_State *L) {
640 // stack shall contain one function argument:
641 lua_settop(L, 1);
642 // try to get corresponding shadow table for first argument:
643 json_regfetch(L, shadowtbl);
644 lua_pushvalue(L, 1);
645 lua_rawget(L, -2);
646 // if shadow table does not exist, return length of argument, else length of shadow table:
647 lua_pushnumber(L, lua_rawlen(L, lua_isnil(L, -1) ? 1 : -1));
648 return 1;
649 }
651 static int json_index(lua_State *L) {
652 // stack shall contain two function arguments:
653 lua_settop(L, 2);
654 // get corresponding shadow table for first argument:
655 json_regfetch(L, shadowtbl);
656 lua_pushvalue(L, 1);
657 lua_rawget(L, -2);
658 // throw error if no shadow table was found:
659 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
660 // use key passed as second argument to lookup value in shadow table:
661 lua_pushvalue(L, 2);
662 lua_rawget(L, -2);
663 // if value is null-marker, then push nil onto stack:
664 if (json_isnullmark(L, -1)) lua_pushnil(L);
665 // return either looked up value, or nil
666 return 1;
667 }
669 static int json_newindex(lua_State *L) {
670 // stack shall contain three function arguments:
671 lua_settop(L, 3);
672 // get corresponding shadow table for first argument:
673 json_regfetch(L, shadowtbl);
674 lua_pushvalue(L, 1);
675 lua_rawget(L, -2);
676 // throw error if no shadow table was found:
677 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
678 // replace first argument with shadow table:
679 lua_replace(L, 1);
680 // reset stack and use second and third argument to write to shadow table:
681 lua_settop(L, 3);
682 lua_rawset(L, 1);
683 // return nothing:
684 return 0;
685 }
687 static int json_pairs_iterfunc(lua_State *L) {
688 // stack shall contain two function arguments:
689 lua_settop(L, 2);
690 // get corresponding shadow table for first argument:
691 json_regfetch(L, shadowtbl);
692 lua_pushvalue(L, 1);
693 lua_rawget(L, -2);
694 // throw error if no shadow table was found:
695 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
696 // get next key value pair from shadow table (using previous key from argument 2)
697 // and return nothing if there is no next pair:
698 lua_pushvalue(L, 2);
699 if (!lua_next(L, -2)) return 0;
700 // replace null-marker with nil:
701 if (json_isnullmark(L, -1)) {
702 lua_pop(L, 1);
703 lua_pushnil(L);
704 }
705 // return key and value (or key and nil, if null-marker was found):
706 return 2;
707 }
709 // returns a triple such that 'for key, value in pairs(obj) do ... end'
710 // iterates through all key value pairs (including JSON null keys represented as Lua nil):
711 static int json_pairs(lua_State *L) {
712 // return triple of function json_pairs_iterfunc, first argument, and nil:
713 lua_pushcfunction(L, json_pairs_iterfunc);
714 lua_pushvalue(L, 1);
715 lua_pushnil(L);
716 return 3;
717 }
719 static int json_ipairs_iterfunc(lua_State *L) {
720 lua_Integer idx;
721 // stack shall contain two function arguments:
722 lua_settop(L, 2);
723 // calculate new index by incrementing second argument:
724 idx = lua_tointeger(L, 2) + 1;
725 // get corresponding shadow table for first argument:
726 json_regfetch(L, shadowtbl);
727 lua_pushvalue(L, 1);
728 lua_rawget(L, -2);
729 // throw error if no shadow table was found:
730 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
731 // do integer lookup in shadow table:
732 lua_rawgeti(L, -1, idx);
733 // return nothing if there was no value:
734 if (lua_isnil(L, -1)) return 0;
735 // return new index and
736 // either the looked up value if it is not equal to the null-marker
737 // or nil instead of null-marker:
738 lua_pushinteger(L, idx);
739 if (json_isnullmark(L, -2)) lua_pushnil(L);
740 else lua_pushvalue(L, -2);
741 return 2;
742 }
744 // returns a triple such that 'for idx, value in ipairs(ary) do ... end'
745 // iterates through all values (including JSON null represented as Lua nil):
746 static int json_ipairs(lua_State *L) {
747 // return triple of function json_ipairs_iterfunc, first argument, and zero:
748 lua_pushcfunction(L, json_ipairs_iterfunc);
749 lua_pushvalue(L, 1);
750 lua_pushinteger(L, 0);
751 return 3;
752 }
754 typedef struct {
755 size_t length;
756 const char *data;
757 } json_key_t;
759 static int json_key_cmp(json_key_t *key1, json_key_t *key2) {
760 size_t pos = 0;
761 unsigned char c1, c2;
762 while (1) {
763 if (key1->length > pos) {
764 if (key2->length > pos) {
765 c1 = key1->data[pos];
766 c2 = key2->data[pos];
767 if (c1 < c2) return -1;
768 else if (c1 > c2) return 1;
769 } else {
770 return 1;
771 }
772 } else {
773 if (key2->length > pos) {
774 return -1;
775 } else {
776 return 0;
777 }
778 }
779 pos++;
780 }
781 }
783 #define JSON_TABLETYPE_UNKNOWN 0
784 #define JSON_TABLETYPE_OBJECT 1
785 #define JSON_TABLETYPE_ARRAY 2
787 #define json_export_internal_indentstring_idx 1
788 #define json_export_internal_level_idx 2
789 #define json_export_internal_value_idx 3
790 #define json_export_internal_tmp_idx 4
792 static int json_export_internal(lua_State *L) {
793 int level;
794 int pretty;
795 int i;
796 lua_Number num;
797 const char *str;
798 unsigned char c;
799 size_t strlen;
800 size_t pos = 0;
801 luaL_Buffer buf;
802 char hexcode[7]; // backslash, character 'u', 4 hex digits, and terminating NULL byte
803 int tabletype = JSON_TABLETYPE_UNKNOWN;
804 int anyelement = 0;
805 size_t keycount = 0;
806 size_t keypos = 0;
807 json_key_t *keybuf = NULL;
808 lua_Integer idx;
809 lua_settop(L, json_export_internal_value_idx);
810 if (json_isnullmark(L, json_export_internal_value_idx)) {
811 lua_pop(L, 1);
812 lua_pushnil(L);
813 }
814 switch (lua_type(L, json_export_internal_value_idx)) {
815 case LUA_TNIL:
816 lua_pushliteral(L, "null");
817 return 1;
818 case LUA_TNUMBER:
819 num = lua_tonumber(L, json_export_internal_value_idx);
820 if (isnan(num)) return luaL_error(L, "JSON export not possible for NaN value");
821 if (isinf(num)) return luaL_error(L, "JSON export not possible for infinite numbers");
822 lua_tostring(L, json_export_internal_value_idx);
823 return 1;
824 case LUA_TBOOLEAN:
825 if (lua_toboolean(L, json_export_internal_value_idx)) {
826 lua_pushliteral(L, "true");
827 } else {
828 lua_pushliteral(L, "false");
829 }
830 return 1;
831 case LUA_TSTRING:
832 str = lua_tolstring(L, 3, &strlen);
833 luaL_buffinit(L, &buf);
834 luaL_addchar(&buf, '"');
835 while (pos < strlen) {
836 c = str[pos++];
837 if (c == '"') luaL_addstring(&buf, "\\\"");
838 else if (c == '\\') luaL_addstring(&buf, "\\\\");
839 else if (c == 127) luaL_addstring(&buf, "\\u007F");
840 else if (c >= 32) luaL_addchar(&buf, c);
841 else if (c == '\b') luaL_addstring(&buf, "\\b");
842 else if (c == '\f') luaL_addstring(&buf, "\\f");
843 else if (c == '\n') luaL_addstring(&buf, "\\n");
844 else if (c == '\r') luaL_addstring(&buf, "\\r");
845 else if (c == '\t') luaL_addstring(&buf, "\\t");
846 else if (c == '\v') luaL_addstring(&buf, "\\v");
847 else {
848 sprintf(hexcode, "\\u%04X", c);
849 luaL_addstring(&buf, hexcode);
850 }
851 }
852 luaL_addchar(&buf, '"');
853 luaL_pushresult(&buf);
854 return 1;
855 case LUA_TTABLE:
856 if (lua_getmetatable(L, json_export_internal_value_idx)) {
857 json_regfetch(L, objectmt);
858 if (lua_rawequal(L, -2, -1)) {
859 tabletype = JSON_TABLETYPE_OBJECT;
860 } else {
861 json_regfetch(L, arraymt);
862 if (lua_rawequal(L, -3, -1)) {
863 tabletype = JSON_TABLETYPE_ARRAY;
864 } else {
865 return luaL_error(L, "JSON export not possible for tables with nonsupported metatable");
866 }
867 }
868 }
869 json_regfetch(L, shadowtbl);
870 lua_pushvalue(L, json_export_internal_value_idx);
871 lua_rawget(L, -2);
872 if (!lua_isnil(L, -1)) lua_replace(L, json_export_internal_value_idx);
873 lua_settop(L, json_export_internal_value_idx);
874 if (tabletype == JSON_TABLETYPE_UNKNOWN) {
875 for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
876 switch (lua_type(L, -2)) {
877 case LUA_TSTRING:
878 keycount++;
879 if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_OBJECT;
880 else if (tabletype == JSON_TABLETYPE_ARRAY) goto json_export_tabletype_error;
881 break;
882 case LUA_TNUMBER:
883 if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_ARRAY;
884 else if (tabletype == JSON_TABLETYPE_OBJECT) goto json_export_tabletype_error;
885 break;
886 }
887 }
888 }
889 pretty = lua_toboolean(L, json_export_internal_indentstring_idx);
890 level = lua_tointeger(L, json_export_internal_level_idx) + 1;
891 if (level > JSON_MAXDEPTH) {
892 return luaL_error(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
893 }
894 switch (tabletype) {
895 case JSON_TABLETYPE_OBJECT:
896 if (!keycount) {
897 for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
898 if (lua_type(L, -2) == LUA_TSTRING) keycount++;
899 }
900 }
901 if (keycount) {
902 keybuf = calloc(keycount, sizeof(json_key_t));
903 if (!keybuf) return luaL_error(L, "Memory allocation failed in JSON library");
904 for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
905 if (lua_type(L, -2) == LUA_TSTRING) {
906 json_key_t *key = keybuf + (keypos++);
907 key->data = lua_tolstring(L, -2, &key->length);
908 }
909 }
910 qsort(keybuf, keycount, sizeof(json_key_t), (void *)json_key_cmp);
911 }
912 luaL_buffinit(L, &buf);
913 luaL_addchar(&buf, '{');
914 for (keypos=0; keypos<keycount; keypos++) {
915 json_key_t *key = keybuf + keypos;
916 if (keypos) luaL_addchar(&buf, ',');
917 if (pretty) {
918 luaL_addchar(&buf, '\n');
919 for (i=0; i<level; i++) {
920 lua_pushvalue(L, json_export_internal_indentstring_idx);
921 luaL_addvalue(&buf);
922 }
923 }
924 lua_pushcfunction(L, json_export_internal);
925 lua_pushvalue(L, json_export_internal_indentstring_idx);
926 lua_pushinteger(L, level);
927 lua_pushlstring(L, key->data, key->length);
928 if (lua_pcall(L, 3, 1, 0)) {
929 if (keybuf) free(keybuf);
930 return lua_error(L);
931 }
932 luaL_addvalue(&buf);
933 luaL_addchar(&buf, ':');
934 if (pretty) luaL_addchar(&buf, ' ');
935 lua_pushcfunction(L, json_export_internal);
936 lua_pushvalue(L, json_export_internal_indentstring_idx);
937 lua_pushinteger(L, level);
938 lua_pushlstring(L, key->data, key->length);
939 lua_rawget(L, json_export_internal_value_idx);
940 if (lua_pcall(L, 3, 1, 0)) {
941 if (keybuf) free(keybuf);
942 return lua_error(L);
943 }
944 luaL_addvalue(&buf);
945 }
946 if (keybuf) free(keybuf);
947 if (pretty && keycount != 0) {
948 luaL_addchar(&buf, '\n');
949 for (i=0; i<level-1; i++) {
950 lua_pushvalue(L, json_export_internal_indentstring_idx);
951 luaL_addvalue(&buf);
952 }
953 }
954 luaL_addchar(&buf, '}');
955 if (pretty && level == 1) luaL_addchar(&buf, '\n');
956 luaL_pushresult(&buf);
957 return 1;
958 case JSON_TABLETYPE_ARRAY:
959 lua_settop(L, json_export_internal_tmp_idx);
960 luaL_buffinit(L, &buf);
961 luaL_addchar(&buf, '[');
962 for (idx = 1; ; idx++) {
963 lua_rawgeti(L, json_export_internal_value_idx, idx);
964 if (lua_isnil(L, -1)) {
965 lua_pop(L, 1);
966 break;
967 }
968 lua_replace(L, json_export_internal_tmp_idx);
969 if (anyelement) luaL_addchar(&buf, ',');
970 anyelement = 1;
971 if (pretty) {
972 luaL_addchar(&buf, '\n');
973 for (i=0; i<level; i++) {
974 lua_pushvalue(L, json_export_internal_indentstring_idx);
975 luaL_addvalue(&buf);
976 }
977 }
978 lua_pushcfunction(L, json_export_internal);
979 lua_pushvalue(L, json_export_internal_indentstring_idx);
980 lua_pushinteger(L, level);
981 lua_pushvalue(L, json_export_internal_tmp_idx);
982 lua_call(L, 3, 1);
983 luaL_addvalue(&buf);
984 }
985 if (pretty && anyelement) {
986 luaL_addchar(&buf, '\n');
987 for (i=0; i<level-1; i++) {
988 lua_pushvalue(L, json_export_internal_indentstring_idx);
989 luaL_addvalue(&buf);
990 }
991 }
992 luaL_addchar(&buf, ']');
993 if (pretty && level == 1) luaL_addchar(&buf, '\n');
994 luaL_pushresult(&buf);
995 return 1;
996 }
997 json_export_tabletype_error:
998 return luaL_error(L, "JSON export not possible for ambiguous table (cannot decide whether it is an object or array)");
999 }
1000 return luaL_error(L, "JSON export not possible for values of type \"%s\"", lua_typename(L, lua_type(L, json_export_internal_value_idx)));
1003 static int json_export(lua_State *L) {
1004 lua_settop(L, 1);
1005 lua_pushcfunction(L, json_export_internal);
1006 lua_pushnil(L);
1007 lua_pushinteger(L, 0);
1008 lua_pushvalue(L, 1);
1009 lua_call(L, 3, 1);
1010 return 1;
1013 static int json_pretty(lua_State *L) {
1014 lua_settop(L, 2);
1015 lua_pushcfunction(L, json_export_internal);
1016 if (lua_isnil(L, 2)) lua_pushliteral(L, " ");
1017 else lua_pushvalue(L, 2);
1018 lua_pushinteger(L, 0);
1019 lua_pushvalue(L, 1);
1020 lua_call(L, 3, 1);
1021 return 1;
1024 // functions in library module:
1025 static const struct luaL_Reg json_module_functions[] = {
1026 {"object", json_object},
1027 {"array", json_array},
1028 {"import", json_import},
1029 {"export", json_export},
1030 {"pretty", json_pretty},
1031 {"get", json_get},
1032 {"type", json_type},
1033 {NULL, NULL}
1034 };
1036 // metamethods for JSON objects, JSON arrays, and unknown JSON collections (object or array):
1037 static const struct luaL_Reg json_metatable_functions[] = {
1038 {"__len", json_len},
1039 {"__index", json_index},
1040 {"__newindex", json_newindex},
1041 {"__pairs", json_pairs},
1042 {"__ipairs", json_ipairs},
1043 {"__tostring", json_export},
1044 {NULL, NULL}
1045 };
1047 // metamethods for JSON null marker:
1048 static const struct luaL_Reg json_nullmark_metamethods[] = {
1049 {"__tostring", json_nullmark_tostring},
1050 {NULL, NULL}
1051 };
1053 // initializes json library:
1054 int luaopen_json(lua_State *L) {
1055 // empty stack:
1056 lua_settop(L, 0);
1057 // push library module onto stack position 1:
1058 lua_newtable(L);
1059 // register library functions:
1060 luaL_setfuncs(L, json_module_functions, 0);
1061 // create and store objectmt:
1062 lua_newtable(L);
1063 luaL_setfuncs(L, json_metatable_functions, 0);
1064 json_regstore(L, objectmt);
1065 // create and store arraymt:
1066 lua_newtable(L);
1067 luaL_setfuncs(L, json_metatable_functions, 0);
1068 json_regstore(L, arraymt);
1069 // create and store ephemeron table to store shadow tables for each JSON object/array
1070 // to allow NULL values returned as nil
1071 lua_newtable(L);
1072 lua_newtable(L); // metatable for ephemeron table
1073 lua_pushliteral(L, "__mode");
1074 lua_pushliteral(L, "k");
1075 lua_rawset(L, -3);
1076 lua_setmetatable(L, -2);
1077 json_regstore(L, shadowtbl);
1078 // set metatable of null marker and make it available through library module:
1079 json_pushnullmark(L);
1080 lua_newtable(L);
1081 luaL_setfuncs(L, json_nullmark_metamethods, 0);
1082 lua_setmetatable(L, -2);
1083 lua_setfield(L, 1, "null");
1084 // return library module (that's expected on top of stack):
1085 return 1;

Impressum / About Us