aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--lua_cjson.c57
-rwxr-xr-xtests/test.lua26
3 files changed, 91 insertions, 5 deletions
diff --git a/README.md b/README.md
index d2094b1..233a094 100644
--- a/README.md
+++ b/README.md
@@ -262,3 +262,16 @@ cjson.encode(t) -- {"my_array":[]} properly re-encoded as an array
262``` 262```
263 263
264[Back to TOC](#table-of-contents) 264[Back to TOC](#table-of-contents)
265
266decode_allow_comments
267--------------------------
268**syntax:** `cjson.decode_allow_comments(enabled)`
269
270**default:** false
271
272If enabled, allows JavaScript-style comments in `cjson.decode` input. Comments
273are treated as whitespace and may appear anywhere whitespace is valid in JSON.
274Supports single-line comments beginning with '//' and block comments enclosed
275with '/* ... */'.
276
277[Back to TOC](#table-of-contents)
diff --git a/lua_cjson.c b/lua_cjson.c
index 789817d..de77f26 100644
--- a/lua_cjson.c
+++ b/lua_cjson.c
@@ -89,6 +89,7 @@
89#define DEFAULT_ENCODE_NUMBER_PRECISION 14 89#define DEFAULT_ENCODE_NUMBER_PRECISION 14
90#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 1 90#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 1
91#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0 91#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
92#define DEFAULT_DECODE_ALLOW_COMMENTS 0
92#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1 93#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
93#define DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES 0 94#define DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES 0
94#define DEFAULT_ENCODE_INDENT NULL 95#define DEFAULT_ENCODE_INDENT NULL
@@ -178,6 +179,7 @@ typedef struct {
178 int decode_invalid_numbers; 179 int decode_invalid_numbers;
179 int decode_max_depth; 180 int decode_max_depth;
180 int decode_array_with_array_mt; 181 int decode_array_with_array_mt;
182 int decode_allow_comments;
181 int encode_skip_unsupported_value_types; 183 int encode_skip_unsupported_value_types;
182} json_config_t; 184} json_config_t;
183 185
@@ -383,6 +385,16 @@ static int json_cfg_decode_array_with_array_mt(lua_State *l)
383 return 1; 385 return 1;
384} 386}
385 387
388/* Configures whether decoder allows comments */
389static int json_cfg_decode_allow_comments(lua_State *l)
390{
391 json_config_t *cfg = json_arg_init(l, 1);
392
393 json_enum_option(l, 1, &cfg->decode_allow_comments, NULL, 1);
394
395 return 1;
396}
397
386/* Configure how to treat invalid types */ 398/* Configure how to treat invalid types */
387static int json_cfg_encode_skip_unsupported_value_types(lua_State *l) 399static int json_cfg_encode_skip_unsupported_value_types(lua_State *l)
388{ 400{
@@ -515,6 +527,7 @@ static void json_create_config(lua_State *l)
515 cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; 527 cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
516 cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT; 528 cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT;
517 cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT; 529 cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT;
530 cfg->decode_allow_comments = DEFAULT_DECODE_ALLOW_COMMENTS;
518 cfg->encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH; 531 cfg->encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH;
519 cfg->encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES; 532 cfg->encode_skip_unsupported_value_types = DEFAULT_ENCODE_SKIP_UNSUPPORTED_VALUE_TYPES;
520 cfg->encode_indent = DEFAULT_ENCODE_INDENT; 533 cfg->encode_indent = DEFAULT_ENCODE_INDENT;
@@ -1279,13 +1292,46 @@ static void json_next_token(json_parse_t *json, json_token_t *token)
1279 const json_token_type_t *ch2token = json->cfg->ch2token; 1292 const json_token_type_t *ch2token = json->cfg->ch2token;
1280 int ch; 1293 int ch;
1281 1294
1282 /* Eat whitespace. */
1283 while (1) { 1295 while (1) {
1284 ch = (unsigned char)*(json->ptr); 1296 /* Eat whitespace. */
1285 token->type = ch2token[ch]; 1297 while (1) {
1286 if (token->type != T_WHITESPACE) 1298 ch = (unsigned char)*(json->ptr);
1299 token->type = ch2token[ch];
1300 if (token->type != T_WHITESPACE)
1301 break;
1302 json->ptr++;
1303 }
1304
1305 if (!json->cfg->decode_allow_comments)
1287 break; 1306 break;
1288 json->ptr++; 1307
1308 /* Eat comments. */
1309 if ((unsigned char)json->ptr[0] != '/' ||
1310 ((unsigned char)json->ptr[1] != '/' &&
1311 (unsigned char)json->ptr[1] != '*')) {
1312 break;
1313 }
1314
1315 if (json->ptr[1] == '/') {
1316 /* Handle single-line comment */
1317 json->ptr += 2;
1318 while (*json->ptr != '\0' && *json->ptr != '\n')
1319 json->ptr++;
1320 } else {
1321 /* Handle multi-line comment */
1322 json->ptr += 2;
1323 while (1) {
1324 if (*json->ptr == '\0') {
1325 json_set_token_error(token, json, "unclosed multi-line comment");
1326 return;
1327 }
1328 if (json->ptr[0] == '*' && json->ptr[1] == '/') {
1329 json->ptr += 2;
1330 break;
1331 }
1332 json->ptr++;
1333 }
1334 }
1289 } 1335 }
1290 1336
1291 /* Store location of new token. Required when throwing errors 1337 /* Store location of new token. Required when throwing errors
@@ -1625,6 +1671,7 @@ static int lua_cjson_new(lua_State *l)
1625 { "decode", json_decode }, 1671 { "decode", json_decode },
1626 { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object }, 1672 { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object },
1627 { "decode_array_with_array_mt", json_cfg_decode_array_with_array_mt }, 1673 { "decode_array_with_array_mt", json_cfg_decode_array_with_array_mt },
1674 { "decode_allow_comments", json_cfg_decode_allow_comments },
1628 { "encode_sparse_array", json_cfg_encode_sparse_array }, 1675 { "encode_sparse_array", json_cfg_encode_sparse_array },
1629 { "encode_max_depth", json_cfg_encode_max_depth }, 1676 { "encode_max_depth", json_cfg_encode_max_depth },
1630 { "decode_max_depth", json_cfg_decode_max_depth }, 1677 { "decode_max_depth", json_cfg_decode_max_depth },
diff --git a/tests/test.lua b/tests/test.lua
index 0513d97..068a9f0 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -333,6 +333,32 @@ local cjson_tests = {
333 json.decode, { [["\uDB00\uD"]] }, 333 json.decode, { [["\uDB00\uD"]] },
334 false, { "Expected value but found invalid unicode escape code at character 2" } }, 334 false, { "Expected value but found invalid unicode escape code at character 2" } },
335 335
336 -- Test comments
337 { 'Set decode_allow_comments(true)',
338 json.decode_allow_comments, { true }, true, { true } },
339 { "Decode single-line comment",
340 json.decode, { '{//comment\n}' }, true, { {} } },
341 { "Decode single-line comment with windows newline",
342 json.decode, { '{//comment\r\n}' }, true, { {} } },
343 { "Decode single-line comment after string value",
344 json.decode, { '"test // /* */ string"//comment' }, true, { "test // /* */ string" } },
345 { "Decode multi-line comment",
346 json.decode, { '{/* A multi-line\ncomment*/}' }, true, { {} } },
347 { "Decode multi-line comment before colon",
348 json.decode, { '{"a" /* Comment */: 1}' }, true, { { a = 1 } } },
349 { "Decode multi-line comment after colon",
350 json.decode, { '{"a": /* Comment */ 1}' }, true, { { a = 1 } } },
351 { "Decode multiple comments in a row",
352 json.decode, { '/*first*//*second*/{}' }, true, { {} } },
353 { "Decode unclosed multi-line comment [throw error]",
354 json.decode, { '{}/*Unclosed' },
355 false, { "Expected the end but found unclosed multi-line comment at character 13" } },
356 { "Decode comment inside number [throw error]",
357 json.decode, { '{"a":1/*x*/0}' },
358 false, { "Expected comma or object end but found T_INTEGER at character 12" } },
359 { 'Set decode_allow_comments(false)',
360 json.decode_allow_comments, { false }, true, { false } },
361
336 -- Test indenting 362 -- Test indenting
337 { 'Set encode_indent(" ")', 363 { 'Set encode_indent(" ")',
338 json.encode_indent, { " " }, true, { " " } }, 364 json.encode_indent, { " " }, true, { " " } },