oj 3.10.6 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }