webmcp
view libraries/json/json.c @ 150:35fb4f92a887
Limit maximum depth for JSON parser to 500
| author | jbe | 
|---|---|
| date | Wed Jul 30 23:11:38 2014 +0200 (2014-07-30) | 
| parents | 5229687c7601 | 
| children | 6d2bb696f736 | 
 line source
     1 #include <lua.h>
     2 #include <lauxlib.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     6 // maximum number of nested JSON values (objects and arrays):
     7 // NOTE: The Lua reference states that the stack may typically contain at least
     8 //       "a few thousand elements". Since every nested level consumes
     9 //       3 elements on the Lua stack (the object/array, its shadow table,
    10 //       a string key or a placeholder), we limit the number of nested levels
    11 //       to 500. If a stack overflow would still happen in the import function,
    12 //       this is detected nevertheless and an error is thrown (instead of
    13 //       returning nil and an error string).
    14 #define JSON_MAXDEPTH 500
    16 // macros for usage of Lua registry:
    17 #define JSON_REGENT char
    18 #define JSON_REGPOINTER void *
    19 #define json_pushlightref(L, x) (lua_pushlightuserdata((L), &json_reference.x))
    20 #define json_regpointer(x) (&json_registry.x)
    21 #define json_regfetchpointer(L, x) (lua_pushlightuserdata((L), (x)), lua_rawget((L), LUA_REGISTRYINDEX))
    22 #define json_regfetch(L, x) (json_regfetchpointer(L, json_regpointer(x)))
    23 #define json_regstore(L, x) (lua_pushlightuserdata(L, json_regpointer(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX));
    25 // generate dummy memory addresses that represent non-modifiable lightuserdata (dummy) objects:
    26 static struct {
    27   JSON_REGENT nullmark;  // magic value to indicate JSON null value in shadow table
    28 } json_reference;
    31 // generate dummy memory addresses that represent Lua objects
    32 // via lightuserdata keys and LUA_REGISTRYINDEX:
    33 static struct {
    34   JSON_REGENT shadowtbl;  // ephemeron table that maps tables to their corresponding shadow table
    35   JSON_REGENT unknownmt;  // metatable for tables that may be either JSON objects or JSON arrays
    36   JSON_REGENT objectmt;   // metatable for JSON objects
    37   JSON_REGENT arraymt;    // metatable for JSON arrays
    38 } json_registry;
    40 // marks a Lua table as JSON object or JSON array:
    41 // (returns its modified argument or a new table if argument is nil)
    42 static int json_mark(lua_State *L, JSON_REGPOINTER mt) {
    43   // check if argument is nil
    44   if (lua_isnoneornil(L, 1)) {
    45     // create new table at stack position 1:
    46     lua_settop(L, 0);
    47     lua_newtable(L);
    48     // create shadow table (leaving previously created table on stack position 1):
    49     json_regfetch(L, shadowtbl);
    50     lua_pushvalue(L, 1);
    51     lua_newtable(L);
    52     lua_rawset(L, -3);
    53   } else {
    54     // push shadow table on top of stack:
    55     json_regfetch(L, shadowtbl);
    56     lua_pushvalue(L, 1);
    57     lua_rawget(L, -2);
    58     // if shadow table does not exist:
    59     if (lua_isnil(L, -1)) {
    60       // create shadow table and leave it on top of stack:
    61       lua_newtable(L);
    62       lua_pushvalue(L, 1);
    63       lua_pushvalue(L, -2);
    64       lua_rawset(L, -5);
    65     }
    66     // move elements from original table to shadow table (that's expected on top of stack):
    67     for(lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
    68       lua_pushvalue(L, -2);
    69       lua_pushnil(L);
    70       lua_rawset(L, 1);
    71       lua_pushvalue(L, -2);
    72       lua_pushvalue(L, -2);
    73       lua_rawset(L, -5);
    74     }
    75   }
    76   // discard everything but table to return:
    77   lua_settop(L, 1);
    78   // set metatable:
    79   json_regfetchpointer(L, mt);
    80   lua_setmetatable(L, 1);
    81   // return table:
    82   return 1;
    83 }
    85 // marks a table as JSON object:
    86 // (returns its modified argument or a new table if argument is nil)
    87 static int json_object(lua_State *L) {
    88   return json_mark(L, json_regpointer(objectmt));
    89 }
    91 // marks a table as JSON array:
    92 // (returns its modified argument or a new table if argument is nil)
    93 static int json_array(lua_State *L) {
    94   return json_mark(L, json_regpointer(arraymt));
    95 }
    97 // internal states of JSON parser:
    98 #define JSON_STATE_VALUE 0
    99 #define JSON_STATE_OBJECT_KEY 1
   100 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2
   101 #define JSON_STATE_OBJECT_VALUE 3
   102 #define JSON_STATE_OBJECT_SEPARATOR 4
   103 #define JSON_STATE_ARRAY_VALUE 5
   104 #define JSON_STATE_ARRAY_SEPARATOR 6
   105 #define JSON_STATE_END 7
   107 // special Lua stack indicies for json_import function:
   108 #define json_import_objectmt_idx 2
   109 #define json_import_arraymt_idx 3
   110 #define json_import_shadowtbl_idx 4
   111 #define json_import_nullmark_idx 5
   113 // decodes a JSON document:
   114 static int json_import(lua_State *L) {
   115   const char *str;   // string to parse
   116   size_t total;      // total length of string to parse
   117   size_t pos = 0;    // current position in string to parse
   118   size_t level = 0;  // nested levels of objects/arrays currently being processed
   119   int mode = JSON_STATE_VALUE;  // state of parser (i.e. "what's expected next?")
   120   char c;              // variable to store a single character to be processed
   121   luaL_Buffer luabuf;  // Lua buffer to decode JSON string values
   122   char *cbuf;          // C buffer to decode JSON string values
   123   size_t writepos;     // write position of decoded strings in C buffer
   124   // stack shall contain one function argument:
   125   lua_settop(L, 1);
   126   // push objectmt onto stack position 2:
   127   json_regfetch(L, objectmt);
   128   // push arraymt onto stack position 3:
   129   json_regfetch(L, arraymt);
   130   // push shadowtbl onto stack position 4:
   131   json_regfetch(L, shadowtbl);
   132   // push nullmark onto stack position 5:
   133   json_pushlightref(L, nullmark);
   134   // require string as first argument:
   135   str = luaL_checklstring(L, 1, &total);
   136   // if string contains a NULL byte, this is a syntax error
   137   if (strlen(str) != total) goto json_import_syntax_error;
   138   // main loop of parser:
   139   json_import_loop:
   140   // skip whitespace and store next character in variable 'c':
   141   while (c = str[pos],
   142     c == ' ' ||
   143     c == '\f' ||
   144     c == '\n' ||
   145     c == '\r' ||
   146     c == '\t' ||
   147     c == '\v'
   148   ) pos++;
   149   // switch statement to handle certain (single) characters:
   150   switch (c) {
   151   // handle end of JSON document:
   152   case 0:
   153     // if end of JSON document was expected, then return top element of stack as result:
   154     if (mode == JSON_STATE_END) return 1;
   155     // otherwise, the JSON document was malformed:
   156     json_import_unexpected_eof:
   157     lua_pushnil(L);
   158     if (level == 0) lua_pushliteral(L, "Empty string");
   159     else lua_pushliteral(L, "Unexpected end of JSON document");
   160     return 2;
   161   // new JSON object:
   162   case '{':
   163     // if a JSON object is not expected here, then return an error:
   164     if (
   165       mode != JSON_STATE_VALUE &&
   166       mode != JSON_STATE_OBJECT_VALUE &&
   167       mode != JSON_STATE_ARRAY_VALUE
   168     ) goto json_import_syntax_error;
   169     // create JSON object on stack:
   170     lua_newtable(L);
   171     // set metatable of JSON object:
   172     lua_pushvalue(L, json_import_objectmt_idx);
   173     lua_setmetatable(L, -2);
   174     // create internal shadow table on stack:
   175     lua_newtable(L);
   176     // register internal shadow table:
   177     lua_pushvalue(L, -2);
   178     lua_pushvalue(L, -2);
   179     lua_rawset(L, json_import_shadowtbl_idx);
   180     // expect object key (or end of object) to follow:
   181     mode = JSON_STATE_OBJECT_KEY;
   182     // jump to common code for opening JSON object and JSON array:
   183     goto json_import_open;
   184   // new JSON array:
   185   case '[':
   186     // if a JSON array is not expected here, then return an error:
   187     if (
   188       mode != JSON_STATE_VALUE &&
   189       mode != JSON_STATE_OBJECT_VALUE &&
   190       mode != JSON_STATE_ARRAY_VALUE
   191     ) goto json_import_syntax_error;
   192     // create JSON array on stack:
   193     lua_newtable(L);
   194     // set metatable of JSON array:
   195     lua_pushvalue(L, json_import_arraymt_idx);
   196     lua_setmetatable(L, -2);
   197     // create internal shadow table on stack:
   198     lua_newtable(L);
   199     // register internal shadow table:
   200     lua_pushvalue(L, -2);
   201     lua_pushvalue(L, -2);
   202     lua_rawset(L, json_import_shadowtbl_idx);
   203     // add nil as key (needed to keep stack balance) and as magic to detect arrays:
   204     lua_pushnil(L);
   205     // expect array value (or end of array) to follow:
   206     mode = JSON_STATE_ARRAY_VALUE;
   207     // continue with common code for opening JSON object and JSON array:
   208   // common code for opening JSON object or JSON array:
   209   json_import_open:
   210     // limit nested levels:
   211     if (level >= JSON_MAXDEPTH) {
   212       lua_pushnil(L);
   213       lua_pushliteral(L, "Too many nested JSON levels");
   214       return 2;
   215     }
   216     // additional buffer overflow protection:
   217     if (!lua_checkstack(L, LUA_MINSTACK))
   218       return luaL_error(L, "Caught stack overflow in JSON import function (too many nested levels and stack size too small)");
   219     // increment level:
   220     level++;
   221     // consume input character:
   222     pos++;
   223     goto json_import_loop;
   224   // end of JSON object:
   225   case '}':
   226     // if end of JSON object is not expected here, then return an error:
   227     if (
   228       mode != JSON_STATE_OBJECT_KEY &&
   229       mode != JSON_STATE_OBJECT_SEPARATOR
   230     ) goto json_import_syntax_error;
   231     // jump to common code for end of JSON object and JSON array:
   232     goto json_import_close;
   233   // end of JSON array:
   234   case ']':
   235     // if end of JSON array is not expected here, then return an error:
   236     if (
   237       mode != JSON_STATE_ARRAY_VALUE &&
   238       mode != JSON_STATE_ARRAY_SEPARATOR
   239     ) goto json_import_syntax_error;
   240     // pop nil key/magic (that was needed to keep stack balance):
   241     lua_pop(L, 1);
   242     // continue with common code for end of JSON object and JSON array:
   243   // common code for end of JSON object or JSON array:
   244   json_import_close:
   245     // consume input character:
   246     pos++;
   247     // pop shadow table:
   248     lua_pop(L, 1);
   249     // check if nested:
   250     if (--level) {
   251       // if nested,
   252       // check if outer(!) structure is an array or object:
   253       if (lua_isnil(L, -2)) {
   254         // select array value processing:
   255         mode = JSON_STATE_ARRAY_VALUE;
   256       } else {
   257         // select object value processing:
   258         mode = JSON_STATE_OBJECT_VALUE;
   259       }
   260       // store value in outer structure:
   261       goto json_import_process_value;
   262     }
   263     // if not nested, then expect end of JSON document and continue with loop:
   264     mode = JSON_STATE_END;
   265     goto json_import_loop;
   266   // key terminator:
   267   case ':':
   268     // if key terminator is not expected here, then return an error:
   269     if (mode != JSON_STATE_OBJECT_KEY_TERMINATOR)
   270       goto json_import_syntax_error;
   271     // consume input character:
   272     pos++;
   273     // expect object value to follow:
   274     mode = JSON_STATE_OBJECT_VALUE;
   275     // continue with loop:
   276     goto json_import_loop;
   277   // value terminator (NOTE: trailing comma at end of value or key-value list is tolerated by this parser)
   278   case ',':
   279     // branch according to parser state:
   280     if (mode == JSON_STATE_OBJECT_SEPARATOR) {
   281       // expect an object key to follow:
   282       mode = JSON_STATE_OBJECT_KEY;
   283     } else if (mode == JSON_STATE_ARRAY_SEPARATOR) {
   284       // expect an array value to follow:
   285       mode = JSON_STATE_ARRAY_VALUE;
   286     } else {
   287        // if value terminator is not expected here, then return an error:
   288        goto json_import_syntax_error;
   289     }
   290     // consume input character:
   291     pos++;
   292     // continue with loop:
   293     goto json_import_loop;
   294   // string literal:
   295   case '"':
   296     // consume quote character:
   297     pos++;
   298     // prepare buffer to decode string (with maximum possible length) and set write position to zero:
   299     cbuf = luaL_buffinitsize(L, &luabuf, total-pos);
   300     writepos = 0;
   301     // loop through the characters until encountering end quote:
   302     while ((c = str[pos++]) != '"') {
   303       if (c == 0) {
   304         // handle unexpected end of JSON document:
   305         goto json_import_unexpected_eof;
   306       } else if (c < 32 || c == 127) {
   307         // do not allow ASCII control characters:
   308         // NOTE: illegal UTF-8 sequences and extended control characters are not sanitized
   309         //       by this parser to allow different encodings than Unicode
   310         lua_pushnil(L);
   311         lua_pushliteral(L, "Unexpected control character in JSON string");
   312         return 2;
   313       } else if (c == '\\') {
   314         // read next char after backslash escape:
   315         c = str[pos++];
   316         switch (c) {
   317         // unexpected end-of-string:
   318         case 0:
   319           goto json_import_unexpected_eof;
   320         // unescaping of quotation mark, slash, and backslash:
   321         case '"':
   322         case '/':
   323         case '\\':
   324           cbuf[writepos++] = c;
   325           break;
   326         // unescaping of backspace:
   327         case 'b': cbuf[writepos++] = '\b'; break;
   328         // unescaping of form-feed:
   329         case 'f': cbuf[writepos++] = '\f'; break;
   330         // unescaping of new-line:
   331         case 'n': cbuf[writepos++] = '\n'; break;
   332         // unescaping of carriage-return:
   333         case 'r': cbuf[writepos++] = '\r'; break;
   334         // unescaping of tabulator:
   335         case 't': cbuf[writepos++] = '\t'; break;
   336         // unescaping of UTF-16 characters
   337         case 'u':
   338           lua_pushnil(L);
   339           lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet");  // TODO
   340           return 2;
   341         // unexpected escape sequence:
   342         default:
   343           lua_pushnil(L);
   344           lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
   345           return 2;
   346         }
   347       } else {
   348         // normal character:
   349         cbuf[writepos++] = c;
   350       }
   351     }
   352     // process buffer to Lua string:
   353     luaL_pushresultsize(&luabuf, writepos);
   354     // continue with processing of decoded string:
   355     goto json_import_process_value;
   356   }
   357   // process values whose type is is not deducible from a single character:
   358   if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
   359     // for numbers,
   360     // use strtod() call to parse a (double precision) floating point number:
   361     char *endptr;
   362     double numval;
   363     numval = strtod(str+pos, &endptr);
   364     // catch parsing errors:
   365     if (endptr == str+pos) goto json_import_syntax_error;
   366     // consume characters that were parsed:
   367     pos += endptr - (str+pos);
   368     // push parsed (double precision) floating point number on Lua stack:
   369     lua_pushnumber(L, numval);
   370   } else if (!strncmp(str+pos, "true", 4)) {
   371     // consume 4 input characters for "true":
   372     pos += 4;
   373     // put Lua true value onto stack:
   374     lua_pushboolean(L, 1);
   375   } else if (!strncmp(str+pos, "false", 5)) {
   376     // consume 5 input characters for "false":
   377     pos += 5;
   378     // put Lua false value onto stack:
   379     lua_pushboolean(L, 0);
   380   } else if (!strncmp(str+pos, "null", 4)) {
   381     // consume 4 input characters for "null":
   382     pos += 4;
   383     // put special null-marker onto stack:
   384     lua_pushvalue(L, json_import_nullmark_idx);
   385   } else {
   386     // all other cases are a syntax error:
   387     goto json_import_syntax_error;
   388   }
   389   // process a decoded value or key value pair (expected on top of Lua stack):
   390   json_import_process_value:
   391   switch (mode) {
   392   // an object key has been read:
   393   case JSON_STATE_OBJECT_KEY:
   394     // if an object key is not a string, then this is a syntax error:
   395     if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
   396     // expect key terminator to follow:
   397     mode = JSON_STATE_OBJECT_KEY_TERMINATOR;
   398     // continue with loop:
   399     goto json_import_loop;
   400   // a key value pair has been read:
   401   case JSON_STATE_OBJECT_VALUE:
   402     // store key value pair in outer shadow table:
   403     lua_rawset(L, -3);
   404     // expect value terminator (or end of object) to follow:
   405     mode = JSON_STATE_OBJECT_SEPARATOR;
   406     // continue with loop:
   407     goto json_import_loop;
   408   // an array value has been read:
   409   case JSON_STATE_ARRAY_VALUE:
   410     // store value in outer shadow table:
   411     lua_rawseti(L, -3, lua_rawlen(L, -3) + 1);
   412     // expect value terminator (or end of object) to follow:
   413     mode = JSON_STATE_ARRAY_SEPARATOR;
   414     // continue with loop
   415     goto json_import_loop;
   416   // a single value has been read:
   417   case JSON_STATE_VALUE:
   418     // leave value on top of stack, expect end of JSON document, and continue with loop:
   419     mode = JSON_STATE_END;
   420     goto json_import_loop;
   421   }
   422   // syntax error handling (reachable by goto statement):
   423   json_import_syntax_error:
   424   lua_pushnil(L);
   425   lua_pushliteral(L, "Syntax error in JSON document");
   426   return 2;
   427 }
   429 // special Lua stack indicies for json_path function:
   430 #define json_path_shadowtbl_idx 1
   431 #define json_path_nullmark_idx 2
   433 // stack offset of arguments to json_path function:
   434 #define json_path_idxshift 2
   436 // gets a value or its type from a JSON document (passed as first argument)
   437 // using a path (passed as variable number of keys after first argument):
   438 static int json_path(lua_State *L, int type_mode) {
   439   int stacktop;                      // stack index of top of stack (after shifting)
   440   int idx = 2 + json_path_idxshift;  // stack index of current argument to process
   441   // insert shadowtbl into stack at position 1 (shifting the arguments):
   442   json_regfetch(L, shadowtbl);
   443   lua_insert(L, 1);
   444   // insert nullmark into stack at position 2 (shifting the arguments):
   445   json_pushlightref(L, nullmark);
   446   lua_insert(L, 2);
   447   // store stack index of top of stack:
   448   stacktop = lua_gettop(L);
   449   // use first argument as "current value" (stored on top of stack):
   450   lua_pushvalue(L, 1 + json_path_idxshift);
   451   // process each "path key" (2nd argument and following arguments):
   452   while (idx <= stacktop) {
   453     // if "current value" (on top of stack) is nil, then the path cannot be walked and nil is returned:
   454     if (lua_isnil(L, -1)) return 1;
   455     // try to get shadow table of "current value":
   456     lua_pushvalue(L, -1);
   457     lua_rawget(L, json_path_shadowtbl_idx);
   458     if (lua_isnil(L, -1)) {
   459       // if no shadow table is found,
   460       if (lua_type(L, -1) == LUA_TTABLE) {
   461         // and if "current value" is a table,
   462         // drop nil from stack:
   463         lua_pop(L, 1);
   464         // get "next value" using the "path key":
   465         lua_pushvalue(L, idx++);
   466         lua_gettable(L, -2);
   467       } else {
   468         // if "current value" is not a table,
   469         // then the path cannot be walked and nil (already on top of stack) is returned:
   470         return 1;
   471       }
   472     } else {
   473       // if a shadow table is found,
   474       // set "current value" to its shadow table:
   475       lua_replace(L, -2);
   476       // get "next value" using the "path key":
   477       lua_pushvalue(L, idx++);
   478       lua_rawget(L, -2);
   479     }
   480     // the "next value" replaces the "current value":
   481     lua_replace(L, -2);
   482   }
   483   if (!type_mode) {
   484     // if a value (and not its type) was requested,
   485     // check if value is the null-marker, and store nil on top of Lua stack in that case:
   486     if (lua_rawequal(L, -1, json_path_nullmark_idx)) lua_pushnil(L);
   487   } else {
   488     // if the type was requested,
   489     // check if value is the null-marker:
   490     if (lua_rawequal(L, -1, json_path_nullmark_idx)) {
   491       // if yes, store string "null" on top of Lua stack:
   492       lua_pushliteral(L, "null");
   493     } else {
   494       // otherwise,
   495       // check if metatable indicates "object" or "array":
   496       if (lua_getmetatable(L, -1)) {
   497         json_regfetch(L, objectmt);
   498         if (lua_rawequal(L, -2, -1)) {
   499           // if value has metatable for JSON objects,
   500           // return string "object":
   501           lua_pushliteral(L, "object");
   502           return 1;
   503         }
   504         json_regfetch(L, arraymt);
   505         if (lua_rawequal(L, -3, -1)) {
   506           // if value has metatable for JSON arrays,
   507           // return string "object":
   508           lua_pushliteral(L, "array");
   509           return 1;
   510         }
   511         // remove 3 metatables (one of the value, two for comparison) from stack:
   512         lua_pop(L, 3);
   513       }
   514       // otherwise, get the Lua type:
   515       lua_pushstring(L, lua_typename(L, lua_type(L, -1)));
   516     }
   517   }
   518   // return the top most value on the Lua stack:
   519   return 1;
   520 }
   522 // gets a value from a JSON document (passed as first argument)
   523 // using a path (passed as variable number of keys after first argument):
   524 static int json_get(lua_State *L) {
   525   return json_path(L, 0);
   526 }
   528 // gets a value's type from a JSON document (passed as first argument)
   529 // using a path (variable number of keys after first argument):
   530 static int json_type(lua_State *L) {
   531   return json_path(L, 1);
   532 }
   534 // checks if a value in a JSON document (first argument) is
   535 // explicitly set to null:
   536 static int json_isnull(lua_State *L) {
   537   const char *jsontype;
   538   // call json_type function with variable arguments:
   539   lua_pushcfunction(L, json_type);
   540   lua_insert(L, 1);
   541   lua_call(L, lua_gettop(L) - 1, 1);
   542   // return true if result equals to string "null", otherwise return false:
   543   jsontype = lua_tostring(L, -1);
   544   if (jsontype && !strcmp(jsontype, "null")) lua_pushboolean(L, 1);
   545   else lua_pushboolean(L, 0);
   546   return 1;
   547 }
   549 // special Lua stack indicies for json_setnull function:
   550 #define json_setnull_unknownmt_idx 3
   551 #define json_setnull_objectmt_idx 4
   552 #define json_setnull_arraymt_idx 5
   553 #define json_setnull_shadowtbl_idx 6
   555 // sets a value in a JSON object or JSON array explicitly to null:
   556 // NOTE: JSON null is different than absence of a key
   557 static int json_setnull(lua_State *L) {
   558   // stack shall contain two function arguments:
   559   lua_settop(L, 2);
   560   // push unknownmt onto stack position 3:
   561   json_regfetch(L, unknownmt);
   562   // push objectmt onto stack position 4:
   563   json_regfetch(L, objectmt);
   564   // push arraymt onto stack position 5:
   565   json_regfetch(L, arraymt);
   566   // push shadowtbl onto stack position 6:
   567   json_regfetch(L, shadowtbl);
   568   // set metatable if necessary (leaves unknown number of elements on stack):
   569   if (
   570     !lua_getmetatable(L, 1) || (
   571       !lua_rawequal(L, -1, json_setnull_unknownmt_idx) &&
   572       !lua_rawequal(L, -1, json_setnull_objectmt_idx) &&
   573       !lua_rawequal(L, -1, json_setnull_arraymt_idx)
   574     )
   575   ) {
   576     lua_pushvalue(L, json_setnull_unknownmt_idx);
   577     lua_setmetatable(L, 1);
   578   }
   579   // try to get shadow table:
   580   lua_pushvalue(L, 1);
   581   lua_rawget(L, json_setnull_shadowtbl_idx);
   582   if (lua_isnil(L, -1)) {
   583     // if no shadow table is found,
   584     // create new shadow table (and leave it on top of stack):
   585     lua_newtable(L);
   586     // register shadow table:
   587     lua_pushvalue(L, 1);
   588     lua_pushvalue(L, -2);
   589     lua_rawset(L, json_setnull_shadowtbl_idx);
   590   }
   591   // push key (second argument) and null-marker after shadow table onto stack:
   592   lua_pushvalue(L, 2);
   593   json_pushlightref(L, nullmark);
   594   // store key and null-marker in shadow table:
   595   lua_rawset(L, -3);
   596   // return nothing:
   597   return 0;
   598 }
   600 // returns the length of a JSON array (or zero for a table without numeric keys):
   601 static int json_len(lua_State *L) {
   602   // stack shall contain one function argument:
   603   lua_settop(L, 1);
   604   // try to get corresponding shadow table for first argument:
   605   json_regfetch(L, shadowtbl);
   606   lua_pushvalue(L, 1);
   607   lua_rawget(L, -2);
   608   // if shadow table does not exist, return length of argument, else length of shadow table:
   609   lua_pushnumber(L, lua_rawlen(L, lua_isnil(L, -1) ? 1 : -1));
   610   return 1;
   611 }
   613 // special Lua stack indicies for json_index function:
   614 #define json_index_nullmark_idx 3
   615 #define json_index_shadowtbl_idx 4
   617 static int json_index(lua_State *L) {
   618   // stack shall contain two function arguments:
   619   lua_settop(L, 2);
   620   // push nullmark onto stack position 3:
   621   json_pushlightref(L, nullmark);
   622   // push shadowtbl onto stack position 4:
   623   json_regfetch(L, shadowtbl);
   624   // get corresponding shadow table for first argument:
   625   lua_pushvalue(L, 1);
   626   lua_rawget(L, json_index_shadowtbl_idx);
   627   // throw error if no shadow table was found:
   628   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   629   // use key passed as second argument to lookup value in shadow table:
   630   lua_pushvalue(L, 2);
   631   lua_rawget(L, -2);
   632   // if value is null-marker, then push nil onto stack:
   633   if (lua_rawequal(L, -1, json_index_nullmark_idx)) lua_pushnil(L);
   634   // return either looked up value, or nil
   635   return 1;
   636 }
   638 static int json_newindex(lua_State *L) {
   639   // stack shall contain three function arguments:
   640   lua_settop(L, 3);
   641   // get corresponding shadow table for first argument:
   642   json_regfetch(L, shadowtbl);
   643   lua_pushvalue(L, 1);
   644   lua_rawget(L, -2);
   645   // throw error if no shadow table was found:
   646   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   647   // replace first argument with shadow table:
   648   lua_replace(L, 1);
   649   // reset stack and use second and third argument to write to shadow table:
   650   lua_settop(L, 3);
   651   lua_rawset(L, 1);
   652   // return nothing:
   653   return 0;
   654 }
   656 // special Lua stack indicies for json_pairs_iterfunc function:
   657 #define json_pairs_iterfunc_nullmark_idx 3
   658 #define json_pairs_iterfunc_shadowtbl_idx 4
   660 static int json_pairs_iterfunc(lua_State *L) {
   661   // stack shall contain two function arguments:
   662   lua_settop(L, 2);
   663   // push nullmark onto stack position 3:
   664   json_pushlightref(L, nullmark);
   665   // push shadowtbl onto stack position 4:
   666   json_regfetch(L, shadowtbl);
   667   // get corresponding shadow table for first argument:
   668   lua_pushvalue(L, 1);
   669   lua_rawget(L, json_pairs_iterfunc_shadowtbl_idx);
   670   // throw error if no shadow table was found:
   671   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   672   // get next key value pair from shadow table (using previous key from argument 2)
   673   // and return nothing if there is no next pair:
   674   lua_pushvalue(L, 2);
   675   if (!lua_next(L, -2)) return 0;
   676   // replace null-marker with nil:
   677   if (lua_rawequal(L, -1, json_pairs_iterfunc_nullmark_idx)) {
   678     lua_pop(L, 1);
   679     lua_pushnil(L);
   680   }
   681   // return key and value (or key and nil, if null-marker was found):
   682   return 2;
   683 }
   685 // returns a triple such that 'for key, value in pairs(obj) do ... end'
   686 // iterates through all key value pairs (including JSON null keys represented as Lua nil):
   687 static int json_pairs(lua_State *L) {
   688   // return triple of function json_pairs_iterfunc, first argument, and nil:
   689   lua_pushcfunction(L, json_pairs_iterfunc);
   690   lua_pushvalue(L, 1);
   691   lua_pushnil(L);
   692   return 3;
   693 }
   695 // special Lua stack indicies for json_ipairs_iterfunc function:
   696 #define json_ipairs_iterfunc_nullmark_idx 3
   697 #define json_ipairs_iterfunc_shadowtbl_idx 4
   699 static int json_ipairs_iterfunc(lua_State *L) {
   700   int idx;
   701   // stack shall contain two function arguments:
   702   lua_settop(L, 2);
   703   // push nullmark onto stack position 3:
   704   json_pushlightref(L, nullmark);
   705   // push shadowtbl onto stack position 4:
   706   json_regfetch(L, shadowtbl);
   707   // calculate new index by incrementing second argument:
   708   idx = lua_tointeger(L, 2) + 1;
   709   // get corresponding shadow table for first argument:
   710   lua_pushvalue(L, 1);
   711   lua_rawget(L, json_ipairs_iterfunc_shadowtbl_idx);
   712   // throw error if no shadow table was found:
   713   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   714   // do integer lookup in shadow table:
   715   lua_rawgeti(L, -1, idx);
   716   // return nothing if there was no value:
   717   if (lua_isnil(L, -1)) return 0;
   718   // return new index and
   719   // either the looked up value if it is not equal to the null-marker
   720   // or nil instead of null-marker:
   721   lua_pushinteger(L, idx);
   722   if (lua_rawequal(L, -2, json_ipairs_iterfunc_nullmark_idx)) lua_pushnil(L);
   723   else lua_pushvalue(L, -2);
   724   return 2;
   725 }
   727 // returns a triple such that 'for idx, value in ipairs(ary) do ... end'
   728 // iterates through all values (including JSON null represented as Lua nil):
   729 static int json_ipairs(lua_State *L) {
   730   // return triple of function json_ipairs_iterfunc, first argument, and zero:
   731   lua_pushcfunction(L, json_ipairs_iterfunc);
   732   lua_pushvalue(L, 1);
   733   lua_pushinteger(L, 0);
   734   return 3;
   735 }
   737 // functions in library module:
   738 static const struct luaL_Reg json_module_functions[] = {
   739   {"object", json_object},
   740   {"array", json_array},
   741   {"import", json_import},
   742   {"get", json_get},
   743   {"type", json_type},
   744   {"isnull", json_isnull},
   745   {"setnull", json_setnull},
   746   {NULL, NULL}
   747 };
   749 // metamethods for JSON objects, JSON arrays, and unknown JSON collections (object or array):
   750 static const struct luaL_Reg json_metatable_functions[] = {
   751   {"__len", json_len},
   752   {"__index", json_index},
   753   {"__newindex", json_newindex},
   754   {"__pairs", json_pairs},
   755   {"__ipairs", json_ipairs},
   756   {NULL, NULL}
   757 };
   759 // initializes json library:
   760 int luaopen_json(lua_State *L) {
   761   // empty stack:
   762   lua_settop(L, 0);
   763   // push library module onto stack position 1:
   764   lua_newtable(L);
   765   // register library functions:
   766   luaL_setfuncs(L, json_module_functions, 0);
   767   // create and store unknownmt:
   768   lua_newtable(L);
   769   luaL_setfuncs(L, json_metatable_functions, 0);
   770   json_regstore(L, unknownmt);
   771   // create and store objectmt:
   772   lua_newtable(L);
   773   luaL_setfuncs(L, json_metatable_functions, 0);
   774   json_regstore(L, objectmt);
   775   // create and store arraymt:
   776   lua_newtable(L);
   777   luaL_setfuncs(L, json_metatable_functions, 0);
   778   json_regstore(L, arraymt);
   779   // create and store ephemeron table to store shadow tables for each JSON object/array
   780   // to allow NULL values returned as nil
   781   lua_newtable(L);
   782   lua_newtable(L);  // metatable for ephemeron table
   783   lua_pushliteral(L, "__mode");
   784   lua_pushliteral(L, "k");
   785   lua_rawset(L, -3);
   786   lua_setmetatable(L, -2);
   787   json_regstore(L, shadowtbl);
   788   // return library module stored on lowest stack position:
   789   lua_settop(L, 1);
   790   return 1;
   791 }
