diff options
Diffstat (limited to 'examples/redis-unstable/deps/lua/src/lua_cjson.c')
| -rw-r--r-- | examples/redis-unstable/deps/lua/src/lua_cjson.c | 1471 |
1 files changed, 1471 insertions, 0 deletions
diff --git a/examples/redis-unstable/deps/lua/src/lua_cjson.c b/examples/redis-unstable/deps/lua/src/lua_cjson.c new file mode 100644 index 0000000..703e3e7 --- /dev/null +++ b/examples/redis-unstable/deps/lua/src/lua_cjson.c | |||
| @@ -0,0 +1,1471 @@ | |||
| 1 | /* Lua CJSON - JSON support for Lua | ||
| 2 | * | ||
| 3 | * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au> | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining | ||
| 6 | * a copy of this software and associated documentation files (the | ||
| 7 | * "Software"), to deal in the Software without restriction, including | ||
| 8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
| 9 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
| 10 | * permit persons to whom the Software is furnished to do so, subject to | ||
| 11 | * the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be | ||
| 14 | * included in all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| 19 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
| 20 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 21 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 22 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* Caveats: | ||
| 26 | * - JSON "null" values are represented as lightuserdata since Lua | ||
| 27 | * tables cannot contain "nil". Compare with cjson.null. | ||
| 28 | * - Invalid UTF-8 characters are not detected and will be passed | ||
| 29 | * untouched. If required, UTF-8 error checking should be done | ||
| 30 | * outside this library. | ||
| 31 | * - Javascript comments are not part of the JSON spec, and are not | ||
| 32 | * currently supported. | ||
| 33 | * | ||
| 34 | * Note: Decoding is slower than encoding. Lua spends significant | ||
| 35 | * time (30%) managing tables when parsing JSON since it is | ||
| 36 | * difficult to know object/array sizes ahead of time. | ||
| 37 | */ | ||
| 38 | |||
| 39 | #include <assert.h> | ||
| 40 | #include <string.h> | ||
| 41 | #include <math.h> | ||
| 42 | #include <stdint.h> | ||
| 43 | #include <limits.h> | ||
| 44 | #include "lua.h" | ||
| 45 | #include "lauxlib.h" | ||
| 46 | |||
| 47 | #include "strbuf.h" | ||
| 48 | #include "fpconv.h" | ||
| 49 | |||
| 50 | #include "../../../src/solarisfixes.h" | ||
| 51 | |||
| 52 | #ifndef CJSON_MODNAME | ||
| 53 | #define CJSON_MODNAME "cjson" | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #ifndef CJSON_VERSION | ||
| 57 | #define CJSON_VERSION "2.1.0" | ||
| 58 | #endif | ||
| 59 | |||
| 60 | /* Workaround for Solaris platforms missing isinf() */ | ||
| 61 | #if !defined(isinf) && (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF)) | ||
| 62 | #define isinf(x) (!isnan(x) && isnan((x) - (x))) | ||
| 63 | #endif | ||
| 64 | |||
| 65 | #define DEFAULT_SPARSE_CONVERT 0 | ||
| 66 | #define DEFAULT_SPARSE_RATIO 2 | ||
| 67 | #define DEFAULT_SPARSE_SAFE 10 | ||
| 68 | #define DEFAULT_ENCODE_MAX_DEPTH 1000 | ||
| 69 | #define DEFAULT_DECODE_MAX_DEPTH 1000 | ||
| 70 | #define DEFAULT_ENCODE_INVALID_NUMBERS 0 | ||
| 71 | #define DEFAULT_DECODE_INVALID_NUMBERS 1 | ||
| 72 | #define DEFAULT_ENCODE_KEEP_BUFFER 1 | ||
| 73 | #define DEFAULT_ENCODE_NUMBER_PRECISION 14 | ||
| 74 | #define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0 | ||
| 75 | |||
| 76 | #ifdef DISABLE_INVALID_NUMBERS | ||
| 77 | #undef DEFAULT_DECODE_INVALID_NUMBERS | ||
| 78 | #define DEFAULT_DECODE_INVALID_NUMBERS 0 | ||
| 79 | #endif | ||
| 80 | |||
| 81 | typedef enum { | ||
| 82 | T_OBJ_BEGIN, | ||
| 83 | T_OBJ_END, | ||
| 84 | T_ARR_BEGIN, | ||
| 85 | T_ARR_END, | ||
| 86 | T_STRING, | ||
| 87 | T_NUMBER, | ||
| 88 | T_BOOLEAN, | ||
| 89 | T_NULL, | ||
| 90 | T_COLON, | ||
| 91 | T_COMMA, | ||
| 92 | T_END, | ||
| 93 | T_WHITESPACE, | ||
| 94 | T_ERROR, | ||
| 95 | T_UNKNOWN | ||
| 96 | } json_token_type_t; | ||
| 97 | |||
| 98 | static const char *json_token_type_name[] = { | ||
| 99 | "T_OBJ_BEGIN", | ||
| 100 | "T_OBJ_END", | ||
| 101 | "T_ARR_BEGIN", | ||
| 102 | "T_ARR_END", | ||
| 103 | "T_STRING", | ||
| 104 | "T_NUMBER", | ||
| 105 | "T_BOOLEAN", | ||
| 106 | "T_NULL", | ||
| 107 | "T_COLON", | ||
| 108 | "T_COMMA", | ||
| 109 | "T_END", | ||
| 110 | "T_WHITESPACE", | ||
| 111 | "T_ERROR", | ||
| 112 | "T_UNKNOWN", | ||
| 113 | NULL | ||
| 114 | }; | ||
| 115 | |||
| 116 | typedef struct { | ||
| 117 | json_token_type_t ch2token[256]; | ||
| 118 | char escape2char[256]; /* Decoding */ | ||
| 119 | |||
| 120 | /* encode_buf is only allocated and used when | ||
| 121 | * encode_keep_buffer is set */ | ||
| 122 | strbuf_t encode_buf; | ||
| 123 | |||
| 124 | int encode_sparse_convert; | ||
| 125 | int encode_sparse_ratio; | ||
| 126 | int encode_sparse_safe; | ||
| 127 | int encode_max_depth; | ||
| 128 | int encode_invalid_numbers; /* 2 => Encode as "null" */ | ||
| 129 | int encode_number_precision; | ||
| 130 | int encode_keep_buffer; | ||
| 131 | |||
| 132 | int decode_invalid_numbers; | ||
| 133 | int decode_max_depth; | ||
| 134 | int decode_array_with_array_mt; | ||
| 135 | } json_config_t; | ||
| 136 | |||
| 137 | typedef struct { | ||
| 138 | const char *data; | ||
| 139 | const char *ptr; | ||
| 140 | strbuf_t *tmp; /* Temporary storage for strings */ | ||
| 141 | json_config_t *cfg; | ||
| 142 | int current_depth; | ||
| 143 | } json_parse_t; | ||
| 144 | |||
| 145 | typedef struct { | ||
| 146 | json_token_type_t type; | ||
| 147 | size_t index; | ||
| 148 | union { | ||
| 149 | const char *string; | ||
| 150 | double number; | ||
| 151 | int boolean; | ||
| 152 | } value; | ||
| 153 | size_t string_len; | ||
| 154 | } json_token_t; | ||
| 155 | |||
| 156 | static const char *char2escape[256] = { | ||
| 157 | "\\u0000", "\\u0001", "\\u0002", "\\u0003", | ||
| 158 | "\\u0004", "\\u0005", "\\u0006", "\\u0007", | ||
| 159 | "\\b", "\\t", "\\n", "\\u000b", | ||
| 160 | "\\f", "\\r", "\\u000e", "\\u000f", | ||
| 161 | "\\u0010", "\\u0011", "\\u0012", "\\u0013", | ||
| 162 | "\\u0014", "\\u0015", "\\u0016", "\\u0017", | ||
| 163 | "\\u0018", "\\u0019", "\\u001a", "\\u001b", | ||
| 164 | "\\u001c", "\\u001d", "\\u001e", "\\u001f", | ||
| 165 | NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL, | ||
| 166 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/", | ||
| 167 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 168 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 169 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 170 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 171 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 172 | NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL, | ||
| 173 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 174 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 175 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 176 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f", | ||
| 177 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 178 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 179 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 180 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 181 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 182 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 183 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 184 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 185 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 186 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 187 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 188 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 189 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 190 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 191 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 192 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
| 193 | }; | ||
| 194 | |||
| 195 | /* ===== CONFIGURATION ===== */ | ||
| 196 | |||
| 197 | static json_config_t *json_fetch_config(lua_State *l) | ||
| 198 | { | ||
| 199 | json_config_t *cfg; | ||
| 200 | |||
| 201 | cfg = lua_touserdata(l, lua_upvalueindex(1)); | ||
| 202 | if (!cfg) | ||
| 203 | luaL_error(l, "BUG: Unable to fetch CJSON configuration"); | ||
| 204 | |||
| 205 | return cfg; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* Ensure the correct number of arguments have been provided. | ||
| 209 | * Pad with nil to allow other functions to simply check arg[i] | ||
| 210 | * to find whether an argument was provided */ | ||
| 211 | static json_config_t *json_arg_init(lua_State *l, int args) | ||
| 212 | { | ||
| 213 | luaL_argcheck(l, lua_gettop(l) <= args, args + 1, | ||
| 214 | "found too many arguments"); | ||
| 215 | |||
| 216 | while (lua_gettop(l) < args) | ||
| 217 | lua_pushnil(l); | ||
| 218 | |||
| 219 | return json_fetch_config(l); | ||
| 220 | } | ||
| 221 | |||
| 222 | /* Process integer options for configuration functions */ | ||
| 223 | static int json_integer_option(lua_State *l, int optindex, int *setting, | ||
| 224 | int min, int max) | ||
| 225 | { | ||
| 226 | char errmsg[64]; | ||
| 227 | int value; | ||
| 228 | |||
| 229 | if (!lua_isnil(l, optindex)) { | ||
| 230 | value = luaL_checkinteger(l, optindex); | ||
| 231 | snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max); | ||
| 232 | luaL_argcheck(l, min <= value && value <= max, 1, errmsg); | ||
| 233 | *setting = value; | ||
| 234 | } | ||
| 235 | |||
| 236 | lua_pushinteger(l, *setting); | ||
| 237 | |||
| 238 | return 1; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* Process enumerated arguments for a configuration function */ | ||
| 242 | static int json_enum_option(lua_State *l, int optindex, int *setting, | ||
| 243 | const char **options, int bool_true) | ||
| 244 | { | ||
| 245 | static const char *bool_options[] = { "off", "on", NULL }; | ||
| 246 | |||
| 247 | if (!options) { | ||
| 248 | options = bool_options; | ||
| 249 | bool_true = 1; | ||
| 250 | } | ||
| 251 | |||
| 252 | if (!lua_isnil(l, optindex)) { | ||
| 253 | if (bool_true && lua_isboolean(l, optindex)) | ||
| 254 | *setting = lua_toboolean(l, optindex) * bool_true; | ||
| 255 | else | ||
| 256 | *setting = luaL_checkoption(l, optindex, NULL, options); | ||
| 257 | } | ||
| 258 | |||
| 259 | if (bool_true && (*setting == 0 || *setting == bool_true)) | ||
| 260 | lua_pushboolean(l, *setting); | ||
| 261 | else | ||
| 262 | lua_pushstring(l, options[*setting]); | ||
| 263 | |||
| 264 | return 1; | ||
| 265 | } | ||
| 266 | |||
| 267 | /* Configures handling of extremely sparse arrays: | ||
| 268 | * convert: Convert extremely sparse arrays into objects? Otherwise error. | ||
| 269 | * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio | ||
| 270 | * safe: Always use an array when the max index <= safe */ | ||
| 271 | static int json_cfg_encode_sparse_array(lua_State *l) | ||
| 272 | { | ||
| 273 | json_config_t *cfg = json_arg_init(l, 3); | ||
| 274 | |||
| 275 | json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1); | ||
| 276 | json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX); | ||
| 277 | json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX); | ||
| 278 | |||
| 279 | return 3; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* Configures the maximum number of nested arrays/objects allowed when | ||
| 283 | * encoding */ | ||
| 284 | static int json_cfg_encode_max_depth(lua_State *l) | ||
| 285 | { | ||
| 286 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 287 | |||
| 288 | return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX); | ||
| 289 | } | ||
| 290 | |||
| 291 | /* Configures the maximum number of nested arrays/objects allowed when | ||
| 292 | * encoding */ | ||
| 293 | static int json_cfg_decode_max_depth(lua_State *l) | ||
| 294 | { | ||
| 295 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 296 | |||
| 297 | return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX); | ||
| 298 | } | ||
| 299 | |||
| 300 | /* Configures number precision when converting doubles to text */ | ||
| 301 | static int json_cfg_encode_number_precision(lua_State *l) | ||
| 302 | { | ||
| 303 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 304 | |||
| 305 | return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 14); | ||
| 306 | } | ||
| 307 | |||
| 308 | /* Configures how to decode arrays */ | ||
| 309 | static int json_cfg_decode_array_with_array_mt(lua_State *l) | ||
| 310 | { | ||
| 311 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 312 | |||
| 313 | return json_enum_option(l, 1, &cfg->decode_array_with_array_mt, NULL, 1); | ||
| 314 | } | ||
| 315 | |||
| 316 | /* Configures JSON encoding buffer persistence */ | ||
| 317 | static int json_cfg_encode_keep_buffer(lua_State *l) | ||
| 318 | { | ||
| 319 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 320 | int old_value; | ||
| 321 | |||
| 322 | old_value = cfg->encode_keep_buffer; | ||
| 323 | |||
| 324 | json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1); | ||
| 325 | |||
| 326 | /* Init / free the buffer if the setting has changed */ | ||
| 327 | if (old_value ^ cfg->encode_keep_buffer) { | ||
| 328 | if (cfg->encode_keep_buffer) | ||
| 329 | strbuf_init(&cfg->encode_buf, 0); | ||
| 330 | else | ||
| 331 | strbuf_free(&cfg->encode_buf); | ||
| 332 | } | ||
| 333 | |||
| 334 | return 1; | ||
| 335 | } | ||
| 336 | |||
| 337 | #if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV) | ||
| 338 | void json_verify_invalid_number_setting(lua_State *l, int *setting) | ||
| 339 | { | ||
| 340 | if (*setting == 1) { | ||
| 341 | *setting = 0; | ||
| 342 | luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | #else | ||
| 346 | #define json_verify_invalid_number_setting(l, s) do { } while(0) | ||
| 347 | #endif | ||
| 348 | |||
| 349 | static int json_cfg_encode_invalid_numbers(lua_State *l) | ||
| 350 | { | ||
| 351 | static const char *options[] = { "off", "on", "null", NULL }; | ||
| 352 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 353 | |||
| 354 | json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1); | ||
| 355 | |||
| 356 | json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); | ||
| 357 | |||
| 358 | return 1; | ||
| 359 | } | ||
| 360 | |||
| 361 | static int json_cfg_decode_invalid_numbers(lua_State *l) | ||
| 362 | { | ||
| 363 | json_config_t *cfg = json_arg_init(l, 1); | ||
| 364 | |||
| 365 | json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1); | ||
| 366 | |||
| 367 | json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); | ||
| 368 | |||
| 369 | return 1; | ||
| 370 | } | ||
| 371 | |||
| 372 | static int json_destroy_config(lua_State *l) | ||
| 373 | { | ||
| 374 | json_config_t *cfg; | ||
| 375 | |||
| 376 | cfg = lua_touserdata(l, 1); | ||
| 377 | if (cfg) | ||
| 378 | strbuf_free(&cfg->encode_buf); | ||
| 379 | cfg = NULL; | ||
| 380 | |||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | |||
| 384 | static void json_create_config(lua_State *l) | ||
| 385 | { | ||
| 386 | json_config_t *cfg; | ||
| 387 | int i; | ||
| 388 | |||
| 389 | cfg = lua_newuserdata(l, sizeof(*cfg)); | ||
| 390 | |||
| 391 | /* Create GC method to clean up strbuf */ | ||
| 392 | lua_newtable(l); | ||
| 393 | lua_pushcfunction(l, json_destroy_config); | ||
| 394 | lua_setfield(l, -2, "__gc"); | ||
| 395 | lua_setmetatable(l, -2); | ||
| 396 | |||
| 397 | cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; | ||
| 398 | cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; | ||
| 399 | cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; | ||
| 400 | cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; | ||
| 401 | cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; | ||
| 402 | cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS; | ||
| 403 | cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS; | ||
| 404 | cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; | ||
| 405 | cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; | ||
| 406 | cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT; | ||
| 407 | |||
| 408 | #if DEFAULT_ENCODE_KEEP_BUFFER > 0 | ||
| 409 | strbuf_init(&cfg->encode_buf, 0); | ||
| 410 | #endif | ||
| 411 | |||
| 412 | /* Decoding init */ | ||
| 413 | |||
| 414 | /* Tag all characters as an error */ | ||
| 415 | for (i = 0; i < 256; i++) | ||
| 416 | cfg->ch2token[i] = T_ERROR; | ||
| 417 | |||
| 418 | /* Set tokens that require no further processing */ | ||
| 419 | cfg->ch2token['{'] = T_OBJ_BEGIN; | ||
| 420 | cfg->ch2token['}'] = T_OBJ_END; | ||
| 421 | cfg->ch2token['['] = T_ARR_BEGIN; | ||
| 422 | cfg->ch2token[']'] = T_ARR_END; | ||
| 423 | cfg->ch2token[','] = T_COMMA; | ||
| 424 | cfg->ch2token[':'] = T_COLON; | ||
| 425 | cfg->ch2token['\0'] = T_END; | ||
| 426 | cfg->ch2token[' '] = T_WHITESPACE; | ||
| 427 | cfg->ch2token['\t'] = T_WHITESPACE; | ||
| 428 | cfg->ch2token['\n'] = T_WHITESPACE; | ||
| 429 | cfg->ch2token['\r'] = T_WHITESPACE; | ||
| 430 | |||
| 431 | /* Update characters that require further processing */ | ||
| 432 | cfg->ch2token['f'] = T_UNKNOWN; /* false? */ | ||
| 433 | cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */ | ||
| 434 | cfg->ch2token['I'] = T_UNKNOWN; | ||
| 435 | cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */ | ||
| 436 | cfg->ch2token['N'] = T_UNKNOWN; | ||
| 437 | cfg->ch2token['t'] = T_UNKNOWN; /* true? */ | ||
| 438 | cfg->ch2token['"'] = T_UNKNOWN; /* string? */ | ||
| 439 | cfg->ch2token['+'] = T_UNKNOWN; /* number? */ | ||
| 440 | cfg->ch2token['-'] = T_UNKNOWN; | ||
| 441 | for (i = 0; i < 10; i++) | ||
| 442 | cfg->ch2token['0' + i] = T_UNKNOWN; | ||
| 443 | |||
| 444 | /* Lookup table for parsing escape characters */ | ||
| 445 | for (i = 0; i < 256; i++) | ||
| 446 | cfg->escape2char[i] = 0; /* String error */ | ||
| 447 | cfg->escape2char['"'] = '"'; | ||
| 448 | cfg->escape2char['\\'] = '\\'; | ||
| 449 | cfg->escape2char['/'] = '/'; | ||
| 450 | cfg->escape2char['b'] = '\b'; | ||
| 451 | cfg->escape2char['t'] = '\t'; | ||
| 452 | cfg->escape2char['n'] = '\n'; | ||
| 453 | cfg->escape2char['f'] = '\f'; | ||
| 454 | cfg->escape2char['r'] = '\r'; | ||
| 455 | cfg->escape2char['u'] = 'u'; /* Unicode parsing required */ | ||
| 456 | } | ||
| 457 | |||
| 458 | /* ===== ENCODING ===== */ | ||
| 459 | |||
| 460 | static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex, | ||
| 461 | const char *reason) | ||
| 462 | { | ||
| 463 | if (!cfg->encode_keep_buffer) | ||
| 464 | strbuf_free(json); | ||
| 465 | luaL_error(l, "Cannot serialise %s: %s", | ||
| 466 | lua_typename(l, lua_type(l, lindex)), reason); | ||
| 467 | } | ||
| 468 | |||
| 469 | /* json_append_string args: | ||
| 470 | * - lua_State | ||
| 471 | * - JSON strbuf | ||
| 472 | * - String (Lua stack index) | ||
| 473 | * | ||
| 474 | * Returns nothing. Doesn't remove string from Lua stack */ | ||
| 475 | static void json_append_string(lua_State *l, strbuf_t *json, int lindex) | ||
| 476 | { | ||
| 477 | const char *escstr; | ||
| 478 | const char *str; | ||
| 479 | size_t i, len; | ||
| 480 | |||
| 481 | str = lua_tolstring(l, lindex, &len); | ||
| 482 | |||
| 483 | /* Worst case is len * 6 (all unicode escapes). | ||
| 484 | * This buffer is reused constantly for small strings | ||
| 485 | * If there are any excess pages, they won't be hit anyway. | ||
| 486 | * This gains ~5% speedup. */ | ||
| 487 | if (len > SIZE_MAX / 6 - 3) | ||
| 488 | abort(); /* Overflow check */ | ||
| 489 | strbuf_ensure_empty_length(json, len * 6 + 2); | ||
| 490 | |||
| 491 | strbuf_append_char_unsafe(json, '\"'); | ||
| 492 | for (i = 0; i < len; i++) { | ||
| 493 | escstr = char2escape[(unsigned char)str[i]]; | ||
| 494 | if (escstr) | ||
| 495 | strbuf_append_string(json, escstr); | ||
| 496 | else | ||
| 497 | strbuf_append_char_unsafe(json, str[i]); | ||
| 498 | } | ||
| 499 | strbuf_append_char_unsafe(json, '\"'); | ||
| 500 | } | ||
| 501 | |||
| 502 | /* Find the size of the array on the top of the Lua stack | ||
| 503 | * -1 object (not a pure array) | ||
| 504 | * >=0 elements in array | ||
| 505 | */ | ||
| 506 | static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json) | ||
| 507 | { | ||
| 508 | double k; | ||
| 509 | int max; | ||
| 510 | int items; | ||
| 511 | |||
| 512 | max = 0; | ||
| 513 | items = 0; | ||
| 514 | |||
| 515 | lua_pushnil(l); | ||
| 516 | /* table, startkey */ | ||
| 517 | while (lua_next(l, -2) != 0) { | ||
| 518 | /* table, key, value */ | ||
| 519 | if (lua_type(l, -2) == LUA_TNUMBER && | ||
| 520 | (k = lua_tonumber(l, -2))) { | ||
| 521 | /* Integer >= 1 ? */ | ||
| 522 | if (floor(k) == k && k >= 1) { | ||
| 523 | if (k > max) | ||
| 524 | max = k; | ||
| 525 | items++; | ||
| 526 | lua_pop(l, 1); | ||
| 527 | continue; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | |||
| 531 | /* Must not be an array (non integer key) */ | ||
| 532 | lua_pop(l, 2); | ||
| 533 | return -1; | ||
| 534 | } | ||
| 535 | |||
| 536 | /* Encode excessively sparse arrays as objects (if enabled) */ | ||
| 537 | if (cfg->encode_sparse_ratio > 0 && | ||
| 538 | max > items * cfg->encode_sparse_ratio && | ||
| 539 | max > cfg->encode_sparse_safe) { | ||
| 540 | if (!cfg->encode_sparse_convert) | ||
| 541 | json_encode_exception(l, cfg, json, -1, "excessively sparse array"); | ||
| 542 | |||
| 543 | return -1; | ||
| 544 | } | ||
| 545 | |||
| 546 | return max; | ||
| 547 | } | ||
| 548 | |||
| 549 | static void json_check_encode_depth(lua_State *l, json_config_t *cfg, | ||
| 550 | int current_depth, strbuf_t *json) | ||
| 551 | { | ||
| 552 | /* Ensure there are enough slots free to traverse a table (key, | ||
| 553 | * value) and push a string for a potential error message. | ||
| 554 | * | ||
| 555 | * Unlike "decode", the key and value are still on the stack when | ||
| 556 | * lua_checkstack() is called. Hence an extra slot for luaL_error() | ||
| 557 | * below is required just in case the next check to lua_checkstack() | ||
| 558 | * fails. | ||
| 559 | * | ||
| 560 | * While this won't cause a crash due to the EXTRA_STACK reserve | ||
| 561 | * slots, it would still be an improper use of the API. */ | ||
| 562 | if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3)) | ||
| 563 | return; | ||
| 564 | |||
| 565 | if (!cfg->encode_keep_buffer) | ||
| 566 | strbuf_free(json); | ||
| 567 | |||
| 568 | luaL_error(l, "Cannot serialise, excessive nesting (%d)", | ||
| 569 | current_depth); | ||
| 570 | } | ||
| 571 | |||
| 572 | static void json_append_data(lua_State *l, json_config_t *cfg, | ||
| 573 | int current_depth, strbuf_t *json); | ||
| 574 | |||
| 575 | /* json_append_array args: | ||
| 576 | * - lua_State | ||
| 577 | * - JSON strbuf | ||
| 578 | * - Size of passwd Lua array (top of stack) */ | ||
| 579 | static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth, | ||
| 580 | strbuf_t *json, int array_length) | ||
| 581 | { | ||
| 582 | int comma, i; | ||
| 583 | |||
| 584 | strbuf_append_char(json, '['); | ||
| 585 | |||
| 586 | comma = 0; | ||
| 587 | for (i = 1; i <= array_length; i++) { | ||
| 588 | if (comma) | ||
| 589 | strbuf_append_char(json, ','); | ||
| 590 | else | ||
| 591 | comma = 1; | ||
| 592 | |||
| 593 | lua_rawgeti(l, -1, i); | ||
| 594 | json_append_data(l, cfg, current_depth, json); | ||
| 595 | lua_pop(l, 1); | ||
| 596 | } | ||
| 597 | |||
| 598 | strbuf_append_char(json, ']'); | ||
| 599 | } | ||
| 600 | |||
| 601 | static void json_append_number(lua_State *l, json_config_t *cfg, | ||
| 602 | strbuf_t *json, int lindex) | ||
| 603 | { | ||
| 604 | double num = lua_tonumber(l, lindex); | ||
| 605 | int len; | ||
| 606 | |||
| 607 | if (cfg->encode_invalid_numbers == 0) { | ||
| 608 | /* Prevent encoding invalid numbers */ | ||
| 609 | if (isinf(num) || isnan(num)) | ||
| 610 | json_encode_exception(l, cfg, json, lindex, "must not be NaN or Inf"); | ||
| 611 | } else if (cfg->encode_invalid_numbers == 1) { | ||
| 612 | /* Encode invalid numbers, but handle "nan" separately | ||
| 613 | * since some platforms may encode as "-nan". */ | ||
| 614 | if (isnan(num)) { | ||
| 615 | strbuf_append_mem(json, "nan", 3); | ||
| 616 | return; | ||
| 617 | } | ||
| 618 | } else { | ||
| 619 | /* Encode invalid numbers as "null" */ | ||
| 620 | if (isinf(num) || isnan(num)) { | ||
| 621 | strbuf_append_mem(json, "null", 4); | ||
| 622 | return; | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); | ||
| 627 | len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision); | ||
| 628 | strbuf_extend_length(json, len); | ||
| 629 | } | ||
| 630 | |||
| 631 | static void json_append_object(lua_State *l, json_config_t *cfg, | ||
| 632 | int current_depth, strbuf_t *json) | ||
| 633 | { | ||
| 634 | int comma, keytype; | ||
| 635 | |||
| 636 | /* Object */ | ||
| 637 | strbuf_append_char(json, '{'); | ||
| 638 | |||
| 639 | lua_pushnil(l); | ||
| 640 | /* table, startkey */ | ||
| 641 | comma = 0; | ||
| 642 | while (lua_next(l, -2) != 0) { | ||
| 643 | if (comma) | ||
| 644 | strbuf_append_char(json, ','); | ||
| 645 | else | ||
| 646 | comma = 1; | ||
| 647 | |||
| 648 | /* table, key, value */ | ||
| 649 | keytype = lua_type(l, -2); | ||
| 650 | if (keytype == LUA_TNUMBER) { | ||
| 651 | strbuf_append_char(json, '"'); | ||
| 652 | json_append_number(l, cfg, json, -2); | ||
| 653 | strbuf_append_mem(json, "\":", 2); | ||
| 654 | } else if (keytype == LUA_TSTRING) { | ||
| 655 | json_append_string(l, json, -2); | ||
| 656 | strbuf_append_char(json, ':'); | ||
| 657 | } else { | ||
| 658 | json_encode_exception(l, cfg, json, -2, | ||
| 659 | "table key must be a number or string"); | ||
| 660 | /* never returns */ | ||
| 661 | } | ||
| 662 | |||
| 663 | /* table, key, value */ | ||
| 664 | json_append_data(l, cfg, current_depth, json); | ||
| 665 | lua_pop(l, 1); | ||
| 666 | /* table, key */ | ||
| 667 | } | ||
| 668 | |||
| 669 | strbuf_append_char(json, '}'); | ||
| 670 | } | ||
| 671 | |||
| 672 | /* Serialise Lua data into JSON string. */ | ||
| 673 | static void json_append_data(lua_State *l, json_config_t *cfg, | ||
| 674 | int current_depth, strbuf_t *json) | ||
| 675 | { | ||
| 676 | int len; | ||
| 677 | |||
| 678 | switch (lua_type(l, -1)) { | ||
| 679 | case LUA_TSTRING: | ||
| 680 | json_append_string(l, json, -1); | ||
| 681 | break; | ||
| 682 | case LUA_TNUMBER: | ||
| 683 | json_append_number(l, cfg, json, -1); | ||
| 684 | break; | ||
| 685 | case LUA_TBOOLEAN: | ||
| 686 | if (lua_toboolean(l, -1)) | ||
| 687 | strbuf_append_mem(json, "true", 4); | ||
| 688 | else | ||
| 689 | strbuf_append_mem(json, "false", 5); | ||
| 690 | break; | ||
| 691 | case LUA_TTABLE: | ||
| 692 | current_depth++; | ||
| 693 | json_check_encode_depth(l, cfg, current_depth, json); | ||
| 694 | |||
| 695 | /* Check if this is an array */ | ||
| 696 | int as_array = 0; | ||
| 697 | if (!lua_checkstack(l, 2)) | ||
| 698 | luaL_error(l, "max lua stack reached"); | ||
| 699 | if (lua_getmetatable(l, -1)) { | ||
| 700 | lua_getfield(l, -1, "__is_cjson_array"); | ||
| 701 | as_array = lua_toboolean(l, -1); | ||
| 702 | lua_pop(l, 2); /* pop value and metatable */ | ||
| 703 | } | ||
| 704 | |||
| 705 | if (as_array) { | ||
| 706 | len = lua_objlen(l, -1); | ||
| 707 | json_append_array(l, cfg, current_depth, json, len); | ||
| 708 | break; | ||
| 709 | } | ||
| 710 | |||
| 711 | len = lua_array_length(l, cfg, json); | ||
| 712 | if (len > 0) | ||
| 713 | json_append_array(l, cfg, current_depth, json, len); | ||
| 714 | else | ||
| 715 | json_append_object(l, cfg, current_depth, json); | ||
| 716 | break; | ||
| 717 | case LUA_TNIL: | ||
| 718 | strbuf_append_mem(json, "null", 4); | ||
| 719 | break; | ||
| 720 | case LUA_TLIGHTUSERDATA: | ||
| 721 | if (lua_touserdata(l, -1) == NULL) { | ||
| 722 | strbuf_append_mem(json, "null", 4); | ||
| 723 | break; | ||
| 724 | } | ||
| 725 | default: | ||
| 726 | /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, | ||
| 727 | * and LUA_TLIGHTUSERDATA) cannot be serialised */ | ||
| 728 | json_encode_exception(l, cfg, json, -1, "type not supported"); | ||
| 729 | /* never returns */ | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | static int json_encode(lua_State *l) | ||
| 734 | { | ||
| 735 | json_config_t *cfg = json_fetch_config(l); | ||
| 736 | strbuf_t local_encode_buf; | ||
| 737 | strbuf_t *encode_buf; | ||
| 738 | char *json; | ||
| 739 | size_t len; | ||
| 740 | |||
| 741 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); | ||
| 742 | |||
| 743 | if (!cfg->encode_keep_buffer) { | ||
| 744 | /* Use private buffer */ | ||
| 745 | encode_buf = &local_encode_buf; | ||
| 746 | strbuf_init(encode_buf, 0); | ||
| 747 | } else { | ||
| 748 | /* Reuse existing buffer */ | ||
| 749 | encode_buf = &cfg->encode_buf; | ||
| 750 | strbuf_reset(encode_buf); | ||
| 751 | } | ||
| 752 | |||
| 753 | json_append_data(l, cfg, 0, encode_buf); | ||
| 754 | json = strbuf_string(encode_buf, &len); | ||
| 755 | |||
| 756 | lua_pushlstring(l, json, len); | ||
| 757 | |||
| 758 | if (!cfg->encode_keep_buffer) | ||
| 759 | strbuf_free(encode_buf); | ||
| 760 | |||
| 761 | return 1; | ||
| 762 | } | ||
| 763 | |||
| 764 | /* ===== DECODING ===== */ | ||
| 765 | |||
| 766 | static void json_process_value(lua_State *l, json_parse_t *json, | ||
| 767 | json_token_t *token); | ||
| 768 | |||
| 769 | static int hexdigit2int(char hex) | ||
| 770 | { | ||
| 771 | if ('0' <= hex && hex <= '9') | ||
| 772 | return hex - '0'; | ||
| 773 | |||
| 774 | /* Force lowercase */ | ||
| 775 | hex |= 0x20; | ||
| 776 | if ('a' <= hex && hex <= 'f') | ||
| 777 | return 10 + hex - 'a'; | ||
| 778 | |||
| 779 | return -1; | ||
| 780 | } | ||
| 781 | |||
| 782 | static int decode_hex4(const char *hex) | ||
| 783 | { | ||
| 784 | int digit[4]; | ||
| 785 | int i; | ||
| 786 | |||
| 787 | /* Convert ASCII hex digit to numeric digit | ||
| 788 | * Note: this returns an error for invalid hex digits, including | ||
| 789 | * NULL */ | ||
| 790 | for (i = 0; i < 4; i++) { | ||
| 791 | digit[i] = hexdigit2int(hex[i]); | ||
| 792 | if (digit[i] < 0) { | ||
| 793 | return -1; | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | return (digit[0] << 12) + | ||
| 798 | (digit[1] << 8) + | ||
| 799 | (digit[2] << 4) + | ||
| 800 | digit[3]; | ||
| 801 | } | ||
| 802 | |||
| 803 | /* Converts a Unicode codepoint to UTF-8. | ||
| 804 | * Returns UTF-8 string length, and up to 4 bytes in *utf8 */ | ||
| 805 | static int codepoint_to_utf8(char *utf8, int codepoint) | ||
| 806 | { | ||
| 807 | /* 0xxxxxxx */ | ||
| 808 | if (codepoint <= 0x7F) { | ||
| 809 | utf8[0] = codepoint; | ||
| 810 | return 1; | ||
| 811 | } | ||
| 812 | |||
| 813 | /* 110xxxxx 10xxxxxx */ | ||
| 814 | if (codepoint <= 0x7FF) { | ||
| 815 | utf8[0] = (codepoint >> 6) | 0xC0; | ||
| 816 | utf8[1] = (codepoint & 0x3F) | 0x80; | ||
| 817 | return 2; | ||
| 818 | } | ||
| 819 | |||
| 820 | /* 1110xxxx 10xxxxxx 10xxxxxx */ | ||
| 821 | if (codepoint <= 0xFFFF) { | ||
| 822 | utf8[0] = (codepoint >> 12) | 0xE0; | ||
| 823 | utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80; | ||
| 824 | utf8[2] = (codepoint & 0x3F) | 0x80; | ||
| 825 | return 3; | ||
| 826 | } | ||
| 827 | |||
| 828 | /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ | ||
| 829 | if (codepoint <= 0x1FFFFF) { | ||
| 830 | utf8[0] = (codepoint >> 18) | 0xF0; | ||
| 831 | utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80; | ||
| 832 | utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80; | ||
| 833 | utf8[3] = (codepoint & 0x3F) | 0x80; | ||
| 834 | return 4; | ||
| 835 | } | ||
| 836 | |||
| 837 | return 0; | ||
| 838 | } | ||
| 839 | |||
| 840 | |||
| 841 | /* Called when index pointing to beginning of UTF-16 code escape: \uXXXX | ||
| 842 | * \u is guaranteed to exist, but the remaining hex characters may be | ||
| 843 | * missing. | ||
| 844 | * Translate to UTF-8 and append to temporary token string. | ||
| 845 | * Must advance index to the next character to be processed. | ||
| 846 | * Returns: 0 success | ||
| 847 | * -1 error | ||
| 848 | */ | ||
| 849 | static int json_append_unicode_escape(json_parse_t *json) | ||
| 850 | { | ||
| 851 | char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */ | ||
| 852 | int codepoint; | ||
| 853 | int surrogate_low; | ||
| 854 | int len; | ||
| 855 | int escape_len = 6; | ||
| 856 | |||
| 857 | /* Fetch UTF-16 code unit */ | ||
| 858 | codepoint = decode_hex4(json->ptr + 2); | ||
| 859 | if (codepoint < 0) | ||
| 860 | return -1; | ||
| 861 | |||
| 862 | /* UTF-16 surrogate pairs take the following 2 byte form: | ||
| 863 | * 11011 x yyyyyyyyyy | ||
| 864 | * When x = 0: y is the high 10 bits of the codepoint | ||
| 865 | * x = 1: y is the low 10 bits of the codepoint | ||
| 866 | * | ||
| 867 | * Check for a surrogate pair (high or low) */ | ||
| 868 | if ((codepoint & 0xF800) == 0xD800) { | ||
| 869 | /* Error if the 1st surrogate is not high */ | ||
| 870 | if (codepoint & 0x400) | ||
| 871 | return -1; | ||
| 872 | |||
| 873 | /* Ensure the next code is a unicode escape */ | ||
| 874 | if (*(json->ptr + escape_len) != '\\' || | ||
| 875 | *(json->ptr + escape_len + 1) != 'u') { | ||
| 876 | return -1; | ||
| 877 | } | ||
| 878 | |||
| 879 | /* Fetch the next codepoint */ | ||
| 880 | surrogate_low = decode_hex4(json->ptr + 2 + escape_len); | ||
| 881 | if (surrogate_low < 0) | ||
| 882 | return -1; | ||
| 883 | |||
| 884 | /* Error if the 2nd code is not a low surrogate */ | ||
| 885 | if ((surrogate_low & 0xFC00) != 0xDC00) | ||
| 886 | return -1; | ||
| 887 | |||
| 888 | /* Calculate Unicode codepoint */ | ||
| 889 | codepoint = (codepoint & 0x3FF) << 10; | ||
| 890 | surrogate_low &= 0x3FF; | ||
| 891 | codepoint = (codepoint | surrogate_low) + 0x10000; | ||
| 892 | escape_len = 12; | ||
| 893 | } | ||
| 894 | |||
| 895 | /* Convert codepoint to UTF-8 */ | ||
| 896 | len = codepoint_to_utf8(utf8, codepoint); | ||
| 897 | if (!len) | ||
| 898 | return -1; | ||
| 899 | |||
| 900 | /* Append bytes and advance parse index */ | ||
| 901 | strbuf_append_mem_unsafe(json->tmp, utf8, len); | ||
| 902 | json->ptr += escape_len; | ||
| 903 | |||
| 904 | return 0; | ||
| 905 | } | ||
| 906 | |||
| 907 | static void json_set_token_error(json_token_t *token, json_parse_t *json, | ||
| 908 | const char *errtype) | ||
| 909 | { | ||
| 910 | token->type = T_ERROR; | ||
| 911 | token->index = json->ptr - json->data; | ||
| 912 | token->value.string = errtype; | ||
| 913 | } | ||
| 914 | |||
| 915 | static void json_next_string_token(json_parse_t *json, json_token_t *token) | ||
| 916 | { | ||
| 917 | char *escape2char = json->cfg->escape2char; | ||
| 918 | char ch; | ||
| 919 | |||
| 920 | /* Caller must ensure a string is next */ | ||
| 921 | assert(*json->ptr == '"'); | ||
| 922 | |||
| 923 | /* Skip " */ | ||
| 924 | json->ptr++; | ||
| 925 | |||
| 926 | /* json->tmp is the temporary strbuf used to accumulate the | ||
| 927 | * decoded string value. | ||
| 928 | * json->tmp is sized to handle JSON containing only a string value. | ||
| 929 | */ | ||
| 930 | strbuf_reset(json->tmp); | ||
| 931 | |||
| 932 | while ((ch = *json->ptr) != '"') { | ||
| 933 | if (!ch) { | ||
| 934 | /* Premature end of the string */ | ||
| 935 | json_set_token_error(token, json, "unexpected end of string"); | ||
| 936 | return; | ||
| 937 | } | ||
| 938 | |||
| 939 | /* Handle escapes */ | ||
| 940 | if (ch == '\\') { | ||
| 941 | /* Fetch escape character */ | ||
| 942 | ch = *(json->ptr + 1); | ||
| 943 | |||
| 944 | /* Translate escape code and append to tmp string */ | ||
| 945 | ch = escape2char[(unsigned char)ch]; | ||
| 946 | if (ch == 'u') { | ||
| 947 | if (json_append_unicode_escape(json) == 0) | ||
| 948 | continue; | ||
| 949 | |||
| 950 | json_set_token_error(token, json, | ||
| 951 | "invalid unicode escape code"); | ||
| 952 | return; | ||
| 953 | } | ||
| 954 | if (!ch) { | ||
| 955 | json_set_token_error(token, json, "invalid escape code"); | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | |||
| 959 | /* Skip '\' */ | ||
| 960 | json->ptr++; | ||
| 961 | } | ||
| 962 | /* Append normal character or translated single character | ||
| 963 | * Unicode escapes are handled above */ | ||
| 964 | strbuf_append_char_unsafe(json->tmp, ch); | ||
| 965 | json->ptr++; | ||
| 966 | } | ||
| 967 | json->ptr++; /* Eat final quote (") */ | ||
| 968 | |||
| 969 | strbuf_ensure_null(json->tmp); | ||
| 970 | |||
| 971 | token->type = T_STRING; | ||
| 972 | token->value.string = strbuf_string(json->tmp, &token->string_len); | ||
| 973 | } | ||
| 974 | |||
| 975 | /* JSON numbers should take the following form: | ||
| 976 | * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)? | ||
| 977 | * | ||
| 978 | * json_next_number_token() uses strtod() which allows other forms: | ||
| 979 | * - numbers starting with '+' | ||
| 980 | * - NaN, -NaN, infinity, -infinity | ||
| 981 | * - hexadecimal numbers | ||
| 982 | * - numbers with leading zeros | ||
| 983 | * | ||
| 984 | * json_is_invalid_number() detects "numbers" which may pass strtod()'s | ||
| 985 | * error checking, but should not be allowed with strict JSON. | ||
| 986 | * | ||
| 987 | * json_is_invalid_number() may pass numbers which cause strtod() | ||
| 988 | * to generate an error. | ||
| 989 | */ | ||
| 990 | static int json_is_invalid_number(json_parse_t *json) | ||
| 991 | { | ||
| 992 | const char *p = json->ptr; | ||
| 993 | |||
| 994 | /* Reject numbers starting with + */ | ||
| 995 | if (*p == '+') | ||
| 996 | return 1; | ||
| 997 | |||
| 998 | /* Skip minus sign if it exists */ | ||
| 999 | if (*p == '-') | ||
| 1000 | p++; | ||
| 1001 | |||
| 1002 | /* Reject numbers starting with 0x, or leading zeros */ | ||
| 1003 | if (*p == '0') { | ||
| 1004 | int ch2 = *(p + 1); | ||
| 1005 | |||
| 1006 | if ((ch2 | 0x20) == 'x' || /* Hex */ | ||
| 1007 | ('0' <= ch2 && ch2 <= '9')) /* Leading zero */ | ||
| 1008 | return 1; | ||
| 1009 | |||
| 1010 | return 0; | ||
| 1011 | } else if (*p <= '9') { | ||
| 1012 | return 0; /* Ordinary number */ | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | /* Reject inf/nan */ | ||
| 1016 | if (!strncasecmp(p, "inf", 3)) | ||
| 1017 | return 1; | ||
| 1018 | if (!strncasecmp(p, "nan", 3)) | ||
| 1019 | return 1; | ||
| 1020 | |||
| 1021 | /* Pass all other numbers which may still be invalid, but | ||
| 1022 | * strtod() will catch them. */ | ||
| 1023 | return 0; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | static void json_next_number_token(json_parse_t *json, json_token_t *token) | ||
| 1027 | { | ||
| 1028 | char *endptr; | ||
| 1029 | |||
| 1030 | token->type = T_NUMBER; | ||
| 1031 | token->value.number = fpconv_strtod(json->ptr, &endptr); | ||
| 1032 | if (json->ptr == endptr) | ||
| 1033 | json_set_token_error(token, json, "invalid number"); | ||
| 1034 | else | ||
| 1035 | json->ptr = endptr; /* Skip the processed number */ | ||
| 1036 | |||
| 1037 | return; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | /* Fills in the token struct. | ||
| 1041 | * T_STRING will return a pointer to the json_parse_t temporary string | ||
| 1042 | * T_ERROR will leave the json->ptr pointer at the error. | ||
| 1043 | */ | ||
| 1044 | static void json_next_token(json_parse_t *json, json_token_t *token) | ||
| 1045 | { | ||
| 1046 | const json_token_type_t *ch2token = json->cfg->ch2token; | ||
| 1047 | int ch; | ||
| 1048 | |||
| 1049 | /* Eat whitespace. */ | ||
| 1050 | while (1) { | ||
| 1051 | ch = (unsigned char)*(json->ptr); | ||
| 1052 | token->type = ch2token[ch]; | ||
| 1053 | if (token->type != T_WHITESPACE) | ||
| 1054 | break; | ||
| 1055 | json->ptr++; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | /* Store location of new token. Required when throwing errors | ||
| 1059 | * for unexpected tokens (syntax errors). */ | ||
| 1060 | token->index = json->ptr - json->data; | ||
| 1061 | |||
| 1062 | /* Don't advance the pointer for an error or the end */ | ||
| 1063 | if (token->type == T_ERROR) { | ||
| 1064 | json_set_token_error(token, json, "invalid token"); | ||
| 1065 | return; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | if (token->type == T_END) { | ||
| 1069 | return; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | /* Found a known single character token, advance index and return */ | ||
| 1073 | if (token->type != T_UNKNOWN) { | ||
| 1074 | json->ptr++; | ||
| 1075 | return; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | /* Process characters which triggered T_UNKNOWN | ||
| 1079 | * | ||
| 1080 | * Must use strncmp() to match the front of the JSON string. | ||
| 1081 | * JSON identifier must be lowercase. | ||
| 1082 | * When strict_numbers if disabled, either case is allowed for | ||
| 1083 | * Infinity/NaN (since we are no longer following the spec..) */ | ||
| 1084 | if (ch == '"') { | ||
| 1085 | json_next_string_token(json, token); | ||
| 1086 | return; | ||
| 1087 | } else if (ch == '-' || ('0' <= ch && ch <= '9')) { | ||
| 1088 | if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) { | ||
| 1089 | json_set_token_error(token, json, "invalid number"); | ||
| 1090 | return; | ||
| 1091 | } | ||
| 1092 | json_next_number_token(json, token); | ||
| 1093 | return; | ||
| 1094 | } else if (!strncmp(json->ptr, "true", 4)) { | ||
| 1095 | token->type = T_BOOLEAN; | ||
| 1096 | token->value.boolean = 1; | ||
| 1097 | json->ptr += 4; | ||
| 1098 | return; | ||
| 1099 | } else if (!strncmp(json->ptr, "false", 5)) { | ||
| 1100 | token->type = T_BOOLEAN; | ||
| 1101 | token->value.boolean = 0; | ||
| 1102 | json->ptr += 5; | ||
| 1103 | return; | ||
| 1104 | } else if (!strncmp(json->ptr, "null", 4)) { | ||
| 1105 | token->type = T_NULL; | ||
| 1106 | json->ptr += 4; | ||
| 1107 | return; | ||
| 1108 | } else if (json->cfg->decode_invalid_numbers && | ||
| 1109 | json_is_invalid_number(json)) { | ||
| 1110 | /* When decode_invalid_numbers is enabled, only attempt to process | ||
| 1111 | * numbers we know are invalid JSON (Inf, NaN, hex) | ||
| 1112 | * This is required to generate an appropriate token error, | ||
| 1113 | * otherwise all bad tokens will register as "invalid number" | ||
| 1114 | */ | ||
| 1115 | json_next_number_token(json, token); | ||
| 1116 | return; | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | /* Token starts with t/f/n but isn't recognised above. */ | ||
| 1120 | json_set_token_error(token, json, "invalid token"); | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | /* This function does not return. | ||
| 1124 | * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED. | ||
| 1125 | * The only supported exception is the temporary parser string | ||
| 1126 | * json->tmp struct. | ||
| 1127 | * json and token should exist on the stack somewhere. | ||
| 1128 | * luaL_error() will long_jmp and release the stack */ | ||
| 1129 | static void json_throw_parse_error(lua_State *l, json_parse_t *json, | ||
| 1130 | const char *exp, json_token_t *token) | ||
| 1131 | { | ||
| 1132 | const char *found; | ||
| 1133 | |||
| 1134 | strbuf_free(json->tmp); | ||
| 1135 | |||
| 1136 | if (token->type == T_ERROR) | ||
| 1137 | found = token->value.string; | ||
| 1138 | else | ||
| 1139 | found = json_token_type_name[token->type]; | ||
| 1140 | |||
| 1141 | /* Note: token->index is 0 based, display starting from 1 */ | ||
| 1142 | luaL_error(l, "Expected %s but found %s at character %d", | ||
| 1143 | exp, found, token->index + 1); | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | static inline void json_decode_ascend(json_parse_t *json) | ||
| 1147 | { | ||
| 1148 | json->current_depth--; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static void json_decode_descend(lua_State *l, json_parse_t *json, int slots) | ||
| 1152 | { | ||
| 1153 | json->current_depth++; | ||
| 1154 | |||
| 1155 | if (json->current_depth <= json->cfg->decode_max_depth && | ||
| 1156 | lua_checkstack(l, slots)) { | ||
| 1157 | return; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | strbuf_free(json->tmp); | ||
| 1161 | luaL_error(l, "Found too many nested data structures (%d) at character %d", | ||
| 1162 | json->current_depth, json->ptr - json->data); | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | static void json_parse_object_context(lua_State *l, json_parse_t *json) | ||
| 1166 | { | ||
| 1167 | json_token_t token; | ||
| 1168 | |||
| 1169 | /* 3 slots required: | ||
| 1170 | * .., table, key, value */ | ||
| 1171 | json_decode_descend(l, json, 3); | ||
| 1172 | |||
| 1173 | lua_newtable(l); | ||
| 1174 | |||
| 1175 | json_next_token(json, &token); | ||
| 1176 | |||
| 1177 | /* Handle empty objects */ | ||
| 1178 | if (token.type == T_OBJ_END) { | ||
| 1179 | json_decode_ascend(json); | ||
| 1180 | return; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | while (1) { | ||
| 1184 | if (token.type != T_STRING) | ||
| 1185 | json_throw_parse_error(l, json, "object key string", &token); | ||
| 1186 | |||
| 1187 | /* Push key */ | ||
| 1188 | lua_pushlstring(l, token.value.string, token.string_len); | ||
| 1189 | |||
| 1190 | json_next_token(json, &token); | ||
| 1191 | if (token.type != T_COLON) | ||
| 1192 | json_throw_parse_error(l, json, "colon", &token); | ||
| 1193 | |||
| 1194 | /* Fetch value */ | ||
| 1195 | json_next_token(json, &token); | ||
| 1196 | json_process_value(l, json, &token); | ||
| 1197 | |||
| 1198 | /* Set key = value */ | ||
| 1199 | lua_rawset(l, -3); | ||
| 1200 | |||
| 1201 | json_next_token(json, &token); | ||
| 1202 | |||
| 1203 | if (token.type == T_OBJ_END) { | ||
| 1204 | json_decode_ascend(json); | ||
| 1205 | return; | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | if (token.type != T_COMMA) | ||
| 1209 | json_throw_parse_error(l, json, "comma or object end", &token); | ||
| 1210 | |||
| 1211 | json_next_token(json, &token); | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | /* Handle the array context */ | ||
| 1216 | static void json_parse_array_context(lua_State *l, json_parse_t *json) | ||
| 1217 | { | ||
| 1218 | json_token_t token; | ||
| 1219 | int i; | ||
| 1220 | |||
| 1221 | /* 2 slots required: | ||
| 1222 | * .., table, value */ | ||
| 1223 | json_decode_descend(l, json, 2); | ||
| 1224 | |||
| 1225 | lua_newtable(l); | ||
| 1226 | |||
| 1227 | /* set array_mt on the table at the top of the stack */ | ||
| 1228 | if (json->cfg->decode_array_with_array_mt) { | ||
| 1229 | /* Ensure sufficient stack space for metatable creation (metatable + boolean) */ | ||
| 1230 | if (!lua_checkstack(l, 2)) | ||
| 1231 | luaL_error(l, "max lua stack reached"); | ||
| 1232 | /* Mark this table so encoder can emit [] for empty arrays */ | ||
| 1233 | lua_newtable(l); | ||
| 1234 | lua_pushboolean(l, 1); | ||
| 1235 | lua_setfield(l, -2, "__is_cjson_array"); | ||
| 1236 | lua_enablereadonlytable(l, -1, 1); /* protect the metatable. */ | ||
| 1237 | lua_setmetatable(l, -2); /* set metatable for the array table */ | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | json_next_token(json, &token); | ||
| 1241 | |||
| 1242 | /* Handle empty arrays */ | ||
| 1243 | if (token.type == T_ARR_END) { | ||
| 1244 | json_decode_ascend(json); | ||
| 1245 | return; | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | for (i = 1; ; i++) { | ||
| 1249 | json_process_value(l, json, &token); | ||
| 1250 | lua_rawseti(l, -2, i); /* arr[i] = value */ | ||
| 1251 | |||
| 1252 | json_next_token(json, &token); | ||
| 1253 | |||
| 1254 | if (token.type == T_ARR_END) { | ||
| 1255 | json_decode_ascend(json); | ||
| 1256 | return; | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | if (token.type != T_COMMA) | ||
| 1260 | json_throw_parse_error(l, json, "comma or array end", &token); | ||
| 1261 | |||
| 1262 | json_next_token(json, &token); | ||
| 1263 | } | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | /* Handle the "value" context */ | ||
| 1267 | static void json_process_value(lua_State *l, json_parse_t *json, | ||
| 1268 | json_token_t *token) | ||
| 1269 | { | ||
| 1270 | switch (token->type) { | ||
| 1271 | case T_STRING: | ||
| 1272 | lua_pushlstring(l, token->value.string, token->string_len); | ||
| 1273 | break;; | ||
| 1274 | case T_NUMBER: | ||
| 1275 | lua_pushnumber(l, token->value.number); | ||
| 1276 | break;; | ||
| 1277 | case T_BOOLEAN: | ||
| 1278 | lua_pushboolean(l, token->value.boolean); | ||
| 1279 | break;; | ||
| 1280 | case T_OBJ_BEGIN: | ||
| 1281 | json_parse_object_context(l, json); | ||
| 1282 | break;; | ||
| 1283 | case T_ARR_BEGIN: | ||
| 1284 | json_parse_array_context(l, json); | ||
| 1285 | break;; | ||
| 1286 | case T_NULL: | ||
| 1287 | /* In Lua, setting "t[k] = nil" will delete k from the table. | ||
| 1288 | * Hence a NULL pointer lightuserdata object is used instead */ | ||
| 1289 | lua_pushlightuserdata(l, NULL); | ||
| 1290 | break;; | ||
| 1291 | default: | ||
| 1292 | json_throw_parse_error(l, json, "value", token); | ||
| 1293 | } | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | static int json_decode(lua_State *l) | ||
| 1297 | { | ||
| 1298 | json_parse_t json; | ||
| 1299 | json_token_t token; | ||
| 1300 | size_t json_len; | ||
| 1301 | |||
| 1302 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); | ||
| 1303 | |||
| 1304 | json.cfg = json_fetch_config(l); | ||
| 1305 | json.data = luaL_checklstring(l, 1, &json_len); | ||
| 1306 | json.current_depth = 0; | ||
| 1307 | json.ptr = json.data; | ||
| 1308 | |||
| 1309 | /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3) | ||
| 1310 | * | ||
| 1311 | * CJSON can support any simple data type, hence only the first | ||
| 1312 | * character is guaranteed to be ASCII (at worst: '"'). This is | ||
| 1313 | * still enough to detect whether the wrong encoding is in use. */ | ||
| 1314 | if (json_len >= 2 && (!json.data[0] || !json.data[1])) | ||
| 1315 | luaL_error(l, "JSON parser does not support UTF-16 or UTF-32"); | ||
| 1316 | |||
| 1317 | /* Ensure the temporary buffer can hold the entire string. | ||
| 1318 | * This means we no longer need to do length checks since the decoded | ||
| 1319 | * string must be smaller than the entire json string */ | ||
| 1320 | json.tmp = strbuf_new(json_len); | ||
| 1321 | |||
| 1322 | json_next_token(&json, &token); | ||
| 1323 | json_process_value(l, &json, &token); | ||
| 1324 | |||
| 1325 | /* Ensure there is no more input left */ | ||
| 1326 | json_next_token(&json, &token); | ||
| 1327 | |||
| 1328 | if (token.type != T_END) | ||
| 1329 | json_throw_parse_error(l, &json, "the end", &token); | ||
| 1330 | |||
| 1331 | strbuf_free(json.tmp); | ||
| 1332 | |||
| 1333 | return 1; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | /* ===== INITIALISATION ===== */ | ||
| 1337 | |||
| 1338 | #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 | ||
| 1339 | /* Compatibility for Lua 5.1. | ||
| 1340 | * | ||
| 1341 | * luaL_setfuncs() is used to create a module table where the functions have | ||
| 1342 | * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */ | ||
| 1343 | static void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup) | ||
| 1344 | { | ||
| 1345 | int i; | ||
| 1346 | |||
| 1347 | luaL_checkstack(l, nup, "too many upvalues"); | ||
| 1348 | for (; reg->name != NULL; reg++) { /* fill the table with given functions */ | ||
| 1349 | for (i = 0; i < nup; i++) /* copy upvalues to the top */ | ||
| 1350 | lua_pushvalue(l, -nup); | ||
| 1351 | lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ | ||
| 1352 | lua_setfield(l, -(nup + 2), reg->name); | ||
| 1353 | } | ||
| 1354 | lua_pop(l, nup); /* remove upvalues */ | ||
| 1355 | } | ||
| 1356 | #endif | ||
| 1357 | |||
| 1358 | /* Call target function in protected mode with all supplied args. | ||
| 1359 | * Assumes target function only returns a single non-nil value. | ||
| 1360 | * Convert and return thrown errors as: nil, "error message" */ | ||
| 1361 | static int json_protect_conversion(lua_State *l) | ||
| 1362 | { | ||
| 1363 | int err; | ||
| 1364 | |||
| 1365 | /* Deliberately throw an error for invalid arguments */ | ||
| 1366 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); | ||
| 1367 | |||
| 1368 | /* pcall() the function stored as upvalue(1) */ | ||
| 1369 | lua_pushvalue(l, lua_upvalueindex(1)); | ||
| 1370 | lua_insert(l, 1); | ||
| 1371 | err = lua_pcall(l, 1, 1, 0); | ||
| 1372 | if (!err) | ||
| 1373 | return 1; | ||
| 1374 | |||
| 1375 | if (err == LUA_ERRRUN) { | ||
| 1376 | lua_pushnil(l); | ||
| 1377 | lua_insert(l, -2); | ||
| 1378 | return 2; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | /* Since we are not using a custom error handler, the only remaining | ||
| 1382 | * errors are memory related */ | ||
| 1383 | return luaL_error(l, "Memory allocation error in CJSON protected call"); | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | /* Return cjson module table */ | ||
| 1387 | static int lua_cjson_new(lua_State *l) | ||
| 1388 | { | ||
| 1389 | luaL_Reg reg[] = { | ||
| 1390 | { "encode", json_encode }, | ||
| 1391 | { "decode", json_decode }, | ||
| 1392 | { "decode_array_with_array_mt", json_cfg_decode_array_with_array_mt }, | ||
| 1393 | { "encode_sparse_array", json_cfg_encode_sparse_array }, | ||
| 1394 | { "encode_max_depth", json_cfg_encode_max_depth }, | ||
| 1395 | { "decode_max_depth", json_cfg_decode_max_depth }, | ||
| 1396 | { "encode_number_precision", json_cfg_encode_number_precision }, | ||
| 1397 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, | ||
| 1398 | { "encode_invalid_numbers", json_cfg_encode_invalid_numbers }, | ||
| 1399 | { "decode_invalid_numbers", json_cfg_decode_invalid_numbers }, | ||
| 1400 | { "new", lua_cjson_new }, | ||
| 1401 | { NULL, NULL } | ||
| 1402 | }; | ||
| 1403 | |||
| 1404 | /* Initialise number conversions */ | ||
| 1405 | fpconv_init(); | ||
| 1406 | |||
| 1407 | /* cjson module table */ | ||
| 1408 | lua_newtable(l); | ||
| 1409 | |||
| 1410 | /* Register functions with config data as upvalue */ | ||
| 1411 | json_create_config(l); | ||
| 1412 | luaL_setfuncs(l, reg, 1); | ||
| 1413 | |||
| 1414 | /* Set cjson.null */ | ||
| 1415 | lua_pushlightuserdata(l, NULL); | ||
| 1416 | lua_setfield(l, -2, "null"); | ||
| 1417 | |||
| 1418 | /* Set module name / version fields */ | ||
| 1419 | lua_pushliteral(l, CJSON_MODNAME); | ||
| 1420 | lua_setfield(l, -2, "_NAME"); | ||
| 1421 | lua_pushliteral(l, CJSON_VERSION); | ||
| 1422 | lua_setfield(l, -2, "_VERSION"); | ||
| 1423 | |||
| 1424 | return 1; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | /* Return cjson.safe module table */ | ||
| 1428 | static int lua_cjson_safe_new(lua_State *l) | ||
| 1429 | { | ||
| 1430 | const char *func[] = { "decode", "encode", NULL }; | ||
| 1431 | int i; | ||
| 1432 | |||
| 1433 | lua_cjson_new(l); | ||
| 1434 | |||
| 1435 | /* Fix new() method */ | ||
| 1436 | lua_pushcfunction(l, lua_cjson_safe_new); | ||
| 1437 | lua_setfield(l, -2, "new"); | ||
| 1438 | |||
| 1439 | for (i = 0; func[i]; i++) { | ||
| 1440 | lua_getfield(l, -1, func[i]); | ||
| 1441 | lua_pushcclosure(l, json_protect_conversion, 1); | ||
| 1442 | lua_setfield(l, -2, func[i]); | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | return 1; | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | int luaopen_cjson(lua_State *l) | ||
| 1449 | { | ||
| 1450 | lua_cjson_new(l); | ||
| 1451 | |||
| 1452 | #ifdef ENABLE_CJSON_GLOBAL | ||
| 1453 | /* Register a global "cjson" table. */ | ||
| 1454 | lua_pushvalue(l, -1); | ||
| 1455 | lua_setglobal(l, CJSON_MODNAME); | ||
| 1456 | #endif | ||
| 1457 | |||
| 1458 | /* Return cjson table */ | ||
| 1459 | return 1; | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | int luaopen_cjson_safe(lua_State *l) | ||
| 1463 | { | ||
| 1464 | lua_cjson_safe_new(l); | ||
| 1465 | |||
| 1466 | /* Return cjson.safe table */ | ||
| 1467 | return 1; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | /* vi:ai et sw=4 ts=4: | ||
| 1471 | */ | ||
