aboutsummaryrefslogtreecommitdiff
path: root/lua_cjson.c
diff options
context:
space:
mode:
Diffstat (limited to 'lua_cjson.c')
-rw-r--r--lua_cjson.c174
1 files changed, 109 insertions, 65 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
77typedef enum { 77typedef 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 */
263static 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 */
264static int json_cfg_encode_max_depth(lua_State *l) 287static 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 */
289static int json_cfg_encode_keep_buffer(lua_State *l) 312static 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 332static 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 */
320static 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
349static 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. */
345static int json_cfg_refuse_invalid_numbers(lua_State *l) 368static 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
605static void json_append_object(lua_State *l, json_config_t *cfg, 647static 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 }