oj 2.18.3 → 3.13.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
data/ext/oj/parse.c CHANGED
@@ -1,783 +1,969 @@
1
- /* parse.c
2
- * Copyright (c) 2013, Peter Ohler
3
- * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
1
+ // Copyright (c) 2013 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
30
3
 
31
- #include <stdlib.h>
4
+ #include "parse.h"
5
+
6
+ #include <math.h>
7
+ #include <ruby/util.h>
32
8
  #include <stdio.h>
9
+ #include <stdlib.h>
33
10
  #include <string.h>
34
11
  #include <unistd.h>
35
- #include <math.h>
36
12
 
37
- #include "oj.h"
38
- #include "parse.h"
39
13
  #include "buf.h"
14
+ #include "encode.h"
15
+ #include "oj.h"
16
+ #include "rxclass.h"
40
17
  #include "val_stack.h"
41
18
 
42
19
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
43
- #define OJ_INFINITY (1.0/0.0)
20
+ #define OJ_INFINITY (1.0 / 0.0)
44
21
 
45
22
  //#define EXP_MAX 1023
46
- #define EXP_MAX 100000
47
- #define DEC_MAX 15
23
+ #define EXP_MAX 100000
24
+ #define DEC_MAX 15
48
25
 
49
- static void
50
- next_non_white(ParseInfo pi) {
26
+ static void next_non_white(ParseInfo pi) {
51
27
  for (; 1; pi->cur++) {
52
- switch(*pi->cur) {
53
- case ' ':
54
- case '\t':
55
- case '\f':
56
- case '\n':
57
- case '\r':
58
- break;
59
- default:
60
- return;
61
- }
28
+ switch (*pi->cur) {
29
+ case ' ':
30
+ case '\t':
31
+ case '\f':
32
+ case '\n':
33
+ case '\r': break;
34
+ default: return;
35
+ }
62
36
  }
63
37
  }
64
38
 
65
- static void
66
- skip_comment(ParseInfo pi) {
39
+ static void skip_comment(ParseInfo pi) {
67
40
  if ('*' == *pi->cur) {
68
- pi->cur++;
69
- for (; pi->cur < pi->end; pi->cur++) {
70
- if ('*' == *pi->cur && '/' == *(pi->cur + 1)) {
71
- pi->cur += 2;
72
- return;
73
- } else if (pi->end <= pi->cur) {
74
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
75
- return;
76
- }
77
- }
41
+ pi->cur++;
42
+ for (; pi->cur < pi->end; pi->cur++) {
43
+ if ('*' == *pi->cur && '/' == *(pi->cur + 1)) {
44
+ pi->cur += 2;
45
+ return;
46
+ } else if (pi->end <= pi->cur) {
47
+ oj_set_error_at(pi,
48
+ oj_parse_error_class,
49
+ __FILE__,
50
+ __LINE__,
51
+ "comment not terminated");
52
+ return;
53
+ }
54
+ }
78
55
  } else if ('/' == *pi->cur) {
79
- for (; 1; pi->cur++) {
80
- switch (*pi->cur) {
81
- case '\n':
82
- case '\r':
83
- case '\f':
84
- case '\0':
85
- return;
86
- default:
87
- break;
88
- }
89
- }
56
+ for (; 1; pi->cur++) {
57
+ switch (*pi->cur) {
58
+ case '\n':
59
+ case '\r':
60
+ case '\f':
61
+ case '\0': return;
62
+ default: break;
63
+ }
64
+ }
90
65
  } else {
91
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
66
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
92
67
  }
93
68
  }
94
69
 
95
- static void
96
- add_value(ParseInfo pi, VALUE rval) {
97
- Val parent = stack_peek(&pi->stack);
70
+ static void add_value(ParseInfo pi, VALUE rval) {
71
+ Val parent = stack_peek(&pi->stack);
98
72
 
99
- if (0 == parent) { // simple add
100
- pi->add_value(pi, rval);
73
+ if (0 == parent) { // simple add
74
+ pi->add_value(pi, rval);
101
75
  } else {
102
- switch (parent->next) {
103
- case NEXT_ARRAY_NEW:
104
- case NEXT_ARRAY_ELEMENT:
105
- pi->array_append_value(pi, rval);
106
- parent->next = NEXT_ARRAY_COMMA;
107
- break;
108
- case NEXT_HASH_VALUE:
109
- pi->hash_set_value(pi, parent, rval);
110
- if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
111
- xfree((char*)parent->key);
112
- parent->key = 0;
113
- }
114
- parent->next = NEXT_HASH_COMMA;
115
- break;
116
- case NEXT_HASH_NEW:
117
- case NEXT_HASH_KEY:
118
- case NEXT_HASH_COMMA:
119
- case NEXT_NONE:
120
- case NEXT_ARRAY_COMMA:
121
- case NEXT_HASH_COLON:
122
- default:
123
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
124
- break;
125
- }
76
+ switch (parent->next) {
77
+ case NEXT_ARRAY_NEW:
78
+ case NEXT_ARRAY_ELEMENT:
79
+ pi->array_append_value(pi, rval);
80
+ parent->next = NEXT_ARRAY_COMMA;
81
+ break;
82
+ case NEXT_HASH_VALUE:
83
+ pi->hash_set_value(pi, parent, rval);
84
+ if (0 != parent->key && 0 < parent->klen &&
85
+ (parent->key < pi->json || pi->cur < parent->key)) {
86
+ xfree((char *)parent->key);
87
+ parent->key = 0;
88
+ }
89
+ parent->next = NEXT_HASH_COMMA;
90
+ break;
91
+ case NEXT_HASH_NEW:
92
+ case NEXT_HASH_KEY:
93
+ case NEXT_HASH_COMMA:
94
+ case NEXT_NONE:
95
+ case NEXT_ARRAY_COMMA:
96
+ case NEXT_HASH_COLON:
97
+ default:
98
+ oj_set_error_at(pi,
99
+ oj_parse_error_class,
100
+ __FILE__,
101
+ __LINE__,
102
+ "expected %s",
103
+ oj_stack_next_string(parent->next));
104
+ break;
105
+ }
126
106
  }
127
107
  }
128
108
 
129
- static void
130
- read_null(ParseInfo pi) {
109
+ static void read_null(ParseInfo pi) {
131
110
  if ('u' == *pi->cur++ && 'l' == *pi->cur++ && 'l' == *pi->cur++) {
132
- add_value(pi, Qnil);
111
+ add_value(pi, Qnil);
133
112
  } else {
134
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
113
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
135
114
  }
136
115
  }
137
116
 
138
- static void
139
- read_true(ParseInfo pi) {
117
+ static void read_true(ParseInfo pi) {
140
118
  if ('r' == *pi->cur++ && 'u' == *pi->cur++ && 'e' == *pi->cur++) {
141
- add_value(pi, Qtrue);
119
+ add_value(pi, Qtrue);
142
120
  } else {
143
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
121
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
144
122
  }
145
123
  }
146
124
 
147
- static void
148
- read_false(ParseInfo pi) {
125
+ static void read_false(ParseInfo pi) {
149
126
  if ('a' == *pi->cur++ && 'l' == *pi->cur++ && 's' == *pi->cur++ && 'e' == *pi->cur++) {
150
- add_value(pi, Qfalse);
127
+ add_value(pi, Qfalse);
151
128
  } else {
152
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
129
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
153
130
  }
154
131
  }
155
132
 
156
- static uint32_t
157
- read_hex(ParseInfo pi, const char *h) {
158
- uint32_t b = 0;
159
- int i;
133
+ static uint32_t read_hex(ParseInfo pi, const char *h) {
134
+ uint32_t b = 0;
135
+ int i;
160
136
 
161
137
  for (i = 0; i < 4; i++, h++) {
162
- b = b << 4;
163
- if ('0' <= *h && *h <= '9') {
164
- b += *h - '0';
165
- } else if ('A' <= *h && *h <= 'F') {
166
- b += *h - 'A' + 10;
167
- } else if ('a' <= *h && *h <= 'f') {
168
- b += *h - 'a' + 10;
169
- } else {
170
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
171
- return 0;
172
- }
138
+ b = b << 4;
139
+ if ('0' <= *h && *h <= '9') {
140
+ b += *h - '0';
141
+ } else if ('A' <= *h && *h <= 'F') {
142
+ b += *h - 'A' + 10;
143
+ } else if ('a' <= *h && *h <= 'f') {
144
+ b += *h - 'a' + 10;
145
+ } else {
146
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
147
+ return 0;
148
+ }
173
149
  }
174
150
  return b;
175
151
  }
176
152
 
177
- static void
178
- unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
153
+ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
179
154
  if (0x0000007F >= code) {
180
- buf_append(buf, (char)code);
155
+ buf_append(buf, (char)code);
181
156
  } else if (0x000007FF >= code) {
182
- buf_append(buf, 0xC0 | (code >> 6));
183
- buf_append(buf, 0x80 | (0x3F & code));
157
+ buf_append(buf, 0xC0 | (code >> 6));
158
+ buf_append(buf, 0x80 | (0x3F & code));
184
159
  } else if (0x0000FFFF >= code) {
185
- buf_append(buf, 0xE0 | (code >> 12));
186
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
187
- buf_append(buf, 0x80 | (0x3F & code));
160
+ buf_append(buf, 0xE0 | (code >> 12));
161
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
162
+ buf_append(buf, 0x80 | (0x3F & code));
188
163
  } else if (0x001FFFFF >= code) {
189
- buf_append(buf, 0xF0 | (code >> 18));
190
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
191
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
192
- buf_append(buf, 0x80 | (0x3F & code));
164
+ buf_append(buf, 0xF0 | (code >> 18));
165
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
166
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
167
+ buf_append(buf, 0x80 | (0x3F & code));
193
168
  } else if (0x03FFFFFF >= code) {
194
- buf_append(buf, 0xF8 | (code >> 24));
195
- buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
196
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
197
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
198
- buf_append(buf, 0x80 | (0x3F & code));
169
+ buf_append(buf, 0xF8 | (code >> 24));
170
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
171
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
172
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
173
+ buf_append(buf, 0x80 | (0x3F & code));
199
174
  } else if (0x7FFFFFFF >= code) {
200
- buf_append(buf, 0xFC | (code >> 30));
201
- buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
202
- buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
203
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
204
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
205
- buf_append(buf, 0x80 | (0x3F & code));
175
+ buf_append(buf, 0xFC | (code >> 30));
176
+ buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
177
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
178
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
179
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
180
+ buf_append(buf, 0x80 | (0x3F & code));
206
181
  } else {
207
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
182
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
208
183
  }
209
184
  }
210
185
 
211
186
  // entered at /
212
- static void
213
- read_escaped_str(ParseInfo pi, const char *start) {
214
- struct _Buf buf;
215
- const char *s;
216
- int cnt = (int)(pi->cur - start);
217
- uint32_t code;
218
- Val parent = stack_peek(&pi->stack);
187
+ static void read_escaped_str(ParseInfo pi, const char *start) {
188
+ struct _buf buf;
189
+ const char *s;
190
+ int cnt = (int)(pi->cur - start);
191
+ uint32_t code;
192
+ Val parent = stack_peek(&pi->stack);
219
193
 
220
194
  buf_init(&buf);
221
195
  if (0 < cnt) {
222
- buf_append_string(&buf, start, cnt);
196
+ buf_append_string(&buf, start, cnt);
223
197
  }
224
198
  for (s = pi->cur; '"' != *s; s++) {
225
- if (s >= pi->end) {
226
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
227
- buf_cleanup(&buf);
228
- return;
229
- } else if ('\\' == *s) {
230
- s++;
231
- switch (*s) {
232
- case 'n': buf_append(&buf, '\n'); break;
233
- case 'r': buf_append(&buf, '\r'); break;
234
- case 't': buf_append(&buf, '\t'); break;
235
- case 'f': buf_append(&buf, '\f'); break;
236
- case 'b': buf_append(&buf, '\b'); break;
237
- case '"': buf_append(&buf, '"'); break;
238
- case '/': buf_append(&buf, '/'); break;
239
- case '\\': buf_append(&buf, '\\'); break;
240
- case 'u':
241
- s++;
242
- if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) {
243
- buf_cleanup(&buf);
244
- return;
245
- }
246
- s += 3;
247
- if (0x0000D800 <= code && code <= 0x0000DFFF) {
248
- uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
249
- uint32_t c2;
250
-
251
- s++;
252
- if ('\\' != *s || 'u' != *(s + 1)) {
253
- if (Yes == pi->options.allow_invalid) {
254
- s--;
255
- unicode_to_chars(pi, &buf, code);
256
- break;
257
- }
258
- pi->cur = s;
259
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
260
- buf_cleanup(&buf);
261
- return;
262
- }
263
- s += 2;
264
- if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) {
265
- buf_cleanup(&buf);
266
- return;
267
- }
268
- s += 3;
269
- c2 = (c2 - 0x0000DC00) & 0x000003FF;
270
- code = ((c1 << 10) | c2) + 0x00010000;
271
- }
272
- unicode_to_chars(pi, &buf, code);
273
- if (err_has(&pi->err)) {
274
- buf_cleanup(&buf);
275
- return;
276
- }
277
- break;
278
- default:
279
- pi->cur = s;
280
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
281
- buf_cleanup(&buf);
282
- return;
283
- }
284
- } else {
285
- buf_append(&buf, *s);
286
- }
199
+ if (s >= pi->end) {
200
+ oj_set_error_at(pi,
201
+ oj_parse_error_class,
202
+ __FILE__,
203
+ __LINE__,
204
+ "quoted string not terminated");
205
+ buf_cleanup(&buf);
206
+ return;
207
+ } else if ('\\' == *s) {
208
+ s++;
209
+ switch (*s) {
210
+ case 'n': buf_append(&buf, '\n'); break;
211
+ case 'r': buf_append(&buf, '\r'); break;
212
+ case 't': buf_append(&buf, '\t'); break;
213
+ case 'f': buf_append(&buf, '\f'); break;
214
+ case 'b': buf_append(&buf, '\b'); break;
215
+ case '"': buf_append(&buf, '"'); break;
216
+ case '/': buf_append(&buf, '/'); break;
217
+ case '\\': buf_append(&buf, '\\'); break;
218
+ case 'u':
219
+ s++;
220
+ if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) {
221
+ buf_cleanup(&buf);
222
+ return;
223
+ }
224
+ s += 3;
225
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
226
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
227
+ uint32_t c2;
228
+
229
+ s++;
230
+ if ('\\' != *s || 'u' != *(s + 1)) {
231
+ if (Yes == pi->options.allow_invalid) {
232
+ s--;
233
+ unicode_to_chars(pi, &buf, code);
234
+ break;
235
+ }
236
+ pi->cur = s;
237
+ oj_set_error_at(pi,
238
+ oj_parse_error_class,
239
+ __FILE__,
240
+ __LINE__,
241
+ "invalid escaped character");
242
+ buf_cleanup(&buf);
243
+ return;
244
+ }
245
+ s += 2;
246
+ if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) {
247
+ buf_cleanup(&buf);
248
+ return;
249
+ }
250
+ s += 3;
251
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
252
+ code = ((c1 << 10) | c2) + 0x00010000;
253
+ }
254
+ unicode_to_chars(pi, &buf, code);
255
+ if (err_has(&pi->err)) {
256
+ buf_cleanup(&buf);
257
+ return;
258
+ }
259
+ break;
260
+ default:
261
+ // The json gem claims this is not an error despite the
262
+ // ECMA-404 indicating it is not valid.
263
+ if (CompatMode == pi->options.mode) {
264
+ buf_append(&buf, *s);
265
+ break;
266
+ }
267
+ pi->cur = s;
268
+ oj_set_error_at(pi,
269
+ oj_parse_error_class,
270
+ __FILE__,
271
+ __LINE__,
272
+ "invalid escaped character");
273
+ buf_cleanup(&buf);
274
+ return;
275
+ }
276
+ } else {
277
+ buf_append(&buf, *s);
278
+ }
287
279
  }
288
280
  if (0 == parent) {
289
- pi->add_cstr(pi, buf.head, buf_len(&buf), start);
281
+ pi->add_cstr(pi, buf.head, buf_len(&buf), start);
290
282
  } else {
291
- switch (parent->next) {
292
- case NEXT_ARRAY_NEW:
293
- case NEXT_ARRAY_ELEMENT:
294
- pi->array_append_cstr(pi, buf.head, buf_len(&buf), start);
295
- parent->next = NEXT_ARRAY_COMMA;
296
- break;
297
- case NEXT_HASH_NEW:
298
- case NEXT_HASH_KEY:
299
- if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
300
- parent->key = strdup(buf.head);
301
- parent->klen = buf_len(&buf);
302
- } else {
303
- parent->key = "";
304
- parent->klen = 0;
305
- }
306
- parent->k1 = *start;
307
- parent->next = NEXT_HASH_COLON;
308
- break;
309
- case NEXT_HASH_VALUE:
310
- pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
311
- if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
312
- xfree((char*)parent->key);
313
- parent->key = 0;
314
- }
315
- parent->next = NEXT_HASH_COMMA;
316
- break;
317
- case NEXT_HASH_COMMA:
318
- case NEXT_NONE:
319
- case NEXT_ARRAY_COMMA:
320
- case NEXT_HASH_COLON:
321
- default:
322
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
323
- break;
324
- }
283
+ switch (parent->next) {
284
+ case NEXT_ARRAY_NEW:
285
+ case NEXT_ARRAY_ELEMENT:
286
+ pi->array_append_cstr(pi, buf.head, buf_len(&buf), start);
287
+ parent->next = NEXT_ARRAY_COMMA;
288
+ break;
289
+ case NEXT_HASH_NEW:
290
+ case NEXT_HASH_KEY:
291
+ if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
292
+ parent->klen = buf_len(&buf);
293
+ parent->key = malloc(parent->klen + 1);
294
+ memcpy((char *)parent->key, buf.head, parent->klen);
295
+ *(char *)(parent->key + parent->klen) = '\0';
296
+ } else {
297
+ parent->key = "";
298
+ parent->klen = 0;
299
+ }
300
+ parent->k1 = *start;
301
+ parent->next = NEXT_HASH_COLON;
302
+ break;
303
+ case NEXT_HASH_VALUE:
304
+ pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
305
+ if (0 != parent->key && 0 < parent->klen &&
306
+ (parent->key < pi->json || pi->cur < parent->key)) {
307
+ xfree((char *)parent->key);
308
+ parent->key = 0;
309
+ }
310
+ parent->next = NEXT_HASH_COMMA;
311
+ break;
312
+ case NEXT_HASH_COMMA:
313
+ case NEXT_NONE:
314
+ case NEXT_ARRAY_COMMA:
315
+ case NEXT_HASH_COLON:
316
+ default:
317
+ oj_set_error_at(pi,
318
+ oj_parse_error_class,
319
+ __FILE__,
320
+ __LINE__,
321
+ "expected %s, not a string",
322
+ oj_stack_next_string(parent->next));
323
+ break;
324
+ }
325
325
  }
326
326
  pi->cur = s + 1;
327
327
  buf_cleanup(&buf);
328
328
  }
329
329
 
330
- static void
331
- read_str(ParseInfo pi) {
332
- const char *str = pi->cur;
333
- Val parent = stack_peek(&pi->stack);
330
+ static void read_str(ParseInfo pi) {
331
+ const char *str = pi->cur;
332
+ Val parent = stack_peek(&pi->stack);
334
333
 
335
334
  for (; '"' != *pi->cur; pi->cur++) {
336
- if (pi->end <= pi->cur) {
337
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
338
- return;
339
- } else if ('\0' == *pi->cur) {
340
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
341
- return;
342
- } else if ('\\' == *pi->cur) {
343
- read_escaped_str(pi, str);
344
- return;
345
- }
335
+ if (pi->end <= pi->cur) {
336
+ oj_set_error_at(pi,
337
+ oj_parse_error_class,
338
+ __FILE__,
339
+ __LINE__,
340
+ "quoted string not terminated");
341
+ return;
342
+ } else if ('\0' == *pi->cur) {
343
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
344
+ return;
345
+ } else if ('\\' == *pi->cur) {
346
+ read_escaped_str(pi, str);
347
+ return;
348
+ }
346
349
  }
347
- if (0 == parent) { // simple add
348
- pi->add_cstr(pi, str, pi->cur - str, str);
350
+ if (0 == parent) { // simple add
351
+ pi->add_cstr(pi, str, pi->cur - str, str);
349
352
  } else {
350
- switch (parent->next) {
351
- case NEXT_ARRAY_NEW:
352
- case NEXT_ARRAY_ELEMENT:
353
- pi->array_append_cstr(pi, str, pi->cur - str, str);
354
- parent->next = NEXT_ARRAY_COMMA;
355
- break;
356
- case NEXT_HASH_NEW:
357
- case NEXT_HASH_KEY:
358
- if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) {
359
- parent->key = str;
360
- parent->klen = pi->cur - str;
361
- } else {
362
- parent->key = "";
363
- parent->klen = 0;
364
- }
365
- parent->k1 = *str;
366
- parent->next = NEXT_HASH_COLON;
367
- break;
368
- case NEXT_HASH_VALUE:
369
- pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
370
- if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
371
- xfree((char*)parent->key);
372
- parent->key = 0;
373
- }
374
- parent->next = NEXT_HASH_COMMA;
375
- break;
376
- case NEXT_HASH_COMMA:
377
- case NEXT_NONE:
378
- case NEXT_ARRAY_COMMA:
379
- case NEXT_HASH_COLON:
380
- default:
381
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
382
- break;
383
- }
353
+ switch (parent->next) {
354
+ case NEXT_ARRAY_NEW:
355
+ case NEXT_ARRAY_ELEMENT:
356
+ pi->array_append_cstr(pi, str, pi->cur - str, str);
357
+ parent->next = NEXT_ARRAY_COMMA;
358
+ break;
359
+ case NEXT_HASH_NEW:
360
+ case NEXT_HASH_KEY:
361
+ if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) {
362
+ parent->key = str;
363
+ parent->klen = pi->cur - str;
364
+ } else {
365
+ parent->key = "";
366
+ parent->klen = 0;
367
+ }
368
+ parent->k1 = *str;
369
+ parent->next = NEXT_HASH_COLON;
370
+ break;
371
+ case NEXT_HASH_VALUE:
372
+ pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
373
+ if (0 != parent->key && 0 < parent->klen &&
374
+ (parent->key < pi->json || pi->cur < parent->key)) {
375
+ xfree((char *)parent->key);
376
+ parent->key = 0;
377
+ }
378
+ parent->next = NEXT_HASH_COMMA;
379
+ break;
380
+ case NEXT_HASH_COMMA:
381
+ case NEXT_NONE:
382
+ case NEXT_ARRAY_COMMA:
383
+ case NEXT_HASH_COLON:
384
+ default:
385
+ oj_set_error_at(pi,
386
+ oj_parse_error_class,
387
+ __FILE__,
388
+ __LINE__,
389
+ "expected %s, not a string",
390
+ oj_stack_next_string(parent->next));
391
+ break;
392
+ }
384
393
  }
385
- pi->cur++; // move past "
394
+ pi->cur++; // move past "
386
395
  }
387
396
 
388
- static void
389
- read_num(ParseInfo pi) {
390
- struct _NumInfo ni;
391
- Val parent = stack_peek(&pi->stack);
392
-
393
- ni.str = pi->cur;
394
- ni.i = 0;
395
- ni.num = 0;
396
- ni.div = 1;
397
- ni.di = 0;
398
- ni.len = 0;
399
- ni.exp = 0;
400
- ni.big = 0;
397
+ static void read_num(ParseInfo pi) {
398
+ struct _numInfo ni;
399
+ Val parent = stack_peek(&pi->stack);
400
+
401
+ ni.str = pi->cur;
402
+ ni.i = 0;
403
+ ni.num = 0;
404
+ ni.div = 1;
405
+ ni.di = 0;
406
+ ni.len = 0;
407
+ ni.exp = 0;
408
+ ni.big = 0;
401
409
  ni.infinity = 0;
402
- ni.nan = 0;
403
- ni.neg = 0;
404
- ni.hasExp = 0;
405
- ni.no_big = (FloatDec == pi->options.bigdec_load);
410
+ ni.nan = 0;
411
+ ni.neg = 0;
412
+ ni.has_exp = 0;
413
+ if (CompatMode == pi->options.mode) {
414
+ ni.no_big = !pi->options.compat_bigdec;
415
+ ni.bigdec_load = pi->options.compat_bigdec;
416
+ } else {
417
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
418
+ RubyDec == pi->options.bigdec_load);
419
+ ni.bigdec_load = pi->options.bigdec_load;
420
+ }
406
421
 
407
422
  if ('-' == *pi->cur) {
408
- pi->cur++;
409
- ni.neg = 1;
423
+ pi->cur++;
424
+ ni.neg = 1;
410
425
  } else if ('+' == *pi->cur) {
411
- pi->cur++;
426
+ if (StrictMode == pi->options.mode) {
427
+ oj_set_error_at(pi,
428
+ oj_parse_error_class,
429
+ __FILE__,
430
+ __LINE__,
431
+ "not a number or other value");
432
+ return;
433
+ }
434
+ pi->cur++;
412
435
  }
413
436
  if ('I' == *pi->cur) {
414
- if (0 != strncmp("Infinity", pi->cur, 8)) {
415
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
416
- return;
417
- }
418
- pi->cur += 8;
419
- ni.infinity = 1;
437
+ if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
438
+ oj_set_error_at(pi,
439
+ oj_parse_error_class,
440
+ __FILE__,
441
+ __LINE__,
442
+ "not a number or other value");
443
+ return;
444
+ }
445
+ pi->cur += 8;
446
+ ni.infinity = 1;
420
447
  } else if ('N' == *pi->cur || 'n' == *pi->cur) {
421
- if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
422
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
423
- return;
424
- }
425
- pi->cur += 3;
426
- ni.nan = 1;
448
+ if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
449
+ oj_set_error_at(pi,
450
+ oj_parse_error_class,
451
+ __FILE__,
452
+ __LINE__,
453
+ "not a number or other value");
454
+ return;
455
+ }
456
+ pi->cur += 3;
457
+ ni.nan = 1;
427
458
  } else {
428
- int dec_cnt = 0;
429
-
430
- for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
431
- if (0 < ni.i) {
432
- dec_cnt++;
433
- }
434
- if (!ni.big) {
435
- int d = (*pi->cur - '0');
436
-
437
- ni.i = ni.i * 10 + d;
438
- if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
439
- ni.big = 1;
440
- }
441
- }
442
- }
443
- if ('.' == *pi->cur) {
444
- pi->cur++;
445
- for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
446
- int d = (*pi->cur - '0');
447
-
448
- if (0 < ni.num || 0 < ni.i) {
449
- dec_cnt++;
450
- }
451
- ni.num = ni.num * 10 + d;
452
- ni.div *= 10;
453
- ni.di++;
454
- if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
455
- ni.big = 1;
456
- }
457
- }
458
- }
459
- if ('e' == *pi->cur || 'E' == *pi->cur) {
460
- int eneg = 0;
461
-
462
- ni.hasExp = 1;
463
- pi->cur++;
464
- if ('-' == *pi->cur) {
465
- pi->cur++;
466
- eneg = 1;
467
- } else if ('+' == *pi->cur) {
468
- pi->cur++;
469
- }
470
- for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
471
- ni.exp = ni.exp * 10 + (*pi->cur - '0');
472
- if (EXP_MAX <= ni.exp) {
473
- ni.big = 1;
474
- }
475
- }
476
- if (eneg) {
477
- ni.exp = -ni.exp;
478
- }
479
- }
480
- ni.len = pi->cur - ni.str;
459
+ int dec_cnt = 0;
460
+ bool zero1 = false;
461
+
462
+ for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
463
+ if (0 == ni.i && '0' == *pi->cur) {
464
+ zero1 = true;
465
+ }
466
+ if (0 < ni.i) {
467
+ dec_cnt++;
468
+ }
469
+ if (!ni.big) {
470
+ int d = (*pi->cur - '0');
471
+
472
+ if (0 < d) {
473
+ if (zero1 && CompatMode == pi->options.mode) {
474
+ oj_set_error_at(pi,
475
+ oj_parse_error_class,
476
+ __FILE__,
477
+ __LINE__,
478
+ "not a number");
479
+ return;
480
+ }
481
+ zero1 = false;
482
+ }
483
+ ni.i = ni.i * 10 + d;
484
+ if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
485
+ ni.big = 1;
486
+ }
487
+ }
488
+ }
489
+ if ('.' == *pi->cur) {
490
+ pi->cur++;
491
+ // A trailing . is not a valid decimal but if encountered allow it
492
+ // except when mimicking the JSON gem or in strict mode.
493
+ if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
494
+ int pos = (int)(pi->cur - ni.str);
495
+
496
+ if (1 == pos || (2 == pos && ni.neg)) {
497
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
498
+ return;
499
+ }
500
+ if (*pi->cur < '0' || '9' < *pi->cur) {
501
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
502
+ return;
503
+ }
504
+ }
505
+ for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
506
+ int d = (*pi->cur - '0');
507
+
508
+ if (0 < ni.num || 0 < ni.i) {
509
+ dec_cnt++;
510
+ }
511
+ if (INT64_MAX <= ni.div) {
512
+ if (!ni.no_big) {
513
+ ni.big = true;
514
+ }
515
+ } else {
516
+ ni.num = ni.num * 10 + d;
517
+ ni.div *= 10;
518
+ ni.di++;
519
+ if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
520
+ if (!ni.no_big) {
521
+ ni.big = true;
522
+ }
523
+ }
524
+ }
525
+ }
526
+ }
527
+ if ('e' == *pi->cur || 'E' == *pi->cur) {
528
+ int eneg = 0;
529
+
530
+ ni.has_exp = 1;
531
+ pi->cur++;
532
+ if ('-' == *pi->cur) {
533
+ pi->cur++;
534
+ eneg = 1;
535
+ } else if ('+' == *pi->cur) {
536
+ pi->cur++;
537
+ }
538
+ for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
539
+ ni.exp = ni.exp * 10 + (*pi->cur - '0');
540
+ if (EXP_MAX <= ni.exp) {
541
+ ni.big = true;
542
+ }
543
+ }
544
+ if (eneg) {
545
+ ni.exp = -ni.exp;
546
+ }
547
+ }
548
+ ni.len = pi->cur - ni.str;
481
549
  }
482
550
  // Check for special reserved values for Infinity and NaN.
483
551
  if (ni.big) {
484
- if (0 == strcasecmp(INF_VAL, ni.str)) {
485
- ni.infinity = 1;
486
- } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
487
- ni.infinity = 1;
488
- ni.neg = 1;
489
- } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
490
- ni.nan = 1;
491
- }
552
+ if (0 == strcasecmp(INF_VAL, ni.str)) {
553
+ ni.infinity = 1;
554
+ } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
555
+ ni.infinity = 1;
556
+ ni.neg = 1;
557
+ } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
558
+ ni.nan = 1;
559
+ }
492
560
  }
493
- if (BigDec == pi->options.bigdec_load) {
494
- ni.big = 1;
561
+ if (CompatMode == pi->options.mode) {
562
+ if (pi->options.compat_bigdec) {
563
+ ni.big = 1;
564
+ }
565
+ } else if (BigDec == pi->options.bigdec_load) {
566
+ ni.big = 1;
495
567
  }
496
568
  if (0 == parent) {
497
- pi->add_num(pi, &ni);
569
+ pi->add_num(pi, &ni);
498
570
  } else {
499
- switch (parent->next) {
500
- case NEXT_ARRAY_NEW:
501
- case NEXT_ARRAY_ELEMENT:
502
- pi->array_append_num(pi, &ni);
503
- parent->next = NEXT_ARRAY_COMMA;
504
- break;
505
- case NEXT_HASH_VALUE:
506
- pi->hash_set_num(pi, parent, &ni);
507
- if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
508
- xfree((char*)parent->key);
509
- parent->key = 0;
510
- }
511
- parent->next = NEXT_HASH_COMMA;
512
- break;
513
- default:
514
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
515
- break;
516
- }
571
+ switch (parent->next) {
572
+ case NEXT_ARRAY_NEW:
573
+ case NEXT_ARRAY_ELEMENT:
574
+ pi->array_append_num(pi, &ni);
575
+ parent->next = NEXT_ARRAY_COMMA;
576
+ break;
577
+ case NEXT_HASH_VALUE:
578
+ pi->hash_set_num(pi, parent, &ni);
579
+ if (0 != parent->key && 0 < parent->klen &&
580
+ (parent->key < pi->json || pi->cur < parent->key)) {
581
+ xfree((char *)parent->key);
582
+ parent->key = 0;
583
+ }
584
+ parent->next = NEXT_HASH_COMMA;
585
+ break;
586
+ default:
587
+ oj_set_error_at(pi,
588
+ oj_parse_error_class,
589
+ __FILE__,
590
+ __LINE__,
591
+ "expected %s",
592
+ oj_stack_next_string(parent->next));
593
+ break;
594
+ }
517
595
  }
518
596
  }
519
597
 
520
- static void
521
- array_start(ParseInfo pi) {
522
- volatile VALUE v = pi->start_array(pi);
598
+ static void array_start(ParseInfo pi) {
599
+ volatile VALUE v = pi->start_array(pi);
523
600
 
524
601
  stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
525
602
  }
526
603
 
527
- static void
528
- array_end(ParseInfo pi) {
529
- Val array = stack_pop(&pi->stack);
604
+ static void array_end(ParseInfo pi) {
605
+ Val array = stack_pop(&pi->stack);
530
606
 
531
607
  if (0 == array) {
532
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
608
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
533
609
  } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
534
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next));
610
+ oj_set_error_at(pi,
611
+ oj_parse_error_class,
612
+ __FILE__,
613
+ __LINE__,
614
+ "expected %s, not an array close",
615
+ oj_stack_next_string(array->next));
535
616
  } else {
536
- pi->end_array(pi);
537
- add_value(pi, array->val);
617
+ pi->end_array(pi);
618
+ add_value(pi, array->val);
538
619
  }
539
620
  }
540
621
 
541
- static void
542
- hash_start(ParseInfo pi) {
543
- volatile VALUE v = pi->start_hash(pi);
622
+ static void hash_start(ParseInfo pi) {
623
+ volatile VALUE v = pi->start_hash(pi);
544
624
 
545
625
  stack_push(&pi->stack, v, NEXT_HASH_NEW);
546
626
  }
547
627
 
548
- static void
549
- hash_end(ParseInfo pi) {
550
- volatile Val hash = stack_peek(&pi->stack);
628
+ static void hash_end(ParseInfo pi) {
629
+ volatile Val hash = stack_peek(&pi->stack);
551
630
 
552
631
  // leave hash on stack until just before
553
632
  if (0 == hash) {
554
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
633
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
555
634
  } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
556
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next));
635
+ oj_set_error_at(pi,
636
+ oj_parse_error_class,
637
+ __FILE__,
638
+ __LINE__,
639
+ "expected %s, not a hash close",
640
+ oj_stack_next_string(hash->next));
557
641
  } else {
558
- pi->end_hash(pi);
559
- stack_pop(&pi->stack);
560
- add_value(pi, hash->val);
642
+ pi->end_hash(pi);
643
+ stack_pop(&pi->stack);
644
+ add_value(pi, hash->val);
561
645
  }
562
646
  }
563
647
 
564
- static void
565
- comma(ParseInfo pi) {
566
- Val parent = stack_peek(&pi->stack);
648
+ static void comma(ParseInfo pi) {
649
+ Val parent = stack_peek(&pi->stack);
567
650
 
568
651
  if (0 == parent) {
569
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
652
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
570
653
  } else if (NEXT_ARRAY_COMMA == parent->next) {
571
- parent->next = NEXT_ARRAY_ELEMENT;
654
+ parent->next = NEXT_ARRAY_ELEMENT;
572
655
  } else if (NEXT_HASH_COMMA == parent->next) {
573
- parent->next = NEXT_HASH_KEY;
656
+ parent->next = NEXT_HASH_KEY;
574
657
  } else {
575
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
658
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
576
659
  }
577
660
  }
578
661
 
579
- static void
580
- colon(ParseInfo pi) {
581
- Val parent = stack_peek(&pi->stack);
662
+ static void colon(ParseInfo pi) {
663
+ Val parent = stack_peek(&pi->stack);
582
664
 
583
665
  if (0 != parent && NEXT_HASH_COLON == parent->next) {
584
- parent->next = NEXT_HASH_VALUE;
666
+ parent->next = NEXT_HASH_VALUE;
585
667
  } else {
586
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
668
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
587
669
  }
588
670
  }
589
671
 
590
- void
591
- oj_parse2(ParseInfo pi) {
592
- int first = 1;
672
+ void oj_parse2(ParseInfo pi) {
673
+ int first = 1;
674
+ long start = 0;
593
675
 
594
676
  pi->cur = pi->json;
595
677
  err_init(&pi->err);
596
678
  while (1) {
597
- next_non_white(pi);
598
- if (!first && '\0' != *pi->cur) {
599
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document");
600
- }
601
- switch (*pi->cur++) {
602
- case '{':
603
- hash_start(pi);
604
- break;
605
- case '}':
606
- hash_end(pi);
607
- break;
608
- case ':':
609
- colon(pi);
610
- break;
611
- case '[':
612
- array_start(pi);
613
- break;
614
- case ']':
615
- array_end(pi);
616
- break;
617
- case ',':
618
- comma(pi);
619
- break;
620
- case '"':
621
- read_str(pi);
622
- break;
623
- case '+':
624
- case '-':
625
- case '0':
626
- case '1':
627
- case '2':
628
- case '3':
629
- case '4':
630
- case '5':
631
- case '6':
632
- case '7':
633
- case '8':
634
- case '9':
635
- case 'I':
636
- case 'N':
637
- pi->cur--;
638
- read_num(pi);
639
- break;
640
- case 't':
641
- read_true(pi);
642
- break;
643
- case 'f':
644
- read_false(pi);
645
- break;
646
- case 'n':
647
- if ('u' == *pi->cur) {
648
- read_null(pi);
649
- } else {
650
- pi->cur--;
651
- read_num(pi);
652
- }
653
- break;
654
- case '/':
655
- skip_comment(pi);
656
- if (first) {
657
- continue;
658
- }
659
- break;
660
- case '\0':
661
- pi->cur--;
662
- return;
663
- default:
664
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
665
- return;
666
- }
667
- if (err_has(&pi->err)) {
668
- return;
669
- }
670
- if (stack_empty(&pi->stack)) {
671
- if (Qundef != pi->proc) {
672
- if (Qnil == pi->proc) {
673
- rb_yield(stack_head_val(&pi->stack));
674
- } else {
675
- #if HAS_PROC_WITH_BLOCK
676
- VALUE args[1];
677
-
678
- *args = stack_head_val(&pi->stack);
679
- rb_proc_call_with_block(pi->proc, 1, args, Qnil);
680
- #else
681
- rb_raise(rb_eNotImpError,
682
- "Calling a Proc with a block not supported in this version. Use func() {|x| } syntax instead.");
683
- #endif
684
- }
685
- } else {
686
- first = 0;
687
- }
688
- }
679
+ if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
680
+ VALUE err_clas = oj_get_json_err_class("NestingError");
681
+
682
+ oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
683
+ pi->err_class = err_clas;
684
+ return;
685
+ }
686
+ next_non_white(pi);
687
+ if (!first && '\0' != *pi->cur) {
688
+ oj_set_error_at(pi,
689
+ oj_parse_error_class,
690
+ __FILE__,
691
+ __LINE__,
692
+ "unexpected characters after the JSON document");
693
+ }
694
+
695
+ // If no tokens are consumed (i.e. empty string), throw a parse error
696
+ // this is the behavior of JSON.parse in both Ruby and JS.
697
+ if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) {
698
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
699
+ }
700
+
701
+ switch (*pi->cur++) {
702
+ case '{': hash_start(pi); break;
703
+ case '}': hash_end(pi); break;
704
+ case ':': colon(pi); break;
705
+ case '[': array_start(pi); break;
706
+ case ']': array_end(pi); break;
707
+ case ',': comma(pi); break;
708
+ case '"':
709
+ read_str(pi);
710
+ break;
711
+ // case '+':
712
+ case '+':
713
+ if (CompatMode == pi->options.mode) {
714
+ oj_set_error_at(pi,
715
+ oj_parse_error_class,
716
+ __FILE__,
717
+ __LINE__,
718
+ "unexpected character");
719
+ return;
720
+ }
721
+ pi->cur--;
722
+ read_num(pi);
723
+ break;
724
+ case '-':
725
+ case '0':
726
+ case '1':
727
+ case '2':
728
+ case '3':
729
+ case '4':
730
+ case '5':
731
+ case '6':
732
+ case '7':
733
+ case '8':
734
+ case '9':
735
+ pi->cur--;
736
+ read_num(pi);
737
+ break;
738
+ case 'I':
739
+ case 'N':
740
+ if (Yes == pi->options.allow_nan) {
741
+ pi->cur--;
742
+ read_num(pi);
743
+ } else {
744
+ oj_set_error_at(pi,
745
+ oj_parse_error_class,
746
+ __FILE__,
747
+ __LINE__,
748
+ "unexpected character");
749
+ }
750
+ break;
751
+ case 't': read_true(pi); break;
752
+ case 'f': read_false(pi); break;
753
+ case 'n':
754
+ if ('u' == *pi->cur) {
755
+ read_null(pi);
756
+ } else {
757
+ pi->cur--;
758
+ read_num(pi);
759
+ }
760
+ break;
761
+ case '/':
762
+ skip_comment(pi);
763
+ if (first) {
764
+ continue;
765
+ }
766
+ break;
767
+ case '\0': pi->cur--; return;
768
+ default:
769
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
770
+ return;
771
+ }
772
+ if (err_has(&pi->err)) {
773
+ return;
774
+ }
775
+ if (stack_empty(&pi->stack)) {
776
+ if (Qundef != pi->proc) {
777
+ VALUE args[3];
778
+ long len = (pi->cur - pi->json) - start;
779
+
780
+ *args = stack_head_val(&pi->stack);
781
+ args[1] = LONG2NUM(start);
782
+ args[2] = LONG2NUM(len);
783
+
784
+ if (Qnil == pi->proc) {
785
+ rb_yield_values2(3, args);
786
+ } else {
787
+ rb_proc_call_with_block(pi->proc, 3, args, Qnil);
788
+ }
789
+ } else if (!pi->has_callbacks) {
790
+ first = 0;
791
+ }
792
+ start = pi->cur - pi->json;
793
+ }
689
794
  }
690
795
  }
691
796
 
797
+ static VALUE rescue_big_decimal(VALUE str, VALUE ignore) {
798
+ rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
799
+ return Qnil;
800
+ }
801
+
802
+ static VALUE parse_big_decimal(VALUE str) {
803
+ return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
804
+ }
805
+
806
+ static long double exp_plus[] = {
807
+ 1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
808
+ 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
809
+ 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29,
810
+ 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39,
811
+ 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
812
+ };
813
+
692
814
  VALUE
693
815
  oj_num_as_value(NumInfo ni) {
694
- volatile VALUE rnum = Qnil;
816
+ volatile VALUE rnum = Qnil;
695
817
 
696
818
  if (ni->infinity) {
697
- if (ni->neg) {
698
- rnum = rb_float_new(-OJ_INFINITY);
699
- } else {
700
- rnum = rb_float_new(OJ_INFINITY);
701
- }
819
+ if (ni->neg) {
820
+ rnum = rb_float_new(-OJ_INFINITY);
821
+ } else {
822
+ rnum = rb_float_new(OJ_INFINITY);
823
+ }
702
824
  } else if (ni->nan) {
703
- rnum = rb_float_new(0.0/0.0);
704
- } else if (1 == ni->div && 0 == ni->exp) { // fixnum
705
- if (ni->big) {
706
- if (256 > ni->len) {
707
- char buf[256];
708
-
709
- memcpy(buf, ni->str, ni->len);
710
- buf[ni->len] = '\0';
711
- rnum = rb_cstr_to_inum(buf, 10, 0);
712
- } else {
713
- char *buf = ALLOC_N(char, ni->len + 1);
714
-
715
- memcpy(buf, ni->str, ni->len);
716
- buf[ni->len] = '\0';
717
- rnum = rb_cstr_to_inum(buf, 10, 0);
718
- xfree(buf);
719
- }
720
- } else {
721
- if (ni->neg) {
722
- rnum = rb_ll2inum(-ni->i);
723
- } else {
724
- rnum = rb_ll2inum(ni->i);
725
- }
726
- }
727
- } else { // decimal
728
- if (ni->big) {
729
- rnum = rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new(ni->str, ni->len));
730
- if (ni->no_big) {
731
- rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
732
- }
733
- } else {
734
- // All these machinations are to get rounding to work better.
735
- long double d = (long double)ni->i * (long double)ni->div + (long double)ni->num;
736
- int x = ni->exp - ni->di;
737
-
738
- // Rounding sometimes cuts off the last digit even if there are only
739
- // 15 digits. This attempts to fix those few cases where this
740
- // occurs.
741
- if ((long double)INT64_MAX > d && (int64_t)d != (ni->i * ni->div + ni->num)) {
742
- rnum = rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new(ni->str, ni->len));
743
- if (ni->no_big) {
744
- rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
745
- }
746
- } else {
747
- d = roundl(d);
748
- if (0 < x) {
749
- d *= powl(10.0L, x);
750
- } else if (0 > x) {
751
- d /= powl(10.0L, -x);
752
- }
753
- if (ni->neg) {
754
- d = -d;
755
- }
756
- rnum = rb_float_new((double)d);
757
- }
758
- }
825
+ rnum = rb_float_new(0.0 / 0.0);
826
+ } else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum
827
+ if (ni->big) {
828
+ if (256 > ni->len) {
829
+ char buf[256];
830
+
831
+ memcpy(buf, ni->str, ni->len);
832
+ buf[ni->len] = '\0';
833
+ rnum = rb_cstr_to_inum(buf, 10, 0);
834
+ } else {
835
+ char *buf = ALLOC_N(char, ni->len + 1);
836
+
837
+ memcpy(buf, ni->str, ni->len);
838
+ buf[ni->len] = '\0';
839
+ rnum = rb_cstr_to_inum(buf, 10, 0);
840
+ xfree(buf);
841
+ }
842
+ } else {
843
+ if (ni->neg) {
844
+ rnum = rb_ll2inum(-ni->i);
845
+ } else {
846
+ rnum = rb_ll2inum(ni->i);
847
+ }
848
+ }
849
+ } else { // decimal
850
+ if (ni->big) {
851
+ volatile VALUE bd = rb_str_new(ni->str, ni->len);
852
+
853
+ rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
854
+ if (ni->no_big) {
855
+ rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
856
+ }
857
+ } else if (FastDec == ni->bigdec_load) {
858
+ long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
859
+ int x = (int)((int64_t)ni->exp - ni->di);
860
+
861
+ if (0 < x) {
862
+ if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
863
+ ld *= exp_plus[x];
864
+ } else {
865
+ ld *= powl(10.0, x);
866
+ }
867
+ } else if (x < 0) {
868
+ if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
869
+ ld /= exp_plus[-x];
870
+ } else {
871
+ ld /= powl(10.0, -x);
872
+ }
873
+ }
874
+ if (ni->neg) {
875
+ ld = -ld;
876
+ }
877
+ rnum = rb_float_new((double)ld);
878
+ } else if (RubyDec == ni->bigdec_load) {
879
+ volatile VALUE sv = rb_str_new(ni->str, ni->len);
880
+
881
+ rnum = rb_funcall(sv, rb_intern("to_f"), 0);
882
+ } else {
883
+ char * end;
884
+ double d = strtod(ni->str, &end);
885
+
886
+ if ((long)ni->len != (long)(end - ni->str)) {
887
+ rb_raise(oj_parse_error_class, "Invalid float");
888
+ }
889
+ rnum = rb_float_new(d);
890
+ }
759
891
  }
760
892
  return rnum;
761
893
  }
762
894
 
763
- void
764
- oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...) {
765
- va_list ap;
766
- char msg[128];
895
+ void oj_set_error_at(ParseInfo pi,
896
+ VALUE err_clas,
897
+ const char *file,
898
+ int line,
899
+ const char *format,
900
+ ...) {
901
+ va_list ap;
902
+ char msg[256];
903
+ char * p = msg;
904
+ char * end = p + sizeof(msg) - 2;
905
+ char * start;
906
+ Val vp;
907
+ int mlen;
767
908
 
768
909
  va_start(ap, format);
769
- vsnprintf(msg, sizeof(msg) - 1, format, ap);
910
+ mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
911
+ if (0 < mlen) {
912
+ if (sizeof(msg) - 2 < (size_t)mlen) {
913
+ p = end - 2;
914
+ } else {
915
+ p += mlen;
916
+ }
917
+ }
770
918
  va_end(ap);
771
919
  pi->err.clas = err_clas;
920
+ if (p + 3 < end) {
921
+ *p++ = ' ';
922
+ *p++ = '(';
923
+ *p++ = 'a';
924
+ *p++ = 'f';
925
+ *p++ = 't';
926
+ *p++ = 'e';
927
+ *p++ = 'r';
928
+ *p++ = ' ';
929
+ start = p;
930
+ for (vp = pi->stack.head; vp < pi->stack.tail; vp++) {
931
+ if (end <= p + 1 + vp->klen) {
932
+ break;
933
+ }
934
+ if (NULL != vp->key) {
935
+ if (start < p) {
936
+ *p++ = '.';
937
+ }
938
+ memcpy(p, vp->key, vp->klen);
939
+ p += vp->klen;
940
+ } else {
941
+ if (RUBY_T_ARRAY == rb_type(vp->val)) {
942
+ if (end <= p + 12) {
943
+ break;
944
+ }
945
+ p += snprintf(p, end - p, "[%ld]", RARRAY_LEN(vp->val));
946
+ }
947
+ }
948
+ }
949
+ *p++ = ')';
950
+ }
951
+ *p = '\0';
772
952
  if (0 == pi->json) {
773
- oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line);
953
+ oj_err_set(&pi->err,
954
+ err_clas,
955
+ "%s at line %d, column %d [%s:%d]",
956
+ msg,
957
+ pi->rd.line,
958
+ pi->rd.col,
959
+ file,
960
+ line);
774
961
  } else {
775
- _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
962
+ _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
776
963
  }
777
964
  }
778
965
 
779
- static VALUE
780
- protect_parse(VALUE pip) {
966
+ static VALUE protect_parse(VALUE pip) {
781
967
  oj_parse2((ParseInfo)pip);
782
968
 
783
969
  return Qnil;
@@ -785,91 +971,103 @@ protect_parse(VALUE pip) {
785
971
 
786
972
  extern int oj_utf8_index;
787
973
 
788
- static void
789
- oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
790
- #if HAS_ENCODING_SUPPORT
791
- rb_encoding *enc = rb_to_encoding(rb_obj_encoding(*inputp));
974
+ static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
975
+ int idx = RB_ENCODING_GET(*inputp);
792
976
 
793
- if (rb_utf8_encoding() != enc) {
794
- *inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding());
977
+ if (oj_utf8_encoding_index != idx) {
978
+ rb_encoding *enc = rb_enc_from_index(idx);
979
+ *inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
795
980
  }
796
- #endif
797
- pi->json = rb_string_value_ptr((VALUE*)inputp);
798
- pi->end = pi->json + RSTRING_LEN(*inputp);
981
+ pi->json = RSTRING_PTR(*inputp);
982
+ pi->end = pi->json + RSTRING_LEN(*inputp);
799
983
  }
800
984
 
801
985
  VALUE
802
986
  oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
803
- char *buf = 0;
804
- volatile VALUE input;
805
- volatile VALUE wrapped_stack;
806
- volatile VALUE result = Qnil;
807
- int line = 0;
808
- int free_json = 0;
987
+ char * buf = 0;
988
+ volatile VALUE input;
989
+ volatile VALUE wrapped_stack;
990
+ volatile VALUE result = Qnil;
991
+ int line = 0;
992
+ int free_json = 0;
809
993
 
810
994
  if (argc < 1) {
811
- rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
995
+ rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
812
996
  }
813
997
  input = argv[0];
814
- if (2 == argc) {
815
- oj_parse_options(argv[1], &pi->options);
998
+ if (2 <= argc) {
999
+ if (T_HASH == rb_type(argv[1])) {
1000
+ oj_parse_options(argv[1], &pi->options);
1001
+ } else if (3 <= argc && T_HASH == rb_type(argv[2])) {
1002
+ oj_parse_options(argv[2], &pi->options);
1003
+ }
816
1004
  }
817
1005
  if (yieldOk && rb_block_given_p()) {
818
- pi->proc = Qnil;
1006
+ pi->proc = Qnil;
819
1007
  } else {
820
- pi->proc = Qundef;
1008
+ pi->proc = Qundef;
821
1009
  }
822
1010
  if (0 != json) {
823
- pi->json = json;
824
- pi->end = json + len;
825
- free_json = 1;
1011
+ pi->json = json;
1012
+ pi->end = json + len;
1013
+ free_json = 1;
826
1014
  } else if (T_STRING == rb_type(input)) {
827
- oj_pi_set_input_str(pi, &input);
828
- } else if (Qnil == input && Yes == pi->options.nilnil) {
829
- return Qnil;
1015
+ if (CompatMode == pi->options.mode) {
1016
+ if (No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
1017
+ rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
1018
+ }
1019
+ }
1020
+ oj_pi_set_input_str(pi, &input);
1021
+ } else if (Qnil == input) {
1022
+ if (Yes == pi->options.nilnil) {
1023
+ return Qnil;
1024
+ } else {
1025
+ rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
1026
+ }
830
1027
  } else {
831
- VALUE clas = rb_obj_class(input);
832
- volatile VALUE s;
1028
+ VALUE clas = rb_obj_class(input);
1029
+ volatile VALUE s;
833
1030
 
834
- if (oj_stringio_class == clas) {
835
- s = rb_funcall2(input, oj_string_id, 0, 0);
836
- oj_pi_set_input_str(pi, &s);
1031
+ if (oj_stringio_class == clas) {
1032
+ s = rb_funcall2(input, oj_string_id, 0, 0);
1033
+ oj_pi_set_input_str(pi, &s);
837
1034
  #if !IS_WINDOWS
838
- } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
839
- int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
840
- ssize_t cnt;
841
- size_t len = lseek(fd, 0, SEEK_END);
842
-
843
- lseek(fd, 0, SEEK_SET);
844
- buf = ALLOC_N(char, len + 1);
845
- pi->json = buf;
846
- pi->end = buf + len;
847
- if (0 >= (cnt = read(fd, (char*)pi->json, len)) || cnt != (ssize_t)len) {
848
- if (0 != buf) {
849
- xfree(buf);
850
- }
851
- rb_raise(rb_eIOError, "failed to read from IO Object.");
852
- }
853
- ((char*)pi->json)[len] = '\0';
854
- /* skip UTF-8 BOM if present */
855
- if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
856
- pi->json += 3;
857
- }
1035
+ } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
1036
+ int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
1037
+ ssize_t cnt;
1038
+ size_t len = lseek(fd, 0, SEEK_END);
1039
+
1040
+ lseek(fd, 0, SEEK_SET);
1041
+ buf = ALLOC_N(char, len + 1);
1042
+ pi->json = buf;
1043
+ pi->end = buf + len;
1044
+ if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
1045
+ if (0 != buf) {
1046
+ xfree(buf);
1047
+ }
1048
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
1049
+ }
1050
+ ((char *)pi->json)[len] = '\0';
1051
+ /* skip UTF-8 BOM if present */
1052
+ if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
1053
+ 0xBF == (uint8_t)pi->json[2]) {
1054
+ pi->cur += 3;
1055
+ }
858
1056
  #endif
859
- } else if (rb_respond_to(input, oj_read_id)) {
860
- // use stream parser instead
861
- return oj_pi_sparse(argc, argv, pi, 0);
862
- } else {
863
- rb_raise(rb_eArgError, "strict_parse() expected a String or IO Object.");
864
- }
1057
+ } else if (rb_respond_to(input, oj_read_id)) {
1058
+ // use stream parser instead
1059
+ return oj_pi_sparse(argc, argv, pi, 0);
1060
+ } else {
1061
+ rb_raise(rb_eArgError, "parse() expected a String or IO Object.");
1062
+ }
865
1063
  }
866
1064
  if (Yes == pi->options.circular) {
867
- pi->circ_array = oj_circ_array_new();
1065
+ pi->circ_array = oj_circ_array_new();
868
1066
  } else {
869
- pi->circ_array = 0;
1067
+ pi->circ_array = 0;
870
1068
  }
871
1069
  if (No == pi->options.allow_gc) {
872
- rb_gc_disable();
1070
+ rb_gc_disable();
873
1071
  }
874
1072
  // GC can run at any time. When it runs any Object created by C will be
875
1073
  // freed. We protect against this by wrapping the value stack in a ruby
@@ -877,78 +1075,117 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
877
1075
  // value stack (while it is in scope).
878
1076
  wrapped_stack = oj_stack_init(&pi->stack);
879
1077
  rb_protect(protect_parse, (VALUE)pi, &line);
880
- result = stack_head_val(&pi->stack);
1078
+ if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
1079
+ if (No == pi->options.nilnil ||
1080
+ (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1081
+ oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
1082
+ }
1083
+ }
1084
+ result = stack_head_val(&pi->stack);
881
1085
  DATA_PTR(wrapped_stack) = 0;
882
1086
  if (No == pi->options.allow_gc) {
883
- rb_gc_enable();
1087
+ rb_gc_enable();
884
1088
  }
885
1089
  if (!err_has(&pi->err)) {
886
- // If the stack is not empty then the JSON terminated early.
887
- Val v;
888
-
889
- if (0 != (v = stack_peek(&pi->stack))) {
890
- switch (v->next) {
891
- case NEXT_ARRAY_NEW:
892
- case NEXT_ARRAY_ELEMENT:
893
- case NEXT_ARRAY_COMMA:
894
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Array not terminated");
895
- break;
896
- case NEXT_HASH_NEW:
897
- case NEXT_HASH_KEY:
898
- case NEXT_HASH_COLON:
899
- case NEXT_HASH_VALUE:
900
- case NEXT_HASH_COMMA:
901
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Hash/Object not terminated");
902
- break;
903
- default:
904
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not terminated");
905
- }
906
- }
1090
+ // If the stack is not empty then the JSON terminated early.
1091
+ Val v;
1092
+ VALUE err_class = oj_parse_error_class;
1093
+
1094
+ if (0 != line) {
1095
+ VALUE ec = rb_obj_class(rb_errinfo());
1096
+
1097
+ if (rb_eArgError != ec && 0 != ec) {
1098
+ err_class = ec;
1099
+ }
1100
+ if (rb_eIOError != ec) {
1101
+ goto CLEANUP;
1102
+ }
1103
+ }
1104
+ if (NULL != (v = stack_peek(&pi->stack))) {
1105
+ switch (v->next) {
1106
+ case NEXT_ARRAY_NEW:
1107
+ case NEXT_ARRAY_ELEMENT:
1108
+ case NEXT_ARRAY_COMMA:
1109
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
1110
+ break;
1111
+ case NEXT_HASH_NEW:
1112
+ case NEXT_HASH_KEY:
1113
+ case NEXT_HASH_COLON:
1114
+ case NEXT_HASH_VALUE:
1115
+ case NEXT_HASH_COMMA:
1116
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
1117
+ break;
1118
+ default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
1119
+ }
1120
+ }
907
1121
  }
1122
+ CLEANUP:
908
1123
  // proceed with cleanup
909
1124
  if (0 != pi->circ_array) {
910
- oj_circ_array_free(pi->circ_array);
1125
+ oj_circ_array_free(pi->circ_array);
911
1126
  }
912
1127
  if (0 != buf) {
913
- xfree(buf);
1128
+ xfree(buf);
914
1129
  } else if (free_json) {
915
- xfree(json);
1130
+ xfree(json);
916
1131
  }
917
1132
  stack_cleanup(&pi->stack);
918
- if (0 != line) {
919
- rb_jump_tag(line);
1133
+ if (pi->str_rx.head != oj_default_options.str_rx.head) {
1134
+ oj_rxclass_cleanup(&pi->str_rx);
920
1135
  }
921
1136
  if (err_has(&pi->err)) {
922
- if (Qnil != pi->err_class) {
923
- pi->err.clas = pi->err_class;
924
- }
925
- oj_err_raise(&pi->err);
1137
+ rb_set_errinfo(Qnil);
1138
+ if (Qnil != pi->err_class) {
1139
+ pi->err.clas = pi->err_class;
1140
+ }
1141
+ if ((CompatMode == pi->options.mode || RailsMode == pi->options.mode) && Yes != pi->options.safe) {
1142
+ // The json gem requires the error message be UTF-8 encoded. In
1143
+ // additional the complete JSON source must be returned. There
1144
+ // does not seem to be a size limit.
1145
+ VALUE msg = oj_encode(rb_str_new2(pi->err.msg));
1146
+ VALUE args[1];
1147
+
1148
+ if (NULL != pi->json) {
1149
+ msg = rb_str_append(msg, oj_encode(rb_str_new2(" in '")));
1150
+ msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
1151
+ }
1152
+ args[0] = msg;
1153
+ if (pi->err.clas == oj_parse_error_class) {
1154
+ // The error was an Oj::ParseError so change to a JSON::ParserError.
1155
+ pi->err.clas = oj_json_parser_error_class;
1156
+ }
1157
+ rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
1158
+ } else {
1159
+ oj_err_raise(&pi->err);
1160
+ }
1161
+ } else if (0 != line) {
1162
+ rb_jump_tag(line);
926
1163
  }
927
1164
  if (pi->options.quirks_mode == No) {
928
- switch (rb_type(result)) {
929
- case T_NIL:
930
- case T_TRUE:
931
- case T_FALSE:
932
- case T_FIXNUM:
933
- case T_FLOAT:
934
- case T_CLASS:
935
- case T_STRING:
936
- case T_SYMBOL: {
937
- struct _Err err;
938
-
939
- if (Qnil == pi->err_class) {
940
- err.clas = oj_parse_error_class;
941
- } else {
942
- err.clas = pi->err_class;
943
- }
944
- snprintf(err.msg, sizeof(err.msg), "unexpected non-document value");
945
- oj_err_raise(&err);
946
- break;
947
- }
948
- default:
949
- // okay
950
- break;
951
- }
1165
+ switch (rb_type(result)) {
1166
+ case T_NIL:
1167
+ case T_TRUE:
1168
+ case T_FALSE:
1169
+ case T_FIXNUM:
1170
+ case T_FLOAT:
1171
+ case T_CLASS:
1172
+ case T_STRING:
1173
+ case T_SYMBOL: {
1174
+ struct _err err;
1175
+
1176
+ if (Qnil == pi->err_class) {
1177
+ err.clas = oj_parse_error_class;
1178
+ } else {
1179
+ err.clas = pi->err_class;
1180
+ }
1181
+ snprintf(err.msg, sizeof(err.msg), "unexpected non-document value");
1182
+ oj_err_raise(&err);
1183
+ break;
1184
+ }
1185
+ default:
1186
+ // okay
1187
+ break;
1188
+ }
952
1189
  }
953
1190
  return result;
954
1191
  }