diff options
| author | Mark Pulford <mark@kyne.com.au> | 2012-01-12 21:28:39 +1030 |
|---|---|---|
| committer | Mark Pulford <mark@kyne.com.au> | 2012-03-04 18:54:34 +1030 |
| commit | 418ee3fe24150c59c9afa6746aab7f09edcb894c (patch) | |
| tree | e23bb79ca8f0146bcc9714658eed6da76d1b293c | |
| parent | 5e36beccab38fa40b2c324c9339bbd5f1a3f24e3 (diff) | |
| download | lua-cjson-418ee3fe24150c59c9afa6746aab7f09edcb894c.tar.gz lua-cjson-418ee3fe24150c59c9afa6746aab7f09edcb894c.tar.bz2 lua-cjson-418ee3fe24150c59c9afa6746aab7f09edcb894c.zip | |
Add option to encode invalid numbers as "null"
Deprecate and replace refuse_invalid_numbers() with
encode_invalid_numbers() and decode_invalid_numbers().
| -rw-r--r-- | lua_cjson.c | 174 | ||||
| -rw-r--r-- | manual.txt | 96 | ||||
| -rwxr-xr-x | tests/test.lua | 21 |
3 files changed, 180 insertions, 111 deletions
diff --git a/lua_cjson.c b/lua_cjson.c index bdfa7d4..1e9e91d 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
| @@ -64,14 +64,14 @@ | |||
| 64 | #define DEFAULT_SPARSE_SAFE 10 | 64 | #define DEFAULT_SPARSE_SAFE 10 |
| 65 | #define DEFAULT_ENCODE_MAX_DEPTH 20 | 65 | #define DEFAULT_ENCODE_MAX_DEPTH 20 |
| 66 | #define DEFAULT_DECODE_MAX_DEPTH 20 | 66 | #define DEFAULT_DECODE_MAX_DEPTH 20 |
| 67 | #define DEFAULT_ENCODE_REFUSE_BADNUM 1 | 67 | #define DEFAULT_ENCODE_INVALID_NUMBERS 0 |
| 68 | #define DEFAULT_DECODE_REFUSE_BADNUM 0 | 68 | #define DEFAULT_DECODE_INVALID_NUMBERS 1 |
| 69 | #define DEFAULT_ENCODE_KEEP_BUFFER 1 | 69 | #define DEFAULT_ENCODE_KEEP_BUFFER 1 |
| 70 | #define DEFAULT_ENCODE_NUMBER_PRECISION 14 | 70 | #define DEFAULT_ENCODE_NUMBER_PRECISION 14 |
| 71 | 71 | ||
| 72 | #ifdef DISABLE_INVALID_NUMBERS | 72 | #ifdef DISABLE_INVALID_NUMBERS |
| 73 | #undef DEFAULT_DECODE_REFUSE_BADNUM | 73 | #undef DEFAULT_DECODE_INVALID_NUMBERS |
| 74 | #define DEFAULT_DECODE_REFUSE_BADNUM 1 | 74 | #define DEFAULT_DECODE_INVALID_NUMBERS 0 |
| 75 | #endif | 75 | #endif |
| 76 | 76 | ||
| 77 | typedef enum { | 77 | typedef enum { |
| @@ -121,11 +121,11 @@ typedef struct { | |||
| 121 | int encode_sparse_ratio; | 121 | int encode_sparse_ratio; |
| 122 | int encode_sparse_safe; | 122 | int encode_sparse_safe; |
| 123 | int encode_max_depth; | 123 | int encode_max_depth; |
| 124 | int encode_refuse_badnum; | 124 | int encode_invalid_numbers; /* 2 => Encode as "null" */ |
| 125 | int encode_number_precision; | 125 | int encode_number_precision; |
| 126 | int encode_keep_buffer; | 126 | int encode_keep_buffer; |
| 127 | 127 | ||
| 128 | int decode_refuse_badnum; | 128 | int decode_invalid_numbers; |
| 129 | int decode_max_depth; | 129 | int decode_max_depth; |
| 130 | } json_config_t; | 130 | } json_config_t; |
| 131 | 131 | ||
| @@ -259,6 +259,29 @@ static int json_integer_option(lua_State *l, int *setting, int min, int max) | |||
| 259 | return 1; | 259 | return 1; |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | /* Process enumerated arguments for a configuration function */ | ||
| 263 | static int json_enum_option(lua_State *l, int *setting, | ||
| 264 | const char **options, int bool_value) | ||
| 265 | { | ||
| 266 | static const char *bool_options[] = { "off", "on", NULL }; | ||
| 267 | |||
| 268 | if (!options) { | ||
| 269 | options = bool_options; | ||
| 270 | bool_value = 1; | ||
| 271 | } | ||
| 272 | |||
| 273 | if (lua_gettop(l)) { | ||
| 274 | if (lua_isboolean(l, 1)) | ||
| 275 | *setting = lua_toboolean(l, 1) * bool_value; | ||
| 276 | else | ||
| 277 | *setting = luaL_checkoption(l, 1, NULL, options); | ||
| 278 | } | ||
| 279 | |||
| 280 | lua_pushstring(l, options[*setting]); | ||
| 281 | |||
| 282 | return 1; | ||
| 283 | } | ||
| 284 | |||
| 262 | /* Configures the maximum number of nested arrays/objects allowed when | 285 | /* Configures the maximum number of nested arrays/objects allowed when |
| 263 | * encoding */ | 286 | * encoding */ |
| 264 | static int json_cfg_encode_max_depth(lua_State *l) | 287 | static int json_cfg_encode_max_depth(lua_State *l) |
| @@ -288,18 +311,12 @@ static int json_cfg_encode_number_precision(lua_State *l) | |||
| 288 | /* Configures JSON encoding buffer persistence */ | 311 | /* Configures JSON encoding buffer persistence */ |
| 289 | static int json_cfg_encode_keep_buffer(lua_State *l) | 312 | static int json_cfg_encode_keep_buffer(lua_State *l) |
| 290 | { | 313 | { |
| 291 | json_config_t *cfg; | 314 | json_config_t *cfg = json_fetch_config(l); |
| 292 | int old_value; | 315 | int old_value; |
| 293 | 316 | ||
| 294 | json_verify_arg_count(l, 1); | ||
| 295 | cfg = json_fetch_config(l); | ||
| 296 | |||
| 297 | old_value = cfg->encode_keep_buffer; | 317 | old_value = cfg->encode_keep_buffer; |
| 298 | 318 | ||
| 299 | if (lua_gettop(l)) { | 319 | json_enum_option(l, &cfg->encode_keep_buffer, NULL, 1); |
| 300 | luaL_checktype(l, 1, LUA_TBOOLEAN); | ||
| 301 | cfg->encode_keep_buffer = lua_toboolean(l, 1); | ||
| 302 | } | ||
| 303 | 320 | ||
| 304 | /* Init / free the buffer if the setting has changed */ | 321 | /* Init / free the buffer if the setting has changed */ |
| 305 | if (old_value ^ cfg->encode_keep_buffer) { | 322 | if (old_value ^ cfg->encode_keep_buffer) { |
| @@ -309,62 +326,76 @@ static int json_cfg_encode_keep_buffer(lua_State *l) | |||
| 309 | strbuf_free(&cfg->encode_buf); | 326 | strbuf_free(&cfg->encode_buf); |
| 310 | } | 327 | } |
| 311 | 328 | ||
| 312 | lua_pushboolean(l, cfg->encode_keep_buffer); | ||
| 313 | |||
| 314 | return 1; | 329 | return 1; |
| 315 | } | 330 | } |
| 316 | 331 | ||
| 317 | /* On argument: decode enum and set config variables | 332 | static int json_cfg_encode_invalid_numbers(lua_State *l) |
| 318 | * **options must point to a NULL terminated array of 4 enums | ||
| 319 | * Returns: current enum value */ | ||
| 320 | static void json_enum_option(lua_State *l, const char **options, | ||
| 321 | int *opt1, int *opt2) | ||
| 322 | { | 333 | { |
| 323 | int setting; | 334 | static const char *options[] = { "off", "on", "null", NULL }; |
| 335 | json_config_t *cfg = json_fetch_config(l); | ||
| 324 | 336 | ||
| 325 | if (lua_gettop(l)) { | 337 | json_enum_option(l, &cfg->encode_invalid_numbers, options, 1); |
| 326 | if (lua_isboolean(l, 1)) | ||
| 327 | setting = lua_toboolean(l, 1) * 3; | ||
| 328 | else | ||
| 329 | setting = luaL_checkoption(l, 1, NULL, options); | ||
| 330 | 338 | ||
| 331 | *opt1 = setting & 1 ? 1 : 0; | 339 | #if DISABLE_INVALID_NUMBERS |
| 332 | *opt2 = setting & 2 ? 1 : 0; | 340 | if (cfg->encode_invalid_numbers == 1) { |
| 333 | } else { | 341 | cfg->encode_invalid_numbers = 0; |
| 334 | setting = *opt1 | (*opt2 << 1); | 342 | luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); |
| 335 | } | 343 | } |
| 344 | #endif | ||
| 336 | 345 | ||
| 337 | if (setting) | 346 | return 1; |
| 338 | lua_pushstring(l, options[setting]); | ||
| 339 | else | ||
| 340 | lua_pushboolean(l, 0); | ||
| 341 | } | 347 | } |
| 342 | 348 | ||
| 349 | static int json_cfg_decode_invalid_numbers(lua_State *l) | ||
| 350 | { | ||
| 351 | json_config_t *cfg = json_fetch_config(l); | ||
| 352 | |||
| 353 | json_enum_option(l, &cfg->decode_invalid_numbers, NULL, 1); | ||
| 354 | |||
| 355 | #if DISABLE_INVALID_NUMBERS | ||
| 356 | if (cfg->decode_invalid_numbers) { | ||
| 357 | cfg->decode_invalid_numbers = 0; | ||
| 358 | luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); | ||
| 359 | } | ||
| 360 | #endif | ||
| 343 | 361 | ||
| 344 | /* When enabled, rejects: NaN, Infinity, hexadecimal numbers */ | 362 | return 1; |
| 363 | } | ||
| 364 | |||
| 365 | /* When enabled, rejects: NaN, Infinity, hexadecimal numbers. | ||
| 366 | * | ||
| 367 | * This function has been deprecated and may be removed in future. */ | ||
| 345 | static int json_cfg_refuse_invalid_numbers(lua_State *l) | 368 | static int json_cfg_refuse_invalid_numbers(lua_State *l) |
| 346 | { | 369 | { |
| 347 | static const char *options_enc_dec[] = { "none", "encode", "decode", | 370 | static const char *options[] = { "none", "encode", "decode", "both", NULL }; |
| 348 | "both", NULL }; | 371 | json_config_t *cfg = json_fetch_config(l); |
| 349 | json_config_t *cfg; | 372 | int have_arg, setting; |
| 350 | 373 | ||
| 351 | json_verify_arg_count(l, 1); | 374 | have_arg = lua_gettop(l); |
| 352 | cfg = json_fetch_config(l); | ||
| 353 | 375 | ||
| 354 | json_enum_option(l, options_enc_dec, | 376 | /* Map config variables to options list index */ |
| 355 | &cfg->encode_refuse_badnum, | 377 | setting = !cfg->encode_invalid_numbers + /* bit 0 */ |
| 356 | &cfg->decode_refuse_badnum); | 378 | (!cfg->decode_invalid_numbers << 1); /* bit 1 */ |
| 379 | |||
| 380 | json_enum_option(l, &setting, options, 3); | ||
| 381 | |||
| 382 | /* Map options list index to config variables | ||
| 383 | * | ||
| 384 | * Only update the config variables when an argument has been provided. | ||
| 385 | * Otherwise a "null" encoding setting may inadvertently be disabled. */ | ||
| 386 | if (have_arg) { | ||
| 387 | cfg->encode_invalid_numbers = !(setting & 1); | ||
| 388 | cfg->decode_invalid_numbers = !(setting & 2); | ||
| 357 | 389 | ||
| 358 | #if DISABLE_INVALID_NUMBERS | 390 | #if DISABLE_INVALID_NUMBERS |
| 359 | /* Some non-POSIX platforms don't handle double <-> string translations | 391 | if (cfg->encode_invalid_numbers || cfg->decode_invalid_numbers) { |
| 360 | * for Infinity/NaN/hexadecimal properly. Throw an error if the | 392 | cfg->encode_invalid_numbers = cfg->decode_invalid_numbers = 0; |
| 361 | * user attempts to enable them. */ | 393 | luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); |
| 362 | if (!cfg->encode_refuse_badnum || !cfg->decode_refuse_badnum) { | 394 | } |
| 363 | cfg->encode_refuse_badnum = cfg->decode_refuse_badnum = 1; | ||
| 364 | luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); | ||
| 365 | } | ||
| 366 | #endif | 395 | #endif |
| 367 | 396 | ||
| 397 | } | ||
| 398 | |||
| 368 | return 1; | 399 | return 1; |
| 369 | } | 400 | } |
| 370 | 401 | ||
| @@ -398,8 +429,8 @@ static void json_create_config(lua_State *l) | |||
| 398 | cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; | 429 | cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; |
| 399 | cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; | 430 | cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; |
| 400 | cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; | 431 | cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; |
| 401 | cfg->encode_refuse_badnum = DEFAULT_ENCODE_REFUSE_BADNUM; | 432 | cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS; |
| 402 | cfg->decode_refuse_badnum = DEFAULT_DECODE_REFUSE_BADNUM; | 433 | cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS; |
| 403 | cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; | 434 | cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; |
| 404 | cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; | 435 | cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; |
| 405 | 436 | ||
| @@ -589,17 +620,28 @@ static void json_append_number(lua_State *l, json_config_t *cfg, | |||
| 589 | double num = lua_tonumber(l, lindex); | 620 | double num = lua_tonumber(l, lindex); |
| 590 | int len; | 621 | int len; |
| 591 | 622 | ||
| 592 | if (cfg->encode_refuse_badnum && (isinf(num) || isnan(num))) | 623 | if (cfg->encode_invalid_numbers == 0) { |
| 593 | json_encode_exception(l, cfg, json, lindex, "must not be NaN or Inf"); | 624 | /* Prevent encoding invalid numbers */ |
| 594 | 625 | if (isinf(num) || isnan(num)) | |
| 595 | if (isnan(num)) { | 626 | json_encode_exception(l, cfg, json, lindex, "must not be NaN or Inf"); |
| 596 | /* Some platforms may print -nan, just hard code it */ | 627 | } else if (cfg->encode_invalid_numbers == 1) { |
| 597 | strbuf_append_mem(json, "nan", 3); | 628 | /* Encode invalid numbers, but handle "nan" separately |
| 629 | * since some platforms may encode as "-nan". */ | ||
| 630 | if (isnan(num)) { | ||
| 631 | strbuf_append_mem(json, "nan", 3); | ||
| 632 | return; | ||
| 633 | } | ||
| 598 | } else { | 634 | } else { |
| 599 | strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); | 635 | /* Encode invalid numbers as "null" */ |
| 600 | len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision); | 636 | if (isinf(num) || isnan(num)) { |
| 601 | strbuf_extend_length(json, len); | 637 | strbuf_append_mem(json, "null", 4); |
| 638 | return; | ||
| 639 | } | ||
| 602 | } | 640 | } |
| 641 | |||
| 642 | strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); | ||
| 643 | len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision); | ||
| 644 | strbuf_extend_length(json, len); | ||
| 603 | } | 645 | } |
| 604 | 646 | ||
| 605 | static void json_append_object(lua_State *l, json_config_t *cfg, | 647 | static void json_append_object(lua_State *l, json_config_t *cfg, |
| @@ -1046,7 +1088,7 @@ static void json_next_token(json_parse_t *json, json_token_t *token) | |||
| 1046 | json_next_string_token(json, token); | 1088 | json_next_string_token(json, token); |
| 1047 | return; | 1089 | return; |
| 1048 | } else if (ch == '-' || ('0' <= ch && ch <= '9')) { | 1090 | } else if (ch == '-' || ('0' <= ch && ch <= '9')) { |
| 1049 | if (json->cfg->decode_refuse_badnum && json_is_invalid_number(json)) { | 1091 | if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) { |
| 1050 | json_set_token_error(token, json, "invalid number"); | 1092 | json_set_token_error(token, json, "invalid number"); |
| 1051 | return; | 1093 | return; |
| 1052 | } | 1094 | } |
| @@ -1066,9 +1108,9 @@ static void json_next_token(json_parse_t *json, json_token_t *token) | |||
| 1066 | token->type = T_NULL; | 1108 | token->type = T_NULL; |
| 1067 | json->ptr += 4; | 1109 | json->ptr += 4; |
| 1068 | return; | 1110 | return; |
| 1069 | } else if (!json->cfg->decode_refuse_badnum && | 1111 | } else if (json->cfg->decode_invalid_numbers && |
| 1070 | json_is_invalid_number(json)) { | 1112 | json_is_invalid_number(json)) { |
| 1071 | /* When refuse_badnum is disabled, only attempt to process | 1113 | /* When decode_invalid_numbers is enabled, only attempt to process |
| 1072 | * numbers we know are invalid JSON (Inf, NaN, hex) | 1114 | * numbers we know are invalid JSON (Inf, NaN, hex) |
| 1073 | * This is required to generate an appropriate token error, | 1115 | * This is required to generate an appropriate token error, |
| 1074 | * otherwise all bad tokens will register as "invalid number" | 1116 | * otherwise all bad tokens will register as "invalid number" |
| @@ -1322,6 +1364,8 @@ static int lua_cjson_new(lua_State *l) | |||
| 1322 | { "decode_max_depth", json_cfg_decode_max_depth }, | 1364 | { "decode_max_depth", json_cfg_decode_max_depth }, |
| 1323 | { "encode_number_precision", json_cfg_encode_number_precision }, | 1365 | { "encode_number_precision", json_cfg_encode_number_precision }, |
| 1324 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, | 1366 | { "encode_keep_buffer", json_cfg_encode_keep_buffer }, |
| 1367 | { "encode_invalid_numbers", json_cfg_encode_invalid_numbers }, | ||
| 1368 | { "decode_invalid_numbers", json_cfg_decode_invalid_numbers }, | ||
| 1325 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, | 1369 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, |
| 1326 | { "new", lua_cjson_new }, | 1370 | { "new", lua_cjson_new }, |
| 1327 | { NULL, NULL } | 1371 | { NULL, NULL } |
| @@ -117,8 +117,10 @@ USE_INTERNAL_ISINF:: Workaround for Solaris platforms missing ++isinf++(3). | |||
| 117 | DISABLE_CJSON_GLOBAL:: Do not store module table in global "cjson" | 117 | DISABLE_CJSON_GLOBAL:: Do not store module table in global "cjson" |
| 118 | variable. Redundant from Lua 5.2 onwards. | 118 | variable. Redundant from Lua 5.2 onwards. |
| 119 | DISABLE_INVALID_NUMBERS:: Recommended on platforms where ++strtod++(3) / | 119 | DISABLE_INVALID_NUMBERS:: Recommended on platforms where ++strtod++(3) / |
| 120 | ++sprintf++(3) are not POSIX compliant (Eg, Windows MinGW). Restricts | 120 | ++sprintf++(3) are not POSIX compliant (Eg, Windows MinGW). Prevents |
| 121 | the +cjson.refuse_invalid_numbers+ runtime configuration to +true+. | 121 | +cjson.encode_invalid_numbers+ and +cjson.decode_invalid_numbers+ |
| 122 | from being enabled. However, +cjson.encode_invalid_numbers+ may be | ||
| 123 | set to +"null"+. | ||
| 122 | 124 | ||
| 123 | 125 | ||
| 124 | Built-in dtoa() support | 126 | Built-in dtoa() support |
| @@ -154,11 +156,12 @@ text = cjson.encode(value) | |||
| 154 | value = cjson.decode(text) | 156 | value = cjson.decode(text) |
| 155 | 157 | ||
| 156 | -- Get and/or set Lua CJSON configuration | 158 | -- Get and/or set Lua CJSON configuration |
| 157 | setting = cjson.refuse_invalid_numbers([setting]) | 159 | setting = cjson.decode_invalid_numbers([setting]) |
| 160 | setting = cjson.encode_invalid_numbers([setting]) | ||
| 158 | depth = cjson.encode_max_depth([depth]) | 161 | depth = cjson.encode_max_depth([depth]) |
| 162 | depth = cjson.decode_max_depth([depth]) | ||
| 159 | convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) | 163 | convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) |
| 160 | keep = cjson.encode_keep_buffer([keep]) | 164 | keep = cjson.encode_keep_buffer([keep]) |
| 161 | depth = cjson.decode_max_depth([depth]) | ||
| 162 | ------------ | 165 | ------------ |
| 163 | 166 | ||
| 164 | 167 | ||
| @@ -226,7 +229,7 @@ can be compared with +cjson.null+ for convenience. | |||
| 226 | 229 | ||
| 227 | By default, numbers incompatible with the JSON specification (NaN, | 230 | By default, numbers incompatible with the JSON specification (NaN, |
| 228 | Infinity, Hexadecimal) can be decoded. This default can be changed | 231 | Infinity, Hexadecimal) can be decoded. This default can be changed |
| 229 | with +cjson.refuse_invalid_numbers+. | 232 | with +cjson.decode_invalid_numbers+. |
| 230 | 233 | ||
| 231 | .Example: Decoding | 234 | .Example: Decoding |
| 232 | [source,lua] | 235 | [source,lua] |
| @@ -240,6 +243,30 @@ numeric key will be stored as a Lua +string+. Any code assuming type | |||
| 240 | +number+ may break. | 243 | +number+ may break. |
| 241 | 244 | ||
| 242 | 245 | ||
| 246 | [[decode_invalid_numbers]] | ||
| 247 | decode_invalid_numbers | ||
| 248 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
| 249 | |||
| 250 | [source,lua] | ||
| 251 | ------------ | ||
| 252 | setting = cjson.decode_invalid_numbers([setting]) | ||
| 253 | -- "setting" must be on of: | ||
| 254 | -- "off", "on", false, true | ||
| 255 | ------------ | ||
| 256 | |||
| 257 | Lua CJSON can throw an error when trying to parse numbers outside of | ||
| 258 | the JSON specification (_invalid numbers_): | ||
| 259 | |||
| 260 | - Infinity | ||
| 261 | - Not-a-number (NaN) | ||
| 262 | - Hexadecimal | ||
| 263 | |||
| 264 | By default Lua CJSON will decode _invalid numbers_. | ||
| 265 | |||
| 266 | This setting is only changed when an argument is provided. The current | ||
| 267 | setting is always returned. | ||
| 268 | |||
| 269 | |||
| 243 | [[decode_max_depth]] | 270 | [[decode_max_depth]] |
| 244 | decode_max_depth | 271 | decode_max_depth |
| 245 | ~~~~~~~~~~~~~~~~ | 272 | ~~~~~~~~~~~~~~~~ |
| @@ -352,7 +379,7 @@ These defaults can be changed with: | |||
| 352 | 379 | ||
| 353 | - <<encode_max_depth,+cjson.encode_max_depth+>> | 380 | - <<encode_max_depth,+cjson.encode_max_depth+>> |
| 354 | - <<encode_sparse_array,+cjson.encode_sparse_array+>> | 381 | - <<encode_sparse_array,+cjson.encode_sparse_array+>> |
| 355 | - <<refuse_invalid_numbers,+cjson.refuse_invalid_numbers+>> | 382 | - <<encode_invalid_numbers,+cjson.encode_invalid_numbers+>> |
| 356 | 383 | ||
| 357 | .Example: Encoding | 384 | .Example: Encoding |
| 358 | [source,lua] | 385 | [source,lua] |
| @@ -361,6 +388,30 @@ json_text = cjson.encode(value) | |||
| 361 | -- Returns: '[true,{"foo":"bar"}]' | 388 | -- Returns: '[true,{"foo":"bar"}]' |
| 362 | 389 | ||
| 363 | 390 | ||
| 391 | [[encode_invalid_numbers]] | ||
| 392 | encode_invalid_numbers | ||
| 393 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
| 394 | [source,lua] | ||
| 395 | ------------ | ||
| 396 | setting = cjson.encode_invalid_numbers([setting]) | ||
| 397 | -- "setting" must be on of: | ||
| 398 | -- "off", "on", "null", false, true | ||
| 399 | ------------ | ||
| 400 | |||
| 401 | By default, Lua CJSON will throw an error when trying to encode | ||
| 402 | numbers outside of the JSON specification (_invalid numbers_): | ||
| 403 | |||
| 404 | - Infinity | ||
| 405 | - Not-a-number (NaN) | ||
| 406 | |||
| 407 | When set to +"null"+, Lua CJSON will encode _invalid numbers_ as a | ||
| 408 | JSON +null+ value. This allows Infinity and NaN to be represented as | ||
| 409 | valid JSON. | ||
| 410 | |||
| 411 | This setting is only changed when an argument is provided. The current | ||
| 412 | setting is always returned. | ||
| 413 | |||
| 414 | |||
| 364 | encode_keep_buffer | 415 | encode_keep_buffer |
| 365 | ~~~~~~~~~~~~~~~~~~ | 416 | ~~~~~~~~~~~~~~~~~~ |
| 366 | 417 | ||
| @@ -473,39 +524,6 @@ cjson.encode({ [1000] = "excessively sparse" }) | |||
| 473 | -- Returns: '{"1000":"excessively sparse"}' | 524 | -- Returns: '{"1000":"excessively sparse"}' |
| 474 | 525 | ||
| 475 | 526 | ||
| 476 | [[refuse_invalid_numbers]] | ||
| 477 | refuse_invalid_numbers | ||
| 478 | ~~~~~~~~~~~~~~~~~~~~~~ | ||
| 479 | |||
| 480 | [source,lua] | ||
| 481 | ------------ | ||
| 482 | setting = cjson.refuse_invalid_numbers([setting]) | ||
| 483 | -- "setting" must be on of: | ||
| 484 | -- false, "encode", "decode", "both", true | ||
| 485 | ------------ | ||
| 486 | |||
| 487 | Lua CJSON can throw an error for numbers outside of the JSON | ||
| 488 | specification (_invalid numbers_): | ||
| 489 | |||
| 490 | - Infinity | ||
| 491 | - NaN | ||
| 492 | - Hexadecimal | ||
| 493 | |||
| 494 | By default Lua CJSON will decode _invalid numbers_, but will refuse to | ||
| 495 | encode them. | ||
| 496 | |||
| 497 | This setting is only changed when an argument is provided. The current | ||
| 498 | setting is always returned. | ||
| 499 | |||
| 500 | This setting can be configured separately for encoding and/or | ||
| 501 | decoding: | ||
| 502 | |||
| 503 | [horizontal] | ||
| 504 | Enabled:: An error will be generated if an _invalid number_ is found. | ||
| 505 | Disabled for encoding:: NaN and Infinity can be encoded. | ||
| 506 | Disabled for decoding:: All numbers supported by +strtod+(3) will be parsed. | ||
| 507 | |||
| 508 | |||
| 509 | API (Variables) | 527 | API (Variables) |
| 510 | --------------- | 528 | --------------- |
| 511 | 529 | ||
diff --git a/tests/test.lua b/tests/test.lua index 0434a38..a4ebafe 100755 --- a/tests/test.lua +++ b/tests/test.lua | |||
| @@ -138,22 +138,28 @@ local encode_error_tests = { | |||
| 138 | { json.encode, { function () end }, | 138 | { json.encode, { function () end }, |
| 139 | false, { "Cannot serialise function: type not supported" } }, | 139 | false, { "Cannot serialise function: type not supported" } }, |
| 140 | function () | 140 | function () |
| 141 | json.refuse_invalid_numbers("encode") | 141 | json.encode_invalid_numbers(false) |
| 142 | return 'Setting refuse_invalid_numbers("encode")' | 142 | return 'Setting encode_invalid_numbers(false)' |
| 143 | end, | 143 | end, |
| 144 | { json.encode, { NaN }, | 144 | { json.encode, { NaN }, |
| 145 | false, { "Cannot serialise number: must not be NaN or Inf" } }, | 145 | false, { "Cannot serialise number: must not be NaN or Inf" } }, |
| 146 | { json.encode, { Inf }, | 146 | { json.encode, { Inf }, |
| 147 | false, { "Cannot serialise number: must not be NaN or Inf" } }, | 147 | false, { "Cannot serialise number: must not be NaN or Inf" } }, |
| 148 | function () | 148 | function () |
| 149 | json.refuse_invalid_numbers(false) | 149 | json.encode_invalid_numbers("null") |
| 150 | return 'Setting refuse_invalid_numbers(false).' | 150 | return 'Setting encode_invalid_numbers("null").' |
| 151 | end, | ||
| 152 | { json.encode, { NaN }, true, { "null" } }, | ||
| 153 | { json.encode, { Inf }, true, { "null" } }, | ||
| 154 | function () | ||
| 155 | json.encode_invalid_numbers(true) | ||
| 156 | return 'Setting encode_invalid_numbers(true).' | ||
| 151 | end, | 157 | end, |
| 152 | { json.encode, { NaN }, true, { "nan" } }, | 158 | { json.encode, { NaN }, true, { "nan" } }, |
| 153 | { json.encode, { Inf }, true, { "inf" } }, | 159 | { json.encode, { Inf }, true, { "inf" } }, |
| 154 | function () | 160 | function () |
| 155 | json.refuse_invalid_numbers("encode") | 161 | json.encode_invalid_numbers(false) |
| 156 | return 'Setting refuse_invalid_numbers("encode")' | 162 | return 'Setting encode_invalid_numbers(false)' |
| 157 | end, | 163 | end, |
| 158 | } | 164 | } |
| 159 | 165 | ||
| @@ -233,7 +239,8 @@ util.run_test_group("encode error", encode_error_tests) | |||
| 233 | util.run_test_group("escape", escape_tests) | 239 | util.run_test_group("escape", escape_tests) |
| 234 | util.run_test_group("locale", locale_tests) | 240 | util.run_test_group("locale", locale_tests) |
| 235 | 241 | ||
| 236 | json.refuse_invalid_numbers(false) | 242 | json.encode_invalid_numbers(true) |
| 243 | json.decode_invalid_numbers(true) | ||
| 237 | json.encode_max_depth(20) | 244 | json.encode_max_depth(20) |
| 238 | for i = 1, #arg do | 245 | for i = 1, #arg do |
| 239 | util.run_test("decode cycle " .. arg[i], test_decode_cycle, { arg[i] }, | 246 | util.run_test("decode cycle " .. arg[i], test_decode_cycle, { arg[i] }, |
