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