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