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