webmcp

annotate libraries/json/json.c @ 180:887b77f71e5e

Added #undef to json.c to avoid compiler warning
author jbe
date Sat Aug 02 00:39:41 2014 +0200 (2014-08-02)
parents 461e5353ffb1
children c2e76617c26c
rev   line source
jbe@121 1 #include <lua.h>
jbe@121 2 #include <lauxlib.h>
jbe@122 3 #include <stdlib.h>
jbe@121 4 #include <string.h>
jbe@154 5 #include <math.h>
jbe@121 6
jbe@144 7 // maximum number of nested JSON values (objects and arrays):
jbe@150 8 // NOTE: The Lua reference states that the stack may typically contain at least
jbe@150 9 // "a few thousand elements". Since every nested level consumes
jbe@150 10 // 3 elements on the Lua stack (the object/array, its shadow table,
jbe@150 11 // a string key or a placeholder), we limit the number of nested levels
jbe@150 12 // to 500. If a stack overflow would still happen in the import function,
jbe@150 13 // this is detected nevertheless and an error is thrown (instead of
jbe@150 14 // returning nil and an error string).
jbe@150 15 #define JSON_MAXDEPTH 500
jbe@179 16 // NOTE: As long as the function json_export_internal is implemented
jbe@179 17 // recursively, JSON_MAXDEPTH needs to be low (e.g. 50) to avoid C stack
jbe@179 18 // overflows.
jbe@179 19 #if JSON_MAXDEPTH > 50
jbe@180 20 #undef JSON_MAXDEPTH
jbe@179 21 #define JSON_MAXDEPTH 50
jbe@179 22 #endif
jbe@142 23
jbe@155 24 // generate dummy memory addresses that represents null values:
jbe@155 25 char json_nullmark;
jbe@155 26 #define json_isnullmark(L, i) (lua_touserdata((L), (i)) == &json_nullmark)
jbe@155 27 #define json_pushnullmark(L) lua_pushlightuserdata((L), &json_nullmark)
jbe@155 28
jbe@144 29 // macros for usage of Lua registry:
jbe@144 30 #define JSON_REGENT char
jbe@145 31 #define JSON_REGPOINTER void *
jbe@145 32 #define json_regpointer(x) (&json_registry.x)
jbe@151 33 #define json_regfetchpointer(L, x) lua_rawgetp((L), LUA_REGISTRYINDEX, (x))
jbe@151 34 #define json_regfetch(L, x) json_regfetchpointer(L, json_regpointer(x))
jbe@151 35 #define json_regstore(L, x) lua_rawsetp(L, LUA_REGISTRYINDEX, json_regpointer(x))
jbe@145 36
jbe@144 37 // generate dummy memory addresses that represent Lua objects
jbe@145 38 // via lightuserdata keys and LUA_REGISTRYINDEX:
jbe@144 39 static struct {
jbe@145 40 JSON_REGENT shadowtbl; // ephemeron table that maps tables to their corresponding shadow table
jbe@145 41 JSON_REGENT objectmt; // metatable for JSON objects
jbe@145 42 JSON_REGENT arraymt; // metatable for JSON arrays
jbe@144 43 } json_registry;
jbe@138 44
jbe@157 45 // returns the string "<JSON null marker>":
jbe@157 46 static int json_nullmark_tostring(lua_State *L) {
jbe@157 47 lua_pushliteral(L, "<JSON null marker>");
jbe@157 48 return 1;
jbe@157 49 }
jbe@157 50
jbe@169 51 #define json_convert_source_idx 1
jbe@169 52 #define json_convert_iterator_idx 2
jbe@169 53 #define json_convert_output_idx 3
jbe@169 54 #define json_convert_shadow_idx 4
jbe@172 55 #define json_convert_iterfun_idx 5
jbe@172 56 #define json_convert_itertbl_idx 6
jbe@169 57
jbe@175 58 // converts a Lua table (or any other iterable value) to a JSON object or JSON array:
jbe@169 59 // (does never modify the argument, returns an empty object or array if argument is nil)
jbe@169 60 static int json_convert(lua_State *L, int array) {
jbe@171 61 int arrayidx = 0;
jbe@171 62 // determine is argument is given:
jbe@169 63 if (lua_isnoneornil(L, json_convert_source_idx)) {
jbe@171 64 // if no argument is given (or if argument is nil),
jbe@171 65 // create table with shadow table, and leave first table on top of stack:
jbe@144 66 json_regfetch(L, shadowtbl);
jbe@169 67 lua_newtable(L);
jbe@169 68 lua_pushvalue(L, -1);
jbe@169 69 lua_newtable(L);
jbe@169 70 lua_rawset(L, -4);
jbe@169 71 } else {
jbe@171 72 // if an argument was given,
jbe@171 73 // push its iterator function on stack position 2 if existent,
jbe@169 74 // else push null for normal tables:
jbe@171 75 lua_settop(L, 1);
jbe@169 76 if (lua_getmetatable(L, json_convert_source_idx)) {
jbe@169 77 lua_getfield(L, -1, array ? "__ipairs" : "__pairs");
jbe@169 78 if (lua_isnil(L, -1)) luaL_checktype(L, 1, LUA_TTABLE);
jbe@169 79 else if (lua_type(L, -1) != LUA_TFUNCTION)
jbe@169 80 return luaL_error(L, "%s metamethod is not a function", array ? "__ipairs" : "__pairs");
jbe@169 81 lua_replace(L, -2);
jbe@169 82 } else {
jbe@169 83 lua_pushnil(L);
jbe@143 84 }
jbe@171 85 // create result table on stack position 3:
jbe@169 86 lua_newtable(L);
jbe@169 87 // create shadow table on stack position 4:
jbe@169 88 json_regfetch(L, shadowtbl);
jbe@169 89 lua_newtable(L);
jbe@169 90 lua_pushvalue(L, json_convert_output_idx);
jbe@169 91 lua_pushvalue(L, -2);
jbe@169 92 lua_rawset(L, -4);
jbe@169 93 lua_replace(L, -2);
jbe@171 94 // check if iterator function exists:
jbe@169 95 if (lua_isnil(L, json_convert_iterator_idx)) {
jbe@171 96 // if there is no iterator function,
jbe@171 97 // distinguish between objects and arrays:
jbe@171 98 if (array == 0) {
jbe@171 99 // for an object, copy all string key value pairs to shadow table:
jbe@171 100 for (lua_pushnil(L); lua_next(L, json_convert_source_idx); lua_pop(L, 1)) {
jbe@171 101 if (lua_type(L, -2) == LUA_TSTRING) {
jbe@171 102 lua_pushvalue(L, -2);
jbe@171 103 lua_pushvalue(L, -2);
jbe@171 104 lua_rawset(L, json_convert_shadow_idx);
jbe@171 105 }
jbe@171 106 }
jbe@171 107 } else {
jbe@171 108 // for an array, copy consecutive integer value pairs to shadow table:
jbe@171 109 while (1) {
jbe@175 110 // throw error if array would exceed INT_MAX elements:
jbe@171 111 // TODO: Lua 5.3 may support more elements
jbe@171 112 if (arrayidx == INT_MAX) {
jbe@171 113 lua_pushnumber(L, (size_t)INT_MAX+1);
jbe@171 114 lua_rawget(L, json_convert_source_idx);
jbe@171 115 if (lua_isnil(L, -1)) break;
jbe@171 116 return luaL_error(L, "Array exceeded length of %d elements", INT_MAX);
jbe@171 117 }
jbe@175 118 // get next array entry:
jbe@171 119 arrayidx++;
jbe@171 120 lua_rawgeti(L, json_convert_source_idx, arrayidx);
jbe@175 121 // break if value is nil:
jbe@171 122 if (lua_isnil(L, -1)) break;
jbe@175 123 // store value in shadow table:
jbe@171 124 lua_rawseti(L, json_convert_shadow_idx, arrayidx);
jbe@171 125 }
jbe@169 126 }
jbe@169 127 } else {
jbe@172 128 // if there is an iterator function,
jbe@172 129 // call iterator function with source value (first argument)
jbe@172 130 // and store 3 result values on stack positions 5 through 7:
jbe@172 131 lua_pushvalue(L, json_convert_iterator_idx);
jbe@172 132 lua_pushvalue(L, 1);
jbe@172 133 lua_call(L, 1, 3);
jbe@175 134 // iterate through key value pairs and store some of them in shadow table
jbe@174 135 // while replacing nil values with null-marker:
jbe@172 136 while (1) {
jbe@175 137 // call iterfun function:
jbe@172 138 lua_pushvalue(L, json_convert_iterfun_idx);
jbe@172 139 lua_pushvalue(L, json_convert_itertbl_idx);
jbe@172 140 lua_pushvalue(L, -3);
jbe@172 141 lua_remove(L, -4);
jbe@172 142 lua_call(L, 2, 2);
jbe@175 143 // break iteration loop if key is nil:
jbe@172 144 if (lua_isnil(L, -2)) break;
jbe@175 145 // store key value pair only if key type is correct:
jbe@172 146 if (lua_type(L, -2) == (array ? LUA_TNUMBER : LUA_TSTRING)) {
jbe@175 147 // if key type is correct,
jbe@175 148 // push key onto stack:
jbe@172 149 lua_pushvalue(L, -2);
jbe@175 150 // if value is nil, push null-marker onto stack (as value):
jbe@174 151 if (lua_isnil(L, -2)) json_pushnullmark(L);
jbe@175 152 // else push value onto stack:
jbe@174 153 else lua_pushvalue(L, -2);
jbe@175 154 // set key value pair in shadow table:
jbe@172 155 lua_rawset(L, json_convert_shadow_idx);
jbe@172 156 }
jbe@175 157 // pop value from stack, but leave key on stack:
jbe@172 158 lua_pop(L, 1);
jbe@172 159 }
jbe@143 160 }
jbe@171 161 // let result table be on top of stack:
jbe@169 162 lua_settop(L, json_convert_output_idx);
jbe@136 163 }
jbe@171 164 // set metatable (for result table on top of stack):
jbe@171 165 if (array == 0) json_regfetch(L, objectmt);
jbe@171 166 else json_regfetch(L, arraymt);
jbe@169 167 lua_setmetatable(L, -2);
jbe@171 168 // return table on top of stack:
jbe@136 169 return 1;
jbe@136 170 }
jbe@136 171
jbe@175 172 // converts a Lua table (or any other iterable value) to a JSON object:
jbe@175 173 // (does never modify the argument, returns an empty object or array if argument is nil)
jbe@136 174 static int json_object(lua_State *L) {
jbe@169 175 return json_convert(L, 0);
jbe@136 176 }
jbe@136 177
jbe@175 178 // converts a Lua table (or any other iterable value) to a JSON array:
jbe@175 179 // (does never modify the argument, returns an empty object or array if argument is nil)
jbe@136 180 static int json_array(lua_State *L) {
jbe@169 181 return json_convert(L, 1);
jbe@136 182 }
jbe@136 183
jbe@145 184 // internal states of JSON parser:
jbe@124 185 #define JSON_STATE_VALUE 0
jbe@124 186 #define JSON_STATE_OBJECT_KEY 1
jbe@124 187 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2
jbe@124 188 #define JSON_STATE_OBJECT_VALUE 3
jbe@124 189 #define JSON_STATE_OBJECT_SEPARATOR 4
jbe@124 190 #define JSON_STATE_ARRAY_VALUE 5
jbe@124 191 #define JSON_STATE_ARRAY_SEPARATOR 6
jbe@124 192 #define JSON_STATE_END 7
jbe@121 193
jbe@145 194 // special Lua stack indicies for json_import function:
jbe@138 195 #define json_import_objectmt_idx 2
jbe@138 196 #define json_import_arraymt_idx 3
jbe@138 197 #define json_import_shadowtbl_idx 4
jbe@138 198
jbe@168 199 // macros for hex decoding:
jbe@168 200 #define json_utf16_surrogate(x) ((x) >= 0xD800 && (x) <= 0xDFFF)
jbe@168 201 #define json_utf16_lead(x) ((x) >= 0xD800 && (x) <= 0xDBFF)
jbe@168 202 #define json_utf16_tail(x) ((x) >= 0xDC00 && (x) <= 0xDFFF)
jbe@167 203 #define json_import_readhex(x) \
jbe@167 204 do { \
jbe@167 205 x = 0; \
jbe@167 206 for (i=0; i<4; i++) { \
jbe@167 207 x <<= 4; \
jbe@167 208 c = str[pos++]; \
jbe@167 209 if (c >= '0' && c <= '9') x += c - '0'; \
jbe@167 210 else if (c >= 'A' && c <= 'F') x += c - 'A' + 10; \
jbe@167 211 else if (c >= 'a' && c <= 'f') x += c - 'a' + 10; \
jbe@167 212 else if (c == 0) goto json_import_unexpected_eof; \
jbe@167 213 else goto json_import_unexpected_escape; \
jbe@167 214 } \
jbe@167 215 } while (0)
jbe@167 216
jbe@136 217 // decodes a JSON document:
jbe@121 218 static int json_import(lua_State *L) {
jbe@167 219 int i; // loop variable
jbe@136 220 const char *str; // string to parse
jbe@136 221 size_t total; // total length of string to parse
jbe@136 222 size_t pos = 0; // current position in string to parse
jbe@136 223 size_t level = 0; // nested levels of objects/arrays currently being processed
jbe@145 224 int mode = JSON_STATE_VALUE; // state of parser (i.e. "what's expected next?")
jbe@170 225 unsigned char c; // variable to store a single character to be processed (unsigned!)
jbe@145 226 luaL_Buffer luabuf; // Lua buffer to decode JSON string values
jbe@145 227 char *cbuf; // C buffer to decode JSON string values
jbe@162 228 size_t outlen; // maximum length or write position of C buffer
jbe@167 229 long codepoint; // decoded UTF-16 character or higher codepoint
jbe@167 230 long utf16tail; // second decoded UTF-16 character (surrogate tail)
jbe@152 231 size_t arraylen; // variable to temporarily store the array length
jbe@166 232 // require string as argument and convert to C string with length information:
jbe@166 233 str = luaL_checklstring(L, 1, &total);
jbe@166 234 // if string contains a NULL byte, this is a syntax error
jbe@166 235 if (strlen(str) != total) goto json_import_syntax_error;
jbe@147 236 // stack shall contain one function argument:
jbe@138 237 lua_settop(L, 1);
jbe@147 238 // push objectmt onto stack position 2:
jbe@144 239 json_regfetch(L, objectmt);
jbe@147 240 // push arraymt onto stack position 3:
jbe@144 241 json_regfetch(L, arraymt);
jbe@147 242 // push shadowtbl onto stack position 4:
jbe@144 243 json_regfetch(L, shadowtbl);
jbe@136 244 // main loop of parser:
jbe@136 245 json_import_loop:
jbe@136 246 // skip whitespace and store next character in variable 'c':
jbe@146 247 while (c = str[pos],
jbe@146 248 c == ' ' ||
jbe@146 249 c == '\f' ||
jbe@146 250 c == '\n' ||
jbe@146 251 c == '\r' ||
jbe@146 252 c == '\t' ||
jbe@146 253 c == '\v'
jbe@146 254 ) pos++;
jbe@170 255 // NOTE: variable c needs to be unsigned in the following code
jbe@136 256 // switch statement to handle certain (single) characters:
jbe@121 257 switch (c) {
jbe@136 258 // handle end of JSON document:
jbe@121 259 case 0:
jbe@136 260 // if end of JSON document was expected, then return top element of stack as result:
jbe@124 261 if (mode == JSON_STATE_END) return 1;
jbe@136 262 // otherwise, the JSON document was malformed:
jbe@167 263 if (level == 0) {
jbe@167 264 lua_pushnil(L);
jbe@167 265 lua_pushliteral(L, "Empty string");
jbe@167 266 } else {
jbe@167 267 json_import_unexpected_eof:
jbe@167 268 lua_pushnil(L);
jbe@167 269 lua_pushliteral(L, "Unexpected end of JSON document");
jbe@167 270 }
jbe@121 271 return 2;
jbe@136 272 // new JSON object:
jbe@121 273 case '{':
jbe@136 274 // if a JSON object is not expected here, then return an error:
jbe@146 275 if (
jbe@146 276 mode != JSON_STATE_VALUE &&
jbe@146 277 mode != JSON_STATE_OBJECT_VALUE &&
jbe@146 278 mode != JSON_STATE_ARRAY_VALUE
jbe@146 279 ) goto json_import_syntax_error;
jbe@136 280 // create JSON object on stack:
jbe@136 281 lua_newtable(L);
jbe@136 282 // set metatable of JSON object:
jbe@138 283 lua_pushvalue(L, json_import_objectmt_idx);
jbe@125 284 lua_setmetatable(L, -2);
jbe@136 285 // create internal shadow table on stack:
jbe@136 286 lua_newtable(L);
jbe@146 287 // register internal shadow table:
jbe@123 288 lua_pushvalue(L, -2);
jbe@123 289 lua_pushvalue(L, -2);
jbe@138 290 lua_rawset(L, json_import_shadowtbl_idx);
jbe@146 291 // expect object key (or end of object) to follow:
jbe@136 292 mode = JSON_STATE_OBJECT_KEY;
jbe@146 293 // jump to common code for opening JSON object and JSON array:
jbe@142 294 goto json_import_open;
jbe@136 295 // new JSON array:
jbe@121 296 case '[':
jbe@136 297 // if a JSON array is not expected here, then return an error:
jbe@146 298 if (
jbe@146 299 mode != JSON_STATE_VALUE &&
jbe@146 300 mode != JSON_STATE_OBJECT_VALUE &&
jbe@146 301 mode != JSON_STATE_ARRAY_VALUE
jbe@146 302 ) goto json_import_syntax_error;
jbe@136 303 // create JSON array on stack:
jbe@136 304 lua_newtable(L);
jbe@136 305 // set metatable of JSON array:
jbe@138 306 lua_pushvalue(L, json_import_arraymt_idx);
jbe@125 307 lua_setmetatable(L, -2);
jbe@136 308 // create internal shadow table on stack:
jbe@136 309 lua_newtable(L);
jbe@146 310 // register internal shadow table:
jbe@123 311 lua_pushvalue(L, -2);
jbe@123 312 lua_pushvalue(L, -2);
jbe@138 313 lua_rawset(L, json_import_shadowtbl_idx);
jbe@140 314 // add nil as key (needed to keep stack balance) and as magic to detect arrays:
jbe@140 315 lua_pushnil(L);
jbe@146 316 // expect array value (or end of array) to follow:
jbe@142 317 mode = JSON_STATE_ARRAY_VALUE;
jbe@142 318 // continue with common code for opening JSON object and JSON array:
jbe@146 319 // common code for opening JSON object or JSON array:
jbe@142 320 json_import_open:
jbe@142 321 // limit nested levels:
jbe@142 322 if (level >= JSON_MAXDEPTH) {
jbe@142 323 lua_pushnil(L);
jbe@164 324 lua_pushfstring(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
jbe@142 325 return 2;
jbe@142 326 }
jbe@142 327 // additional buffer overflow protection:
jbe@142 328 if (!lua_checkstack(L, LUA_MINSTACK))
jbe@142 329 return luaL_error(L, "Caught stack overflow in JSON import function (too many nested levels and stack size too small)");
jbe@136 330 // increment level:
jbe@121 331 level++;
jbe@142 332 // consume input character:
jbe@142 333 pos++;
jbe@121 334 goto json_import_loop;
jbe@136 335 // end of JSON object:
jbe@121 336 case '}':
jbe@136 337 // if end of JSON object is not expected here, then return an error:
jbe@146 338 if (
jbe@146 339 mode != JSON_STATE_OBJECT_KEY &&
jbe@146 340 mode != JSON_STATE_OBJECT_SEPARATOR
jbe@146 341 ) goto json_import_syntax_error;
jbe@136 342 // jump to common code for end of JSON object and JSON array:
jbe@121 343 goto json_import_close;
jbe@136 344 // end of JSON array:
jbe@121 345 case ']':
jbe@136 346 // if end of JSON array is not expected here, then return an error:
jbe@146 347 if (
jbe@146 348 mode != JSON_STATE_ARRAY_VALUE &&
jbe@146 349 mode != JSON_STATE_ARRAY_SEPARATOR
jbe@146 350 ) goto json_import_syntax_error;
jbe@146 351 // pop nil key/magic (that was needed to keep stack balance):
jbe@140 352 lua_pop(L, 1);
jbe@136 353 // continue with common code for end of JSON object and JSON array:
jbe@136 354 // common code for end of JSON object or JSON array:
jbe@121 355 json_import_close:
jbe@136 356 // consume input character:
jbe@121 357 pos++;
jbe@136 358 // pop shadow table:
jbe@136 359 lua_pop(L, 1);
jbe@136 360 // check if nested:
jbe@121 361 if (--level) {
jbe@146 362 // if nested,
jbe@146 363 // check if outer(!) structure is an array or object:
jbe@140 364 if (lua_isnil(L, -2)) {
jbe@136 365 // select array value processing:
jbe@124 366 mode = JSON_STATE_ARRAY_VALUE;
jbe@121 367 } else {
jbe@136 368 // select object value processing:
jbe@124 369 mode = JSON_STATE_OBJECT_VALUE;
jbe@121 370 }
jbe@136 371 // store value in outer structure:
jbe@121 372 goto json_import_process_value;
jbe@121 373 }
jbe@136 374 // if not nested, then expect end of JSON document and continue with loop:
jbe@136 375 mode = JSON_STATE_END;
jbe@121 376 goto json_import_loop;
jbe@136 377 // key terminator:
jbe@121 378 case ':':
jbe@136 379 // if key terminator is not expected here, then return an error:
jbe@124 380 if (mode != JSON_STATE_OBJECT_KEY_TERMINATOR)
jbe@121 381 goto json_import_syntax_error;
jbe@136 382 // consume input character:
jbe@121 383 pos++;
jbe@146 384 // expect object value to follow:
jbe@124 385 mode = JSON_STATE_OBJECT_VALUE;
jbe@146 386 // continue with loop:
jbe@121 387 goto json_import_loop;
jbe@136 388 // value terminator (NOTE: trailing comma at end of value or key-value list is tolerated by this parser)
jbe@121 389 case ',':
jbe@146 390 // branch according to parser state:
jbe@124 391 if (mode == JSON_STATE_OBJECT_SEPARATOR) {
jbe@146 392 // expect an object key to follow:
jbe@124 393 mode = JSON_STATE_OBJECT_KEY;
jbe@124 394 } else if (mode == JSON_STATE_ARRAY_SEPARATOR) {
jbe@146 395 // expect an array value to follow:
jbe@124 396 mode = JSON_STATE_ARRAY_VALUE;
jbe@121 397 } else {
jbe@136 398 // if value terminator is not expected here, then return an error:
jbe@136 399 goto json_import_syntax_error;
jbe@121 400 }
jbe@136 401 // consume input character:
jbe@121 402 pos++;
jbe@136 403 // continue with loop:
jbe@121 404 goto json_import_loop;
jbe@136 405 // string literal:
jbe@121 406 case '"':
jbe@146 407 // consume quote character:
jbe@146 408 pos++;
jbe@162 409 // find last character in input string:
jbe@162 410 outlen = pos;
jbe@162 411 while ((c = str[outlen]) != '"') {
jbe@161 412 // consume one character:
jbe@162 413 outlen++;
jbe@161 414 // handle unexpected end of JSON document:
jbe@161 415 if (c == 0) goto json_import_unexpected_eof;
jbe@161 416 // consume one extra character when encountering an escaped quote:
jbe@162 417 else if (c == '\\' && str[outlen] == '"') outlen++;
jbe@161 418 }
jbe@162 419 // determine buffer length:
jbe@162 420 outlen -= pos;
jbe@161 421 // check if string is non empty:
jbe@162 422 if (outlen) {
jbe@161 423 // prepare buffer to decode string (with maximum possible length) and set write position to zero:
jbe@162 424 cbuf = luaL_buffinitsize(L, &luabuf, outlen);
jbe@162 425 outlen = 0;
jbe@161 426 // loop through the characters until encountering end quote:
jbe@161 427 while ((c = str[pos++]) != '"') {
jbe@162 428 // NOTE: unexpected end cannot happen anymore
jbe@162 429 if (c < 32 || c == 127) {
jbe@161 430 // do not allow ASCII control characters:
jbe@161 431 // NOTE: illegal UTF-8 sequences and extended control characters are not sanitized
jbe@161 432 // by this parser to allow different encodings than Unicode
jbe@161 433 lua_pushnil(L);
jbe@161 434 lua_pushliteral(L, "Unexpected control character in JSON string");
jbe@161 435 return 2;
jbe@161 436 } else if (c == '\\') {
jbe@161 437 // read next char after backslash escape:
jbe@161 438 c = str[pos++];
jbe@161 439 switch (c) {
jbe@161 440 // unexpected end-of-string:
jbe@161 441 case 0:
jbe@161 442 goto json_import_unexpected_eof;
jbe@161 443 // unescaping of quotation mark, slash, and backslash:
jbe@161 444 case '"':
jbe@161 445 case '/':
jbe@161 446 case '\\':
jbe@162 447 cbuf[outlen++] = c;
jbe@161 448 break;
jbe@161 449 // unescaping of backspace:
jbe@162 450 case 'b': cbuf[outlen++] = '\b'; break;
jbe@161 451 // unescaping of form-feed:
jbe@162 452 case 'f': cbuf[outlen++] = '\f'; break;
jbe@161 453 // unescaping of new-line:
jbe@162 454 case 'n': cbuf[outlen++] = '\n'; break;
jbe@161 455 // unescaping of carriage-return:
jbe@162 456 case 'r': cbuf[outlen++] = '\r'; break;
jbe@161 457 // unescaping of tabulator:
jbe@162 458 case 't': cbuf[outlen++] = '\t'; break;
jbe@161 459 // unescaping of UTF-16 characters
jbe@161 460 case 'u':
jbe@167 461 // decode 4 hex nibbles:
jbe@167 462 json_import_readhex(codepoint);
jbe@167 463 // handle surrogate character:
jbe@167 464 if (json_utf16_surrogate(codepoint)) {
jbe@167 465 // check if first surrogate is in valid range:
jbe@167 466 if (json_utf16_lead(codepoint)) {
jbe@167 467 // require second surrogate:
jbe@167 468 if ((c = str[pos++]) != '\\' || (c = str[pos++]) != 'u') {
jbe@167 469 if (c == 0) goto json_import_unexpected_eof;
jbe@167 470 else goto json_import_wrong_surrogate;
jbe@167 471 }
jbe@167 472 // read 4 hex nibbles of second surrogate character:
jbe@167 473 json_import_readhex(utf16tail);
jbe@167 474 // check if second surrogate is in valid range:
jbe@167 475 if (!json_utf16_tail(utf16tail)) goto json_import_wrong_surrogate;
jbe@167 476 // calculate codepoint:
jbe@167 477 codepoint = 0x10000 + (utf16tail - 0xDC00) + (codepoint - 0xD800) * 0x400;
jbe@167 478 } else {
jbe@167 479 // throw error for wrong surrogates:
jbe@167 480 json_import_wrong_surrogate:
jbe@167 481 lua_pushnil(L);
jbe@167 482 lua_pushliteral(L, "Illegal UTF-16 surrogate in JSON string escape sequence");
jbe@167 483 return 2;
jbe@167 484 }
jbe@167 485 }
jbe@167 486 // encode as UTF-8:
jbe@167 487 if (codepoint < 0x80) {
jbe@167 488 cbuf[outlen++] = (char)codepoint;
jbe@167 489 } else if (codepoint < 0x800) {
jbe@167 490 cbuf[outlen++] = (char)(0xc0 | (codepoint >> 6));
jbe@167 491 cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
jbe@167 492 } else if (codepoint < 0x10000) {
jbe@167 493 cbuf[outlen++] = (char)(0xe0 | (codepoint >> 12));
jbe@167 494 cbuf[outlen++] = (char)(0x80 | ((codepoint >> 6) & 0x3f));
jbe@167 495 cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
jbe@167 496 } else {
jbe@167 497 cbuf[outlen++] = (char)(0xf0 | (codepoint >> 18));
jbe@167 498 cbuf[outlen++] = (char)(0x80 | ((codepoint >> 12) & 0x3f));
jbe@167 499 cbuf[outlen++] = (char)(0x80 | ((codepoint >> 6) & 0x3f));
jbe@167 500 cbuf[outlen++] = (char)(0x80 | (codepoint & 0x3f));
jbe@167 501 }
jbe@167 502 break;
jbe@161 503 // unexpected escape sequence:
jbe@161 504 default:
jbe@167 505 json_import_unexpected_escape:
jbe@161 506 lua_pushnil(L);
jbe@161 507 lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
jbe@161 508 return 2;
jbe@161 509 }
jbe@161 510 } else {
jbe@161 511 // normal character:
jbe@162 512 cbuf[outlen++] = c;
jbe@121 513 }
jbe@121 514 }
jbe@161 515 // process buffer to Lua string:
jbe@162 516 luaL_pushresultsize(&luabuf, outlen);
jbe@161 517 } else {
jbe@161 518 // if JSON string is empty,
jbe@161 519 // push empty Lua string:
jbe@161 520 lua_pushliteral(L, "");
jbe@167 521 // consume closing quote:
jbe@167 522 pos++;
jbe@121 523 }
jbe@136 524 // continue with processing of decoded string:
jbe@121 525 goto json_import_process_value;
jbe@121 526 }
jbe@136 527 // process values whose type is is not deducible from a single character:
jbe@136 528 if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
jbe@146 529 // for numbers,
jbe@146 530 // use strtod() call to parse a (double precision) floating point number:
jbe@167 531 double numval;
jbe@122 532 char *endptr;
jbe@122 533 numval = strtod(str+pos, &endptr);
jbe@146 534 // catch parsing errors:
jbe@122 535 if (endptr == str+pos) goto json_import_syntax_error;
jbe@146 536 // consume characters that were parsed:
jbe@122 537 pos += endptr - (str+pos);
jbe@146 538 // push parsed (double precision) floating point number on Lua stack:
jbe@122 539 lua_pushnumber(L, numval);
jbe@122 540 } else if (!strncmp(str+pos, "true", 4)) {
jbe@136 541 // consume 4 input characters for "true":
jbe@121 542 pos += 4;
jbe@147 543 // put Lua true value onto stack:
jbe@136 544 lua_pushboolean(L, 1);
jbe@121 545 } else if (!strncmp(str+pos, "false", 5)) {
jbe@136 546 // consume 5 input characters for "false":
jbe@121 547 pos += 5;
jbe@147 548 // put Lua false value onto stack:
jbe@136 549 lua_pushboolean(L, 0);
jbe@121 550 } else if (!strncmp(str+pos, "null", 4)) {
jbe@136 551 // consume 4 input characters for "null":
jbe@136 552 pos += 4;
jbe@153 553 // different behavor for top-level and sub-levels:
jbe@153 554 if (level) {
jbe@153 555 // if sub-level,
jbe@153 556 // push special null-marker onto stack:
jbe@155 557 json_pushnullmark(L);
jbe@153 558 } else {
jbe@153 559 // if top-level,
jbe@153 560 // push nil onto stack:
jbe@153 561 lua_pushnil(L);
jbe@153 562 }
jbe@121 563 } else {
jbe@136 564 // all other cases are a syntax error:
jbe@121 565 goto json_import_syntax_error;
jbe@121 566 }
jbe@136 567 // process a decoded value or key value pair (expected on top of Lua stack):
jbe@136 568 json_import_process_value:
jbe@121 569 switch (mode) {
jbe@136 570 // an object key has been read:
jbe@124 571 case JSON_STATE_OBJECT_KEY:
jbe@136 572 // if an object key is not a string, then this is a syntax error:
jbe@121 573 if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
jbe@146 574 // expect key terminator to follow:
jbe@124 575 mode = JSON_STATE_OBJECT_KEY_TERMINATOR;
jbe@146 576 // continue with loop:
jbe@121 577 goto json_import_loop;
jbe@136 578 // a key value pair has been read:
jbe@124 579 case JSON_STATE_OBJECT_VALUE:
jbe@136 580 // store key value pair in outer shadow table:
jbe@130 581 lua_rawset(L, -3);
jbe@146 582 // expect value terminator (or end of object) to follow:
jbe@124 583 mode = JSON_STATE_OBJECT_SEPARATOR;
jbe@146 584 // continue with loop:
jbe@121 585 goto json_import_loop;
jbe@136 586 // an array value has been read:
jbe@124 587 case JSON_STATE_ARRAY_VALUE:
jbe@152 588 // get current array length:
jbe@152 589 arraylen = lua_rawlen(L, -3);
jbe@152 590 // throw error if array would exceed INT_MAX elements:
jbe@152 591 // TODO: Lua 5.3 may support more elements
jbe@152 592 if (arraylen >= INT_MAX) {
jbe@152 593 lua_pushnil(L);
jbe@152 594 lua_pushfstring(L, "Array exceeded length of %d elements", INT_MAX);
jbe@152 595 }
jbe@136 596 // store value in outer shadow table:
jbe@152 597 lua_rawseti(L, -3, arraylen + 1);
jbe@146 598 // expect value terminator (or end of object) to follow:
jbe@124 599 mode = JSON_STATE_ARRAY_SEPARATOR;
jbe@146 600 // continue with loop
jbe@121 601 goto json_import_loop;
jbe@136 602 // a single value has been read:
jbe@124 603 case JSON_STATE_VALUE:
jbe@136 604 // leave value on top of stack, expect end of JSON document, and continue with loop:
jbe@124 605 mode = JSON_STATE_END;
jbe@121 606 goto json_import_loop;
jbe@121 607 }
jbe@146 608 // syntax error handling (reachable by goto statement):
jbe@136 609 json_import_syntax_error:
jbe@121 610 lua_pushnil(L);
jbe@121 611 lua_pushliteral(L, "Syntax error in JSON document");
jbe@121 612 return 2;
jbe@121 613 }
jbe@121 614
jbe@146 615 // special Lua stack indicies for json_path function:
jbe@138 616 #define json_path_shadowtbl_idx 1
jbe@146 617
jbe@146 618 // stack offset of arguments to json_path function:
jbe@155 619 #define json_path_idxshift 1
jbe@138 620
jbe@146 621 // gets a value or its type from a JSON document (passed as first argument)
jbe@175 622 // using a path (passed as variable number of keys after the first argument):
jbe@137 623 static int json_path(lua_State *L, int type_mode) {
jbe@146 624 int stacktop; // stack index of top of stack (after shifting)
jbe@146 625 int idx = 2 + json_path_idxshift; // stack index of current argument to process
jbe@173 626 // require at least one argument:
jbe@173 627 luaL_checkany(L, 1);
jbe@148 628 // insert shadowtbl into stack at position 1 (shifting the arguments):
jbe@144 629 json_regfetch(L, shadowtbl);
jbe@138 630 lua_insert(L, 1);
jbe@146 631 // store stack index of top of stack:
jbe@138 632 stacktop = lua_gettop(L);
jbe@146 633 // use first argument as "current value" (stored on top of stack):
jbe@138 634 lua_pushvalue(L, 1 + json_path_idxshift);
jbe@146 635 // process each "path key" (2nd argument and following arguments):
jbe@138 636 while (idx <= stacktop) {
jbe@146 637 // if "current value" (on top of stack) is nil, then the path cannot be walked and nil is returned:
jbe@137 638 if (lua_isnil(L, -1)) return 1;
jbe@137 639 // try to get shadow table of "current value":
jbe@130 640 lua_pushvalue(L, -1);
jbe@138 641 lua_rawget(L, json_path_shadowtbl_idx);
jbe@126 642 if (lua_isnil(L, -1)) {
jbe@137 643 // if no shadow table is found,
jbe@130 644 if (lua_type(L, -1) == LUA_TTABLE) {
jbe@146 645 // and if "current value" is a table,
jbe@146 646 // drop nil from stack:
jbe@146 647 lua_pop(L, 1);
jbe@137 648 // get "next value" using the "path key":
jbe@130 649 lua_pushvalue(L, idx++);
jbe@130 650 lua_gettable(L, -2);
jbe@130 651 } else {
jbe@137 652 // if "current value" is not a table,
jbe@146 653 // then the path cannot be walked and nil (already on top of stack) is returned:
jbe@137 654 return 1;
jbe@130 655 }
jbe@130 656 } else {
jbe@137 657 // if a shadow table is found,
jbe@137 658 // set "current value" to its shadow table:
jbe@130 659 lua_replace(L, -2);
jbe@137 660 // get "next value" using the "path key":
jbe@130 661 lua_pushvalue(L, idx++);
jbe@130 662 lua_rawget(L, -2);
jbe@126 663 }
jbe@137 664 // the "next value" replaces the "current value":
jbe@130 665 lua_replace(L, -2);
jbe@126 666 }
jbe@137 667 if (!type_mode) {
jbe@137 668 // if a value (and not its type) was requested,
jbe@137 669 // check if value is the null-marker, and store nil on top of Lua stack in that case:
jbe@155 670 if (json_isnullmark(L, -1)) lua_pushnil(L);
jbe@137 671 } else {
jbe@137 672 // if the type was requested,
jbe@137 673 // check if value is the null-marker:
jbe@155 674 if (json_isnullmark(L, -1)) {
jbe@137 675 // if yes, store string "null" on top of Lua stack:
jbe@130 676 lua_pushliteral(L, "null");
jbe@137 677 } else {
jbe@137 678 // otherwise,
jbe@138 679 // check if metatable indicates "object" or "array":
jbe@138 680 if (lua_getmetatable(L, -1)) {
jbe@144 681 json_regfetch(L, objectmt);
jbe@138 682 if (lua_rawequal(L, -2, -1)) {
jbe@146 683 // if value has metatable for JSON objects,
jbe@138 684 // return string "object":
jbe@138 685 lua_pushliteral(L, "object");
jbe@138 686 return 1;
jbe@138 687 }
jbe@144 688 json_regfetch(L, arraymt);
jbe@138 689 if (lua_rawequal(L, -3, -1)) {
jbe@146 690 // if value has metatable for JSON arrays,
jbe@146 691 // return string "object":
jbe@138 692 lua_pushliteral(L, "array");
jbe@138 693 return 1;
jbe@138 694 }
jbe@146 695 // remove 3 metatables (one of the value, two for comparison) from stack:
jbe@138 696 lua_pop(L, 3);
jbe@138 697 }
jbe@138 698 // otherwise, get the Lua type:
jbe@138 699 lua_pushstring(L, lua_typename(L, lua_type(L, -1)));
jbe@126 700 }
jbe@126 701 }
jbe@137 702 // return the top most value on the Lua stack:
jbe@137 703 return 1;
jbe@130 704 }
jbe@130 705
jbe@147 706 // gets a value from a JSON document (passed as first argument)
jbe@175 707 // using a path (passed as variable number of keys after the first argument):
jbe@130 708 static int json_get(lua_State *L) {
jbe@137 709 return json_path(L, 0);
jbe@130 710 }
jbe@130 711
jbe@147 712 // gets a value's type from a JSON document (passed as first argument)
jbe@175 713 // using a path (passed as variable number of keys after first the argument):
jbe@130 714 static int json_type(lua_State *L) {
jbe@137 715 return json_path(L, 1);
jbe@130 716 }
jbe@130 717
jbe@173 718 // special Lua stack indicies for json_set function:
jbe@173 719 #define json_set_shadowtbl_idx 1
jbe@173 720 #define json_set_objectmt_idx 2
jbe@173 721 #define json_set_arraymt_idx 3
jbe@173 722
jbe@173 723 // stack offset of arguments to json_set function:
jbe@173 724 #define json_set_idxshift 3
jbe@173 725
jbe@173 726 // sets a value (passed as second argument) in a JSON document (passed as first argument)
jbe@175 727 // using a path (passed as variable number of keys starting at third argument):
jbe@173 728 static int json_set(lua_State *L) {
jbe@173 729 int stacktop; // stack index of top of stack (after shifting)
jbe@173 730 int idx = 3; // stack index of current argument to process
jbe@173 731 // require at least two arguments:
jbe@173 732 luaL_checkany(L, 1);
jbe@173 733 luaL_checkany(L, 2);
jbe@173 734 // insert shadowtbl into stack at position 1 (shifting the arguments):
jbe@173 735 json_regfetch(L, shadowtbl);
jbe@173 736 lua_insert(L, 1);
jbe@173 737 // insert objectmt into stack at position 2 (shifting the arguments):
jbe@173 738 json_regfetch(L, objectmt);
jbe@173 739 lua_insert(L, 2);
jbe@173 740 // insert arraymt into stack at position 3 (shifting the arguments):
jbe@173 741 json_regfetch(L, arraymt);
jbe@173 742 lua_insert(L, 3);
jbe@173 743 // store stack index of top of stack:
jbe@173 744 stacktop = lua_gettop(L);
jbe@173 745 // use nil as initial "parent value":
jbe@173 746 lua_pushnil(L);
jbe@173 747 // use first argument as "current value":
jbe@173 748 lua_pushvalue(L, 1 + json_set_idxshift);
jbe@173 749 // set all necessary values in path:
jbe@173 750 for (idx = 3 + json_set_idxshift; idx<=stacktop; idx++) {
jbe@173 751 // push metatable of "current value" onto stack:
jbe@173 752 if (!lua_getmetatable(L, -1)) lua_pushnil(L);
jbe@173 753 // distinguish according to type of path key:
jbe@173 754 switch (lua_type(L, idx)) {
jbe@173 755 case LUA_TSTRING:
jbe@173 756 // if path key is a string,
jbe@173 757 // check if "current value" is a JSON object (or table without metatable):
jbe@173 758 if (
jbe@173 759 lua_rawequal(L, -1, json_set_objectmt_idx) ||
jbe@173 760 (lua_isnil(L, -1) && lua_type(L, -2) == LUA_TTABLE)
jbe@173 761 ) {
jbe@173 762 // if "current value" is acceptable,
jbe@173 763 // pop metatable and leave "current value" on top of stack:
jbe@173 764 lua_pop(L, 1);
jbe@173 765 } else {
jbe@173 766 // if "current value" is not acceptable:
jbe@173 767 // pop metatable and "current value":
jbe@173 768 lua_pop(L, 2);
jbe@173 769 // throw error if parent element does not exist:
jbe@173 770 if (lua_isnil(L, -1)) return luaL_error(L, "Root element is not a JSON object");
jbe@173 771 // push new JSON object as "current value" onto stack:
jbe@173 772 lua_newtable(L);
jbe@173 773 // create and register shadow table:
jbe@173 774 lua_pushvalue(L, -1);
jbe@173 775 lua_newtable(L);
jbe@173 776 lua_rawset(L, json_set_shadowtbl_idx);
jbe@173 777 // set metatable of JSON object:
jbe@173 778 lua_pushvalue(L, json_set_objectmt_idx);
jbe@173 779 lua_setmetatable(L, -2);
jbe@173 780 // set entry in "parent value":
jbe@173 781 lua_pushvalue(L, idx-1);
jbe@173 782 lua_pushvalue(L, -2);
jbe@173 783 lua_settable(L, -4);
jbe@173 784 }
jbe@173 785 break;
jbe@173 786 case LUA_TNUMBER:
jbe@173 787 // if path key is a number,
jbe@173 788 // check if "current value" is a JSON array (or table without metatable):
jbe@173 789 if (
jbe@173 790 lua_rawequal(L, -1, json_set_arraymt_idx) ||
jbe@173 791 (lua_isnil(L, -1) && lua_type(L, -2) == LUA_TTABLE)
jbe@173 792 ) {
jbe@173 793 // if "current value" is acceptable,
jbe@173 794 // pop metatable and leave "current value" on top of stack:
jbe@173 795 lua_pop(L, 1);
jbe@173 796 } else {
jbe@173 797 // if "current value" is not acceptable:
jbe@173 798 // pop metatable and "current value":
jbe@173 799 lua_pop(L, 2);
jbe@173 800 // throw error if parent element does not exist:
jbe@173 801 if (lua_isnil(L, -1)) return luaL_error(L, "Root element is not a JSON array");
jbe@173 802 // push new JSON array as "current value" onto stack:
jbe@173 803 lua_newtable(L);
jbe@173 804 // create and register shadow table:
jbe@173 805 lua_pushvalue(L, -1);
jbe@173 806 lua_newtable(L);
jbe@173 807 lua_rawset(L, json_set_shadowtbl_idx);
jbe@173 808 // set metatable of JSON array:
jbe@173 809 lua_pushvalue(L, json_set_arraymt_idx);
jbe@173 810 lua_setmetatable(L, -2);
jbe@173 811 // set entry in "parent value":
jbe@173 812 lua_pushvalue(L, idx-1);
jbe@173 813 lua_pushvalue(L, -2);
jbe@173 814 lua_settable(L, -4);
jbe@173 815 }
jbe@173 816 break;
jbe@173 817 default:
jbe@173 818 return luaL_error(L, "Invalid path key of type %s", lua_typename(L, lua_type(L, idx)));
jbe@173 819 }
jbe@173 820 // check if last path element is being processed:
jbe@173 821 if (idx == stacktop) {
jbe@173 822 // if the last path element is being processed,
jbe@173 823 // set last path value in "current value" container:
jbe@173 824 lua_pushvalue(L, idx);
jbe@173 825 lua_pushvalue(L, 2 + json_set_idxshift);
jbe@173 826 lua_settable(L, -3);
jbe@173 827 } else {
jbe@173 828 // if the processed path element is not the last,
jbe@173 829 // use old "current value" as new "parent value"
jbe@173 830 lua_remove(L, -2);
jbe@173 831 // push new "current value" onto stack by performing a lookup:
jbe@173 832 lua_pushvalue(L, idx);
jbe@173 833 lua_gettable(L, -2);
jbe@173 834 }
jbe@173 835 }
jbe@173 836 // return first argument for convenience:
jbe@173 837 lua_settop(L, 1 + json_set_idxshift);
jbe@173 838 return 1;
jbe@173 839 }
jbe@173 840
jbe@147 841 // returns the length of a JSON array (or zero for a table without numeric keys):
jbe@130 842 static int json_len(lua_State *L) {
jbe@147 843 // stack shall contain one function argument:
jbe@130 844 lua_settop(L, 1);
jbe@148 845 // try to get corresponding shadow table for first argument:
jbe@144 846 json_regfetch(L, shadowtbl);
jbe@130 847 lua_pushvalue(L, 1);
jbe@138 848 lua_rawget(L, -2);
jbe@147 849 // if shadow table does not exist, return length of argument, else length of shadow table:
jbe@147 850 lua_pushnumber(L, lua_rawlen(L, lua_isnil(L, -1) ? 1 : -1));
jbe@123 851 return 1;
jbe@123 852 }
jbe@123 853
jbe@175 854 // __index metamethod for JSON objects and JSON arrays:
jbe@130 855 static int json_index(lua_State *L) {
jbe@148 856 // stack shall contain two function arguments:
jbe@130 857 lua_settop(L, 2);
jbe@155 858 // get corresponding shadow table for first argument:
jbe@144 859 json_regfetch(L, shadowtbl);
jbe@130 860 lua_pushvalue(L, 1);
jbe@155 861 lua_rawget(L, -2);
jbe@148 862 // throw error if no shadow table was found:
jbe@139 863 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
jbe@148 864 // use key passed as second argument to lookup value in shadow table:
jbe@130 865 lua_pushvalue(L, 2);
jbe@130 866 lua_rawget(L, -2);
jbe@148 867 // if value is null-marker, then push nil onto stack:
jbe@155 868 if (json_isnullmark(L, -1)) lua_pushnil(L);
jbe@148 869 // return either looked up value, or nil
jbe@127 870 return 1;
jbe@127 871 }
jbe@127 872
jbe@175 873 // __newindex metamethod for JSON objects and JSON arrays:
jbe@130 874 static int json_newindex(lua_State *L) {
jbe@148 875 // stack shall contain three function arguments:
jbe@130 876 lua_settop(L, 3);
jbe@148 877 // get corresponding shadow table for first argument:
jbe@144 878 json_regfetch(L, shadowtbl);
jbe@123 879 lua_pushvalue(L, 1);
jbe@143 880 lua_rawget(L, -2);
jbe@148 881 // throw error if no shadow table was found:
jbe@130 882 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
jbe@148 883 // replace first argument with shadow table:
jbe@130 884 lua_replace(L, 1);
jbe@148 885 // reset stack and use second and third argument to write to shadow table:
jbe@139 886 lua_settop(L, 3);
jbe@130 887 lua_rawset(L, 1);
jbe@148 888 // return nothing:
jbe@148 889 return 0;
jbe@121 890 }
jbe@121 891
jbe@175 892 // function returned as first value by json_pairs function:
jbe@135 893 static int json_pairs_iterfunc(lua_State *L) {
jbe@149 894 // stack shall contain two function arguments:
jbe@135 895 lua_settop(L, 2);
jbe@155 896 // get corresponding shadow table for first argument:
jbe@144 897 json_regfetch(L, shadowtbl);
jbe@135 898 lua_pushvalue(L, 1);
jbe@155 899 lua_rawget(L, -2);
jbe@149 900 // throw error if no shadow table was found:
jbe@135 901 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
jbe@149 902 // get next key value pair from shadow table (using previous key from argument 2)
jbe@149 903 // and return nothing if there is no next pair:
jbe@135 904 lua_pushvalue(L, 2);
jbe@135 905 if (!lua_next(L, -2)) return 0;
jbe@149 906 // replace null-marker with nil:
jbe@155 907 if (json_isnullmark(L, -1)) {
jbe@135 908 lua_pop(L, 1);
jbe@135 909 lua_pushnil(L);
jbe@135 910 }
jbe@149 911 // return key and value (or key and nil, if null-marker was found):
jbe@135 912 return 2;
jbe@135 913 }
jbe@135 914
jbe@149 915 // returns a triple such that 'for key, value in pairs(obj) do ... end'
jbe@175 916 // iterates through all key value pairs (including JSON null values represented as Lua nil):
jbe@135 917 static int json_pairs(lua_State *L) {
jbe@172 918 // require one argument to function
jbe@172 919 luaL_checkany(L, 1);
jbe@149 920 // return triple of function json_pairs_iterfunc, first argument, and nil:
jbe@139 921 lua_pushcfunction(L, json_pairs_iterfunc);
jbe@135 922 lua_pushvalue(L, 1);
jbe@135 923 lua_pushnil(L);
jbe@135 924 return 3;
jbe@135 925 }
jbe@135 926
jbe@175 927 // function returned as first value by json_ipairs function:
jbe@134 928 static int json_ipairs_iterfunc(lua_State *L) {
jbe@152 929 lua_Integer idx;
jbe@149 930 // stack shall contain two function arguments:
jbe@134 931 lua_settop(L, 2);
jbe@149 932 // calculate new index by incrementing second argument:
jbe@134 933 idx = lua_tointeger(L, 2) + 1;
jbe@149 934 // get corresponding shadow table for first argument:
jbe@155 935 json_regfetch(L, shadowtbl);
jbe@134 936 lua_pushvalue(L, 1);
jbe@155 937 lua_rawget(L, -2);
jbe@149 938 // throw error if no shadow table was found:
jbe@134 939 if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
jbe@149 940 // do integer lookup in shadow table:
jbe@134 941 lua_rawgeti(L, -1, idx);
jbe@149 942 // return nothing if there was no value:
jbe@134 943 if (lua_isnil(L, -1)) return 0;
jbe@149 944 // return new index and
jbe@149 945 // either the looked up value if it is not equal to the null-marker
jbe@149 946 // or nil instead of null-marker:
jbe@134 947 lua_pushinteger(L, idx);
jbe@155 948 if (json_isnullmark(L, -2)) lua_pushnil(L);
jbe@134 949 else lua_pushvalue(L, -2);
jbe@134 950 return 2;
jbe@134 951 }
jbe@134 952
jbe@149 953 // returns a triple such that 'for idx, value in ipairs(ary) do ... end'
jbe@175 954 // iterates through all values (including JSON null values represented as Lua nil):
jbe@134 955 static int json_ipairs(lua_State *L) {
jbe@172 956 // require one argument to function
jbe@172 957 luaL_checkany(L, 1);
jbe@149 958 // return triple of function json_ipairs_iterfunc, first argument, and zero:
jbe@139 959 lua_pushcfunction(L, json_ipairs_iterfunc);
jbe@134 960 lua_pushvalue(L, 1);
jbe@134 961 lua_pushinteger(L, 0);
jbe@134 962 return 3;
jbe@134 963 }
jbe@134 964
jbe@175 965 // datatype representing a table key:
jbe@175 966 // (used for sorting)
jbe@163 967 typedef struct {
jbe@163 968 size_t length;
jbe@163 969 const char *data;
jbe@163 970 } json_key_t;
jbe@163 971
jbe@175 972 // comparation function for table keys to be passed to qsort function:
jbe@163 973 static int json_key_cmp(json_key_t *key1, json_key_t *key2) {
jbe@163 974 size_t pos = 0;
jbe@163 975 unsigned char c1, c2;
jbe@163 976 while (1) {
jbe@163 977 if (key1->length > pos) {
jbe@163 978 if (key2->length > pos) {
jbe@163 979 c1 = key1->data[pos];
jbe@163 980 c2 = key2->data[pos];
jbe@163 981 if (c1 < c2) return -1;
jbe@163 982 else if (c1 > c2) return 1;
jbe@163 983 } else {
jbe@163 984 return 1;
jbe@163 985 }
jbe@163 986 } else {
jbe@163 987 if (key2->length > pos) {
jbe@163 988 return -1;
jbe@163 989 } else {
jbe@163 990 return 0;
jbe@163 991 }
jbe@163 992 }
jbe@163 993 pos++;
jbe@163 994 }
jbe@163 995 }
jbe@163 996
jbe@175 997 // constants for type detection of ambiguous tables:
jbe@154 998 #define JSON_TABLETYPE_UNKNOWN 0
jbe@154 999 #define JSON_TABLETYPE_OBJECT 1
jbe@154 1000 #define JSON_TABLETYPE_ARRAY 2
jbe@154 1001
jbe@175 1002 // special Lua stack indicies for json_export_internal function:
jbe@164 1003 #define json_export_internal_indentstring_idx 1
jbe@164 1004 #define json_export_internal_level_idx 2
jbe@164 1005 #define json_export_internal_value_idx 3
jbe@164 1006 #define json_export_internal_tmp_idx 4
jbe@164 1007
jbe@175 1008 // encodes a JSON document (passed as third argument)
jbe@175 1009 // optionally using indentation (indentation string passed as first argument)
jbe@175 1010 // for a certain depth level (passed as second argument):
jbe@164 1011 static int json_export_internal(lua_State *L) {
jbe@175 1012 int level; // current depth level
jbe@175 1013 int pretty; // pretty printing on? (i.e. printing with indentation)
jbe@175 1014 int i; // iteration variable for level dependent repetitions:
jbe@175 1015 lua_Number num; // number to encode
jbe@175 1016 const char *str; // string to encode
jbe@175 1017 size_t strlen; // length of string to encode
jbe@175 1018 unsigned char c; // character to encode (unsigned!)
jbe@175 1019 size_t pos = 0; // position in string or position of current key (initialized with zero!)
jbe@175 1020 luaL_Buffer buf; // Lua buffer to create strings
jbe@175 1021 char hexcode[7]; // store for unicode hex escape sequence
jbe@175 1022 // NOTE: 7 bytes due to backslash, character 'u', 4 hex digits, and terminating NULL byte
jbe@175 1023 int tabletype = JSON_TABLETYPE_UNKNOWN; // table type: unknown, JSON object, or JSON array
jbe@175 1024 int anyelement = 0; // set to 1 if at least one array element has been processed
jbe@175 1025 size_t keycount = 0; // number of string keys in object
jbe@175 1026 json_key_t *keybuf = NULL; // temporary buffer to store (and sort) string keys of objects
jbe@175 1027 lua_Integer arrayidx; // index to iterate through arrays
jbe@175 1028 // stack shall contain three function arguments:
jbe@164 1029 lua_settop(L, json_export_internal_value_idx);
jbe@175 1030 // if value to encode is the null-marker, then treat it the same as nil:
jbe@164 1031 if (json_isnullmark(L, json_export_internal_value_idx)) {
jbe@164 1032 lua_pop(L, 1);
jbe@157 1033 lua_pushnil(L);
jbe@157 1034 }
jbe@175 1035 // distinguish between different Lua types:
jbe@164 1036 switch (lua_type(L, json_export_internal_value_idx)) {
jbe@175 1037 // value to encode is nil:
jbe@154 1038 case LUA_TNIL:
jbe@175 1039 // return string "null":
jbe@154 1040 lua_pushliteral(L, "null");
jbe@154 1041 return 1;
jbe@175 1042 // value to encode is of type number:
jbe@154 1043 case LUA_TNUMBER:
jbe@175 1044 // convert value to double precision number:
jbe@164 1045 num = lua_tonumber(L, json_export_internal_value_idx);
jbe@175 1046 // throw error if number is not-a-number:
jbe@154 1047 if (isnan(num)) return luaL_error(L, "JSON export not possible for NaN value");
jbe@175 1048 // throw error if number is positive or negative infinity:
jbe@154 1049 if (isinf(num)) return luaL_error(L, "JSON export not possible for infinite numbers");
jbe@175 1050 // return Lua's string encoding of the number:
jbe@164 1051 lua_tostring(L, json_export_internal_value_idx);
jbe@154 1052 return 1;
jbe@175 1053 // value to encode is of type boolean:
jbe@154 1054 case LUA_TBOOLEAN:
jbe@175 1055 // return string "true" or "false" according to boolean value:
jbe@164 1056 if (lua_toboolean(L, json_export_internal_value_idx)) {
jbe@164 1057 lua_pushliteral(L, "true");
jbe@164 1058 } else {
jbe@164 1059 lua_pushliteral(L, "false");
jbe@164 1060 }
jbe@154 1061 return 1;
jbe@175 1062 // value to encode is of type string:
jbe@154 1063 case LUA_TSTRING:
jbe@175 1064 // quote, escape and return string:
jbe@164 1065 str = lua_tolstring(L, 3, &strlen);
jbe@154 1066 luaL_buffinit(L, &buf);
jbe@154 1067 luaL_addchar(&buf, '"');
jbe@154 1068 while (pos < strlen) {
jbe@154 1069 c = str[pos++];
jbe@154 1070 if (c == '"') luaL_addstring(&buf, "\\\"");
jbe@154 1071 else if (c == '\\') luaL_addstring(&buf, "\\\\");
jbe@154 1072 else if (c == 127) luaL_addstring(&buf, "\\u007F");
jbe@154 1073 else if (c >= 32) luaL_addchar(&buf, c);
jbe@154 1074 else if (c == '\b') luaL_addstring(&buf, "\\b");
jbe@154 1075 else if (c == '\f') luaL_addstring(&buf, "\\f");
jbe@154 1076 else if (c == '\n') luaL_addstring(&buf, "\\n");
jbe@154 1077 else if (c == '\r') luaL_addstring(&buf, "\\r");
jbe@154 1078 else if (c == '\t') luaL_addstring(&buf, "\\t");
jbe@154 1079 else if (c == '\v') luaL_addstring(&buf, "\\v");
jbe@154 1080 else {
jbe@154 1081 sprintf(hexcode, "\\u%04X", c);
jbe@154 1082 luaL_addstring(&buf, hexcode);
jbe@154 1083 }
jbe@154 1084 }
jbe@154 1085 luaL_addchar(&buf, '"');
jbe@154 1086 luaL_pushresult(&buf);
jbe@154 1087 return 1;
jbe@175 1088 // value to encode is of type table (this includes JSON objects and JSON arrays):
jbe@154 1089 case LUA_TTABLE:
jbe@175 1090 // use table's metatable to try to determine type of table:
jbe@164 1091 if (lua_getmetatable(L, json_export_internal_value_idx)) {
jbe@154 1092 json_regfetch(L, objectmt);
jbe@154 1093 if (lua_rawequal(L, -2, -1)) {
jbe@154 1094 tabletype = JSON_TABLETYPE_OBJECT;
jbe@154 1095 } else {
jbe@154 1096 json_regfetch(L, arraymt);
jbe@164 1097 if (lua_rawequal(L, -3, -1)) {
jbe@164 1098 tabletype = JSON_TABLETYPE_ARRAY;
jbe@164 1099 } else {
jbe@164 1100 return luaL_error(L, "JSON export not possible for tables with nonsupported metatable");
jbe@164 1101 }
jbe@154 1102 }
jbe@154 1103 }
jbe@175 1104 // replace table with its shadow table if existent, and reset stack:
jbe@154 1105 json_regfetch(L, shadowtbl);
jbe@164 1106 lua_pushvalue(L, json_export_internal_value_idx);
jbe@154 1107 lua_rawget(L, -2);
jbe@164 1108 if (!lua_isnil(L, -1)) lua_replace(L, json_export_internal_value_idx);
jbe@164 1109 lua_settop(L, json_export_internal_value_idx);
jbe@175 1110 // check if type of table is still undetermined:
jbe@154 1111 if (tabletype == JSON_TABLETYPE_UNKNOWN) {
jbe@175 1112 // if yes, iterate over all keys:
jbe@164 1113 for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
jbe@164 1114 switch (lua_type(L, -2)) {
jbe@164 1115 case LUA_TSTRING:
jbe@175 1116 // for string keys,
jbe@175 1117 // increase keycount (may avoid another iteration):
jbe@164 1118 keycount++;
jbe@175 1119 // if type of table was unknown, then type of table is a JSON object now:
jbe@164 1120 if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_OBJECT;
jbe@175 1121 // if type of table was a JSON array, then the type of table is ambiguous now
jbe@175 1122 // and an error is thrown:
jbe@164 1123 else if (tabletype == JSON_TABLETYPE_ARRAY) goto json_export_tabletype_error;
jbe@164 1124 break;
jbe@164 1125 case LUA_TNUMBER:
jbe@175 1126 // for numeric keys,
jbe@175 1127 // if type of table was unknown, then type of table is a JSON array now:
jbe@164 1128 if (tabletype == JSON_TABLETYPE_UNKNOWN) tabletype = JSON_TABLETYPE_ARRAY;
jbe@175 1129 // if type of table was a JSON object, then the type of table is ambiguous now
jbe@175 1130 // and an error is thrown:
jbe@164 1131 else if (tabletype == JSON_TABLETYPE_OBJECT) goto json_export_tabletype_error;
jbe@164 1132 break;
jbe@154 1133 }
jbe@154 1134 }
jbe@154 1135 }
jbe@175 1136 // set pretty variable to 1 if pretty printing (with indentation) is desired:
jbe@164 1137 pretty = lua_toboolean(L, json_export_internal_indentstring_idx);
jbe@175 1138 // set level variable to corresponding function argument increased by one:
jbe@164 1139 level = lua_tointeger(L, json_export_internal_level_idx) + 1;
jbe@175 1140 // throw error if there are more levels that could be imported by this library:
jbe@164 1141 if (level > JSON_MAXDEPTH) {
jbe@164 1142 return luaL_error(L, "More than %d nested JSON levels", JSON_MAXDEPTH);
jbe@164 1143 }
jbe@175 1144 // distinguish between JSON objects and JSON arrays:
jbe@154 1145 switch (tabletype) {
jbe@175 1146 // JSON object:
jbe@154 1147 case JSON_TABLETYPE_OBJECT:
jbe@175 1148 // calculate count of string keys unless it has been calculated before:
jbe@164 1149 if (!keycount) {
jbe@164 1150 for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
jbe@164 1151 if (lua_type(L, -2) == LUA_TSTRING) keycount++;
jbe@164 1152 }
jbe@163 1153 }
jbe@175 1154 // create a sorted list of all string keys in memory:
jbe@163 1155 if (keycount) {
jbe@175 1156 // allocate memory for string keys:
jbe@163 1157 keybuf = calloc(keycount, sizeof(json_key_t));
jbe@175 1158 // check if memory allocation was successful:
jbe@175 1159 if (!keybuf) {
jbe@175 1160 // in case of memory exhaustion, try to collect garbage:
jbe@175 1161 lua_gc(L, LUA_GCCOLLECT, 0);
jbe@175 1162 // try to allocate memory again:
jbe@175 1163 keybuf = calloc(keycount, sizeof(json_key_t));
jbe@175 1164 // throw error if memory allocation failed again:
jbe@175 1165 if (!keybuf) {
jbe@175 1166 return luaL_error(L, "Memory allocation failed in JSON library");
jbe@175 1167 }
jbe@175 1168 }
jbe@175 1169 // copy all string keys to the C array:
jbe@164 1170 for (lua_pushnil(L); lua_next(L, json_export_internal_value_idx); lua_pop(L, 1)) {
jbe@163 1171 if (lua_type(L, -2) == LUA_TSTRING) {
jbe@175 1172 json_key_t *key = keybuf + (pos++);
jbe@163 1173 key->data = lua_tolstring(L, -2, &key->length);
jbe@163 1174 }
jbe@163 1175 }
jbe@175 1176 // sort C array using quicksort:
jbe@163 1177 qsort(keybuf, keycount, sizeof(json_key_t), (void *)json_key_cmp);
jbe@163 1178 }
jbe@175 1179 // create Lua string buffer:
jbe@154 1180 luaL_buffinit(L, &buf);
jbe@175 1181 // add opening bracket to output buffer:
jbe@154 1182 luaL_addchar(&buf, '{');
jbe@175 1183 // iterate through all (sorted) string keys:
jbe@175 1184 for (pos=0; pos<keycount; pos++) {
jbe@175 1185 json_key_t *key = keybuf + pos;
jbe@175 1186 // add comma to output buffer unless we process the first key:
jbe@175 1187 if (pos) luaL_addchar(&buf, ',');
jbe@175 1188 // handle indentation for pretty results:
jbe@164 1189 if (pretty) {
jbe@164 1190 luaL_addchar(&buf, '\n');
jbe@164 1191 for (i=0; i<level; i++) {
jbe@164 1192 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1193 luaL_addvalue(&buf);
jbe@164 1194 }
jbe@164 1195 }
jbe@175 1196 // recursive call to encode key:
jbe@164 1197 lua_pushcfunction(L, json_export_internal);
jbe@164 1198 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1199 lua_pushinteger(L, level);
jbe@163 1200 lua_pushlstring(L, key->data, key->length);
jbe@164 1201 if (lua_pcall(L, 3, 1, 0)) {
jbe@175 1202 // free memory of sorted string keys on error:
jbe@163 1203 if (keybuf) free(keybuf);
jbe@175 1204 // rethrow error:
jbe@163 1205 return lua_error(L);
jbe@154 1206 }
jbe@175 1207 // add encoded key to output buffer:
jbe@163 1208 luaL_addvalue(&buf);
jbe@175 1209 // add colon to output buffer:
jbe@163 1210 luaL_addchar(&buf, ':');
jbe@175 1211 // handle indentation for pretty results:
jbe@164 1212 if (pretty) luaL_addchar(&buf, ' ');
jbe@175 1213 // recursive call to encode value:
jbe@164 1214 lua_pushcfunction(L, json_export_internal);
jbe@164 1215 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1216 lua_pushinteger(L, level);
jbe@163 1217 lua_pushlstring(L, key->data, key->length);
jbe@164 1218 lua_rawget(L, json_export_internal_value_idx);
jbe@164 1219 if (lua_pcall(L, 3, 1, 0)) {
jbe@175 1220 // free memory of sorted string keys on error:
jbe@163 1221 if (keybuf) free(keybuf);
jbe@175 1222 // rethrow error:
jbe@163 1223 return lua_error(L);
jbe@163 1224 }
jbe@175 1225 // add encoded value to output buffer:
jbe@163 1226 luaL_addvalue(&buf);
jbe@154 1227 }
jbe@175 1228 // decrement level variable for all following statements:
jbe@175 1229 level--;
jbe@175 1230 // free memory of sorted string keys:
jbe@163 1231 if (keybuf) free(keybuf);
jbe@175 1232 // handle indentation for pretty results:
jbe@164 1233 if (pretty && keycount != 0) {
jbe@164 1234 luaL_addchar(&buf, '\n');
jbe@175 1235 for (i=0; i<level; i++) {
jbe@164 1236 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1237 luaL_addvalue(&buf);
jbe@164 1238 }
jbe@164 1239 }
jbe@175 1240 // add closing bracket to output buffer:
jbe@154 1241 luaL_addchar(&buf, '}');
jbe@175 1242 // for pretty results, add final newline character if outermost container is processed:
jbe@175 1243 if (pretty && level == 0) luaL_addchar(&buf, '\n');
jbe@175 1244 // convert and return buffer:
jbe@154 1245 luaL_pushresult(&buf);
jbe@154 1246 return 1;
jbe@175 1247 // JSON array:
jbe@154 1248 case JSON_TABLETYPE_ARRAY:
jbe@175 1249 // reserve an extra element on the stack (needed because Lua buffer has unknown size on stack):
jbe@164 1250 lua_settop(L, json_export_internal_tmp_idx);
jbe@175 1251 // create Lua string buffer:
jbe@154 1252 luaL_buffinit(L, &buf);
jbe@175 1253 // add opening bracket to output buffer:
jbe@154 1254 luaL_addchar(&buf, '[');
jbe@175 1255 // iterate through integer keys:
jbe@175 1256 for (arrayidx = 1; ; arrayidx++) {
jbe@175 1257 // get value in array, and break if nil:
jbe@175 1258 lua_rawgeti(L, json_export_internal_value_idx, arrayidx);
jbe@154 1259 if (lua_isnil(L, -1)) {
jbe@154 1260 lua_pop(L, 1);
jbe@154 1261 break;
jbe@154 1262 }
jbe@175 1263 // store value below Lua string buffer on stack (to allow operation on string buffer):
jbe@164 1264 lua_replace(L, json_export_internal_tmp_idx);
jbe@175 1265 //
jbe@175 1266 // add comma to output buffer unless we process the first element:
jbe@164 1267 if (anyelement) luaL_addchar(&buf, ',');
jbe@175 1268 // remember that we processed an element:
jbe@164 1269 anyelement = 1;
jbe@175 1270 // handle indentation for pretty results:
jbe@164 1271 if (pretty) {
jbe@164 1272 luaL_addchar(&buf, '\n');
jbe@164 1273 for (i=0; i<level; i++) {
jbe@164 1274 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1275 luaL_addvalue(&buf);
jbe@164 1276 }
jbe@164 1277 }
jbe@175 1278 // recursive call to encode previously stored value:
jbe@164 1279 lua_pushcfunction(L, json_export_internal);
jbe@164 1280 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1281 lua_pushinteger(L, level);
jbe@164 1282 lua_pushvalue(L, json_export_internal_tmp_idx);
jbe@164 1283 lua_call(L, 3, 1);
jbe@175 1284 // add encoded value to output buffer:
jbe@154 1285 luaL_addvalue(&buf);
jbe@154 1286 }
jbe@175 1287 // decrement level variable for all following statements:
jbe@175 1288 level--;
jbe@175 1289 // handle indentation for pretty results:
jbe@164 1290 if (pretty && anyelement) {
jbe@164 1291 luaL_addchar(&buf, '\n');
jbe@175 1292 for (i=0; i<level; i++) {
jbe@164 1293 lua_pushvalue(L, json_export_internal_indentstring_idx);
jbe@164 1294 luaL_addvalue(&buf);
jbe@164 1295 }
jbe@164 1296 }
jbe@175 1297 // add closing bracket to output buffer:
jbe@154 1298 luaL_addchar(&buf, ']');
jbe@175 1299 // for pretty results, add final newline character if outermost container is processed:
jbe@175 1300 if (pretty && level == 0) luaL_addchar(&buf, '\n');
jbe@175 1301 // convert and return buffer:
jbe@154 1302 luaL_pushresult(&buf);
jbe@154 1303 return 1;
jbe@154 1304 }
jbe@175 1305 // throw error if table type is unknown:
jbe@154 1306 json_export_tabletype_error:
jbe@154 1307 return luaL_error(L, "JSON export not possible for ambiguous table (cannot decide whether it is an object or array)");
jbe@154 1308 }
jbe@175 1309 // all other datatypes are considered an error:
jbe@166 1310 return luaL_error(L, "JSON export not possible for values of type \"%s\"", lua_typename(L, lua_type(L, json_export_internal_value_idx)));
jbe@154 1311 }
jbe@154 1312
jbe@175 1313 // encodes a JSON document (passed as argument):
jbe@164 1314 static int json_export(lua_State *L) {
jbe@175 1315 // stack shall contain one function argument:
jbe@164 1316 lua_settop(L, 1);
jbe@175 1317 // call json_export_internal function with proper arguments:
jbe@164 1318 lua_pushcfunction(L, json_export_internal);
jbe@164 1319 lua_pushnil(L);
jbe@164 1320 lua_pushinteger(L, 0);
jbe@164 1321 lua_pushvalue(L, 1);
jbe@164 1322 lua_call(L, 3, 1);
jbe@175 1323 // return result:
jbe@164 1324 return 1;
jbe@164 1325 }
jbe@164 1326
jbe@175 1327 // encodes a JSON document (passed as first argument)
jbe@175 1328 // with indentation (indentation string may be passed as second argument):
jbe@164 1329 static int json_pretty(lua_State *L) {
jbe@175 1330 // stack shall contain two function arguments:
jbe@164 1331 lua_settop(L, 2);
jbe@175 1332 // call json_export_internal function with proper arguments:
jbe@164 1333 lua_pushcfunction(L, json_export_internal);
jbe@164 1334 if (lua_isnil(L, 2)) lua_pushliteral(L, " ");
jbe@164 1335 else lua_pushvalue(L, 2);
jbe@164 1336 lua_pushinteger(L, 0);
jbe@164 1337 lua_pushvalue(L, 1);
jbe@164 1338 lua_call(L, 3, 1);
jbe@175 1339 // return result:
jbe@164 1340 return 1;
jbe@164 1341 }
jbe@164 1342
jbe@149 1343 // functions in library module:
jbe@121 1344 static const struct luaL_Reg json_module_functions[] = {
jbe@133 1345 {"object", json_object},
jbe@173 1346 {"array", json_array},
jbe@121 1347 {"import", json_import},
jbe@154 1348 {"export", json_export},
jbe@164 1349 {"pretty", json_pretty},
jbe@173 1350 {"get", json_get},
jbe@173 1351 {"type", json_type},
jbe@173 1352 {"set", json_set},
jbe@121 1353 {NULL, NULL}
jbe@121 1354 };
jbe@121 1355
jbe@149 1356 // metamethods for JSON objects, JSON arrays, and unknown JSON collections (object or array):
jbe@126 1357 static const struct luaL_Reg json_metatable_functions[] = {
jbe@130 1358 {"__len", json_len},
jbe@130 1359 {"__index", json_index},
jbe@130 1360 {"__newindex", json_newindex},
jbe@135 1361 {"__pairs", json_pairs},
jbe@134 1362 {"__ipairs", json_ipairs},
jbe@160 1363 {"__tostring", json_export},
jbe@126 1364 {NULL, NULL}
jbe@126 1365 };
jbe@126 1366
jbe@157 1367 // metamethods for JSON null marker:
jbe@157 1368 static const struct luaL_Reg json_nullmark_metamethods[] = {
jbe@157 1369 {"__tostring", json_nullmark_tostring},
jbe@157 1370 {NULL, NULL}
jbe@157 1371 };
jbe@157 1372
jbe@149 1373 // initializes json library:
jbe@121 1374 int luaopen_json(lua_State *L) {
jbe@149 1375 // empty stack:
jbe@126 1376 lua_settop(L, 0);
jbe@149 1377 // push library module onto stack position 1:
jbe@149 1378 lua_newtable(L);
jbe@149 1379 // register library functions:
jbe@149 1380 luaL_setfuncs(L, json_module_functions, 0);
jbe@149 1381 // create and store objectmt:
jbe@138 1382 lua_newtable(L);
jbe@138 1383 luaL_setfuncs(L, json_metatable_functions, 0);
jbe@144 1384 json_regstore(L, objectmt);
jbe@149 1385 // create and store arraymt:
jbe@138 1386 lua_newtable(L);
jbe@138 1387 luaL_setfuncs(L, json_metatable_functions, 0);
jbe@144 1388 json_regstore(L, arraymt);
jbe@149 1389 // create and store ephemeron table to store shadow tables for each JSON object/array
jbe@149 1390 // to allow NULL values returned as nil
jbe@149 1391 lua_newtable(L);
jbe@138 1392 lua_newtable(L); // metatable for ephemeron table
jbe@121 1393 lua_pushliteral(L, "__mode");
jbe@121 1394 lua_pushliteral(L, "k");
jbe@138 1395 lua_rawset(L, -3);
jbe@138 1396 lua_setmetatable(L, -2);
jbe@144 1397 json_regstore(L, shadowtbl);
jbe@157 1398 // set metatable of null marker and make it available through library module:
jbe@157 1399 json_pushnullmark(L);
jbe@157 1400 lua_newtable(L);
jbe@157 1401 luaL_setfuncs(L, json_nullmark_metamethods, 0);
jbe@157 1402 lua_setmetatable(L, -2);
jbe@157 1403 lua_setfield(L, 1, "null");
jbe@157 1404 // return library module (that's expected on top of stack):
jbe@121 1405 return 1;
jbe@121 1406 }

Impressum / About Us