oj 3.10.6 → 3.12.0

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