├── test ├── parsing │ ├── cases │ │ ├── ap_eof_str.json │ │ ├── empty_array.json │ │ ├── null.json │ │ ├── true.json │ │ ├── am_eof.json │ │ ├── ap_array_open.json │ │ ├── ap_map_open.json │ │ ├── array_close.json │ │ ├── empty_string.json │ │ ├── false.json │ │ ├── map_close.json │ │ ├── am_integers.json │ │ ├── lonely_number.json │ │ ├── zerobyte.json │ │ ├── ag_false_then_garbage.json │ │ ├── ag_true_then_garbage.json │ │ ├── fg_false_then_garbage.json │ │ ├── multiple.json │ │ ├── ag_null_then_garbage.json │ │ ├── am_multiple.json │ │ ├── ap_partial_ok.json │ │ ├── fg_null_then_garbage.json │ │ ├── fg_true_then_garbage.json │ │ ├── high_overflow.json │ │ ├── low_overflow.json │ │ ├── np_partial_bad.json │ │ ├── ap_eof_str.json.gold │ │ ├── isolated_surrogate_marker.json │ │ ├── missing_integer_after_exponent.json │ │ ├── null.json.gold │ │ ├── fg_issue_7.json │ │ ├── four_byte_utf8.json │ │ ├── true.json.gold │ │ ├── false.json.gold │ │ ├── leading_zero_in_number.json │ │ ├── missing_integer_after_decimal_point.json │ │ ├── unescaped_bulgarian.json │ │ ├── zerobyte.json.gold │ │ ├── ag_null_then_garbage.json.gold │ │ ├── ap_map_open.json.gold │ │ ├── empty_string.json.gold │ │ ├── three_byte_utf8.json │ │ ├── ap_array_open.json.gold │ │ ├── bignums.json │ │ ├── doubles.json │ │ ├── escaped_foobar.json │ │ ├── ag_false_then_garbage.json.gold │ │ ├── ag_true_then_garbage.json.gold │ │ ├── codepoints_from_unicode_org.json │ │ ├── escaped_foobar.json.gold │ │ ├── lonely_number.json.gold │ │ ├── isolated_surrogate_marker.json.gold │ │ ├── am_integers.json.gold │ │ ├── codepoints_from_unicode_org.json.gold │ │ ├── doubles_in_array.json │ │ ├── high_overflow.json.gold │ │ ├── low_overflow.json.gold │ │ ├── empty_array.json.gold │ │ ├── am_stuff.json │ │ ├── fg_issue_7.json.gold │ │ ├── fg_null_then_garbage.json.gold │ │ ├── simple.json │ │ ├── am_eof.json.gold │ │ ├── ap_partial_ok.json.gold │ │ ├── fg_true_then_garbage.json.gold │ │ ├── integers.json │ │ ├── map_close.json.gold │ │ ├── string_invalid_escape.json │ │ ├── array_close.json.gold │ │ ├── fg_false_then_garbage.json.gold │ │ ├── invalid_utf8.json │ │ ├── multiple.json.gold │ │ ├── nulls_and_bools.json │ │ ├── string_invalid_hex_char.json │ │ ├── string_with_invalid_newline.json │ │ ├── string_with_invalid_newline.json.gold │ │ ├── am_multiple.json.gold │ │ ├── invalid_utf8.json.gold │ │ ├── four_byte_utf8.json.gold │ │ ├── unescaped_bulgarian.json.gold │ │ ├── array.json │ │ ├── non_utf8_char_in_string.json │ │ ├── np_partial_bad.json.gold │ │ ├── string_invalid_hex_char.json.gold │ │ ├── lonely_minus_sign.json │ │ ├── missing_integer_after_exponent.json.gold │ │ ├── bignums.json.gold │ │ ├── doubles.json.gold │ │ ├── escaped_bulgarian.json │ │ ├── missing_integer_after_decimal_point.json.gold │ │ ├── string_invalid_escape.json.gold │ │ ├── three_byte_utf8.json.gold │ │ ├── escaped_bulgarian.json.gold │ │ ├── string_with_escapes.json │ │ ├── doubles_in_array.json.gold │ │ ├── leading_zero_in_number.json.gold │ │ ├── bogus_char.json │ │ ├── simple_with_comments.json.gold │ │ ├── simple.json.gold │ │ ├── nulls_and_bools.json.gold │ │ ├── ac_simple_with_comments.json │ │ ├── simple_with_comments.json │ │ ├── ac_simple_with_comments.json.gold │ │ ├── string_with_escapes.json.gold │ │ ├── non_utf8_char_in_string.json.gold │ │ ├── lonely_minus_sign.json.gold │ │ ├── am_stuff.json.gold │ │ ├── bogus_char.json.gold │ │ ├── integers.json.gold │ │ ├── array.json.gold │ │ ├── difficult_json_c_test_case.json │ │ ├── ac_difficult_json_c_test_case_with_comments.json │ │ ├── difficult_json_c_test_case.json.gold │ │ ├── ac_difficult_json_c_test_case_with_comments.json.gold │ │ └── deep_arrays.json │ ├── CMakeLists.txt │ ├── run_tests.sh │ └── yajl_test.c ├── api │ ├── run_tests.sh │ ├── gen-extra-close.c │ └── CMakeLists.txt └── CMakeLists.txt ├── .gitignore ├── src ├── yajl_version.c ├── yajl.pc.cmake ├── api │ ├── yajl_version.h │ ├── yajl_version.h.cmake │ ├── yajl_common.h │ ├── yajl_gen.h │ ├── yajl_tree.h │ └── yajl_parse.h ├── yajl ├── yajl_alloc.h ├── yajl_encode.h ├── yajl_alloc.c ├── yajl_buf.h ├── yajl_bytestack.h ├── yajl_parser.h ├── yajl_buf.c ├── CMakeLists.txt ├── yajl_lex.h ├── yajl.c ├── yajl_encode.c ├── yajl_gen.c ├── yajl_tree.c └── yajl_parser.c ├── TODO ├── example ├── README.md ├── CMakeLists.txt ├── parse_config.c └── sample.config ├── BUILDING ├── COPYING ├── YAJLDoc.cmake ├── BUILDING.win32 ├── perf ├── CMakeLists.txt ├── documents.h └── perftest.c ├── verify ├── CMakeLists.txt └── json_verify.c ├── reformatter ├── CMakeLists.txt └── json_reformat.c ├── configure ├── README.md ├── CMakeLists.txt └── ChangeLog /test/parsing/cases/ap_eof_str.json: -------------------------------------------------------------------------------- 1 | "abc -------------------------------------------------------------------------------- /test/parsing/cases/empty_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/parsing/cases/null.json: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /test/parsing/cases/true.json: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /test/parsing/cases/am_eof.json: -------------------------------------------------------------------------------- 1 | { "123": 2 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_array_open.json: -------------------------------------------------------------------------------- 1 | [ 2 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_map_open.json: -------------------------------------------------------------------------------- 1 | { 2 | -------------------------------------------------------------------------------- /test/parsing/cases/array_close.json: -------------------------------------------------------------------------------- 1 | ] 2 | -------------------------------------------------------------------------------- /test/parsing/cases/empty_string.json: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/false.json: -------------------------------------------------------------------------------- 1 | false 2 | -------------------------------------------------------------------------------- /test/parsing/cases/map_close.json: -------------------------------------------------------------------------------- 1 | } 2 | -------------------------------------------------------------------------------- /test/parsing/cases/am_integers.json: -------------------------------------------------------------------------------- 1 | 1221 21 2 | -------------------------------------------------------------------------------- /test/parsing/cases/lonely_number.json: -------------------------------------------------------------------------------- 1 | 123456789 -------------------------------------------------------------------------------- /test/parsing/cases/zerobyte.json: -------------------------------------------------------------------------------- 1 | "\u0000" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/ag_false_then_garbage.json: -------------------------------------------------------------------------------- 1 | falsex -------------------------------------------------------------------------------- /test/parsing/cases/ag_true_then_garbage.json: -------------------------------------------------------------------------------- 1 | truex -------------------------------------------------------------------------------- /test/parsing/cases/fg_false_then_garbage.json: -------------------------------------------------------------------------------- 1 | falsex -------------------------------------------------------------------------------- /test/parsing/cases/multiple.json: -------------------------------------------------------------------------------- 1 | 2 | {} 3 | {} 4 | -------------------------------------------------------------------------------- /test/parsing/cases/ag_null_then_garbage.json: -------------------------------------------------------------------------------- 1 | nullx 2 | -------------------------------------------------------------------------------- /test/parsing/cases/am_multiple.json: -------------------------------------------------------------------------------- 1 | 2 | {} 3 | {} 4 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_partial_ok.json: -------------------------------------------------------------------------------- 1 | [ "foo", "bar" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_null_then_garbage.json: -------------------------------------------------------------------------------- 1 | nullx 2 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_true_then_garbage.json: -------------------------------------------------------------------------------- 1 | truex 2 | -------------------------------------------------------------------------------- /test/parsing/cases/high_overflow.json: -------------------------------------------------------------------------------- 1 | 9223372036854775808 -------------------------------------------------------------------------------- /test/parsing/cases/low_overflow.json: -------------------------------------------------------------------------------- 1 | -9223372036854775808 -------------------------------------------------------------------------------- /test/parsing/cases/np_partial_bad.json: -------------------------------------------------------------------------------- 1 | [ "foo", "bar" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Makefile 3 | /build/ 4 | *.swp 5 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_eof_str.json.gold: -------------------------------------------------------------------------------- 1 | memory leaks: 0 2 | -------------------------------------------------------------------------------- /test/parsing/cases/isolated_surrogate_marker.json: -------------------------------------------------------------------------------- 1 | "\ud800" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/missing_integer_after_exponent.json: -------------------------------------------------------------------------------- 1 | 10e 2 | -------------------------------------------------------------------------------- /test/parsing/cases/null.json.gold: -------------------------------------------------------------------------------- 1 | null 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_issue_7.json: -------------------------------------------------------------------------------- 1 | 2009-10-20@20:38:21.539575 2 | -------------------------------------------------------------------------------- /test/parsing/cases/four_byte_utf8.json: -------------------------------------------------------------------------------- 1 | { "U+10ABCD": "􊯍" } 2 | 3 | -------------------------------------------------------------------------------- /test/parsing/cases/true.json.gold: -------------------------------------------------------------------------------- 1 | bool: true 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/false.json.gold: -------------------------------------------------------------------------------- 1 | bool: false 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/leading_zero_in_number.json: -------------------------------------------------------------------------------- 1 | { "bad thing": 01 } 2 | -------------------------------------------------------------------------------- /test/parsing/cases/missing_integer_after_decimal_point.json: -------------------------------------------------------------------------------- 1 | 10.e2 2 | -------------------------------------------------------------------------------- /test/parsing/cases/unescaped_bulgarian.json: -------------------------------------------------------------------------------- 1 | ["Да Му Еба Майката"] 2 | -------------------------------------------------------------------------------- /test/parsing/cases/zerobyte.json.gold: -------------------------------------------------------------------------------- 1 | string: '' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/ag_null_then_garbage.json.gold: -------------------------------------------------------------------------------- 1 | null 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_map_open.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/empty_string.json.gold: -------------------------------------------------------------------------------- 1 | string: '' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/three_byte_utf8.json: -------------------------------------------------------------------------------- 1 | {"matzue": "松江", "asakusa": "浅草"} 2 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_array_open.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/bignums.json: -------------------------------------------------------------------------------- 1 | [ 9223372036854775807, -9223372036854775807 ] 2 | -------------------------------------------------------------------------------- /test/parsing/cases/doubles.json: -------------------------------------------------------------------------------- 1 | [ 0.1e2, 1e1, 3.141569, 10000000000000e-10] 2 | -------------------------------------------------------------------------------- /test/parsing/cases/escaped_foobar.json: -------------------------------------------------------------------------------- 1 | "\u0066\u006f\u006f\u0062\u0061\u0072" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/ag_false_then_garbage.json.gold: -------------------------------------------------------------------------------- 1 | bool: false 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/ag_true_then_garbage.json.gold: -------------------------------------------------------------------------------- 1 | bool: true 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/codepoints_from_unicode_org.json: -------------------------------------------------------------------------------- 1 | "\u004d\u0430\u4e8c\ud800\udf02" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/escaped_foobar.json.gold: -------------------------------------------------------------------------------- 1 | string: 'foobar' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/lonely_number.json.gold: -------------------------------------------------------------------------------- 1 | integer: 123456789 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/isolated_surrogate_marker.json.gold: -------------------------------------------------------------------------------- 1 | string: '?' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/am_integers.json.gold: -------------------------------------------------------------------------------- 1 | integer: 1221 2 | integer: 21 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/codepoints_from_unicode_org.json.gold: -------------------------------------------------------------------------------- 1 | string: 'Mа二𐌂' 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/doubles_in_array.json: -------------------------------------------------------------------------------- 1 | [0.00011999999999999999, 6E-06, 6E-06, 1E-06, 1E-06] 2 | -------------------------------------------------------------------------------- /test/parsing/cases/high_overflow.json.gold: -------------------------------------------------------------------------------- 1 | parse error: integer overflow 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/low_overflow.json.gold: -------------------------------------------------------------------------------- 1 | parse error: integer overflow 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/empty_array.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | array close ']' 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/am_stuff.json: -------------------------------------------------------------------------------- 1 | {} 2 | [] 3 | [] 4 | "sdfasd" 5 | 123 6 | { "123" : 123 } 7 | 3.1e124 8 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_issue_7.json.gold: -------------------------------------------------------------------------------- 1 | integer: 2009 2 | parse error: trailing garbage 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_null_then_garbage.json.gold: -------------------------------------------------------------------------------- 1 | null 2 | parse error: trailing garbage 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "this": "is", 3 | "really": "simple", 4 | "json": "right?" 5 | } 6 | -------------------------------------------------------------------------------- /test/parsing/cases/am_eof.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: '123' 3 | parse error: premature EOF 4 | memory leaks: 0 5 | -------------------------------------------------------------------------------- /test/parsing/cases/ap_partial_ok.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'foo' 3 | string: 'bar' 4 | memory leaks: 0 5 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_true_then_garbage.json.gold: -------------------------------------------------------------------------------- 1 | bool: true 2 | parse error: trailing garbage 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/integers.json: -------------------------------------------------------------------------------- 1 | [ 1,2,3,4,5,6,7, 2 | 123456789 , -123456789, 3 | 2147483647, -2147483647 ] 4 | -------------------------------------------------------------------------------- /test/parsing/cases/map_close.json.gold: -------------------------------------------------------------------------------- 1 | parse error: unallowed token at this point in JSON text 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/string_invalid_escape.json: -------------------------------------------------------------------------------- 1 | ["\n foo \/ bar \r\f\\\uffff\t\b\"\\ and you can't escape thi\s"] 2 | -------------------------------------------------------------------------------- /test/parsing/cases/array_close.json.gold: -------------------------------------------------------------------------------- 1 | parse error: unallowed token at this point in JSON text 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/fg_false_then_garbage.json.gold: -------------------------------------------------------------------------------- 1 | bool: false 2 | parse error: trailing garbage 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /src/yajl_version.c: -------------------------------------------------------------------------------- 1 | #include "api/yajl_version.h" 2 | 3 | int yajl_version(void) 4 | { 5 | return YAJL_VERSION; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /test/parsing/cases/invalid_utf8.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasschnelli/yajl/master/test/parsing/cases/invalid_utf8.json -------------------------------------------------------------------------------- /test/parsing/cases/multiple.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | map close '}' 3 | parse error: trailing garbage 4 | memory leaks: 0 5 | -------------------------------------------------------------------------------- /test/parsing/cases/nulls_and_bools.json: -------------------------------------------------------------------------------- 1 | { 2 | "boolean, true": true, 3 | "boolean, false": false, 4 | "null": null 5 | } 6 | -------------------------------------------------------------------------------- /test/parsing/cases/string_invalid_hex_char.json: -------------------------------------------------------------------------------- 1 | "foo foo, blah blah \u0123 \u4567 \u89ab \uc/ef \uABCD \uEFFE bar baz bing" 2 | -------------------------------------------------------------------------------- /test/parsing/cases/string_with_invalid_newline.json: -------------------------------------------------------------------------------- 1 | "la di dah. this is a string, and I can do this, \n, but not this 2 | " 3 | -------------------------------------------------------------------------------- /test/parsing/cases/string_with_invalid_newline.json.gold: -------------------------------------------------------------------------------- 1 | lexical error: invalid character inside string. 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/am_multiple.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | map close '}' 3 | map open '{' 4 | map close '}' 5 | memory leaks: 0 6 | -------------------------------------------------------------------------------- /test/parsing/cases/invalid_utf8.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | lexical error: invalid bytes in UTF8 string. 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/four_byte_utf8.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'U+10ABCD' 3 | string: '􊯍' 4 | map close '}' 5 | memory leaks: 0 6 | -------------------------------------------------------------------------------- /test/parsing/cases/unescaped_bulgarian.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'Да Му Еба Майката' 3 | array close ']' 4 | memory leaks: 0 5 | -------------------------------------------------------------------------------- /test/parsing/cases/array.json: -------------------------------------------------------------------------------- 1 | ["foo", 2 | "bar", "baz", 3 | true,false,null,{"key":"value"}, 4 | [null,null,null,[]], 5 | "\n\r\\" 6 | ] 7 | -------------------------------------------------------------------------------- /test/parsing/cases/non_utf8_char_in_string.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonasschnelli/yajl/master/test/parsing/cases/non_utf8_char_in_string.json -------------------------------------------------------------------------------- /test/parsing/cases/np_partial_bad.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'foo' 3 | string: 'bar' 4 | parse error: premature EOF 5 | memory leaks: 0 6 | -------------------------------------------------------------------------------- /test/parsing/cases/string_invalid_hex_char.json.gold: -------------------------------------------------------------------------------- 1 | lexical error: invalid (non-hex) character occurs after '\u' inside string. 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/lonely_minus_sign.json: -------------------------------------------------------------------------------- 1 | [ 2 | "foo", true, 3 | true, "blue", 4 | "baby where are you?", "oh boo hoo!", 5 | - 6 | ] 7 | 8 | -------------------------------------------------------------------------------- /test/parsing/cases/missing_integer_after_exponent.json.gold: -------------------------------------------------------------------------------- 1 | lexical error: malformed number, a digit is required after the exponent. 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/bignums.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | integer: 9223372036854775807 3 | integer: -9223372036854775807 4 | array close ']' 5 | memory leaks: 0 6 | -------------------------------------------------------------------------------- /test/parsing/cases/doubles.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | double: 10 3 | double: 10 4 | double: 3.14157 5 | double: 1000 6 | array close ']' 7 | memory leaks: 0 8 | -------------------------------------------------------------------------------- /test/parsing/cases/escaped_bulgarian.json: -------------------------------------------------------------------------------- 1 | ["\u0414\u0430", 2 | "\u041c\u0443", 3 | "\u0415\u0431\u0430", 4 | "\u041c\u0430\u0439\u043a\u0430\u0442\u0430"] 5 | -------------------------------------------------------------------------------- /test/parsing/cases/missing_integer_after_decimal_point.json.gold: -------------------------------------------------------------------------------- 1 | lexical error: malformed number, a digit is required after the decimal point. 2 | memory leaks: 0 3 | -------------------------------------------------------------------------------- /test/parsing/cases/string_invalid_escape.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | lexical error: inside a string, '\' occurs before a character which it may not. 3 | memory leaks: 0 4 | -------------------------------------------------------------------------------- /test/parsing/cases/three_byte_utf8.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'matzue' 3 | string: '松江' 4 | key: 'asakusa' 5 | string: '浅草' 6 | map close '}' 7 | memory leaks: 0 8 | -------------------------------------------------------------------------------- /test/parsing/cases/escaped_bulgarian.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'Да' 3 | string: 'Му' 4 | string: 'Еба' 5 | string: 'Майката' 6 | array close ']' 7 | memory leaks: 0 8 | -------------------------------------------------------------------------------- /test/parsing/cases/string_with_escapes.json: -------------------------------------------------------------------------------- 1 | ["\n foo \/ bar \r\f\\\uffff\t\b\"\\", 2 | "\"and this string has an escape at the beginning", 3 | "and this string has no escapes" ] 4 | -------------------------------------------------------------------------------- /test/parsing/cases/doubles_in_array.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | double: 0.00012 3 | double: 6e-06 4 | double: 6e-06 5 | double: 1e-06 6 | double: 1e-06 7 | array close ']' 8 | memory leaks: 0 9 | -------------------------------------------------------------------------------- /test/parsing/cases/leading_zero_in_number.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'bad thing' 3 | integer: 0 4 | parse error: after key and value, inside map, I expect ',' or '}' 5 | memory leaks: 0 6 | -------------------------------------------------------------------------------- /test/parsing/cases/bogus_char.json: -------------------------------------------------------------------------------- 1 | ["this","is","what","should","be", 2 | "a happy bit of json", 3 | "but someone, misspelled \"true\"", ture, 4 | "who says JSON is easy for humans to generate?"] 5 | -------------------------------------------------------------------------------- /test/parsing/cases/simple_with_comments.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'this' 3 | string: 'is' 4 | lexical error: probable comment found in input text, comments are not enabled. 5 | memory leaks: 0 6 | -------------------------------------------------------------------------------- /test/parsing/cases/simple.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'this' 3 | string: 'is' 4 | key: 'really' 5 | string: 'simple' 6 | key: 'json' 7 | string: 'right?' 8 | map close '}' 9 | memory leaks: 0 10 | -------------------------------------------------------------------------------- /test/parsing/cases/nulls_and_bools.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'boolean, true' 3 | bool: true 4 | key: 'boolean, false' 5 | bool: false 6 | key: 'null' 7 | null 8 | map close '}' 9 | memory leaks: 0 10 | -------------------------------------------------------------------------------- /test/parsing/cases/ac_simple_with_comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "this": "is", // ignore this 3 | "really": "simple", 4 | /* ignore 5 | this 6 | too * / 7 | ** // 8 | (/ 9 | ******/ 10 | "json": "right?" 11 | } 12 | -------------------------------------------------------------------------------- /test/parsing/cases/simple_with_comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "this": "is", // ignore this 3 | "really": "simple", 4 | /* ignore 5 | this 6 | too * / 7 | ** // 8 | (/ 9 | ******/ 10 | "json": "right?" 11 | } 12 | -------------------------------------------------------------------------------- /test/parsing/cases/ac_simple_with_comments.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'this' 3 | string: 'is' 4 | key: 'really' 5 | string: 'simple' 6 | key: 'json' 7 | string: 'right?' 8 | map close '}' 9 | memory leaks: 0 10 | -------------------------------------------------------------------------------- /test/parsing/cases/string_with_escapes.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: ' 3 | foo / bar \￿ "\' 4 | string: '"and this string has an escape at the beginning' 5 | string: 'and this string has no escapes' 6 | array close ']' 7 | memory leaks: 0 8 | -------------------------------------------------------------------------------- /test/parsing/cases/non_utf8_char_in_string.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'CoreletAPIVersion' 3 | integer: 2 4 | key: 'CoreletType' 5 | string: 'standalone' 6 | key: 'documentation' 7 | lexical error: invalid bytes in UTF8 string. 8 | memory leaks: 0 9 | -------------------------------------------------------------------------------- /test/parsing/cases/lonely_minus_sign.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'foo' 3 | bool: true 4 | bool: true 5 | string: 'blue' 6 | string: 'baby where are you?' 7 | string: 'oh boo hoo!' 8 | lexical error: malformed number, a digit is required after the minus sign. 9 | memory leaks: 0 10 | -------------------------------------------------------------------------------- /test/parsing/cases/am_stuff.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | map close '}' 3 | array open '[' 4 | array close ']' 5 | array open '[' 6 | array close ']' 7 | string: 'sdfasd' 8 | integer: 123 9 | map open '{' 10 | key: '123' 11 | integer: 123 12 | map close '}' 13 | double: 3.1e+124 14 | memory leaks: 0 15 | -------------------------------------------------------------------------------- /test/parsing/cases/bogus_char.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'this' 3 | string: 'is' 4 | string: 'what' 5 | string: 'should' 6 | string: 'be' 7 | string: 'a happy bit of json' 8 | string: 'but someone, misspelled "true"' 9 | lexical error: invalid string in json text. 10 | memory leaks: 0 11 | -------------------------------------------------------------------------------- /test/parsing/cases/integers.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | integer: 1 3 | integer: 2 4 | integer: 3 5 | integer: 4 6 | integer: 5 7 | integer: 6 8 | integer: 7 9 | integer: 123456789 10 | integer: -123456789 11 | integer: 2147483647 12 | integer: -2147483647 13 | array close ']' 14 | memory leaks: 0 15 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * add a test for 0x1F bug 2 | * numeric overflow in integers and double 3 | * line and char offsets in the lexer and in error messages 4 | * testing: 5 | a. the permuter 6 | b. some performance comparison against json_checker. 7 | * investigate pull instead of push parsing 8 | * Handle memory allocation failures gracefully 9 | * cygwin/msys support on win32 10 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This directory holds an example of how one might use yajl in the 2 | simplest possible way, to do something like parse and extract values 3 | from a configuration file. 4 | 5 | Note that use of the yajl_tree.h utility is completely optional, and 6 | yajl_parse.h offers a lower level stream parsing API that is more 7 | efficient and flexible at the cost of some complexity. 8 | -------------------------------------------------------------------------------- /src/yajl.pc.cmake: -------------------------------------------------------------------------------- 1 | prefix=${CMAKE_INSTALL_PREFIX} 2 | libdir=${dollar}{prefix}/lib${LIB_SUFFIX} 3 | includedir=${dollar}{prefix}/include/yajl 4 | 5 | Name: Yet Another JSON Library 6 | Description: A Portable JSON parsing and serialization library in ANSI C 7 | Version: ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO} 8 | Cflags: -I${dollar}{includedir} 9 | Libs: -L${dollar}{libdir} -lyajl 10 | -------------------------------------------------------------------------------- /test/parsing/cases/array.json.gold: -------------------------------------------------------------------------------- 1 | array open '[' 2 | string: 'foo' 3 | string: 'bar' 4 | string: 'baz' 5 | bool: true 6 | bool: false 7 | null 8 | map open '{' 9 | key: 'key' 10 | string: 'value' 11 | map close '}' 12 | array open '[' 13 | null 14 | null 15 | null 16 | array open '[' 17 | array close ']' 18 | array close ']' 19 | string: ' 20 | \' 21 | array close ']' 22 | memory leaks: 0 23 | -------------------------------------------------------------------------------- /test/parsing/cases/difficult_json_c_test_case.json: -------------------------------------------------------------------------------- 1 | { "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"] } ] } } } 2 | -------------------------------------------------------------------------------- /src/api/yajl_version.h: -------------------------------------------------------------------------------- 1 | #ifndef YAJL_VERSION_H_ 2 | #define YAJL_VERSION_H_ 3 | 4 | #include "yajl_common.h" 5 | 6 | #define YAJL_MAJOR 2 7 | #define YAJL_MINOR 1 8 | #define YAJL_MICRO 1 9 | 10 | #define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO) 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | extern int YAJL_API yajl_version(void); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif /* YAJL_VERSION_H_ */ 23 | 24 | -------------------------------------------------------------------------------- /test/api/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo Running api tests: 4 | 5 | tests=0 6 | passed=0 7 | 8 | for file in `ls`; do 9 | [ ! -x $file -o -d $file ] && continue 10 | tests=`expr 1 + $tests` 11 | printf " test(%s): " $file 12 | ./$file 13 | if [ $? ]; then 14 | passed=`expr 1 + $passed` 15 | echo 'SUCCESS' 16 | else 17 | echo 'FAILURE' 18 | fi 19 | done 20 | 21 | echo "$passed/$tests tests successful" 22 | 23 | exit 0 24 | -------------------------------------------------------------------------------- /src/api/yajl_version.h.cmake: -------------------------------------------------------------------------------- 1 | #ifndef YAJL_VERSION_H_ 2 | #define YAJL_VERSION_H_ 3 | 4 | #include 5 | 6 | #define YAJL_MAJOR ${YAJL_MAJOR} 7 | #define YAJL_MINOR ${YAJL_MINOR} 8 | #define YAJL_MICRO ${YAJL_MICRO} 9 | 10 | #define YAJL_VERSION ((YAJL_MAJOR * 10000) + (YAJL_MINOR * 100) + YAJL_MICRO) 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | extern int YAJL_API yajl_version(void); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif /* YAJL_VERSION_H_ */ 23 | 24 | -------------------------------------------------------------------------------- /test/api/gen-extra-close.c: -------------------------------------------------------------------------------- 1 | /* ensure that if we try to generate an extra closing brace 2 | * we get the expected error */ 3 | 4 | #include 5 | #include 6 | 7 | #define CHK(x) if (x != yajl_gen_status_ok) return 1; 8 | 9 | int main(void) { 10 | yajl_gen yg; 11 | yajl_gen_status s; 12 | 13 | yg = yajl_gen_alloc(NULL); 14 | CHK(yajl_gen_map_open(yg)); 15 | CHK(yajl_gen_map_close(yg)); 16 | s = yajl_gen_map_close(yg); 17 | 18 | return (yajl_gen_generation_complete == s); 19 | } 20 | -------------------------------------------------------------------------------- /BUILDING: -------------------------------------------------------------------------------- 1 | Short story (If you already have ruby and cmake): 2 | 3 | ./configure && make install 4 | 5 | When things go wrong: 6 | 7 | attain CMake (http://www.cmake.org) and ruby (http://ruby-lang.org) and 8 | try again. 9 | 10 | OR, attain CMake and build by hand: 11 | 12 | 1. mkdir build 13 | 2. cd build 14 | 3. cmake .. 15 | 4. make 16 | 5. build output left in yajl-X.Y.Z 17 | 18 | NOTE: for 64-bit systems where lib64 is used you can pass the cmake 19 | variable LIB_SUFFIX to cause installation into the system's 'lib64' 20 | directory. 21 | 22 | best, 23 | lloyd 24 | -------------------------------------------------------------------------------- /test/parsing/cases/ac_difficult_json_c_test_case_with_comments.json: -------------------------------------------------------------------------------- 1 | { "glossary": { /* you */ "title": /**/ "example glossary", /*should*/"GlossDiv": { "title": /*never*/"S", /*ever*/"GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", /*see*/"GlossSeeAlso"/*this*/:/*coming*/[/*out*/"GML"/*of*/,/*the*/"XML"/*parser!*/, "markup"] /*hey*/}/*ho*/]/*hey*/}/*ho*/} } // and the parser won't even get this far, so chill. /* hah! 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2014, Lloyd Hilaiel 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /test/parsing/cases/difficult_json_c_test_case.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'glossary' 3 | map open '{' 4 | key: 'title' 5 | string: 'example glossary' 6 | key: 'GlossDiv' 7 | map open '{' 8 | key: 'title' 9 | string: 'S' 10 | key: 'GlossList' 11 | array open '[' 12 | map open '{' 13 | key: 'ID' 14 | string: 'SGML' 15 | key: 'SortAs' 16 | string: 'SGML' 17 | key: 'GlossTerm' 18 | string: 'Standard Generalized Markup Language' 19 | key: 'Acronym' 20 | string: 'SGML' 21 | key: 'Abbrev' 22 | string: 'ISO 8879:1986' 23 | key: 'GlossDef' 24 | string: 'A meta-markup language, used to create markup languages such as DocBook.' 25 | key: 'GlossSeeAlso' 26 | array open '[' 27 | string: 'GML' 28 | string: 'XML' 29 | string: 'markup' 30 | array close ']' 31 | map close '}' 32 | array close ']' 33 | map close '}' 34 | map close '}' 35 | map close '}' 36 | memory leaks: 0 37 | -------------------------------------------------------------------------------- /test/parsing/cases/ac_difficult_json_c_test_case_with_comments.json.gold: -------------------------------------------------------------------------------- 1 | map open '{' 2 | key: 'glossary' 3 | map open '{' 4 | key: 'title' 5 | string: 'example glossary' 6 | key: 'GlossDiv' 7 | map open '{' 8 | key: 'title' 9 | string: 'S' 10 | key: 'GlossList' 11 | array open '[' 12 | map open '{' 13 | key: 'ID' 14 | string: 'SGML' 15 | key: 'SortAs' 16 | string: 'SGML' 17 | key: 'GlossTerm' 18 | string: 'Standard Generalized Markup Language' 19 | key: 'Acronym' 20 | string: 'SGML' 21 | key: 'Abbrev' 22 | string: 'ISO 8879:1986' 23 | key: 'GlossDef' 24 | string: 'A meta-markup language, used to create markup languages such as DocBook.' 25 | key: 'GlossSeeAlso' 26 | array open '[' 27 | string: 'GML' 28 | string: 'XML' 29 | string: 'markup' 30 | array close ']' 31 | map close '}' 32 | array close ']' 33 | map close '}' 34 | map close '}' 35 | map close '}' 36 | memory leaks: 0 37 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | ADD_SUBDIRECTORY(parsing) 16 | ADD_SUBDIRECTORY(api) 17 | -------------------------------------------------------------------------------- /YAJLDoc.cmake: -------------------------------------------------------------------------------- 1 | FIND_PROGRAM(doxygenPath doxygen) 2 | 3 | IF (doxygenPath) 4 | SET (YAJL_VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO}) 5 | SET(yajlDirName yajl-${YAJL_VERSION}) 6 | SET(docPath 7 | "${CMAKE_CURRENT_BINARY_DIR}/${yajlDirName}/share/doc/${yajlDirName}") 8 | MESSAGE("** using doxygen at: ${doxygenPath}") 9 | MESSAGE("** documentation output to: ${docPath}") 10 | 11 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/src/YAJL.dxy 12 | ${CMAKE_CURRENT_BINARY_DIR}/YAJL.dxy @ONLY) 13 | 14 | FILE(MAKE_DIRECTORY "${docPath}") 15 | 16 | ADD_CUSTOM_TARGET(doc 17 | ${doxygenPath} YAJL.dxy 18 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 19 | 20 | ELSE (doxygenPath) 21 | MESSAGE("!! doxygen not found, not generating documentation") 22 | ADD_CUSTOM_TARGET( 23 | doc 24 | echo doxygen not installed, not generating documentation 25 | ) 26 | ENDIF (doxygenPath) 27 | -------------------------------------------------------------------------------- /BUILDING.win32: -------------------------------------------------------------------------------- 1 | YAJL has been successfully built using Visual Studio 8. CMake, a 2 | build file generator, is used to build the software. CMake supports 3 | several different build environments, so you may either build YAJL 4 | using the IDE via the following steps: 5 | 6 | 1. acquire cmake (http://www.cmake.org) 7 | 2. mkdir build 8 | 3. cd build 9 | 4. cmake .. 10 | 5. devenv YetAnotherJSONParser.sln /project ALL_BUILD /build Release 11 | 6. build output is left in build/yajl-X.Y.Z 12 | 13 | Or you can build from the command line using nmake: 14 | 15 | 1. Click Start > Programs > Microsoft Visual Studio > Visual Studio 16 | Tools > Visual Studio Command Prompt -- for your version of Visual 17 | Studio, which will open a command prompt. You may verify that the 18 | compiler is in your path by typing "cl /?" at the prompt. 19 | 2. cd C:\path\to\yajl\source\ 20 | 3. mkdir build 21 | 4. cd build 22 | 5. cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release .. 23 | 6. nmake 24 | 7. nmake install 25 | 26 | Earlier versions of visual studio and other build generators haven't 27 | been thoroughly tested, but should work without any major issues. 28 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | SET (SRCS parse_config.c) 16 | 17 | # use the library we build, duh. 18 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include) 19 | LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib) 20 | 21 | ADD_EXECUTABLE(parse_config ${SRCS}) 22 | 23 | TARGET_LINK_LIBRARIES(parse_config yajl_s) 24 | -------------------------------------------------------------------------------- /src/yajl: -------------------------------------------------------------------------------- 1 | /** 2 | \example reformatter/json_reformat.c 3 | \example example/parse_config.c 4 | */ 5 | 6 | /*! 7 | \mainpage Yet Another JSON Library (YAJL) 8 | \author Lloyd Hilaiel 9 | \date 2007-2014 10 | 11 | Yet Another JSON Library (YAJL) is a small event-driven (SAX-style) 12 | JSON parser written in ANSI C, and a small validating JSON 13 | generator. YAJL is released under the permissive ISC license. 14 | 15 | \section features Features 16 | 17 | -# Stream (incremental) parsing and generation of JSON 18 | -# ANSI C 19 | -# Human readable error messages with context 20 | -# tiny 21 | -# event driven 22 | -# support for generating "beautified" JSON 23 | -# includes 24 | It also includes a small simplified tree interface for 25 | simplified parsing and extraction of data from smallish JSON documents. 26 | 27 | \section usage Usage 28 | 29 | See json_reformat.c for a complete example of stream based parsing 30 | and generation of JSON. See parse_config.c for an example of the 31 | simplified tree interface. 32 | 33 | */ 34 | -------------------------------------------------------------------------------- /test/parsing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | SET (SRCS yajl_test.c) 16 | 17 | # use the library we build, duh. 18 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../../${YAJL_DIST_NAME}/include) 19 | LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../../${YAJL_DIST_NAME}/lib) 20 | 21 | ADD_EXECUTABLE(yajl_test ${SRCS}) 22 | 23 | TARGET_LINK_LIBRARIES(yajl_test yajl_s) 24 | -------------------------------------------------------------------------------- /perf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | SET (SRCS perftest.c documents.c documents.h) 16 | 17 | # use the library we build, duh. 18 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include) 19 | LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib) 20 | 21 | ADD_EXECUTABLE(perftest ${SRCS}) 22 | 23 | TARGET_LINK_LIBRARIES(perftest yajl_s) 24 | -------------------------------------------------------------------------------- /perf/documents.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __DOCUMENTS_H__ 18 | #define __DOCUMENTS_H__ 19 | 20 | /* a header that provides access to several json documents broken into chunks of 21 | * less than 4k, cause C99 says that's what we should do and YAJL likes streams */ 22 | 23 | extern const char ** g_documents[]; 24 | int num_docs(void); 25 | const char ** get_doc(int i); 26 | unsigned int doc_size(int i); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /test/api/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | SET (TESTS gen-extra-close.c 16 | ) 17 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../../${YAJL_DIST_NAME}/include) 18 | LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../../${YAJL_DIST_NAME}/lib) 19 | 20 | # for each test, we'll create a target, and make the api-tests target depend on it 21 | FOREACH (test ${TESTS}) 22 | GET_FILENAME_COMPONENT(testProg ${test} NAME_WE) 23 | ADD_EXECUTABLE(${testProg} ${test}) 24 | TARGET_LINK_LIBRARIES(${testProg} yajl) 25 | ENDFOREACH() 26 | -------------------------------------------------------------------------------- /src/yajl_alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_alloc.h 19 | * default memory allocation routines for yajl which use malloc/realloc and 20 | * free 21 | */ 22 | 23 | #ifndef __YAJL_ALLOC_H__ 24 | #define __YAJL_ALLOC_H__ 25 | 26 | #include "api/yajl_common.h" 27 | 28 | #define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) 29 | #define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) 30 | #define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) 31 | 32 | void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/yajl_encode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_ENCODE_H__ 18 | #define __YAJL_ENCODE_H__ 19 | 20 | #include "yajl_buf.h" 21 | #include "api/yajl_gen.h" 22 | 23 | void yajl_string_encode(const yajl_print_t printer, 24 | void * ctx, 25 | const unsigned char * str, 26 | size_t length, 27 | int escape_solidus); 28 | 29 | void yajl_string_decode(yajl_buf buf, const unsigned char * str, 30 | size_t length); 31 | 32 | int yajl_string_validate_utf8(const unsigned char * s, size_t len); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /verify/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | # set up some paths 16 | SET (binDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/bin) 17 | 18 | # create some directories 19 | FILE(MAKE_DIRECTORY ${binDir}) 20 | 21 | SET (SRCS json_verify.c) 22 | 23 | # use the library we build, duh. 24 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include) 25 | LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib) 26 | 27 | ADD_EXECUTABLE(json_verify ${SRCS}) 28 | 29 | TARGET_LINK_LIBRARIES(json_verify yajl_s) 30 | 31 | # copy in the binary 32 | GET_TARGET_PROPERTY(binPath json_verify LOCATION) 33 | 34 | ADD_CUSTOM_COMMAND(TARGET json_verify POST_BUILD 35 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${binPath} ${binDir}) 36 | 37 | INSTALL(TARGETS json_verify RUNTIME DESTINATION bin) 38 | -------------------------------------------------------------------------------- /src/yajl_alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_alloc.h 19 | * default memory allocation routines for yajl which use malloc/realloc and 20 | * free 21 | */ 22 | 23 | #include "yajl_alloc.h" 24 | #include 25 | 26 | static void * yajl_internal_malloc(void *ctx, size_t sz) 27 | { 28 | (void)ctx; 29 | return malloc(sz); 30 | } 31 | 32 | static void * yajl_internal_realloc(void *ctx, void * previous, 33 | size_t sz) 34 | { 35 | (void)ctx; 36 | return realloc(previous, sz); 37 | } 38 | 39 | static void yajl_internal_free(void *ctx, void * ptr) 40 | { 41 | (void)ctx; 42 | free(ptr); 43 | } 44 | 45 | void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) 46 | { 47 | yaf->malloc = yajl_internal_malloc; 48 | yaf->free = yajl_internal_free; 49 | yaf->realloc = yajl_internal_realloc; 50 | yaf->ctx = NULL; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /reformatter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | # set up a paths 16 | SET (binDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/bin) 17 | 18 | # create a directories 19 | FILE(MAKE_DIRECTORY ${binDir}) 20 | 21 | SET (SRCS json_reformat.c) 22 | 23 | # use the library we build, duh. 24 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include) 25 | LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib) 26 | 27 | ADD_EXECUTABLE(json_reformat ${SRCS}) 28 | 29 | TARGET_LINK_LIBRARIES(json_reformat yajl_s) 30 | 31 | # In some environments, we must explicitly link libm (like qnx, 32 | # thanks @shahbag) 33 | IF (NOT WIN32) 34 | TARGET_LINK_LIBRARIES(json_reformat m) 35 | ENDIF (NOT WIN32) 36 | 37 | # copy the binary into the output directory 38 | GET_TARGET_PROPERTY(binPath json_reformat LOCATION) 39 | 40 | ADD_CUSTOM_COMMAND(TARGET json_reformat POST_BUILD 41 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${binPath} ${binDir}) 42 | 43 | INSTALL(TARGETS json_reformat RUNTIME DESTINATION bin) 44 | -------------------------------------------------------------------------------- /test/parsing/cases/deep_arrays.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /src/yajl_buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_BUF_H__ 18 | #define __YAJL_BUF_H__ 19 | 20 | #include "api/yajl_common.h" 21 | #include "yajl_alloc.h" 22 | 23 | /* 24 | * Implementation/performance notes. If this were moved to a header 25 | * only implementation using #define's where possible we might be 26 | * able to sqeeze a little performance out of the guy by killing function 27 | * call overhead. YMMV. 28 | */ 29 | 30 | /** 31 | * yajl_buf is a buffer with exponential growth. the buffer ensures that 32 | * you are always null padded. 33 | */ 34 | typedef struct yajl_buf_t * yajl_buf; 35 | 36 | /* allocate a new buffer */ 37 | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); 38 | 39 | /* free the buffer */ 40 | void yajl_buf_free(yajl_buf buf); 41 | 42 | /* append a number of bytes to the buffer */ 43 | void yajl_buf_append(yajl_buf buf, const void * data, size_t len); 44 | 45 | /* empty the buffer */ 46 | void yajl_buf_clear(yajl_buf buf); 47 | 48 | /* get a pointer to the beginning of the buffer */ 49 | const unsigned char * yajl_buf_data(yajl_buf buf); 50 | 51 | /* get the length of the buffer */ 52 | size_t yajl_buf_len(yajl_buf buf); 53 | 54 | /* truncate the buffer */ 55 | void yajl_buf_truncate(yajl_buf buf, size_t len); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2007-2014, Lloyd Hilaiel 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | prefix="/usr/local" 18 | if [ "$1" = "--help" ] 19 | then 20 | cat < ./Makefile < 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "yajl/yajl_tree.h" 21 | 22 | static unsigned char fileData[65536]; 23 | 24 | int 25 | main(void) 26 | { 27 | size_t rd; 28 | yajl_val node; 29 | char errbuf[1024]; 30 | 31 | /* null plug buffers */ 32 | fileData[0] = errbuf[0] = 0; 33 | 34 | /* read the entire config file */ 35 | rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); 36 | 37 | /* file read error handling */ 38 | if (rd == 0 && !feof(stdin)) { 39 | fprintf(stderr, "error encountered on file read\n"); 40 | return 1; 41 | } else if (rd >= sizeof(fileData) - 1) { 42 | fprintf(stderr, "config file too big\n"); 43 | return 1; 44 | } 45 | 46 | /* we have the whole config file in memory. let's parse it ... */ 47 | node = yajl_tree_parse((const char *) fileData, errbuf, sizeof(errbuf)); 48 | 49 | /* parse error handling */ 50 | if (node == NULL) { 51 | fprintf(stderr, "parse_error: "); 52 | if (strlen(errbuf)) fprintf(stderr, " %s", errbuf); 53 | else fprintf(stderr, "unknown error"); 54 | fprintf(stderr, "\n"); 55 | return 1; 56 | } 57 | 58 | /* ... and extract a nested value from the config file */ 59 | { 60 | const char * path[] = { "Logging", "timeFormat", (const char *) 0 }; 61 | yajl_val v = yajl_tree_get(node, path, yajl_t_string); 62 | if (v) printf("%s/%s: %s\n", path[0], path[1], YAJL_GET_STRING(v)); 63 | else printf("no such node: %s/%s\n", path[0], path[1]); 64 | } 65 | 66 | yajl_tree_free(node); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /test/parsing/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ECHO=`which echo` 4 | 5 | DIFF_FLAGS="-u" 6 | case "$(uname)" in 7 | *W32*) 8 | DIFF_FLAGS="-wu" 9 | ;; 10 | esac 11 | 12 | if [ -z "$testBin" ]; then 13 | testBin="$1" 14 | fi 15 | 16 | # find test binary on both platforms. allow the caller to force a 17 | # particular test binary (useful for non-cmake build systems). 18 | if [ -z "$testBin" ]; then 19 | testBin="../../build/test/parsing/Release/yajl_test.exe" 20 | if [ ! -x $testBin ] ; then 21 | testBin="../../build/test/parsing/Debug/yajl_test.exe" 22 | if [ ! -x $testBin ] ; then 23 | testBin="../../build/test/parsing/yajl_test" 24 | if [ ! -x $testBin ] ; then 25 | ${ECHO} "cannot execute test binary: '$testBin'" 26 | exit 1; 27 | fi 28 | fi 29 | fi 30 | fi 31 | 32 | ${ECHO} "using test binary: $testBin" 33 | 34 | testBinShort=`basename $testBin` 35 | 36 | testsSucceeded=0 37 | testsTotal=0 38 | 39 | for file in cases/*.json ; do 40 | allowComments="" 41 | allowGarbage="" 42 | allowMultiple="" 43 | allowPartials="" 44 | 45 | # if the filename starts with dc_, we disallow comments for this test 46 | case $(basename $file) in 47 | ac_*) 48 | allowComments="-c " 49 | ;; 50 | ag_*) 51 | allowGarbage="-g " 52 | ;; 53 | am_*) 54 | allowMultiple="-m "; 55 | ;; 56 | ap_*) 57 | allowPartials="-p "; 58 | ;; 59 | esac 60 | fileShort=`basename $file` 61 | testName=`echo $fileShort | sed -e 's/\.json$//'` 62 | 63 | ${ECHO} -n " test ($testName): " 64 | iter=1 65 | success="SUCCESS" 66 | 67 | # ${ECHO} -n "$testBinShort $allowPartials$allowComments$allowGarbage$allowMultiple-b $iter < $fileShort > ${fileShort}.test : " 68 | # parse with a read buffer size ranging from 1-31 to stress stream parsing 69 | while [ $iter -lt 32 ] && [ $success = "SUCCESS" ] ; do 70 | $testBin $allowPartials $allowComments $allowGarbage $allowMultiple -b $iter < $file > ${file}.test 2>&1 71 | diff ${DIFF_FLAGS} ${file}.gold ${file}.test > ${file}.out 72 | if [ $? -eq 0 ] ; then 73 | if [ $iter -eq 31 ] ; then testsSucceeded=$(( $testsSucceeded + 1 )) ; fi 74 | else 75 | success="FAILURE" 76 | iter=32 77 | ${ECHO} 78 | cat ${file}.out 79 | fi 80 | iter=$(( iter + 1 )) 81 | rm ${file}.test ${file}.out 82 | done 83 | 84 | ${ECHO} $success 85 | testsTotal=$(( testsTotal + 1 )) 86 | done 87 | 88 | ${ECHO} $testsSucceeded/$testsTotal tests successful 89 | 90 | if [ $testsSucceeded != $testsTotal ] ; then 91 | exit 1 92 | fi 93 | 94 | exit 0 95 | -------------------------------------------------------------------------------- /src/yajl_bytestack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * A header only implementation of a simple stack of bytes, used in YAJL 19 | * to maintain parse state. 20 | */ 21 | 22 | #ifndef __YAJL_BYTESTACK_H__ 23 | #define __YAJL_BYTESTACK_H__ 24 | 25 | #include "api/yajl_common.h" 26 | 27 | #define YAJL_BS_INC 128 28 | 29 | typedef struct yajl_bytestack_t 30 | { 31 | unsigned char * stack; 32 | size_t size; 33 | size_t used; 34 | yajl_alloc_funcs * yaf; 35 | } yajl_bytestack; 36 | 37 | /* initialize a bytestack */ 38 | #define yajl_bs_init(obs, _yaf) { \ 39 | (obs).stack = NULL; \ 40 | (obs).size = 0; \ 41 | (obs).used = 0; \ 42 | (obs).yaf = (_yaf); \ 43 | } \ 44 | 45 | 46 | /* initialize a bytestack */ 47 | #define yajl_bs_free(obs) \ 48 | if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); 49 | 50 | #define yajl_bs_current(obs) \ 51 | (assert((obs).used > 0), (obs).stack[(obs).used - 1]) 52 | 53 | #define yajl_bs_push(obs, byte) { \ 54 | if (((obs).size - (obs).used) == 0) { \ 55 | (obs).size += YAJL_BS_INC; \ 56 | (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\ 57 | (void *) (obs).stack, (obs).size);\ 58 | } \ 59 | (obs).stack[((obs).used)++] = (byte); \ 60 | } 61 | 62 | /* removes the top item of the stack, returns nothing */ 63 | #define yajl_bs_pop(obs) { ((obs).used)--; } 64 | 65 | #define yajl_bs_set(obs, byte) \ 66 | (obs).stack[((obs).used) - 1] = (byte); 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/yajl_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_PARSER_H__ 18 | #define __YAJL_PARSER_H__ 19 | 20 | #include "api/yajl_parse.h" 21 | #include "yajl_bytestack.h" 22 | #include "yajl_buf.h" 23 | #include "yajl_lex.h" 24 | 25 | 26 | typedef enum { 27 | yajl_state_start = 0, 28 | yajl_state_parse_complete, 29 | yajl_state_parse_error, 30 | yajl_state_lexical_error, 31 | yajl_state_map_start, 32 | yajl_state_map_sep, 33 | yajl_state_map_need_val, 34 | yajl_state_map_got_val, 35 | yajl_state_map_need_key, 36 | yajl_state_array_start, 37 | yajl_state_array_got_val, 38 | yajl_state_array_need_val, 39 | yajl_state_got_value, 40 | } yajl_state; 41 | 42 | struct yajl_handle_t { 43 | const yajl_callbacks * callbacks; 44 | void * ctx; 45 | yajl_lexer lexer; 46 | const char * parseError; 47 | /* the number of bytes consumed from the last client buffer, 48 | * in the case of an error this will be an error offset, in the 49 | * case of an error this can be used as the error offset */ 50 | size_t bytesConsumed; 51 | /* temporary storage for decoded strings */ 52 | yajl_buf decodeBuf; 53 | /* a stack of states. access with yajl_state_XXX routines */ 54 | yajl_bytestack stateStack; 55 | /* memory allocation routines */ 56 | yajl_alloc_funcs alloc; 57 | /* bitfield */ 58 | unsigned int flags; 59 | }; 60 | 61 | yajl_status 62 | yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, 63 | size_t jsonTextLen); 64 | 65 | yajl_status 66 | yajl_do_finish(yajl_handle handle); 67 | 68 | unsigned char * 69 | yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, 70 | size_t jsonTextLen, int verbose); 71 | 72 | /* A little built in integer parsing routine with the same semantics as strtol 73 | * that's unaffected by LOCALE. */ 74 | long long 75 | yajl_parse_integer(const unsigned char *number, unsigned int length); 76 | 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/api/yajl_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_COMMON_H__ 18 | #define __YAJL_COMMON_H__ 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #define YAJL_MAX_DEPTH 128 27 | 28 | /* msft dll export gunk. To build a DLL on windows, you 29 | * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared 30 | * DLL, you must define YAJL_SHARED and WIN32 */ 31 | #if (defined(_WIN32) || defined(WIN32)) && defined(YAJL_SHARED) 32 | # ifdef YAJL_BUILD 33 | # define YAJL_API __declspec(dllexport) 34 | # else 35 | # define YAJL_API __declspec(dllimport) 36 | # endif 37 | #else 38 | # if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303 39 | # define YAJL_API __attribute__ ((visibility("default"))) 40 | # else 41 | # define YAJL_API 42 | # endif 43 | #endif 44 | 45 | /** pointer to a malloc function, supporting client overriding memory 46 | * allocation routines */ 47 | typedef void * (*yajl_malloc_func)(void *ctx, size_t sz); 48 | 49 | /** pointer to a free function, supporting client overriding memory 50 | * allocation routines */ 51 | typedef void (*yajl_free_func)(void *ctx, void * ptr); 52 | 53 | /** pointer to a realloc function which can resize an allocation. */ 54 | typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz); 55 | 56 | /** A structure which can be passed to yajl_*_alloc routines to allow the 57 | * client to specify memory allocation functions to be used. */ 58 | typedef struct 59 | { 60 | /** pointer to a function that can allocate uninitialized memory */ 61 | yajl_malloc_func malloc; 62 | /** pointer to a function that can resize memory allocations */ 63 | yajl_realloc_func realloc; 64 | /** pointer to a function that can free memory allocated using 65 | * reallocFunction or mallocFunction */ 66 | yajl_free_func free; 67 | /** a context pointer that will be passed to above allocation routines */ 68 | void * ctx; 69 | } yajl_alloc_funcs; 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/yajl_buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "yajl_buf.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define YAJL_BUF_INIT_SIZE 2048 24 | 25 | struct yajl_buf_t { 26 | size_t len; 27 | size_t used; 28 | unsigned char * data; 29 | yajl_alloc_funcs * alloc; 30 | }; 31 | 32 | static 33 | void yajl_buf_ensure_available(yajl_buf buf, size_t want) 34 | { 35 | size_t need; 36 | 37 | assert(buf != NULL); 38 | 39 | /* first call */ 40 | if (buf->data == NULL) { 41 | buf->len = YAJL_BUF_INIT_SIZE; 42 | buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); 43 | buf->data[0] = 0; 44 | } 45 | 46 | need = buf->len; 47 | 48 | while (want >= (need - buf->used)) need <<= 1; 49 | 50 | if (need != buf->len) { 51 | buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); 52 | buf->len = need; 53 | } 54 | } 55 | 56 | yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) 57 | { 58 | yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); 59 | memset((void *) b, 0, sizeof(struct yajl_buf_t)); 60 | b->alloc = alloc; 61 | return b; 62 | } 63 | 64 | void yajl_buf_free(yajl_buf buf) 65 | { 66 | assert(buf != NULL); 67 | if (buf->data) YA_FREE(buf->alloc, buf->data); 68 | YA_FREE(buf->alloc, buf); 69 | } 70 | 71 | void yajl_buf_append(yajl_buf buf, const void * data, size_t len) 72 | { 73 | yajl_buf_ensure_available(buf, len); 74 | if (len > 0) { 75 | assert(data != NULL); 76 | memcpy(buf->data + buf->used, data, len); 77 | buf->used += len; 78 | buf->data[buf->used] = 0; 79 | } 80 | } 81 | 82 | void yajl_buf_clear(yajl_buf buf) 83 | { 84 | buf->used = 0; 85 | if (buf->data) buf->data[buf->used] = 0; 86 | } 87 | 88 | const unsigned char * yajl_buf_data(yajl_buf buf) 89 | { 90 | return buf->data; 91 | } 92 | 93 | size_t yajl_buf_len(yajl_buf buf) 94 | { 95 | return buf->used; 96 | } 97 | 98 | void 99 | yajl_buf_truncate(yajl_buf buf, size_t len) 100 | { 101 | assert(len <= buf->used); 102 | buf->used = len; 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ********************************************************************** 2 | This is YAJL 2. For the legacy version of YAJL see 3 | https://github.com/lloyd/yajl/tree/1.x 4 | ********************************************************************** 5 | 6 | Welcome to Yet Another JSON Library (YAJL) 7 | 8 | ## Why does the world need another C library for parsing JSON? 9 | 10 | Good question. In a review of current C JSON parsing libraries I was 11 | unable to find one that satisfies my requirements. Those are, 12 | 0. written in C 13 | 1. portable 14 | 2. robust -- as close to "crash proof" as possible 15 | 3. data representation independent 16 | 4. fast 17 | 5. generates verbose, useful error messages including context of where 18 | the error occurs in the input text. 19 | 6. can parse JSON data off a stream, incrementally 20 | 7. simple to use 21 | 8. tiny 22 | 23 | Numbers 3, 5, 6, and 7 were particularly hard to find, and were what 24 | caused me to ultimately create YAJL. This document is a tour of some 25 | of the more important aspects of YAJL. 26 | 27 | ## YAJL is Free. 28 | 29 | Permissive licensing means you can use it in open source and 30 | commercial products alike without any fees. My request beyond the 31 | licensing is that if you find bugs drop me a email, or better yet, 32 | fork and fix. 33 | 34 | Porting YAJL should be trivial, the implementation is ANSI C. If you 35 | port to new systems I'd love to hear of it and integrate your patches. 36 | 37 | ## YAJL is data representation independent. 38 | 39 | BYODR! Many JSON libraries impose a structure based data representation 40 | on you. This is a benefit in some cases and a drawback in others. 41 | YAJL uses callbacks to remain agnostic of the in-memory representation. 42 | So if you wish to build up an in-memory representation, you may do so 43 | using YAJL, but you must bring the code that defines and populates the 44 | in memory structure. 45 | 46 | This also means that YAJL can be used by other (higher level) JSON 47 | libraries if so desired. 48 | 49 | ## YAJL supports stream parsing 50 | 51 | This means you do not need to hold the whole JSON representation in 52 | textual form in memory. This makes YAJL ideal for filtering projects, 53 | where you're converting YAJL from one form to another (i.e. XML). The 54 | included JSON pretty printer is an example of such a filter program. 55 | 56 | ## YAJL is fast 57 | 58 | Minimal memory copying is performed. YAJL, when possible, returns 59 | pointers into the client provided text (i.e. for strings that have no 60 | embedded escape chars, hopefully the common case). I've put a lot of 61 | effort into profiling and tuning performance, but I have ignored a 62 | couple possible performance improvements to keep the interface clean, 63 | small, and flexible. My hope is that YAJL will perform comparably to 64 | the fastest JSON parser out there. 65 | 66 | YAJL should impose both minimal CPU and memory requirements on your 67 | application. 68 | 69 | ## YAJL is tiny. 70 | 71 | Fat free. No whip. 72 | 73 | enjoy, 74 | Lloyd - July, 2007 75 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 16 | 17 | PROJECT(YetAnotherJSONParser C) 18 | 19 | SET (YAJL_MAJOR 2) 20 | SET (YAJL_MINOR 1) 21 | SET (YAJL_MICRO 1) 22 | 23 | SET (YAJL_DIST_NAME "yajl-${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO}") 24 | 25 | IF (NOT CMAKE_BUILD_TYPE) 26 | SET(CMAKE_BUILD_TYPE "Release") 27 | ENDIF (NOT CMAKE_BUILD_TYPE) 28 | 29 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") 30 | 31 | IF (WIN32) 32 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4") 33 | ADD_DEFINITIONS(-DWIN32) 34 | SET(linkFlags "/PDB:NONE /INCREMENTAL:NO /OPT:NOREF /OPT:NOICF") 35 | SET(CMAKE_EXE_LINKER_FLAGS "${linkFlags}" 36 | CACHE STRING "YAJL linker flags" FORCE) 37 | SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "" 38 | CACHE STRING "YAJL debug linker flags" FORCE) 39 | SET(CMAKE_EXE_LINKER_FLAGS_RELEASE 40 | CACHE STRING "YAJL release linker flags" FORCE) 41 | SET(CMAKE_SHARED_LINKER_FLAGS "${linkFlags}" 42 | CACHE STRING "YAJL shared linker flags" FORCE) 43 | SET(CMAKE_MODULE_LINKER_FLAGS "${linkFlags}" 44 | CACHE STRING "YAJL module linker flags" FORCE) 45 | 46 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996 /wd4255 /wd4130 /wd4100 /wd4711") 47 | SET(CMAKE_C_FLAGS_DEBUG "/D DEBUG /Od /Z7") 48 | SET(CMAKE_C_FLAGS_RELEASE "/D NDEBUG /O2") 49 | ELSE (WIN32) 50 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") 51 | IF(CMAKE_COMPILER_IS_GNUCC) 52 | INCLUDE(CheckCCompilerFlag) 53 | CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_GCC_VISIBILITY) 54 | IF(HAVE_GCC_VISIBILITY) 55 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") 56 | ENDIF(HAVE_GCC_VISIBILITY) 57 | ENDIF(CMAKE_COMPILER_IS_GNUCC) 58 | SET(CMAKE_C_FLAGS 59 | "${CMAKE_C_FLAGS} -std=c99 -pedantic -Wpointer-arith -Wno-format-y2k -Wstrict-prototypes -Wmissing-declarations -Wnested-externs -Wextra -Wundef -Wwrite-strings -Wold-style-definition -Wredundant-decls -Wno-unused-parameter -Wno-sign-compare -Wmissing-prototypes") 60 | 61 | SET(CMAKE_C_FLAGS_DEBUG "-DDEBUG -g") 62 | SET(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2 -Wuninitialized") 63 | ENDIF (WIN32) 64 | 65 | 66 | ADD_SUBDIRECTORY(src) 67 | ADD_SUBDIRECTORY(test) 68 | ADD_SUBDIRECTORY(reformatter) 69 | ADD_SUBDIRECTORY(verify) 70 | ADD_SUBDIRECTORY(example) 71 | ADD_SUBDIRECTORY(perf) 72 | 73 | INCLUDE(YAJLDoc.cmake) 74 | 75 | # a test target 76 | ADD_CUSTOM_TARGET(test 77 | ./run_tests.sh ${CMAKE_CURRENT_BINARY_DIR}/test/parsing/yajl_test 78 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test/parsing) 79 | 80 | ADD_CUSTOM_TARGET(test-api ${CMAKE_CURRENT_SOURCE_DIR}/test/api/run_tests.sh 81 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test/api) 82 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2007-2014, Lloyd Hilaiel 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | SET (SRCS yajl.c yajl_lex.c yajl_parser.c yajl_buf.c 16 | yajl_encode.c yajl_gen.c yajl_alloc.c 17 | yajl_tree.c yajl_version.c 18 | ) 19 | SET (HDRS yajl_parser.h yajl_lex.h yajl_buf.h yajl_encode.h yajl_alloc.h) 20 | SET (PUB_HDRS api/yajl_parse.h api/yajl_gen.h api/yajl_common.h api/yajl_tree.h) 21 | 22 | # useful when fixing lexer bugs. 23 | #ADD_DEFINITIONS(-DYAJL_LEXER_DEBUG) 24 | 25 | # Ensure defined when building YAJL (as opposed to using it from 26 | # another project). Used to ensure correct function export when 27 | # building win32 DLL. 28 | ADD_DEFINITIONS(-DYAJL_BUILD) 29 | 30 | # set up some paths 31 | SET (libDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib) 32 | SET (incDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include/yajl) 33 | SET (shareDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/share/pkgconfig) 34 | 35 | # set the output path for libraries 36 | SET(LIBRARY_OUTPUT_PATH ${libDir}) 37 | 38 | ADD_LIBRARY(yajl_s STATIC ${SRCS} ${HDRS} ${PUB_HDRS}) 39 | 40 | ADD_LIBRARY(yajl SHARED ${SRCS} ${HDRS} ${PUB_HDRS}) 41 | 42 | #### setup shared library version number 43 | SET_TARGET_PROPERTIES(yajl PROPERTIES 44 | DEFINE_SYMBOL YAJL_SHARED 45 | SOVERSION ${YAJL_MAJOR} 46 | VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO}) 47 | 48 | #### ensure a .dylib has correct absolute installation paths upon installation 49 | IF(APPLE) 50 | MESSAGE("INSTALL_NAME_DIR: ${CMAKE_INSTALL_PREFIX}/lib") 51 | SET_TARGET_PROPERTIES(yajl PROPERTIES 52 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib") 53 | ENDIF(APPLE) 54 | 55 | #### build up an sdk as a post build step 56 | 57 | # create some directories 58 | FILE(MAKE_DIRECTORY ${libDir}) 59 | FILE(MAKE_DIRECTORY ${incDir}) 60 | 61 | # generate build-time source 62 | SET(dollar $) 63 | CONFIGURE_FILE(api/yajl_version.h.cmake ${incDir}/yajl_version.h) 64 | CONFIGURE_FILE(yajl.pc.cmake ${shareDir}/yajl.pc) 65 | 66 | # copy public headers to output directory 67 | FOREACH (header ${PUB_HDRS}) 68 | SET (header ${CMAKE_CURRENT_SOURCE_DIR}/${header}) 69 | 70 | EXEC_PROGRAM(${CMAKE_COMMAND} ARGS -E copy_if_different ${header} ${incDir}) 71 | 72 | ADD_CUSTOM_COMMAND(TARGET yajl_s POST_BUILD 73 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${header} ${incDir}) 74 | ENDFOREACH (header ${PUB_HDRS}) 75 | 76 | INCLUDE_DIRECTORIES(${incDir}/..) 77 | 78 | # at build time you may specify the cmake variable LIB_SUFFIX to handle 79 | # 64-bit systems which use 'lib64' 80 | INSTALL(TARGETS yajl 81 | RUNTIME DESTINATION lib${LIB_SUFFIX} 82 | LIBRARY DESTINATION lib${LIB_SUFFIX} 83 | ARCHIVE DESTINATION lib${LIB_SUFFIX}) 84 | INSTALL(TARGETS yajl_s ARCHIVE DESTINATION lib${LIB_SUFFIX}) 85 | INSTALL(FILES ${PUB_HDRS} DESTINATION include/yajl) 86 | INSTALL(FILES ${incDir}/yajl_version.h DESTINATION include/yajl) 87 | INSTALL(FILES ${shareDir}/yajl.pc DESTINATION share/pkgconfig) 88 | -------------------------------------------------------------------------------- /verify/json_verify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | static void 24 | usage(const char * progname) 25 | { 26 | fprintf(stderr, "%s: validate json from stdin\n" 27 | "usage: json_verify [options]\n" 28 | " -c allow comments\n" 29 | " -q quiet mode\n" 30 | " -s verify a stream of multiple json entities\n" 31 | " -u allow invalid utf8 inside strings\n", 32 | progname); 33 | exit(1); 34 | } 35 | 36 | int 37 | main(int argc, char ** argv) 38 | { 39 | yajl_status stat; 40 | size_t rd; 41 | yajl_handle hand; 42 | static unsigned char fileData[65536]; 43 | int quiet = 0; 44 | int retval = 0; 45 | int a = 1; 46 | 47 | /* allocate a parser */ 48 | hand = yajl_alloc(NULL, NULL, NULL); 49 | 50 | /* check arguments.*/ 51 | while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) { 52 | unsigned int i; 53 | for ( i=1; i < strlen(argv[a]); i++) { 54 | switch (argv[a][i]) { 55 | case 'q': 56 | quiet = 1; 57 | break; 58 | case 'c': 59 | yajl_config(hand, yajl_allow_comments, 1); 60 | break; 61 | case 'u': 62 | yajl_config(hand, yajl_dont_validate_strings, 1); 63 | break; 64 | case 's': 65 | yajl_config(hand, yajl_allow_multiple_values, 1); 66 | break; 67 | default: 68 | fprintf(stderr, "unrecognized option: '%c'\n\n", argv[a][i]); 69 | usage(argv[0]); 70 | } 71 | } 72 | ++a; 73 | } 74 | if (a < argc) { 75 | usage(argv[0]); 76 | } 77 | 78 | for (;;) { 79 | rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); 80 | 81 | retval = 0; 82 | 83 | if (rd == 0) { 84 | if (!feof(stdin)) { 85 | if (!quiet) { 86 | fprintf(stderr, "error encountered on file read\n"); 87 | } 88 | retval = 1; 89 | } 90 | break; 91 | } 92 | fileData[rd] = 0; 93 | 94 | /* read file data, pass to parser */ 95 | stat = yajl_parse(hand, fileData, rd); 96 | 97 | if (stat != yajl_status_ok) break; 98 | } 99 | 100 | /* parse any remaining buffered data */ 101 | stat = yajl_complete_parse(hand); 102 | 103 | if (stat != yajl_status_ok) 104 | { 105 | if (!quiet) { 106 | unsigned char * str = yajl_get_error(hand, 1, fileData, rd); 107 | fprintf(stderr, "%s", (const char *) str); 108 | yajl_free_error(hand, str); 109 | } 110 | retval = 1; 111 | } 112 | 113 | yajl_free(hand); 114 | 115 | if (!quiet) { 116 | printf("JSON is %s\n", retval ? "invalid" : "valid"); 117 | } 118 | 119 | return retval; 120 | } 121 | -------------------------------------------------------------------------------- /perf/perftest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "documents.h" 23 | 24 | /* a platform specific defn' of a function to get a high res time in a 25 | * portable format */ 26 | #ifndef WIN32 27 | #include 28 | static double mygettime(void) { 29 | struct timeval now; 30 | gettimeofday(&now, NULL); 31 | return now.tv_sec + (now.tv_usec / 1000000.0); 32 | } 33 | #else 34 | #define _WIN32 1 35 | #include 36 | static double mygettime(void) { 37 | long long tval; 38 | FILETIME ft; 39 | GetSystemTimeAsFileTime(&ft); 40 | tval = ft.dwHighDateTime; 41 | tval <<=32; 42 | tval |= ft.dwLowDateTime; 43 | return tval / 10000000.00; 44 | } 45 | #endif 46 | 47 | #define PARSE_TIME_SECS 3 48 | 49 | static int 50 | run(int validate_utf8) 51 | { 52 | long long times = 0; 53 | double starttime; 54 | 55 | starttime = mygettime(); 56 | 57 | /* allocate a parser */ 58 | for (;;) { 59 | int i; 60 | { 61 | double now = mygettime(); 62 | if (now - starttime >= PARSE_TIME_SECS) break; 63 | } 64 | 65 | for (i = 0; i < 100; i++) { 66 | yajl_handle hand = yajl_alloc(NULL, NULL, NULL); 67 | yajl_status stat; 68 | const char ** d; 69 | 70 | yajl_config(hand, yajl_dont_validate_strings, validate_utf8 ? 0 : 1); 71 | 72 | for (d = get_doc(times % num_docs()); *d; d++) { 73 | stat = yajl_parse(hand, (unsigned char *) *d, strlen(*d)); 74 | if (stat != yajl_status_ok) break; 75 | } 76 | 77 | stat = yajl_complete_parse(hand); 78 | 79 | if (stat != yajl_status_ok) { 80 | unsigned char * str = 81 | yajl_get_error(hand, 1, 82 | (unsigned char *) *d, 83 | (*d ? strlen(*d) : 0)); 84 | fprintf(stderr, "%s", (const char *) str); 85 | yajl_free_error(hand, str); 86 | return 1; 87 | } 88 | yajl_free(hand); 89 | times++; 90 | } 91 | } 92 | 93 | /* parsed doc 'times' times */ 94 | { 95 | double throughput; 96 | double now; 97 | const char * all_units[] = { "B/s", "KB/s", "MB/s", (char *) 0 }; 98 | const char ** units = all_units; 99 | int i, avg_doc_size = 0; 100 | 101 | now = mygettime(); 102 | 103 | for (i = 0; i < num_docs(); i++) avg_doc_size += doc_size(i); 104 | avg_doc_size /= num_docs(); 105 | 106 | throughput = (times * avg_doc_size) / (now - starttime); 107 | 108 | while (*(units + 1) && throughput > 1024) { 109 | throughput /= 1024; 110 | units++; 111 | } 112 | 113 | printf("Parsing speed: %g %s\n", throughput, *units); 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | int 120 | main(void) 121 | { 122 | int rv = 0; 123 | 124 | printf("-- speed tests determine parsing throughput given %d different sample documents --\n", 125 | num_docs()); 126 | 127 | printf("With UTF8 validation:\n"); 128 | rv = run(1); 129 | if (rv != 0) return rv; 130 | printf("Without UTF8 validation:\n"); 131 | rv = run(0); 132 | return rv; 133 | } 134 | 135 | -------------------------------------------------------------------------------- /example/sample.config: -------------------------------------------------------------------------------- 1 | /* 2 | * The configuration file for Yahoo! BrowserPlus, included in the YAJL 3 | * tree as a sample configuration file for parsing. 4 | * 5 | * This is the configuration file for BrowserPlus 6 | */ 7 | 8 | { 9 | // The type of build this is, which is accessible to JavaScript via 10 | // BrowserPlus.getPlatformInfo(); 11 | // Different build types should only differ in signatures accepted 12 | // (BrowserPlus.crt) and configured distribution servers. 13 | "BuildType": "ephemeral", 14 | 15 | // the base url for the "primary" distribution server. This server will 16 | // be the single source of truth for Permissions, and will used to 17 | // attain services 18 | "DistServer": "http://browserplus.yahoo.com", 19 | 20 | // An array of "secondary" distribution servers, which will be checked 21 | // in order for services if the primary server has no components 22 | // available which match an issued require statement. 23 | "SecondaryDistServers": [ 24 | "http://first.fictional.server", 25 | "http://second.fictional.server" 26 | ], 27 | 28 | // Logging Setup 29 | "Logging" : 30 | { 31 | // Log level. Values: "debug"|"info"|"warn"|"error"|"fatal"|"off" 32 | "level": "BP_LOG_LEVEL", 33 | 34 | // Destination. Values: "file"|"console"|"win32" 35 | "dest": "BP_LOG_DEST", 36 | 37 | // Log message layout. Values: "standard"|"source"|"raw" 38 | "layout": "standard", 39 | 40 | // Time format. Values: "utc"|"local"|"msec" 41 | "timeFormat": "utc", 42 | 43 | // File size in KB which will trigger a rollover 44 | "fileRolloverKB": 2048, 45 | 46 | // Whether to send file logging from each service to a distinct file. 47 | // Values: "combined"|"separate" 48 | "serviceLogMode": "combined" 49 | }, 50 | 51 | // Daemon setup 52 | // Syntax: "Options": "option1 option2 etc" 53 | // -fg run in foreground, log to console 54 | "Options":"", 55 | 56 | // Auto-shutdown daemon if idle for this time. Use 0 for no auto-shutdown. 57 | "MaxIdleSecs": 5, 58 | 59 | // At the end of each BrowserPlus session a small web request is made 60 | // to yahoo to indicate that BrowserPlus was used. This report includes 61 | // * information about the browser being used 62 | // * an "installation id", which is a unique token that's generated 63 | // the first time BrowserPlus runs. 64 | // 65 | // By design, there is *no information* in this request that gives 66 | // Yahoo! information about: 67 | // a) the site that the user is visiting (see, "url": false) 68 | // b) who the user is (the installation token cannot be tracked to a 69 | // specific user). 70 | // 71 | // This information is primarily captured to help Yahoo! understand 72 | // adoption and usage of the BrowserPlus platform. 73 | "UsageReporting": 74 | { 75 | "enabled": true, 76 | "url": false, 77 | "id": true 78 | }, 79 | 80 | // "Breakpoints" is an array of strings holding named breakpoints. 81 | // Platform code checks for specific entries at certain key points, and if 82 | // a matching entry is found here a DebugBreak will be performed. 83 | // For developers with Visual Studio installed, the DebugBreak will cause an 84 | // opportunity to perform just-in-time attachment of an existing or new 85 | // debugger instance. 86 | // The currently-defined breakpoints are listed below: 87 | // runServiceProcess - A DebugBreak is performed in the service 88 | // "harness" just prior to service load. 89 | // ax.FinalConstruct - A DebugBreak is performed at entry to 90 | // FinalConstruct of the ActiveX plugin. 91 | // PluginInit - Very early in the NPAPI plugin initialization. 92 | // A wonderful spot to stop and set more 93 | // breakpoints. 94 | //"Breakpoints": ["runServiceProcess"], 95 | 96 | // How often we check for service updates. We guarantee at least this 97 | // much time will pass between checks, though the true time may be 98 | // much more if sites which use browserplus are not visited. 99 | // The time is in seconds. 100 | "ServiceUpdatePollPeriod": 86400 101 | } 102 | -------------------------------------------------------------------------------- /src/yajl_lex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __YAJL_LEX_H__ 18 | #define __YAJL_LEX_H__ 19 | 20 | #include "api/yajl_common.h" 21 | 22 | typedef enum { 23 | yajl_tok_bool, 24 | yajl_tok_colon, 25 | yajl_tok_comma, 26 | yajl_tok_eof, 27 | yajl_tok_error, 28 | yajl_tok_left_brace, 29 | yajl_tok_left_bracket, 30 | yajl_tok_null, 31 | yajl_tok_right_brace, 32 | yajl_tok_right_bracket, 33 | 34 | /* we differentiate between integers and doubles to allow the 35 | * parser to interpret the number without re-scanning */ 36 | yajl_tok_integer, 37 | yajl_tok_double, 38 | 39 | /* we differentiate between strings which require further processing, 40 | * and strings that do not */ 41 | yajl_tok_string, 42 | yajl_tok_string_with_escapes, 43 | 44 | /* comment tokens are not currently returned to the parser, ever */ 45 | yajl_tok_comment 46 | } yajl_tok; 47 | 48 | typedef struct yajl_lexer_t * yajl_lexer; 49 | 50 | yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, 51 | unsigned int allowComments, 52 | unsigned int validateUTF8); 53 | 54 | void yajl_lex_free(yajl_lexer lexer); 55 | 56 | /** 57 | * run/continue a lex. "offset" is an input/output parameter. 58 | * It should be initialized to zero for a 59 | * new chunk of target text, and upon subsetquent calls with the same 60 | * target text should passed with the value of the previous invocation. 61 | * 62 | * the client may be interested in the value of offset when an error is 63 | * returned from the lexer. This allows the client to render useful 64 | * error messages. 65 | * 66 | * When you pass the next chunk of data, context should be reinitialized 67 | * to zero. 68 | * 69 | * Finally, the output buffer is usually just a pointer into the jsonText, 70 | * however in cases where the entity being lexed spans multiple chunks, 71 | * the lexer will buffer the entity and the data returned will be 72 | * a pointer into that buffer. 73 | * 74 | * This behavior is abstracted from client code except for the performance 75 | * implications which require that the client choose a reasonable chunk 76 | * size to get adequate performance. 77 | */ 78 | yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, 79 | size_t jsonTextLen, size_t * offset, 80 | const unsigned char ** outBuf, size_t * outLen); 81 | 82 | /** have a peek at the next token, but don't move the lexer forward */ 83 | yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, 84 | size_t jsonTextLen, size_t offset); 85 | 86 | 87 | typedef enum { 88 | yajl_lex_e_ok = 0, 89 | yajl_lex_string_invalid_utf8, 90 | yajl_lex_string_invalid_escaped_char, 91 | yajl_lex_string_invalid_json_char, 92 | yajl_lex_string_invalid_hex_char, 93 | yajl_lex_invalid_char, 94 | yajl_lex_invalid_string, 95 | yajl_lex_missing_integer_after_decimal, 96 | yajl_lex_missing_integer_after_exponent, 97 | yajl_lex_missing_integer_after_minus, 98 | yajl_lex_unallowed_comment 99 | } yajl_lex_error; 100 | 101 | const char * yajl_lex_error_to_string(yajl_lex_error error); 102 | 103 | /** allows access to more specific information about the lexical 104 | * error when yajl_lex_lex returns yajl_tok_error. */ 105 | yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); 106 | 107 | /** get the current offset into the most recently lexed json string. */ 108 | size_t yajl_lex_current_offset(yajl_lexer lexer); 109 | 110 | /** get the number of lines lexed by this lexer instance */ 111 | size_t yajl_lex_current_line(yajl_lexer lexer); 112 | 113 | /** get the number of chars lexed by this lexer instance since the last 114 | * \n or \r */ 115 | size_t yajl_lex_current_char(yajl_lexer lexer); 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/yajl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "api/yajl_parse.h" 18 | #include "yajl_lex.h" 19 | #include "yajl_parser.h" 20 | #include "yajl_alloc.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | const char * 28 | yajl_status_to_string(yajl_status stat) 29 | { 30 | const char * statStr = "unknown"; 31 | switch (stat) { 32 | case yajl_status_ok: 33 | statStr = "ok, no error"; 34 | break; 35 | case yajl_status_client_canceled: 36 | statStr = "client canceled parse"; 37 | break; 38 | case yajl_status_error: 39 | statStr = "parse error"; 40 | break; 41 | default: 42 | break; 43 | } 44 | return statStr; 45 | } 46 | 47 | yajl_handle 48 | yajl_alloc(const yajl_callbacks * callbacks, 49 | yajl_alloc_funcs * afs, 50 | void * ctx) 51 | { 52 | yajl_handle hand = NULL; 53 | yajl_alloc_funcs afsBuffer; 54 | 55 | /* first order of business is to set up memory allocation routines */ 56 | if (afs != NULL) { 57 | if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) 58 | { 59 | return NULL; 60 | } 61 | } else { 62 | yajl_set_default_alloc_funcs(&afsBuffer); 63 | afs = &afsBuffer; 64 | } 65 | 66 | hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); 67 | 68 | /* copy in pointers to allocation routines */ 69 | memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); 70 | 71 | hand->callbacks = callbacks; 72 | hand->ctx = ctx; 73 | hand->lexer = NULL; 74 | hand->bytesConsumed = 0; 75 | hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); 76 | hand->flags = 0; 77 | yajl_bs_init(hand->stateStack, &(hand->alloc)); 78 | yajl_bs_push(hand->stateStack, yajl_state_start); 79 | 80 | return hand; 81 | } 82 | 83 | int 84 | yajl_config(yajl_handle h, yajl_option opt, ...) 85 | { 86 | int rv = 1; 87 | va_list ap; 88 | va_start(ap, opt); 89 | 90 | switch(opt) { 91 | case yajl_allow_comments: 92 | case yajl_dont_validate_strings: 93 | case yajl_allow_trailing_garbage: 94 | case yajl_allow_multiple_values: 95 | case yajl_allow_partial_values: 96 | if (va_arg(ap, int)) h->flags |= opt; 97 | else h->flags &= ~opt; 98 | break; 99 | default: 100 | rv = 0; 101 | } 102 | va_end(ap); 103 | 104 | return rv; 105 | } 106 | 107 | void 108 | yajl_free(yajl_handle handle) 109 | { 110 | yajl_bs_free(handle->stateStack); 111 | yajl_buf_free(handle->decodeBuf); 112 | if (handle->lexer) { 113 | yajl_lex_free(handle->lexer); 114 | handle->lexer = NULL; 115 | } 116 | YA_FREE(&(handle->alloc), handle); 117 | } 118 | 119 | yajl_status 120 | yajl_parse(yajl_handle hand, const unsigned char * jsonText, 121 | size_t jsonTextLen) 122 | { 123 | yajl_status status; 124 | 125 | /* lazy allocation of the lexer */ 126 | if (hand->lexer == NULL) { 127 | hand->lexer = yajl_lex_alloc(&(hand->alloc), 128 | hand->flags & yajl_allow_comments, 129 | !(hand->flags & yajl_dont_validate_strings)); 130 | } 131 | 132 | status = yajl_do_parse(hand, jsonText, jsonTextLen); 133 | return status; 134 | } 135 | 136 | 137 | yajl_status 138 | yajl_complete_parse(yajl_handle hand) 139 | { 140 | /* The lexer is lazy allocated in the first call to parse. if parse is 141 | * never called, then no data was provided to parse at all. This is a 142 | * "premature EOF" error unless yajl_allow_partial_values is specified. 143 | * allocating the lexer now is the simplest possible way to handle this 144 | * case while preserving all the other semantics of the parser 145 | * (multiple values, partial values, etc). */ 146 | if (hand->lexer == NULL) { 147 | hand->lexer = yajl_lex_alloc(&(hand->alloc), 148 | hand->flags & yajl_allow_comments, 149 | !(hand->flags & yajl_dont_validate_strings)); 150 | } 151 | 152 | return yajl_do_finish(hand); 153 | } 154 | 155 | unsigned char * 156 | yajl_get_error(yajl_handle hand, int verbose, 157 | const unsigned char * jsonText, size_t jsonTextLen) 158 | { 159 | return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); 160 | } 161 | 162 | size_t 163 | yajl_get_bytes_consumed(yajl_handle hand) 164 | { 165 | if (!hand) return 0; 166 | else return hand->bytesConsumed; 167 | } 168 | 169 | 170 | void 171 | yajl_free_error(yajl_handle hand, unsigned char * str) 172 | { 173 | /* use memory allocation functions if set */ 174 | YA_FREE(&(hand->alloc), str); 175 | } 176 | 177 | /* XXX: add utility routines to parse from file */ 178 | -------------------------------------------------------------------------------- /reformatter/json_reformat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | /* non-zero when we're reformatting a stream */ 25 | static int s_streamReformat = 0; 26 | 27 | #define GEN_AND_RETURN(func) \ 28 | { \ 29 | yajl_gen_status __stat = func; \ 30 | if (__stat == yajl_gen_generation_complete && s_streamReformat) { \ 31 | yajl_gen_reset(g, "\n"); \ 32 | __stat = func; \ 33 | } \ 34 | return __stat == yajl_gen_status_ok; } 35 | 36 | static int reformat_null(void * ctx) 37 | { 38 | yajl_gen g = (yajl_gen) ctx; 39 | GEN_AND_RETURN(yajl_gen_null(g)); 40 | } 41 | 42 | static int reformat_boolean(void * ctx, int boolean) 43 | { 44 | yajl_gen g = (yajl_gen) ctx; 45 | GEN_AND_RETURN(yajl_gen_bool(g, boolean)); 46 | } 47 | 48 | static int reformat_number(void * ctx, const char * s, size_t l) 49 | { 50 | yajl_gen g = (yajl_gen) ctx; 51 | GEN_AND_RETURN(yajl_gen_number(g, s, l)); 52 | } 53 | 54 | static int reformat_string(void * ctx, const unsigned char * stringVal, 55 | size_t stringLen) 56 | { 57 | yajl_gen g = (yajl_gen) ctx; 58 | GEN_AND_RETURN(yajl_gen_string(g, stringVal, stringLen)); 59 | } 60 | 61 | static int reformat_map_key(void * ctx, const unsigned char * stringVal, 62 | size_t stringLen) 63 | { 64 | yajl_gen g = (yajl_gen) ctx; 65 | GEN_AND_RETURN(yajl_gen_string(g, stringVal, stringLen)); 66 | } 67 | 68 | static int reformat_start_map(void * ctx) 69 | { 70 | yajl_gen g = (yajl_gen) ctx; 71 | GEN_AND_RETURN(yajl_gen_map_open(g)); 72 | } 73 | 74 | 75 | static int reformat_end_map(void * ctx) 76 | { 77 | yajl_gen g = (yajl_gen) ctx; 78 | GEN_AND_RETURN(yajl_gen_map_close(g)); 79 | } 80 | 81 | static int reformat_start_array(void * ctx) 82 | { 83 | yajl_gen g = (yajl_gen) ctx; 84 | GEN_AND_RETURN(yajl_gen_array_open(g)); 85 | } 86 | 87 | static int reformat_end_array(void * ctx) 88 | { 89 | yajl_gen g = (yajl_gen) ctx; 90 | GEN_AND_RETURN(yajl_gen_array_close(g)); 91 | } 92 | 93 | static yajl_callbacks callbacks = { 94 | reformat_null, 95 | reformat_boolean, 96 | NULL, 97 | NULL, 98 | reformat_number, 99 | reformat_string, 100 | reformat_start_map, 101 | reformat_map_key, 102 | reformat_end_map, 103 | reformat_start_array, 104 | reformat_end_array 105 | }; 106 | 107 | static void 108 | usage(const char * progname) 109 | { 110 | fprintf(stderr, "%s: reformat json from stdin\n" 111 | "usage: json_reformat [options]\n" 112 | " -e escape any forward slashes (for embedding in HTML)\n" 113 | " -m minimize json rather than beautify (default)\n" 114 | " -s reformat a stream of multiple json entites\n" 115 | " -u allow invalid UTF8 inside strings during parsing\n", 116 | progname); 117 | exit(1); 118 | } 119 | 120 | int 121 | main(int argc, char ** argv) 122 | { 123 | yajl_handle hand; 124 | static unsigned char fileData[65536]; 125 | /* generator config */ 126 | yajl_gen g; 127 | yajl_status stat; 128 | size_t rd; 129 | int retval = 0; 130 | int a = 1; 131 | 132 | g = yajl_gen_alloc(NULL); 133 | yajl_gen_config(g, yajl_gen_beautify, 1); 134 | yajl_gen_config(g, yajl_gen_validate_utf8, 1); 135 | 136 | /* ok. open file. let's read and parse */ 137 | hand = yajl_alloc(&callbacks, NULL, (void *) g); 138 | /* and let's allow comments by default */ 139 | yajl_config(hand, yajl_allow_comments, 1); 140 | 141 | /* check arguments.*/ 142 | while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) { 143 | unsigned int i; 144 | for ( i=1; i < strlen(argv[a]); i++) { 145 | switch (argv[a][i]) { 146 | case 'm': 147 | yajl_gen_config(g, yajl_gen_beautify, 0); 148 | break; 149 | case 's': 150 | yajl_config(hand, yajl_allow_multiple_values, 1); 151 | s_streamReformat = 1; 152 | break; 153 | case 'u': 154 | yajl_config(hand, yajl_dont_validate_strings, 1); 155 | break; 156 | case 'e': 157 | yajl_gen_config(g, yajl_gen_escape_solidus, 1); 158 | break; 159 | default: 160 | fprintf(stderr, "unrecognized option: '%c'\n\n", 161 | argv[a][i]); 162 | usage(argv[0]); 163 | } 164 | } 165 | ++a; 166 | } 167 | if (a < argc) { 168 | usage(argv[0]); 169 | } 170 | 171 | 172 | for (;;) { 173 | rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); 174 | 175 | if (rd == 0) { 176 | if (!feof(stdin)) { 177 | fprintf(stderr, "error on file read.\n"); 178 | retval = 1; 179 | } 180 | break; 181 | } 182 | fileData[rd] = 0; 183 | 184 | stat = yajl_parse(hand, fileData, rd); 185 | 186 | if (stat != yajl_status_ok) break; 187 | 188 | { 189 | const unsigned char * buf; 190 | size_t len; 191 | yajl_gen_get_buf(g, &buf, &len); 192 | fwrite(buf, 1, len, stdout); 193 | yajl_gen_clear(g); 194 | } 195 | } 196 | 197 | stat = yajl_complete_parse(hand); 198 | 199 | if (stat != yajl_status_ok) { 200 | unsigned char * str = yajl_get_error(hand, 1, fileData, rd); 201 | fprintf(stderr, "%s", (const char *) str); 202 | yajl_free_error(hand, str); 203 | retval = 1; 204 | } 205 | 206 | yajl_gen_free(g); 207 | yajl_free(hand); 208 | 209 | return retval; 210 | } 211 | -------------------------------------------------------------------------------- /src/api/yajl_gen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_gen.h 19 | * Interface to YAJL's JSON generation facilities. 20 | */ 21 | 22 | #include "yajl_common.h" 23 | 24 | #ifndef __YAJL_GEN_H__ 25 | #define __YAJL_GEN_H__ 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | /** generator status codes */ 33 | typedef enum { 34 | /** no error */ 35 | yajl_gen_status_ok = 0, 36 | /** at a point where a map key is generated, a function other than 37 | * yajl_gen_string was called */ 38 | yajl_gen_keys_must_be_strings, 39 | /** YAJL's maximum generation depth was exceeded. see 40 | * YAJL_MAX_DEPTH */ 41 | yajl_max_depth_exceeded, 42 | /** A generator function (yajl_gen_XXX) was called while in an error 43 | * state */ 44 | yajl_gen_in_error_state, 45 | /** A complete JSON document has been generated */ 46 | yajl_gen_generation_complete, 47 | /** yajl_gen_double was passed an invalid floating point value 48 | * (infinity or NaN). */ 49 | yajl_gen_invalid_number, 50 | /** A print callback was passed in, so there is no internal 51 | * buffer to get from */ 52 | yajl_gen_no_buf, 53 | /** returned from yajl_gen_string() when the yajl_gen_validate_utf8 54 | * option is enabled and an invalid was passed by client code. 55 | */ 56 | yajl_gen_invalid_string 57 | } yajl_gen_status; 58 | 59 | /** an opaque handle to a generator */ 60 | typedef struct yajl_gen_t * yajl_gen; 61 | 62 | /** a callback used for "printing" the results. */ 63 | typedef void (*yajl_print_t)(void * ctx, 64 | const char * str, 65 | size_t len); 66 | 67 | /** configuration parameters for the parser, these may be passed to 68 | * yajl_gen_config() along with option specific argument(s). In general, 69 | * all configuration parameters default to *off*. */ 70 | typedef enum { 71 | /** generate indented (beautiful) output */ 72 | yajl_gen_beautify = 0x01, 73 | /** 74 | * Set an indent string which is used when yajl_gen_beautify 75 | * is enabled. Maybe something like \\t or some number of 76 | * spaces. The default is four spaces ' '. 77 | */ 78 | yajl_gen_indent_string = 0x02, 79 | /** 80 | * Set a function and context argument that should be used to 81 | * output generated json. the function should conform to the 82 | * yajl_print_t prototype while the context argument is a 83 | * void * of your choosing. 84 | * 85 | * example: 86 | * yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr); 87 | */ 88 | yajl_gen_print_callback = 0x04, 89 | /** 90 | * Normally the generator does not validate that strings you 91 | * pass to it via yajl_gen_string() are valid UTF8. Enabling 92 | * this option will cause it to do so. 93 | */ 94 | yajl_gen_validate_utf8 = 0x08, 95 | /** 96 | * the forward solidus (slash or '/' in human) is not required to be 97 | * escaped in json text. By default, YAJL will not escape it in the 98 | * iterest of saving bytes. Setting this flag will cause YAJL to 99 | * always escape '/' in generated JSON strings. 100 | */ 101 | yajl_gen_escape_solidus = 0x10 102 | } yajl_gen_option; 103 | 104 | /** allow the modification of generator options subsequent to handle 105 | * allocation (via yajl_alloc) 106 | * \returns zero in case of errors, non-zero otherwise 107 | */ 108 | YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...); 109 | 110 | /** allocate a generator handle 111 | * \param allocFuncs an optional pointer to a structure which allows 112 | * the client to overide the memory allocation 113 | * used by yajl. May be NULL, in which case 114 | * malloc/free/realloc will be used. 115 | * 116 | * \returns an allocated handle on success, NULL on failure (bad params) 117 | */ 118 | YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs); 119 | 120 | /** free a generator handle */ 121 | YAJL_API void yajl_gen_free(yajl_gen handle); 122 | 123 | YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number); 124 | /** generate a floating point number. number may not be infinity or 125 | * NaN, as these have no representation in JSON. In these cases the 126 | * generator will return 'yajl_gen_invalid_number' */ 127 | YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); 128 | YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, 129 | const char * num, 130 | size_t len); 131 | YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand, 132 | const unsigned char * str, 133 | size_t len); 134 | YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand); 135 | YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); 136 | YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand); 137 | YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand); 138 | YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand); 139 | YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand); 140 | 141 | /** access the null terminated generator buffer. If incrementally 142 | * outputing JSON, one should call yajl_gen_clear to clear the 143 | * buffer. This allows stream generation. */ 144 | YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand, 145 | const unsigned char ** buf, 146 | size_t * len); 147 | 148 | /** clear yajl's output buffer, but maintain all internal generation 149 | * state. This function will not "reset" the generator state, and is 150 | * intended to enable incremental JSON outputing. */ 151 | YAJL_API void yajl_gen_clear(yajl_gen hand); 152 | 153 | /** Reset the generator state. Allows a client to generate multiple 154 | * json entities in a stream. The "sep" string will be inserted to 155 | * separate the previously generated entity from the current, 156 | * NULL means *no separation* of entites (clients beware, generating 157 | * multiple JSON numbers without a separator, for instance, will result in ambiguous output) 158 | * 159 | * Note: this call will not clear yajl's output buffer. This 160 | * may be accomplished explicitly by calling yajl_gen_clear() */ 161 | YAJL_API void yajl_gen_reset(yajl_gen hand, const char * sep); 162 | 163 | #ifdef __cplusplus 164 | } 165 | #endif 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /src/api/yajl_tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Florian Forster 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_tree.h 19 | * 20 | * Parses JSON data and returns the data in tree form. 21 | * 22 | * \author Florian Forster 23 | * \date August 2010 24 | * 25 | * This interface makes quick parsing and extraction of 26 | * smallish JSON docs trivial: 27 | * 28 | * \include example/parse_config.c 29 | */ 30 | 31 | #ifndef YAJL_TREE_H 32 | #define YAJL_TREE_H 1 33 | 34 | #include "yajl_common.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** possible data types that a yajl_val_s can hold */ 41 | typedef enum { 42 | yajl_t_string = 1, 43 | yajl_t_number = 2, 44 | yajl_t_object = 3, 45 | yajl_t_array = 4, 46 | yajl_t_true = 5, 47 | yajl_t_false = 6, 48 | yajl_t_null = 7, 49 | /** The any type isn't valid for yajl_val_s.type, but can be 50 | * used as an argument to routines like yajl_tree_get(). 51 | */ 52 | yajl_t_any = 8 53 | } yajl_type; 54 | 55 | #define YAJL_NUMBER_INT_VALID 0x01 56 | #define YAJL_NUMBER_DOUBLE_VALID 0x02 57 | 58 | #define strlens(s) (s == NULL ? 0 : strlen(s)) 59 | 60 | /** A pointer to a node in the parse tree */ 61 | typedef struct yajl_val_s * yajl_val; 62 | 63 | /** 64 | * A JSON value representation capable of holding one of the seven 65 | * types above. For "string", "number", "object", and "array" 66 | * additional data is available in the union. The "YAJL_IS_*" 67 | * and "YAJL_GET_*" macros below allow type checking and convenient 68 | * value extraction. 69 | */ 70 | struct yajl_val_s 71 | { 72 | /** Type of the value contained. Use the "YAJL_IS_*" macros to check for a 73 | * specific type. */ 74 | yajl_type type; 75 | /** Type-specific data. You may use the "YAJL_GET_*" macros to access these 76 | * members. */ 77 | union 78 | { 79 | char * string; 80 | struct { 81 | long long i; /*< integer value, if representable. */ 82 | double d; /*< double value, if representable. */ 83 | char *r; /*< unparsed number in string form. */ 84 | /** Signals whether the \em i and \em d members are 85 | * valid. See \c YAJL_NUMBER_INT_VALID and 86 | * \c YAJL_NUMBER_DOUBLE_VALID. */ 87 | unsigned int flags; 88 | } number; 89 | struct { 90 | const char **keys; /*< Array of keys */ 91 | yajl_val *values; /*< Array of values. */ 92 | size_t len; /*< Number of key-value-pairs. */ 93 | } object; 94 | struct { 95 | yajl_val *values; /*< Array of elements. */ 96 | size_t len; /*< Number of elements. */ 97 | } array; 98 | } u; 99 | }; 100 | 101 | /** 102 | * Parse a string. 103 | * 104 | * Parses an null-terminated string containing JSON data and returns a pointer 105 | * to the top-level value (root of the parse tree). 106 | * 107 | * \param input Pointer to a null-terminated utf8 string containing 108 | * JSON data. 109 | * \param error_buffer Pointer to a buffer in which an error message will 110 | * be stored if \em yajl_tree_parse fails, or 111 | * \c NULL. The buffer will be initialized before 112 | * parsing, so its content will be destroyed even if 113 | * \em yajl_tree_parse succeeds. 114 | * \param error_buffer_size Size of the memory area pointed to by 115 | * \em error_buffer_size. If \em error_buffer_size is 116 | * \c NULL, this argument is ignored. 117 | * 118 | * \returns Pointer to the top-level value or \c NULL on error. The memory 119 | * pointed to must be freed using \em yajl_tree_free. In case of an error, a 120 | * null terminated message describing the error in more detail is stored in 121 | * \em error_buffer if it is not \c NULL. 122 | */ 123 | YAJL_API yajl_val yajl_tree_parse (const char *input, 124 | char *error_buffer, size_t error_buffer_size); 125 | 126 | 127 | /** 128 | * Free a parse tree returned by "yajl_tree_parse". 129 | * 130 | * \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL 131 | * is valid and results in a no-op. 132 | */ 133 | YAJL_API void yajl_tree_free (yajl_val v); 134 | 135 | /** 136 | * Access a nested value inside a tree. 137 | * 138 | * \param parent the node under which you'd like to extract values. 139 | * \param path A null terminated array of strings, each the name of an object key 140 | * \param type the yajl_type of the object you seek, or yajl_t_any if any will do. 141 | * 142 | * \returns a pointer to the found value, or NULL if we came up empty. 143 | * 144 | * Future Ideas: it'd be nice to move path to a string and implement support for 145 | * a teeny tiny micro language here, so you can extract array elements, do things 146 | * like .first and .last, even .length. Inspiration from JSONPath and css selectors? 147 | * No it wouldn't be fast, but that's not what this API is about. 148 | */ 149 | YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type); 150 | 151 | /* Various convenience macros to check the type of a `yajl_val` */ 152 | #define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string)) 153 | #define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number)) 154 | #define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_INT_VALID)) 155 | #define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)) 156 | #define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object)) 157 | #define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array )) 158 | #define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true )) 159 | #define YAJL_IS_FALSE(v) (((v) != NULL) && ((v)->type == yajl_t_false )) 160 | #define YAJL_IS_NULL(v) (((v) != NULL) && ((v)->type == yajl_t_null )) 161 | 162 | /** Given a yajl_val_string return a ptr to the bare string it contains, 163 | * or NULL if the value is not a string. */ 164 | #define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL) 165 | 166 | /** Get the string representation of a number. You should check type first, 167 | * perhaps using YAJL_IS_NUMBER */ 168 | #define YAJL_GET_NUMBER(v) ((v)->u.number.r) 169 | 170 | /** Get the double representation of a number. You should check type first, 171 | * perhaps using YAJL_IS_DOUBLE */ 172 | #define YAJL_GET_DOUBLE(v) ((v)->u.number.d) 173 | 174 | /** Get the 64bit (long long) integer representation of a number. You should 175 | * check type first, perhaps using YAJL_IS_INTEGER */ 176 | #define YAJL_GET_INTEGER(v) ((v)->u.number.i) 177 | 178 | /** Get a pointer to a yajl_val_object or NULL if the value is not an object. */ 179 | #define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL) 180 | 181 | /** Get a pointer to a yajl_val_array or NULL if the value is not an object. */ 182 | #define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL) 183 | 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | 188 | #endif /* YAJL_TREE_H */ 189 | -------------------------------------------------------------------------------- /src/yajl_encode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "yajl_encode.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static void CharToHex(unsigned char c, char * hexBuf) 25 | { 26 | const char * hexchar = "0123456789ABCDEF"; 27 | hexBuf[0] = hexchar[c >> 4]; 28 | hexBuf[1] = hexchar[c & 0x0F]; 29 | } 30 | 31 | void 32 | yajl_string_encode(const yajl_print_t print, 33 | void * ctx, 34 | const unsigned char * str, 35 | size_t len, 36 | int escape_solidus) 37 | { 38 | size_t beg = 0; 39 | size_t end = 0; 40 | char hexBuf[7]; 41 | hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; 42 | hexBuf[6] = 0; 43 | 44 | while (end < len) { 45 | const char * escaped = NULL; 46 | switch (str[end]) { 47 | case '\r': escaped = "\\r"; break; 48 | case '\n': escaped = "\\n"; break; 49 | case '\\': escaped = "\\\\"; break; 50 | /* it is not required to escape a solidus in JSON: 51 | * read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt 52 | * specifically, this production from the grammar: 53 | * unescaped = %x20-21 / %x23-5B / %x5D-10FFFF 54 | */ 55 | case '/': if (escape_solidus) escaped = "\\/"; break; 56 | case '"': escaped = "\\\""; break; 57 | case '\f': escaped = "\\f"; break; 58 | case '\b': escaped = "\\b"; break; 59 | case '\t': escaped = "\\t"; break; 60 | default: 61 | if ((unsigned char) str[end] < 32) { 62 | CharToHex(str[end], hexBuf + 4); 63 | escaped = hexBuf; 64 | } 65 | break; 66 | } 67 | if (escaped != NULL) { 68 | print(ctx, (const char *) (str + beg), end - beg); 69 | print(ctx, escaped, (unsigned int)strlen(escaped)); 70 | beg = ++end; 71 | } else { 72 | ++end; 73 | } 74 | } 75 | print(ctx, (const char *) (str + beg), end - beg); 76 | } 77 | 78 | static void hexToDigit(unsigned int * val, const unsigned char * hex) 79 | { 80 | unsigned int i; 81 | for (i=0;i<4;i++) { 82 | unsigned char c = hex[i]; 83 | if (c >= 'A') c = (c & ~0x20) - 7; 84 | c -= '0'; 85 | assert(!(c & 0xF0)); 86 | *val = (*val << 4) | c; 87 | } 88 | } 89 | 90 | static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) 91 | { 92 | if (codepoint < 0x80) { 93 | utf8Buf[0] = (char) codepoint; 94 | utf8Buf[1] = 0; 95 | } else if (codepoint < 0x0800) { 96 | utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); 97 | utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); 98 | utf8Buf[2] = 0; 99 | } else if (codepoint < 0x10000) { 100 | utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); 101 | utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); 102 | utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); 103 | utf8Buf[3] = 0; 104 | } else if (codepoint < 0x200000) { 105 | utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); 106 | utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); 107 | utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); 108 | utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); 109 | utf8Buf[4] = 0; 110 | } else { 111 | utf8Buf[0] = '?'; 112 | utf8Buf[1] = 0; 113 | } 114 | } 115 | 116 | void yajl_string_decode(yajl_buf buf, const unsigned char * str, 117 | size_t len) 118 | { 119 | size_t beg = 0; 120 | size_t end = 0; 121 | 122 | while (end < len) { 123 | if (str[end] == '\\') { 124 | char utf8Buf[5]; 125 | const char * unescaped = "?"; 126 | yajl_buf_append(buf, str + beg, end - beg); 127 | switch (str[++end]) { 128 | case 'r': unescaped = "\r"; break; 129 | case 'n': unescaped = "\n"; break; 130 | case '\\': unescaped = "\\"; break; 131 | case '/': unescaped = "/"; break; 132 | case '"': unescaped = "\""; break; 133 | case 'f': unescaped = "\f"; break; 134 | case 'b': unescaped = "\b"; break; 135 | case 't': unescaped = "\t"; break; 136 | case 'u': { 137 | unsigned int codepoint = 0; 138 | hexToDigit(&codepoint, str + ++end); 139 | end+=3; 140 | /* check if this is a surrogate */ 141 | if ((codepoint & 0xFC00) == 0xD800) { 142 | end++; 143 | if (str[end] == '\\' && str[end + 1] == 'u') { 144 | unsigned int surrogate = 0; 145 | hexToDigit(&surrogate, str + end + 2); 146 | codepoint = 147 | (((codepoint & 0x3F) << 10) | 148 | ((((codepoint >> 6) & 0xF) + 1) << 16) | 149 | (surrogate & 0x3FF)); 150 | end += 5; 151 | } else { 152 | unescaped = "?"; 153 | break; 154 | } 155 | } 156 | 157 | Utf32toUtf8(codepoint, utf8Buf); 158 | unescaped = utf8Buf; 159 | 160 | if (codepoint == 0) { 161 | yajl_buf_append(buf, unescaped, 1); 162 | beg = ++end; 163 | continue; 164 | } 165 | 166 | break; 167 | } 168 | default: 169 | assert("this should never happen" == NULL); 170 | } 171 | yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped)); 172 | beg = ++end; 173 | } else { 174 | end++; 175 | } 176 | } 177 | yajl_buf_append(buf, str + beg, end - beg); 178 | } 179 | 180 | #define ADV_PTR s++; if (!(len--)) return 0; 181 | 182 | int yajl_string_validate_utf8(const unsigned char * s, size_t len) 183 | { 184 | if (!len) return 1; 185 | if (!s) return 0; 186 | 187 | while (len--) { 188 | /* single byte */ 189 | if (*s <= 0x7f) { 190 | /* noop */ 191 | } 192 | /* two byte */ 193 | else if ((*s >> 5) == 0x6) { 194 | ADV_PTR; 195 | if (!((*s >> 6) == 0x2)) return 0; 196 | } 197 | /* three byte */ 198 | else if ((*s >> 4) == 0x0e) { 199 | ADV_PTR; 200 | if (!((*s >> 6) == 0x2)) return 0; 201 | ADV_PTR; 202 | if (!((*s >> 6) == 0x2)) return 0; 203 | } 204 | /* four byte */ 205 | else if ((*s >> 3) == 0x1e) { 206 | ADV_PTR; 207 | if (!((*s >> 6) == 0x2)) return 0; 208 | ADV_PTR; 209 | if (!((*s >> 6) == 0x2)) return 0; 210 | ADV_PTR; 211 | if (!((*s >> 6) == 0x2)) return 0; 212 | } else { 213 | return 0; 214 | } 215 | 216 | s++; 217 | } 218 | 219 | return 1; 220 | } 221 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2.1.0 2 | * @nonodename, @patperry - fixed some compiler warnings 3 | * @yep, @emaste - documentation improvements 4 | * @sgravrock - build fix for NetBSD (and whenever sh != bash) 5 | * @rotty, @brimstone3, @lloyd - allow client to reset generator 6 | * @sgravrock - remove bash dependencies 7 | * @lloyd - add api tests 8 | * @rflynn - remove ruby dependency 9 | * @cloderic - nmake install works on windows 10 | * @shahbag - build fix for qnx 11 | * @breese - debugging improvements 12 | * @lloyd - json_verify supports -s flag for stream processing 13 | * @lloyd - json_reformat supports -s flag for stream processing 14 | 15 | 2.0.4 16 | * @jcekstrom - additional checking in integer parsing 17 | * @jcekstrom - fix a bug in yajl_tree that would cause valid json integersto fail to parse 18 | * @plaguemorin - fix a memory leak in yajl_tree (error strings were being leaked) 19 | * @7AC - reset errno 20 | * @ConradIrwin - include flags to reformatter to allow toggling of escape solidus option 21 | 22 | 2.0.3 23 | * John Stamp generation of a pkgconfig file at build time. 24 | * @robzuber bugfix in yajl_tree_get() 25 | * @lloyd - fix for compilation on 64 bit windows 26 | 27 | 2.0.2 28 | * lth fix typos in yajl_tree.h macros YAJL_IS_INTEGER and YAJL_IS_DOUBLE, 29 | contributed by Artem S Vybornov. 30 | * lth add #ifdef __cplusplus wrappers to yajl_tree to allow proper 31 | usage from many populer C++ compilers. 32 | 33 | 2.0.1 34 | * lth generator flag to allow client to specify they want 35 | escaped solidi '/'. issue #28 36 | * lth crash fix when yajl_parse() is never called. issue #27 37 | 38 | 2.0.0 39 | * lth YAJL is now ISC licensed: http://en.wikipedia.org/wiki/ISC_license 40 | * lth 20-35% (osx and linux respectively) parsing performance 41 | improvement attained by tweaking string scanning (idea: @michaelrhanson). 42 | * Florian Forster & lth - yajl_tree interface introduced as a higher level 43 | interface to the parser (eats JSON, poops a memory representation) 44 | * lth require a C99 compiler 45 | * lth integers are now represented with long long (64bit+) on all platforms. 46 | * lth size_t now used throughout to represent buffer lengths, so you can 47 | safely manage buffers greater than 4GB. 48 | * gno semantic improvements to yajl's API regarding partial value parsing and 49 | trailing garbage 50 | * lth new configuration mechanism for yajl, see yajl_config() and 51 | yajl_gen_config() 52 | * gno more allocation checking in more places 53 | * gno remove usage of strtol, replace with custom implementation that cares 54 | not about your locale. 55 | * lth yajl_parse_complete renamed to yajl_complete_parse. 56 | * lth add a switch to validate utf8 strings as they are generated. 57 | * lth tests are a lot quieter in their output. 58 | * lth addition of a little in tree performance benchmark, `perftest` in 59 | perf/perftest.c 60 | 61 | 1.0.12 62 | * Conrad Irwin - Parse null bytes correctly 63 | * Mirek Rusin - fix LLVM warnings 64 | * gno - Don't generate numbers for keys. closes #13 65 | * lth - various win32 fixes, including build documentation improvements 66 | * John Stamp - Don't export private symbols. 67 | * John Stamp - Install yajl_version.h, not the template. 68 | * John Stamp - Don't use -fPIC for static lib. Cmake will automatically add it for the shared. 69 | * lth 0 fix paths embedded in dylib upon installation on osx. closes #11 70 | 71 | 1.0.11 72 | * lth remove -Wno-missing-field-initializers for greater gcc compat (3.4.6) 73 | 74 | 1.0.10 75 | * Brian Maher - yajl is now buildable without a c++ compiler present 76 | * Brian Maher - fix header installation on OSX with cmake 2.8.0 installed 77 | * lth & vitali - allow builder to specify alternate lib directory 78 | for installation (i.e. lib64) 79 | * Vitali Lovich - yajl version number now programatically accessible 80 | * lth - prevent cmake from embedding rpaths in binaries. Static linking 81 | makes this unneccesary. 82 | 83 | 1.0.9 84 | * lth - fix inverted logic causing yajl_gen_double() to always fail on 85 | win32 (thanks to Fredrik Kihlander for the report) 86 | 87 | 1.0.8 88 | * Randall E. Barker - move dllexport defnitions so dlls with proper 89 | exports can again be generated on windows 90 | * lth - add yajl_get_bytes_consumed() which allows the client to 91 | determine the offset as an error, as well as determine how 92 | many bytes of an input buffer were consumed. 93 | * lth - fixes to keep "error offset" up to date (like when the 94 | client callback returns 0) 95 | * Brian Maher - allow client to specify a printing function in 96 | generation 97 | 98 | 1.0.7 99 | * lth fix win32 build (isinf and isnan) 100 | 101 | 1.0.6 102 | * lth fix several compiler warnings 103 | * lth fix generation of invalid json from yajl_gen_double 104 | (NaN is not JSON) 105 | * jstamp support for combining short options in tools 106 | * jstamp exit properly on errors from tools 107 | * octo test success no longer depends on integer size 108 | * max fix configure --prefix 109 | 110 | 1.0.5 111 | * lth several performance improvements related to function 112 | inlinin' 113 | 114 | 1.0.4 115 | * lth fix broken utf8 validation for three & four byte represenations. 116 | thanks to http://github.com/brianmario and 117 | http://github.com/technoweenie 118 | 119 | 1.0.3 120 | * lth fix syntax error in cplusplus extern "C" statements for wider 121 | compiler support 122 | 123 | 1.0.2 124 | * lth update doxygen documentation with new sample code, passing NULL 125 | for allocation functions added in 1.0.0 126 | 127 | 1.0.1 128 | * lth resolve crash in json_reformatter due to incorrectly ordered 129 | parameters. 130 | 131 | 1.0.0 132 | * lth add 'make install' rules, thaks to Andrei Soroker for the 133 | contribution. 134 | * lth client may override allocation routines at generator or parser 135 | allocation time 136 | * tjw add yajl_parse_complete routine to allow client to explicitly 137 | specify end-of-input, solving the "lonely number" case, where 138 | json text consists only of an element with no explicit syntactic 139 | end. 140 | * tjw many new test cases 141 | * tjw cleanup of code for symmetry and ease of reading 142 | * lth integration of patches from Robert Varga which cleanup 143 | compilation warnings on 64 bit linux 144 | 145 | 0.4.0 146 | * lth buffer overflow bug in yajl_gen_double s/%lf/%g/ - thanks to 147 | Eric Bergstrome 148 | * lth yajl_number callback to allow passthrough of arbitrary precision 149 | numbers to client. Thanks to Hatem Nassrat. 150 | * lth yajl_integer now deals in long, instead of long long. This 151 | combined with yajl_number improves compiler compatibility while 152 | maintaining precision. 153 | * lth better ./configure && make experience (still requires cmake and 154 | ruby) 155 | * lth fix handling of special characters hex 0F and 1F in yajl_encode 156 | (thanks to Robert Geiger) 157 | * lth allow leading zeros in exponents (thanks to Hatem Nassrat) 158 | 159 | 0.3.0 160 | * lth doxygen documentation (html & man) generated as part of the 161 | build 162 | * lth many documentation updates. 163 | * lth fix to work with older versions of cmake (don't use LOOSE_LOOP 164 | constructs) 165 | * lth work around different behavior of freebsd 4 scanf. initialize 166 | parameter to scanf to zero. 167 | * lth all tests run 32x with ranging buffer sizes to stress stream 168 | parsing 169 | * lth yajl_test accepts -b option to allow read buffer size to be 170 | set 171 | * lth option to validate UTF8 added to parser (argument in 172 | yajl_parser_cfg) 173 | * lth fix buffer overrun when chunk ends inside \u escaped text 174 | * lth support client cancelation 175 | 176 | 0.2.2 177 | * lth on windows build debug with C7 symbols and no pdb files. 178 | 179 | 0.2.1 180 | * fix yajl_reformat and yajl_verify to work on arbitrarily sized 181 | inputs. 182 | * fix win32 build break, clean up all errors and warnings. 183 | * fix optimized build flags. 184 | 185 | 0.2.0 186 | * optionally support comments in input text 187 | 188 | 0.1.0 189 | * Initial release 190 | -------------------------------------------------------------------------------- /test/parsing/yajl_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | /* memory debugging routines */ 27 | typedef struct 28 | { 29 | unsigned int numFrees; 30 | unsigned int numMallocs; 31 | /* XXX: we really need a hash table here with per-allocation 32 | * information */ 33 | } yajlTestMemoryContext; 34 | 35 | /* cast void * into context */ 36 | #define TEST_CTX(vptr) ((yajlTestMemoryContext *) (vptr)) 37 | 38 | static void yajlTestFree(void * ctx, void * ptr) 39 | { 40 | assert(ptr != NULL); 41 | TEST_CTX(ctx)->numFrees++; 42 | free(ptr); 43 | } 44 | 45 | static void * yajlTestMalloc(void * ctx, size_t sz) 46 | { 47 | assert(sz != 0); 48 | TEST_CTX(ctx)->numMallocs++; 49 | return malloc(sz); 50 | } 51 | 52 | static void * yajlTestRealloc(void * ctx, void * ptr, size_t sz) 53 | { 54 | if (ptr == NULL) { 55 | assert(sz != 0); 56 | TEST_CTX(ctx)->numMallocs++; 57 | } else if (sz == 0) { 58 | TEST_CTX(ctx)->numFrees++; 59 | } 60 | 61 | return realloc(ptr, sz); 62 | } 63 | 64 | 65 | /* begin parsing callback routines */ 66 | #define BUF_SIZE 2048 67 | 68 | static int test_yajl_null(void *ctx) 69 | { 70 | printf("null\n"); 71 | return 1; 72 | } 73 | 74 | static int test_yajl_boolean(void * ctx, int boolVal) 75 | { 76 | printf("bool: %s\n", boolVal ? "true" : "false"); 77 | return 1; 78 | } 79 | 80 | static int test_yajl_integer(void *ctx, long long integerVal) 81 | { 82 | printf("integer: %lld\n", integerVal); 83 | return 1; 84 | } 85 | 86 | static int test_yajl_double(void *ctx, double doubleVal) 87 | { 88 | printf("double: %g\n", doubleVal); 89 | return 1; 90 | } 91 | 92 | static int test_yajl_string(void *ctx, const unsigned char * stringVal, 93 | size_t stringLen) 94 | { 95 | printf("string: '"); 96 | fwrite(stringVal, 1, stringLen, stdout); 97 | printf("'\n"); 98 | return 1; 99 | } 100 | 101 | static int test_yajl_map_key(void *ctx, const unsigned char * stringVal, 102 | size_t stringLen) 103 | { 104 | char * str = (char *) malloc(stringLen + 1); 105 | str[stringLen] = 0; 106 | memcpy(str, stringVal, stringLen); 107 | printf("key: '%s'\n", str); 108 | free(str); 109 | return 1; 110 | } 111 | 112 | static int test_yajl_start_map(void *ctx) 113 | { 114 | printf("map open '{'\n"); 115 | return 1; 116 | } 117 | 118 | 119 | static int test_yajl_end_map(void *ctx) 120 | { 121 | printf("map close '}'\n"); 122 | return 1; 123 | } 124 | 125 | static int test_yajl_start_array(void *ctx) 126 | { 127 | printf("array open '['\n"); 128 | return 1; 129 | } 130 | 131 | static int test_yajl_end_array(void *ctx) 132 | { 133 | printf("array close ']'\n"); 134 | return 1; 135 | } 136 | 137 | static yajl_callbacks callbacks = { 138 | test_yajl_null, 139 | test_yajl_boolean, 140 | test_yajl_integer, 141 | test_yajl_double, 142 | NULL, 143 | test_yajl_string, 144 | test_yajl_start_map, 145 | test_yajl_map_key, 146 | test_yajl_end_map, 147 | test_yajl_start_array, 148 | test_yajl_end_array 149 | }; 150 | 151 | static void usage(const char * progname) 152 | { 153 | fprintf(stderr, 154 | "usage: %s [options]\n" 155 | "Parse input from stdin as JSON and ouput parsing details " 156 | "to stdout\n" 157 | " -b set the read buffer size\n" 158 | " -c allow comments\n" 159 | " -g allow *g*arbage after valid JSON text\n" 160 | " -m allows the parser to consume multiple JSON values\n" 161 | " from a single string separated by whitespace\n" 162 | " -p partial JSON documents should not cause errors\n", 163 | progname); 164 | exit(1); 165 | } 166 | 167 | int 168 | main(int argc, char ** argv) 169 | { 170 | yajl_handle hand; 171 | const char * fileName = NULL; 172 | static unsigned char * fileData = NULL; 173 | FILE *file; 174 | size_t bufSize = BUF_SIZE; 175 | yajl_status stat; 176 | size_t rd; 177 | int i, j; 178 | 179 | /* memory allocation debugging: allocate a structure which collects 180 | * statistics */ 181 | yajlTestMemoryContext memCtx = { 0,0 }; 182 | 183 | /* memory allocation debugging: allocate a structure which holds 184 | * allocation routines */ 185 | yajl_alloc_funcs allocFuncs = { 186 | yajlTestMalloc, 187 | yajlTestRealloc, 188 | yajlTestFree, 189 | (void *) NULL 190 | }; 191 | 192 | allocFuncs.ctx = (void *) &memCtx; 193 | 194 | /* allocate the parser */ 195 | hand = yajl_alloc(&callbacks, &allocFuncs, NULL); 196 | 197 | /* check arguments. We expect exactly one! */ 198 | for (i=1;i= argc) usage(argv[0]); 203 | 204 | /* validate integer */ 205 | for (j=0;j<(int)strlen(argv[i]);j++) { 206 | if (argv[i][j] <= '9' && argv[i][j] >= '0') continue; 207 | fprintf(stderr, "-b requires an integer argument. '%s' " 208 | "is invalid\n", argv[i]); 209 | usage(argv[0]); 210 | } 211 | 212 | bufSize = atoi(argv[i]); 213 | if (!bufSize) { 214 | fprintf(stderr, "%zu is an invalid buffer size\n", 215 | bufSize); 216 | } 217 | } else if (!strcmp("-g", argv[i])) { 218 | yajl_config(hand, yajl_allow_trailing_garbage, 1); 219 | } else if (!strcmp("-m", argv[i])) { 220 | yajl_config(hand, yajl_allow_multiple_values, 1); 221 | } else if (!strcmp("-p", argv[i])) { 222 | yajl_config(hand, yajl_allow_partial_values, 1); 223 | } else { 224 | fileName = argv[i]; 225 | break; 226 | } 227 | } 228 | 229 | fileData = (unsigned char *) malloc(bufSize); 230 | 231 | if (fileData == NULL) { 232 | fprintf(stderr, 233 | "failed to allocate read buffer of %zu bytes, exiting.", 234 | bufSize); 235 | yajl_free(hand); 236 | exit(2); 237 | } 238 | 239 | if (fileName) 240 | { 241 | file = fopen(fileName, "r"); 242 | } 243 | else 244 | { 245 | file = stdin; 246 | } 247 | for (;;) { 248 | rd = fread((void *) fileData, 1, bufSize, file); 249 | 250 | if (rd == 0) { 251 | if (!feof(stdin)) { 252 | fprintf(stderr, "error reading from '%s'\n", fileName); 253 | } 254 | break; 255 | } 256 | /* read file data, now pass to parser */ 257 | stat = yajl_parse(hand, fileData, rd); 258 | 259 | if (stat != yajl_status_ok) break; 260 | } 261 | 262 | stat = yajl_complete_parse(hand); 263 | if (stat != yajl_status_ok) 264 | { 265 | unsigned char * str = yajl_get_error(hand, 0, fileData, rd); 266 | fflush(stdout); 267 | fprintf(stderr, "%s", (char *) str); 268 | yajl_free_error(hand, str); 269 | } 270 | 271 | yajl_free(hand); 272 | free(fileData); 273 | 274 | if (fileName) 275 | { 276 | fclose(file); 277 | } 278 | /* finally, print out some memory statistics */ 279 | 280 | /* (lth) only print leaks here, as allocations and frees may vary depending 281 | * on read buffer size, causing false failures. 282 | * 283 | * printf("allocations:\t%u\n", memCtx.numMallocs); 284 | * printf("frees:\t\t%u\n", memCtx.numFrees); 285 | */ 286 | fflush(stderr); 287 | fflush(stdout); 288 | printf("memory leaks:\t%u\n", memCtx.numMallocs - memCtx.numFrees); 289 | 290 | return 0; 291 | } 292 | -------------------------------------------------------------------------------- /src/api/yajl_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * \file yajl_parse.h 19 | * Interface to YAJL's JSON stream parsing facilities. 20 | */ 21 | 22 | #include "yajl_common.h" 23 | 24 | #ifndef __YAJL_PARSE_H__ 25 | #define __YAJL_PARSE_H__ 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | /** error codes returned from this interface */ 33 | typedef enum { 34 | /** no error was encountered */ 35 | yajl_status_ok, 36 | /** a client callback returned zero, stopping the parse */ 37 | yajl_status_client_canceled, 38 | /** An error occured during the parse. Call yajl_get_error for 39 | * more information about the encountered error */ 40 | yajl_status_error 41 | } yajl_status; 42 | 43 | /** attain a human readable, english, string for an error */ 44 | YAJL_API const char * yajl_status_to_string(yajl_status code); 45 | 46 | /** an opaque handle to a parser */ 47 | typedef struct yajl_handle_t * yajl_handle; 48 | 49 | /** yajl is an event driven parser. this means as json elements are 50 | * parsed, you are called back to do something with the data. The 51 | * functions in this table indicate the various events for which 52 | * you will be called back. Each callback accepts a "context" 53 | * pointer, this is a void * that is passed into the yajl_parse 54 | * function which the client code may use to pass around context. 55 | * 56 | * All callbacks return an integer. If non-zero, the parse will 57 | * continue. If zero, the parse will be canceled and 58 | * yajl_status_client_canceled will be returned from the parse. 59 | * 60 | * \attention { 61 | * A note about the handling of numbers: 62 | * 63 | * yajl will only convert numbers that can be represented in a 64 | * double or a 64 bit (long long) int. All other numbers will 65 | * be passed to the client in string form using the yajl_number 66 | * callback. Furthermore, if yajl_number is not NULL, it will 67 | * always be used to return numbers, that is yajl_integer and 68 | * yajl_double will be ignored. If yajl_number is NULL but one 69 | * of yajl_integer or yajl_double are defined, parsing of a 70 | * number larger than is representable in a double or 64 bit 71 | * integer will result in a parse error. 72 | * } 73 | */ 74 | typedef struct { 75 | int (* yajl_null)(void * ctx); 76 | int (* yajl_boolean)(void * ctx, int boolVal); 77 | int (* yajl_integer)(void * ctx, long long integerVal); 78 | int (* yajl_double)(void * ctx, double doubleVal); 79 | /** A callback which passes the string representation of the number 80 | * back to the client. Will be used for all numbers when present */ 81 | int (* yajl_number)(void * ctx, const char * numberVal, 82 | size_t numberLen); 83 | 84 | /** strings are returned as pointers into the JSON text when, 85 | * possible, as a result, they are _not_ null padded */ 86 | int (* yajl_string)(void * ctx, const unsigned char * stringVal, 87 | size_t stringLen); 88 | 89 | int (* yajl_start_map)(void * ctx); 90 | int (* yajl_map_key)(void * ctx, const unsigned char * key, 91 | size_t stringLen); 92 | int (* yajl_end_map)(void * ctx); 93 | 94 | int (* yajl_start_array)(void * ctx); 95 | int (* yajl_end_array)(void * ctx); 96 | } yajl_callbacks; 97 | 98 | /** allocate a parser handle 99 | * \param callbacks a yajl callbacks structure specifying the 100 | * functions to call when different JSON entities 101 | * are encountered in the input text. May be NULL, 102 | * which is only useful for validation. 103 | * \param afs memory allocation functions, may be NULL for to use 104 | * C runtime library routines (malloc and friends) 105 | * \param ctx a context pointer that will be passed to callbacks. 106 | */ 107 | YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks, 108 | yajl_alloc_funcs * afs, 109 | void * ctx); 110 | 111 | 112 | /** configuration parameters for the parser, these may be passed to 113 | * yajl_config() along with option specific argument(s). In general, 114 | * all configuration parameters default to *off*. */ 115 | typedef enum { 116 | /** Ignore javascript style comments present in 117 | * JSON input. Non-standard, but rather fun 118 | * arguments: toggled off with integer zero, on otherwise. 119 | * 120 | * example: 121 | * yajl_config(h, yajl_allow_comments, 1); // turn comment support on 122 | */ 123 | yajl_allow_comments = 0x01, 124 | /** 125 | * When set the parser will verify that all strings in JSON input are 126 | * valid UTF8 and will emit a parse error if this is not so. When set, 127 | * this option makes parsing slightly more expensive (~7% depending 128 | * on processor and compiler in use) 129 | * 130 | * example: 131 | * yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking 132 | */ 133 | yajl_dont_validate_strings = 0x02, 134 | /** 135 | * By default, upon calls to yajl_complete_parse(), yajl will 136 | * ensure the entire input text was consumed and will raise an error 137 | * otherwise. Enabling this flag will cause yajl to disable this 138 | * check. This can be useful when parsing json out of a that contains more 139 | * than a single JSON document. 140 | */ 141 | yajl_allow_trailing_garbage = 0x04, 142 | /** 143 | * Allow multiple values to be parsed by a single handle. The 144 | * entire text must be valid JSON, and values can be seperated 145 | * by any kind of whitespace. This flag will change the 146 | * behavior of the parser, and cause it continue parsing after 147 | * a value is parsed, rather than transitioning into a 148 | * complete state. This option can be useful when parsing multiple 149 | * values from an input stream. 150 | */ 151 | yajl_allow_multiple_values = 0x08, 152 | /** 153 | * When yajl_complete_parse() is called the parser will 154 | * check that the top level value was completely consumed. I.E., 155 | * if called whilst in the middle of parsing a value 156 | * yajl will enter an error state (premature EOF). Setting this 157 | * flag suppresses that check and the corresponding error. 158 | */ 159 | yajl_allow_partial_values = 0x10 160 | } yajl_option; 161 | 162 | /** allow the modification of parser options subsequent to handle 163 | * allocation (via yajl_alloc) 164 | * \returns zero in case of errors, non-zero otherwise 165 | */ 166 | YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...); 167 | 168 | /** free a parser handle */ 169 | YAJL_API void yajl_free(yajl_handle handle); 170 | 171 | /** Parse some json! 172 | * \param hand - a handle to the json parser allocated with yajl_alloc 173 | * \param jsonText - a pointer to the UTF8 json text to be parsed 174 | * \param jsonTextLength - the length, in bytes, of input text 175 | */ 176 | YAJL_API yajl_status yajl_parse(yajl_handle hand, 177 | const unsigned char * jsonText, 178 | size_t jsonTextLength); 179 | 180 | /** Parse any remaining buffered json. 181 | * Since yajl is a stream-based parser, without an explicit end of 182 | * input, yajl sometimes can't decide if content at the end of the 183 | * stream is valid or not. For example, if "1" has been fed in, 184 | * yajl can't know whether another digit is next or some character 185 | * that would terminate the integer token. 186 | * 187 | * \param hand - a handle to the json parser allocated with yajl_alloc 188 | */ 189 | YAJL_API yajl_status yajl_complete_parse(yajl_handle hand); 190 | 191 | /** get an error string describing the state of the 192 | * parse. 193 | * 194 | * If verbose is non-zero, the message will include the JSON 195 | * text where the error occured, along with an arrow pointing to 196 | * the specific char. 197 | * 198 | * \returns A dynamically allocated string will be returned which should 199 | * be freed with yajl_free_error 200 | */ 201 | YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose, 202 | const unsigned char * jsonText, 203 | size_t jsonTextLength); 204 | 205 | /** 206 | * get the amount of data consumed from the last chunk passed to YAJL. 207 | * 208 | * In the case of a successful parse this can help you understand if 209 | * the entire buffer was consumed (which will allow you to handle 210 | * "junk at end of input"). 211 | * 212 | * In the event an error is encountered during parsing, this function 213 | * affords the client a way to get the offset into the most recent 214 | * chunk where the error occured. 0 will be returned if no error 215 | * was encountered. 216 | */ 217 | YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand); 218 | 219 | /** free an error returned from yajl_get_error */ 220 | YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str); 221 | 222 | #ifdef __cplusplus 223 | } 224 | #endif 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /src/yajl_gen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "api/yajl_gen.h" 18 | #include "yajl_buf.h" 19 | #include "yajl_encode.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef enum { 28 | yajl_gen_start, 29 | yajl_gen_map_start, 30 | yajl_gen_map_key, 31 | yajl_gen_map_val, 32 | yajl_gen_array_start, 33 | yajl_gen_in_array, 34 | yajl_gen_complete, 35 | yajl_gen_error 36 | } yajl_gen_state; 37 | 38 | struct yajl_gen_t 39 | { 40 | unsigned int flags; 41 | unsigned int depth; 42 | const char * indentString; 43 | yajl_gen_state state[YAJL_MAX_DEPTH]; 44 | yajl_print_t print; 45 | void * ctx; /* yajl_buf */ 46 | /* memory allocation routines */ 47 | yajl_alloc_funcs alloc; 48 | }; 49 | 50 | int 51 | yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...) 52 | { 53 | int rv = 1; 54 | va_list ap; 55 | va_start(ap, opt); 56 | 57 | switch(opt) { 58 | case yajl_gen_beautify: 59 | case yajl_gen_validate_utf8: 60 | case yajl_gen_escape_solidus: 61 | if (va_arg(ap, int)) g->flags |= opt; 62 | else g->flags &= ~opt; 63 | break; 64 | case yajl_gen_indent_string: { 65 | const char *indent = va_arg(ap, const char *); 66 | g->indentString = indent; 67 | for (; *indent; indent++) { 68 | if (*indent != '\n' 69 | && *indent != '\v' 70 | && *indent != '\f' 71 | && *indent != '\t' 72 | && *indent != '\r' 73 | && *indent != ' ') 74 | { 75 | g->indentString = NULL; 76 | rv = 0; 77 | } 78 | } 79 | break; 80 | } 81 | case yajl_gen_print_callback: 82 | yajl_buf_free(g->ctx); 83 | g->print = va_arg(ap, const yajl_print_t); 84 | g->ctx = va_arg(ap, void *); 85 | break; 86 | default: 87 | rv = 0; 88 | } 89 | 90 | va_end(ap); 91 | 92 | return rv; 93 | } 94 | 95 | 96 | 97 | yajl_gen 98 | yajl_gen_alloc(const yajl_alloc_funcs * afs) 99 | { 100 | yajl_gen g = NULL; 101 | yajl_alloc_funcs afsBuffer; 102 | 103 | /* first order of business is to set up memory allocation routines */ 104 | if (afs != NULL) { 105 | if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) 106 | { 107 | return NULL; 108 | } 109 | } else { 110 | yajl_set_default_alloc_funcs(&afsBuffer); 111 | afs = &afsBuffer; 112 | } 113 | 114 | g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t)); 115 | if (!g) return NULL; 116 | 117 | memset((void *) g, 0, sizeof(struct yajl_gen_t)); 118 | /* copy in pointers to allocation routines */ 119 | memcpy((void *) &(g->alloc), (const void *) afs, sizeof(yajl_alloc_funcs)); 120 | 121 | g->print = (yajl_print_t)&yajl_buf_append; 122 | g->ctx = yajl_buf_alloc(&(g->alloc)); 123 | g->indentString = " "; 124 | 125 | return g; 126 | } 127 | 128 | void 129 | yajl_gen_reset(yajl_gen g, const char * sep) 130 | { 131 | g->depth = 0; 132 | memset((void *) &(g->state), 0, sizeof(g->state)); 133 | if (sep != NULL) g->print(g->ctx, sep, strlen(sep)); 134 | } 135 | 136 | void 137 | yajl_gen_free(yajl_gen g) 138 | { 139 | if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx); 140 | YA_FREE(&(g->alloc), g); 141 | } 142 | 143 | #define INSERT_SEP \ 144 | if (g->state[g->depth] == yajl_gen_map_key || \ 145 | g->state[g->depth] == yajl_gen_in_array) { \ 146 | g->print(g->ctx, ",", 1); \ 147 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \ 148 | } else if (g->state[g->depth] == yajl_gen_map_val) { \ 149 | g->print(g->ctx, ":", 1); \ 150 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \ 151 | } 152 | 153 | #define INSERT_WHITESPACE \ 154 | if ((g->flags & yajl_gen_beautify)) { \ 155 | if (g->state[g->depth] != yajl_gen_map_val) { \ 156 | unsigned int _i; \ 157 | for (_i=0;_idepth;_i++) \ 158 | g->print(g->ctx, \ 159 | g->indentString, \ 160 | (unsigned int)strlen(g->indentString)); \ 161 | } \ 162 | } 163 | 164 | #define ENSURE_NOT_KEY \ 165 | if (g->state[g->depth] == yajl_gen_map_key || \ 166 | g->state[g->depth] == yajl_gen_map_start) { \ 167 | return yajl_gen_keys_must_be_strings; \ 168 | } \ 169 | 170 | /* check that we're not complete, or in error state. in a valid state 171 | * to be generating */ 172 | #define ENSURE_VALID_STATE \ 173 | if (g->state[g->depth] == yajl_gen_error) { \ 174 | return yajl_gen_in_error_state;\ 175 | } else if (g->state[g->depth] == yajl_gen_complete) { \ 176 | return yajl_gen_generation_complete; \ 177 | } 178 | 179 | #define INCREMENT_DEPTH \ 180 | if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded; 181 | 182 | #define DECREMENT_DEPTH \ 183 | if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_generation_complete; 184 | 185 | #define APPENDED_ATOM \ 186 | switch (g->state[g->depth]) { \ 187 | case yajl_gen_start: \ 188 | g->state[g->depth] = yajl_gen_complete; \ 189 | break; \ 190 | case yajl_gen_map_start: \ 191 | case yajl_gen_map_key: \ 192 | g->state[g->depth] = yajl_gen_map_val; \ 193 | break; \ 194 | case yajl_gen_array_start: \ 195 | g->state[g->depth] = yajl_gen_in_array; \ 196 | break; \ 197 | case yajl_gen_map_val: \ 198 | g->state[g->depth] = yajl_gen_map_key; \ 199 | break; \ 200 | default: \ 201 | break; \ 202 | } \ 203 | 204 | #define FINAL_NEWLINE \ 205 | if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \ 206 | g->print(g->ctx, "\n", 1); 207 | 208 | yajl_gen_status 209 | yajl_gen_integer(yajl_gen g, long long int number) 210 | { 211 | char i[32]; 212 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 213 | sprintf(i, "%lld", number); 214 | g->print(g->ctx, i, (unsigned int)strlen(i)); 215 | APPENDED_ATOM; 216 | FINAL_NEWLINE; 217 | return yajl_gen_status_ok; 218 | } 219 | 220 | #if defined(_WIN32) || defined(WIN32) 221 | #include 222 | #define isnan _isnan 223 | #define isinf !_finite 224 | #endif 225 | 226 | yajl_gen_status 227 | yajl_gen_double(yajl_gen g, double number) 228 | { 229 | char i[32]; 230 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; 231 | if (isnan(number) || isinf(number)) return yajl_gen_invalid_number; 232 | INSERT_SEP; INSERT_WHITESPACE; 233 | sprintf(i, "%.20g", number); 234 | if (strspn(i, "0123456789-") == strlen(i)) { 235 | strcat(i, ".0"); 236 | } 237 | g->print(g->ctx, i, (unsigned int)strlen(i)); 238 | APPENDED_ATOM; 239 | FINAL_NEWLINE; 240 | return yajl_gen_status_ok; 241 | } 242 | 243 | yajl_gen_status 244 | yajl_gen_number(yajl_gen g, const char * s, size_t l) 245 | { 246 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 247 | g->print(g->ctx, s, l); 248 | APPENDED_ATOM; 249 | FINAL_NEWLINE; 250 | return yajl_gen_status_ok; 251 | } 252 | 253 | yajl_gen_status 254 | yajl_gen_string(yajl_gen g, const unsigned char * str, 255 | size_t len) 256 | { 257 | // if validation is enabled, check that the string is valid utf8 258 | // XXX: This checking could be done a little faster, in the same pass as 259 | // the string encoding 260 | if (g->flags & yajl_gen_validate_utf8) { 261 | if (!yajl_string_validate_utf8(str, len)) { 262 | return yajl_gen_invalid_string; 263 | } 264 | } 265 | ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; 266 | g->print(g->ctx, "\"", 1); 267 | yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus); 268 | g->print(g->ctx, "\"", 1); 269 | APPENDED_ATOM; 270 | FINAL_NEWLINE; 271 | return yajl_gen_status_ok; 272 | } 273 | 274 | yajl_gen_status 275 | yajl_gen_null(yajl_gen g) 276 | { 277 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 278 | g->print(g->ctx, "null", strlen("null")); 279 | APPENDED_ATOM; 280 | FINAL_NEWLINE; 281 | return yajl_gen_status_ok; 282 | } 283 | 284 | yajl_gen_status 285 | yajl_gen_bool(yajl_gen g, int boolean) 286 | { 287 | const char * val = boolean ? "true" : "false"; 288 | 289 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 290 | g->print(g->ctx, val, (unsigned int)strlen(val)); 291 | APPENDED_ATOM; 292 | FINAL_NEWLINE; 293 | return yajl_gen_status_ok; 294 | } 295 | 296 | yajl_gen_status 297 | yajl_gen_map_open(yajl_gen g) 298 | { 299 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 300 | INCREMENT_DEPTH; 301 | 302 | g->state[g->depth] = yajl_gen_map_start; 303 | g->print(g->ctx, "{", 1); 304 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 305 | FINAL_NEWLINE; 306 | return yajl_gen_status_ok; 307 | } 308 | 309 | yajl_gen_status 310 | yajl_gen_map_close(yajl_gen g) 311 | { 312 | ENSURE_VALID_STATE; 313 | DECREMENT_DEPTH; 314 | 315 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 316 | APPENDED_ATOM; 317 | INSERT_WHITESPACE; 318 | g->print(g->ctx, "}", 1); 319 | FINAL_NEWLINE; 320 | return yajl_gen_status_ok; 321 | } 322 | 323 | yajl_gen_status 324 | yajl_gen_array_open(yajl_gen g) 325 | { 326 | ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; 327 | INCREMENT_DEPTH; 328 | g->state[g->depth] = yajl_gen_array_start; 329 | g->print(g->ctx, "[", 1); 330 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 331 | FINAL_NEWLINE; 332 | return yajl_gen_status_ok; 333 | } 334 | 335 | yajl_gen_status 336 | yajl_gen_array_close(yajl_gen g) 337 | { 338 | ENSURE_VALID_STATE; 339 | DECREMENT_DEPTH; 340 | if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); 341 | APPENDED_ATOM; 342 | INSERT_WHITESPACE; 343 | g->print(g->ctx, "]", 1); 344 | FINAL_NEWLINE; 345 | return yajl_gen_status_ok; 346 | } 347 | 348 | yajl_gen_status 349 | yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, 350 | size_t * len) 351 | { 352 | if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; 353 | *buf = yajl_buf_data((yajl_buf)g->ctx); 354 | *len = yajl_buf_len((yajl_buf)g->ctx); 355 | return yajl_gen_status_ok; 356 | } 357 | 358 | void 359 | yajl_gen_clear(yajl_gen g) 360 | { 361 | if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx); 362 | } 363 | -------------------------------------------------------------------------------- /src/yajl_tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Florian Forster 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "api/yajl_tree.h" 24 | #include "api/yajl_parse.h" 25 | 26 | #include "yajl_parser.h" 27 | 28 | #if ( (defined(_WIN32) || defined(WIN32) ) && ( defined(_MSC_VER) ) ) 29 | #define snprintf sprintf_s 30 | #endif 31 | 32 | #ifdef __GNUC__ 33 | #pragma GCC diagnostic ignored "-Wcast-qual" 34 | #endif 35 | 36 | #define STATUS_CONTINUE 1 37 | #define STATUS_ABORT 0 38 | 39 | struct stack_elem_s; 40 | typedef struct stack_elem_s stack_elem_t; 41 | struct stack_elem_s 42 | { 43 | char * key; 44 | yajl_val value; 45 | stack_elem_t *next; 46 | }; 47 | 48 | struct context_s 49 | { 50 | stack_elem_t *stack; 51 | yajl_val root; 52 | char *errbuf; 53 | size_t errbuf_size; 54 | }; 55 | typedef struct context_s context_t; 56 | 57 | #define RETURN_ERROR(ctx,retval,...) { \ 58 | if ((ctx)->errbuf != NULL) \ 59 | snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \ 60 | return (retval); \ 61 | } 62 | 63 | static yajl_val value_alloc (yajl_type type) 64 | { 65 | yajl_val v; 66 | 67 | v = malloc (sizeof (*v)); 68 | if (v == NULL) return (NULL); 69 | memset (v, 0, sizeof (*v)); 70 | v->type = type; 71 | 72 | return (v); 73 | } 74 | 75 | static void yajl_object_free (yajl_val v) 76 | { 77 | size_t i; 78 | 79 | if (!YAJL_IS_OBJECT(v)) return; 80 | 81 | for (i = 0; i < v->u.object.len; i++) 82 | { 83 | free((char *) v->u.object.keys[i]); 84 | v->u.object.keys[i] = NULL; 85 | yajl_tree_free (v->u.object.values[i]); 86 | v->u.object.values[i] = NULL; 87 | } 88 | 89 | free((void*) v->u.object.keys); 90 | free(v->u.object.values); 91 | free(v); 92 | } 93 | 94 | static void yajl_array_free (yajl_val v) 95 | { 96 | size_t i; 97 | 98 | if (!YAJL_IS_ARRAY(v)) return; 99 | 100 | for (i = 0; i < v->u.array.len; i++) 101 | { 102 | yajl_tree_free (v->u.array.values[i]); 103 | v->u.array.values[i] = NULL; 104 | } 105 | 106 | free(v->u.array.values); 107 | free(v); 108 | } 109 | 110 | /* 111 | * Parsing nested objects and arrays is implemented using a stack. When a new 112 | * object or array starts (a curly or a square opening bracket is read), an 113 | * appropriate value is pushed on the stack. When the end of the object is 114 | * reached (an appropriate closing bracket has been read), the value is popped 115 | * off the stack and added to the enclosing object using "context_add_value". 116 | */ 117 | static int context_push(context_t *ctx, yajl_val v) 118 | { 119 | stack_elem_t *stack; 120 | 121 | stack = malloc (sizeof (*stack)); 122 | if (stack == NULL) 123 | RETURN_ERROR (ctx, ENOMEM, "Out of memory"); 124 | memset (stack, 0, sizeof (*stack)); 125 | 126 | assert ((ctx->stack == NULL) 127 | || YAJL_IS_OBJECT (v) 128 | || YAJL_IS_ARRAY (v)); 129 | 130 | stack->value = v; 131 | stack->next = ctx->stack; 132 | ctx->stack = stack; 133 | 134 | return (0); 135 | } 136 | 137 | static yajl_val context_pop(context_t *ctx) 138 | { 139 | stack_elem_t *stack; 140 | yajl_val v; 141 | 142 | if (ctx->stack == NULL) 143 | RETURN_ERROR (ctx, NULL, "context_pop: " 144 | "Bottom of stack reached prematurely"); 145 | 146 | stack = ctx->stack; 147 | ctx->stack = stack->next; 148 | 149 | v = stack->value; 150 | 151 | free (stack); 152 | 153 | return (v); 154 | } 155 | 156 | static int object_add_keyval(context_t *ctx, 157 | yajl_val obj, char *key, yajl_val value) 158 | { 159 | const char **tmpk; 160 | yajl_val *tmpv; 161 | 162 | /* We're checking for NULL in "context_add_value" or its callers. */ 163 | assert (ctx != NULL); 164 | assert (obj != NULL); 165 | assert (key != NULL); 166 | assert (value != NULL); 167 | 168 | /* We're assuring that "obj" is an object in "context_add_value". */ 169 | assert(YAJL_IS_OBJECT(obj)); 170 | 171 | tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1)); 172 | if (tmpk == NULL) 173 | RETURN_ERROR(ctx, ENOMEM, "Out of memory"); 174 | obj->u.object.keys = tmpk; 175 | 176 | tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1)); 177 | if (tmpv == NULL) 178 | RETURN_ERROR(ctx, ENOMEM, "Out of memory"); 179 | obj->u.object.values = tmpv; 180 | 181 | obj->u.object.keys[obj->u.object.len] = key; 182 | obj->u.object.values[obj->u.object.len] = value; 183 | obj->u.object.len++; 184 | 185 | return (0); 186 | } 187 | 188 | static int array_add_value (context_t *ctx, 189 | yajl_val array, yajl_val value) 190 | { 191 | yajl_val *tmp; 192 | 193 | /* We're checking for NULL pointers in "context_add_value" or its 194 | * callers. */ 195 | assert (ctx != NULL); 196 | assert (array != NULL); 197 | assert (value != NULL); 198 | 199 | /* "context_add_value" will only call us with array values. */ 200 | assert(YAJL_IS_ARRAY(array)); 201 | 202 | tmp = realloc(array->u.array.values, 203 | sizeof(*(array->u.array.values)) * (array->u.array.len + 1)); 204 | if (tmp == NULL) 205 | RETURN_ERROR(ctx, ENOMEM, "Out of memory"); 206 | array->u.array.values = tmp; 207 | array->u.array.values[array->u.array.len] = value; 208 | array->u.array.len++; 209 | 210 | return 0; 211 | } 212 | 213 | /* 214 | * Add a value to the value on top of the stack or the "root" member in the 215 | * context if the end of the parsing process is reached. 216 | */ 217 | static int context_add_value (context_t *ctx, yajl_val v) 218 | { 219 | /* We're checking for NULL values in all the calling functions. */ 220 | assert (ctx != NULL); 221 | assert (v != NULL); 222 | 223 | /* 224 | * There are three valid states in which this function may be called: 225 | * - There is no value on the stack => This is the only value. This is the 226 | * last step done when parsing a document. We assign the value to the 227 | * "root" member and return. 228 | * - The value on the stack is an object. In this case store the key on the 229 | * stack or, if the key has already been read, add key and value to the 230 | * object. 231 | * - The value on the stack is an array. In this case simply add the value 232 | * and return. 233 | */ 234 | if (ctx->stack == NULL) 235 | { 236 | assert (ctx->root == NULL); 237 | ctx->root = v; 238 | return (0); 239 | } 240 | else if (YAJL_IS_OBJECT (ctx->stack->value)) 241 | { 242 | if (ctx->stack->key == NULL) 243 | { 244 | if (!YAJL_IS_STRING (v)) 245 | RETURN_ERROR (ctx, EINVAL, "context_add_value: " 246 | "Object key is not a string (%#04x)", 247 | v->type); 248 | 249 | ctx->stack->key = v->u.string; 250 | v->u.string = NULL; 251 | free(v); 252 | return (0); 253 | } 254 | else /* if (ctx->key != NULL) */ 255 | { 256 | char * key; 257 | 258 | key = ctx->stack->key; 259 | ctx->stack->key = NULL; 260 | return (object_add_keyval (ctx, ctx->stack->value, key, v)); 261 | } 262 | } 263 | else if (YAJL_IS_ARRAY (ctx->stack->value)) 264 | { 265 | return (array_add_value (ctx, ctx->stack->value, v)); 266 | } 267 | else 268 | { 269 | RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to " 270 | "a value of type %#04x (not a composite type)", 271 | ctx->stack->value->type); 272 | } 273 | } 274 | 275 | static int handle_string (void *ctx, 276 | const unsigned char *string, size_t string_length) 277 | { 278 | yajl_val v; 279 | 280 | v = value_alloc (yajl_t_string); 281 | if (v == NULL) 282 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 283 | 284 | v->u.string = malloc (string_length + 1); 285 | if (v->u.string == NULL) 286 | { 287 | free (v); 288 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 289 | } 290 | memcpy(v->u.string, string, string_length); 291 | v->u.string[string_length] = 0; 292 | 293 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 294 | } 295 | 296 | static int handle_number (void *ctx, const char *string, size_t string_length) 297 | { 298 | yajl_val v; 299 | char *endptr; 300 | 301 | v = value_alloc(yajl_t_number); 302 | if (v == NULL) 303 | RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); 304 | 305 | v->u.number.r = malloc(string_length + 1); 306 | if (v->u.number.r == NULL) 307 | { 308 | free(v); 309 | RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); 310 | } 311 | memcpy(v->u.number.r, string, string_length); 312 | v->u.number.r[string_length] = 0; 313 | 314 | v->u.number.flags = 0; 315 | 316 | errno = 0; 317 | v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r, 318 | strlen(v->u.number.r)); 319 | if (errno == 0) 320 | v->u.number.flags |= YAJL_NUMBER_INT_VALID; 321 | 322 | endptr = NULL; 323 | errno = 0; 324 | v->u.number.d = strtod(v->u.number.r, &endptr); 325 | if ((errno == 0) && (endptr != NULL) && (*endptr == 0)) 326 | v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID; 327 | 328 | return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 329 | } 330 | 331 | static int handle_start_map (void *ctx) 332 | { 333 | yajl_val v; 334 | 335 | v = value_alloc(yajl_t_object); 336 | if (v == NULL) 337 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 338 | 339 | v->u.object.keys = NULL; 340 | v->u.object.values = NULL; 341 | v->u.object.len = 0; 342 | 343 | return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 344 | } 345 | 346 | static int handle_end_map (void *ctx) 347 | { 348 | yajl_val v; 349 | 350 | v = context_pop (ctx); 351 | if (v == NULL) 352 | return (STATUS_ABORT); 353 | 354 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 355 | } 356 | 357 | static int handle_start_array (void *ctx) 358 | { 359 | yajl_val v; 360 | 361 | v = value_alloc(yajl_t_array); 362 | if (v == NULL) 363 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 364 | 365 | v->u.array.values = NULL; 366 | v->u.array.len = 0; 367 | 368 | return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 369 | } 370 | 371 | static int handle_end_array (void *ctx) 372 | { 373 | yajl_val v; 374 | 375 | v = context_pop (ctx); 376 | if (v == NULL) 377 | return (STATUS_ABORT); 378 | 379 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 380 | } 381 | 382 | static int handle_boolean (void *ctx, int boolean_value) 383 | { 384 | yajl_val v; 385 | 386 | v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false); 387 | if (v == NULL) 388 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 389 | 390 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 391 | } 392 | 393 | static int handle_null (void *ctx) 394 | { 395 | yajl_val v; 396 | 397 | v = value_alloc (yajl_t_null); 398 | if (v == NULL) 399 | RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); 400 | 401 | return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); 402 | } 403 | 404 | /* 405 | * Public functions 406 | */ 407 | yajl_val yajl_tree_parse (const char *input, 408 | char *error_buffer, size_t error_buffer_size) 409 | { 410 | static const yajl_callbacks callbacks = 411 | { 412 | /* null = */ handle_null, 413 | /* boolean = */ handle_boolean, 414 | /* integer = */ NULL, 415 | /* double = */ NULL, 416 | /* number = */ handle_number, 417 | /* string = */ handle_string, 418 | /* start map = */ handle_start_map, 419 | /* map key = */ handle_string, 420 | /* end map = */ handle_end_map, 421 | /* start array = */ handle_start_array, 422 | /* end array = */ handle_end_array 423 | }; 424 | 425 | yajl_handle handle; 426 | yajl_status status; 427 | char * internal_err_str; 428 | context_t ctx = { NULL, NULL, NULL, 0 }; 429 | 430 | ctx.errbuf = error_buffer; 431 | ctx.errbuf_size = error_buffer_size; 432 | 433 | if (error_buffer != NULL) 434 | memset (error_buffer, 0, error_buffer_size); 435 | 436 | handle = yajl_alloc (&callbacks, NULL, &ctx); 437 | yajl_config(handle, yajl_allow_comments, 1); 438 | 439 | status = yajl_parse(handle, 440 | (const unsigned char *) input, 441 | strlen (input)); 442 | status = yajl_complete_parse (handle); 443 | if (status != yajl_status_ok) { 444 | if (error_buffer != NULL && error_buffer_size > 0) { 445 | internal_err_str = (char *) yajl_get_error(handle, 1, 446 | (const unsigned char *) input, 447 | strlen(input)); 448 | snprintf(error_buffer, error_buffer_size, "%s", internal_err_str); 449 | YA_FREE(&(handle->alloc), internal_err_str); 450 | } 451 | yajl_free (handle); 452 | return NULL; 453 | } 454 | 455 | yajl_free (handle); 456 | return (ctx.root); 457 | } 458 | 459 | yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type) 460 | { 461 | if (!path) return NULL; 462 | while (n && *path) { 463 | size_t i; 464 | size_t len; 465 | 466 | if (n->type != yajl_t_object) return NULL; 467 | len = n->u.object.len; 468 | for (i = 0; i < len; i++) { 469 | if (!strcmp(*path, n->u.object.keys[i])) { 470 | n = n->u.object.values[i]; 471 | break; 472 | } 473 | } 474 | if (i == len) return NULL; 475 | path++; 476 | } 477 | if (n && type != yajl_t_any && type != n->type) n = NULL; 478 | return n; 479 | } 480 | 481 | void yajl_tree_free (yajl_val v) 482 | { 483 | if (v == NULL) return; 484 | 485 | if (YAJL_IS_STRING(v)) 486 | { 487 | memset(v->u.string, 0, strlens(v->u.string)); 488 | free(v->u.string); 489 | free(v); 490 | } 491 | else if (YAJL_IS_NUMBER(v)) 492 | { 493 | free(v->u.number.r); 494 | free(v); 495 | } 496 | else if (YAJL_GET_OBJECT(v)) 497 | { 498 | yajl_object_free(v); 499 | } 500 | else if (YAJL_GET_ARRAY(v)) 501 | { 502 | yajl_array_free(v); 503 | } 504 | else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */ 505 | { 506 | free(v); 507 | } 508 | } 509 | -------------------------------------------------------------------------------- /src/yajl_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2014, Lloyd Hilaiel 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "api/yajl_parse.h" 18 | #include "yajl_lex.h" 19 | #include "yajl_parser.h" 20 | #include "yajl_encode.h" 21 | #include "yajl_bytestack.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10)) 33 | 34 | #ifdef __GNUC__ 35 | #pragma GCC diagnostic ignored "-Wfloat-equal" 36 | #endif 37 | #ifdef __clang__ 38 | #pragma clang diagnostic ignored "-Wfloat-equal" 39 | #endif 40 | 41 | /* same semantics as strtol */ 42 | long long 43 | yajl_parse_integer(const unsigned char *number, unsigned int length) 44 | { 45 | long long ret = 0; 46 | long sign = 1; 47 | const unsigned char *pos = number; 48 | if (*pos == '-') { pos++; sign = -1; } 49 | if (*pos == '+') { pos++; } 50 | 51 | while (pos < number + length) { 52 | if ( ret > MAX_VALUE_TO_MULTIPLY ) { 53 | errno = ERANGE; 54 | return sign == 1 ? LLONG_MAX : LLONG_MIN; 55 | } 56 | ret *= 10; 57 | if (LLONG_MAX - ret < (*pos - '0')) { 58 | errno = ERANGE; 59 | return sign == 1 ? LLONG_MAX : LLONG_MIN; 60 | } 61 | if (*pos < '0' || *pos > '9') { 62 | errno = ERANGE; 63 | return sign == 1 ? LLONG_MAX : LLONG_MIN; 64 | } 65 | ret += (*pos++ - '0'); 66 | } 67 | 68 | return sign * ret; 69 | } 70 | 71 | unsigned char * 72 | yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, 73 | size_t jsonTextLen, int verbose) 74 | { 75 | size_t offset = hand->bytesConsumed; 76 | unsigned char * str; 77 | const char * errorType = NULL; 78 | const char * errorText = NULL; 79 | char text[72]; 80 | const char * arrow = " (right here) ------^\n"; 81 | 82 | if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) { 83 | errorType = "parse"; 84 | errorText = hand->parseError; 85 | } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) { 86 | errorType = "lexical"; 87 | errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer)); 88 | } else { 89 | errorType = "unknown"; 90 | } 91 | 92 | { 93 | size_t memneeded = 0; 94 | memneeded += strlen(errorType); 95 | memneeded += strlen(" error"); 96 | if (errorText != NULL) { 97 | memneeded += strlen(": "); 98 | memneeded += strlen(errorText); 99 | } 100 | str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); 101 | if (!str) return NULL; 102 | str[0] = 0; 103 | strcat((char *) str, errorType); 104 | strcat((char *) str, " error"); 105 | if (errorText != NULL) { 106 | strcat((char *) str, ": "); 107 | strcat((char *) str, errorText); 108 | } 109 | strcat((char *) str, "\n"); 110 | } 111 | 112 | /* now we append as many spaces as needed to make sure the error 113 | * falls at char 41, if verbose was specified */ 114 | if (verbose) { 115 | size_t start, end, i; 116 | size_t spacesNeeded; 117 | 118 | spacesNeeded = (offset < 30 ? 40 - offset : 10); 119 | start = (offset >= 30 ? offset - 30 : 0); 120 | end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30); 121 | 122 | for (i=0;ialloc), (unsigned int)(strlen((char *) str) + 140 | strlen((char *) text) + 141 | strlen(arrow) + 1)); 142 | if (newStr) { 143 | newStr[0] = 0; 144 | strcat((char *) newStr, (char *) str); 145 | strcat((char *) newStr, text); 146 | strcat((char *) newStr, arrow); 147 | } 148 | YA_FREE(&(hand->alloc), str); 149 | str = (unsigned char *) newStr; 150 | } 151 | } 152 | return str; 153 | } 154 | 155 | /* check for client cancelation */ 156 | #define _CC_CHK(x) \ 157 | if (!(x)) { \ 158 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); \ 159 | hand->parseError = \ 160 | "client cancelled parse via callback return value"; \ 161 | return yajl_status_client_canceled; \ 162 | } 163 | 164 | 165 | yajl_status 166 | yajl_do_finish(yajl_handle hand) 167 | { 168 | yajl_status stat; 169 | stat = yajl_do_parse(hand,(const unsigned char *) " ",1); 170 | 171 | if (stat != yajl_status_ok) return stat; 172 | 173 | switch(yajl_bs_current(hand->stateStack)) 174 | { 175 | case yajl_state_parse_error: 176 | case yajl_state_lexical_error: 177 | return yajl_status_error; 178 | case yajl_state_got_value: 179 | case yajl_state_parse_complete: 180 | return yajl_status_ok; 181 | default: 182 | if (!(hand->flags & yajl_allow_partial_values)) 183 | { 184 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 185 | hand->parseError = "premature EOF"; 186 | return yajl_status_error; 187 | } 188 | return yajl_status_ok; 189 | } 190 | } 191 | 192 | yajl_status 193 | yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, 194 | size_t jsonTextLen) 195 | { 196 | yajl_tok tok; 197 | const unsigned char * buf; 198 | size_t bufLen; 199 | size_t * offset = &(hand->bytesConsumed); 200 | 201 | *offset = 0; 202 | 203 | around_again: 204 | switch (yajl_bs_current(hand->stateStack)) { 205 | case yajl_state_parse_complete: 206 | if (hand->flags & yajl_allow_multiple_values) { 207 | yajl_bs_set(hand->stateStack, yajl_state_got_value); 208 | goto around_again; 209 | } 210 | if (!(hand->flags & yajl_allow_trailing_garbage)) { 211 | if (*offset != jsonTextLen) { 212 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 213 | offset, &buf, &bufLen); 214 | if (tok != yajl_tok_eof) { 215 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 216 | hand->parseError = "trailing garbage"; 217 | } 218 | goto around_again; 219 | } 220 | } 221 | return yajl_status_ok; 222 | case yajl_state_lexical_error: 223 | case yajl_state_parse_error: 224 | return yajl_status_error; 225 | case yajl_state_start: 226 | case yajl_state_got_value: 227 | case yajl_state_map_need_val: 228 | case yajl_state_array_need_val: 229 | case yajl_state_array_start: { 230 | /* for arrays and maps, we advance the state for this 231 | * depth, then push the state of the next depth. 232 | * If an error occurs during the parsing of the nesting 233 | * enitity, the state at this level will not matter. 234 | * a state that needs pushing will be anything other 235 | * than state_start */ 236 | 237 | yajl_state stateToPush = yajl_state_start; 238 | 239 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 240 | offset, &buf, &bufLen); 241 | 242 | switch (tok) { 243 | case yajl_tok_eof: 244 | return yajl_status_ok; 245 | case yajl_tok_error: 246 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 247 | goto around_again; 248 | case yajl_tok_string: 249 | if (hand->callbacks && hand->callbacks->yajl_string) { 250 | _CC_CHK(hand->callbacks->yajl_string(hand->ctx, 251 | buf, bufLen)); 252 | } 253 | break; 254 | case yajl_tok_string_with_escapes: 255 | if (hand->callbacks && hand->callbacks->yajl_string) { 256 | yajl_buf_clear(hand->decodeBuf); 257 | yajl_string_decode(hand->decodeBuf, buf, bufLen); 258 | _CC_CHK(hand->callbacks->yajl_string( 259 | hand->ctx, yajl_buf_data(hand->decodeBuf), 260 | yajl_buf_len(hand->decodeBuf))); 261 | } 262 | break; 263 | case yajl_tok_bool: 264 | if (hand->callbacks && hand->callbacks->yajl_boolean) { 265 | _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx, 266 | *buf == 't')); 267 | } 268 | break; 269 | case yajl_tok_null: 270 | if (hand->callbacks && hand->callbacks->yajl_null) { 271 | _CC_CHK(hand->callbacks->yajl_null(hand->ctx)); 272 | } 273 | break; 274 | case yajl_tok_left_bracket: 275 | if (hand->callbacks && hand->callbacks->yajl_start_map) { 276 | _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx)); 277 | } 278 | stateToPush = yajl_state_map_start; 279 | break; 280 | case yajl_tok_left_brace: 281 | if (hand->callbacks && hand->callbacks->yajl_start_array) { 282 | _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx)); 283 | } 284 | stateToPush = yajl_state_array_start; 285 | break; 286 | case yajl_tok_integer: 287 | if (hand->callbacks) { 288 | if (hand->callbacks->yajl_number) { 289 | _CC_CHK(hand->callbacks->yajl_number( 290 | hand->ctx,(const char *) buf, bufLen)); 291 | } else if (hand->callbacks->yajl_integer) { 292 | long long int i = 0; 293 | errno = 0; 294 | i = yajl_parse_integer(buf, bufLen); 295 | if ((i == LLONG_MIN || i == LLONG_MAX) && 296 | errno == ERANGE) 297 | { 298 | yajl_bs_set(hand->stateStack, 299 | yajl_state_parse_error); 300 | hand->parseError = "integer overflow" ; 301 | /* try to restore error offset */ 302 | if (*offset >= bufLen) *offset -= bufLen; 303 | else *offset = 0; 304 | goto around_again; 305 | } 306 | _CC_CHK(hand->callbacks->yajl_integer(hand->ctx, 307 | i)); 308 | } 309 | } 310 | break; 311 | case yajl_tok_double: 312 | if (hand->callbacks) { 313 | if (hand->callbacks->yajl_number) { 314 | _CC_CHK(hand->callbacks->yajl_number( 315 | hand->ctx, (const char *) buf, bufLen)); 316 | } else if (hand->callbacks->yajl_double) { 317 | double d = 0.0; 318 | yajl_buf_clear(hand->decodeBuf); 319 | yajl_buf_append(hand->decodeBuf, buf, bufLen); 320 | buf = yajl_buf_data(hand->decodeBuf); 321 | errno = 0; 322 | d = strtod((const char *) buf, NULL); 323 | if ((d == HUGE_VAL || d == -HUGE_VAL) && 324 | errno == ERANGE) 325 | { 326 | yajl_bs_set(hand->stateStack, 327 | yajl_state_parse_error); 328 | hand->parseError = "numeric (floating point) " 329 | "overflow"; 330 | /* try to restore error offset */ 331 | if (*offset >= bufLen) *offset -= bufLen; 332 | else *offset = 0; 333 | goto around_again; 334 | } 335 | _CC_CHK(hand->callbacks->yajl_double(hand->ctx, 336 | d)); 337 | } 338 | } 339 | break; 340 | case yajl_tok_right_brace: { 341 | if (yajl_bs_current(hand->stateStack) == 342 | yajl_state_array_start) 343 | { 344 | if (hand->callbacks && 345 | hand->callbacks->yajl_end_array) 346 | { 347 | _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); 348 | } 349 | yajl_bs_pop(hand->stateStack); 350 | goto around_again; 351 | } 352 | /* intentional fall-through */ 353 | } 354 | case yajl_tok_colon: 355 | case yajl_tok_comma: 356 | case yajl_tok_right_bracket: 357 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 358 | hand->parseError = 359 | "unallowed token at this point in JSON text"; 360 | goto around_again; 361 | default: 362 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 363 | hand->parseError = "invalid token, internal error"; 364 | goto around_again; 365 | } 366 | /* got a value. transition depends on the state we're in. */ 367 | { 368 | yajl_state s = yajl_bs_current(hand->stateStack); 369 | if (s == yajl_state_start || s == yajl_state_got_value) { 370 | yajl_bs_set(hand->stateStack, yajl_state_parse_complete); 371 | } else if (s == yajl_state_map_need_val) { 372 | yajl_bs_set(hand->stateStack, yajl_state_map_got_val); 373 | } else { 374 | yajl_bs_set(hand->stateStack, yajl_state_array_got_val); 375 | } 376 | } 377 | if (stateToPush != yajl_state_start) { 378 | yajl_bs_push(hand->stateStack, stateToPush); 379 | } 380 | 381 | goto around_again; 382 | } 383 | case yajl_state_map_start: 384 | case yajl_state_map_need_key: { 385 | /* only difference between these two states is that in 386 | * start '}' is valid, whereas in need_key, we've parsed 387 | * a comma, and a string key _must_ follow */ 388 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 389 | offset, &buf, &bufLen); 390 | switch (tok) { 391 | case yajl_tok_eof: 392 | return yajl_status_ok; 393 | case yajl_tok_error: 394 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 395 | goto around_again; 396 | case yajl_tok_string_with_escapes: 397 | if (hand->callbacks && hand->callbacks->yajl_map_key) { 398 | yajl_buf_clear(hand->decodeBuf); 399 | yajl_string_decode(hand->decodeBuf, buf, bufLen); 400 | buf = yajl_buf_data(hand->decodeBuf); 401 | bufLen = yajl_buf_len(hand->decodeBuf); 402 | } 403 | /* intentional fall-through */ 404 | case yajl_tok_string: 405 | if (hand->callbacks && hand->callbacks->yajl_map_key) { 406 | _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf, 407 | bufLen)); 408 | } 409 | yajl_bs_set(hand->stateStack, yajl_state_map_sep); 410 | goto around_again; 411 | case yajl_tok_right_bracket: 412 | if (yajl_bs_current(hand->stateStack) == 413 | yajl_state_map_start) 414 | { 415 | if (hand->callbacks && hand->callbacks->yajl_end_map) { 416 | _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); 417 | } 418 | yajl_bs_pop(hand->stateStack); 419 | goto around_again; 420 | } 421 | default: 422 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 423 | hand->parseError = 424 | "invalid object key (must be a string)"; 425 | goto around_again; 426 | } 427 | } 428 | case yajl_state_map_sep: { 429 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 430 | offset, &buf, &bufLen); 431 | switch (tok) { 432 | case yajl_tok_colon: 433 | yajl_bs_set(hand->stateStack, yajl_state_map_need_val); 434 | goto around_again; 435 | case yajl_tok_eof: 436 | return yajl_status_ok; 437 | case yajl_tok_error: 438 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 439 | goto around_again; 440 | default: 441 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 442 | hand->parseError = "object key and value must " 443 | "be separated by a colon (':')"; 444 | goto around_again; 445 | } 446 | } 447 | case yajl_state_map_got_val: { 448 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 449 | offset, &buf, &bufLen); 450 | switch (tok) { 451 | case yajl_tok_right_bracket: 452 | if (hand->callbacks && hand->callbacks->yajl_end_map) { 453 | _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); 454 | } 455 | yajl_bs_pop(hand->stateStack); 456 | goto around_again; 457 | case yajl_tok_comma: 458 | yajl_bs_set(hand->stateStack, yajl_state_map_need_key); 459 | goto around_again; 460 | case yajl_tok_eof: 461 | return yajl_status_ok; 462 | case yajl_tok_error: 463 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 464 | goto around_again; 465 | default: 466 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 467 | hand->parseError = "after key and value, inside map, " 468 | "I expect ',' or '}'"; 469 | /* try to restore error offset */ 470 | if (*offset >= bufLen) *offset -= bufLen; 471 | else *offset = 0; 472 | goto around_again; 473 | } 474 | } 475 | case yajl_state_array_got_val: { 476 | tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, 477 | offset, &buf, &bufLen); 478 | switch (tok) { 479 | case yajl_tok_right_brace: 480 | if (hand->callbacks && hand->callbacks->yajl_end_array) { 481 | _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); 482 | } 483 | yajl_bs_pop(hand->stateStack); 484 | goto around_again; 485 | case yajl_tok_comma: 486 | yajl_bs_set(hand->stateStack, yajl_state_array_need_val); 487 | goto around_again; 488 | case yajl_tok_eof: 489 | return yajl_status_ok; 490 | case yajl_tok_error: 491 | yajl_bs_set(hand->stateStack, yajl_state_lexical_error); 492 | goto around_again; 493 | default: 494 | yajl_bs_set(hand->stateStack, yajl_state_parse_error); 495 | hand->parseError = 496 | "after array element, I expect ',' or ']'"; 497 | goto around_again; 498 | } 499 | } 500 | default: 501 | break; 502 | } 503 | 504 | abort(); 505 | return yajl_status_error; 506 | } 507 | 508 | --------------------------------------------------------------------------------