oj 3.11.3 → 3.11.8

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