oj 3.10.18 → 3.11.4

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -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 +1008 -1038
  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 +406 -407
  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 +1132 -918
  31. data/ext/oj/oj.h +286 -297
  32. data/ext/oj/parse.c +943 -926
  33. data/ext/oj/parse.h +70 -69
  34. data/ext/oj/rails.c +836 -839
  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 +781 -716
  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/easy_hash.rb +5 -4
  57. data/lib/oj/mimic.rb +0 -12
  58. data/lib/oj/version.rb +1 -1
  59. data/pages/Modes.md +2 -1
  60. data/pages/Options.md +8 -0
  61. data/test/activerecord/result_test.rb +7 -2
  62. data/test/foo.rb +35 -32
  63. data/test/helper.rb +10 -0
  64. data/test/json_gem/json_generator_test.rb +15 -3
  65. data/test/json_gem/test_helper.rb +8 -0
  66. data/test/test_compat.rb +3 -3
  67. data/test/test_hash.rb +10 -0
  68. data/test/test_scp.rb +1 -1
  69. data/test/test_various.rb +1 -0
  70. metadata +82 -82
data/ext/oj/parse.c CHANGED
@@ -1,944 +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;
388
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
389
- ni.bigdec_load = 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
+ }
390
421
 
391
422
  if ('-' == *pi->cur) {
392
- pi->cur++;
393
- ni.neg = 1;
423
+ pi->cur++;
424
+ ni.neg = 1;
394
425
  } else if ('+' == *pi->cur) {
395
- if (StrictMode == pi->options.mode) {
396
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
397
- return;
398
- }
399
- 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++;
400
435
  }
401
436
  if ('I' == *pi->cur) {
402
- if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
403
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
404
- return;
405
- }
406
- pi->cur += 8;
407
- 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;
408
447
  } else if ('N' == *pi->cur || 'n' == *pi->cur) {
409
- if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
410
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
411
- return;
412
- }
413
- pi->cur += 3;
414
- 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;
415
458
  } else {
416
- int dec_cnt = 0;
417
- bool zero1 = false;
418
-
419
- for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
420
- if (0 == ni.i && '0' == *pi->cur) {
421
- zero1 = true;
422
- }
423
- if (0 < ni.i) {
424
- dec_cnt++;
425
- }
426
- if (!ni.big) {
427
- int d = (*pi->cur - '0');
428
-
429
- if (0 < d) {
430
- if (zero1 && CompatMode == pi->options.mode) {
431
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
432
- return;
433
- }
434
- zero1 = false;
435
- }
436
- ni.i = ni.i * 10 + d;
437
- if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
438
- ni.big = 1;
439
- }
440
- }
441
- }
442
- if ('.' == *pi->cur) {
443
- pi->cur++;
444
- // A trailing . is not a valid decimal but if encountered allow it
445
- // except when mimicing the JSON gem or in strict mode.
446
- if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
447
- int pos = (int)(pi->cur - ni.str);
448
-
449
- if (1 == pos || (2 == pos && ni.neg)) {
450
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
451
- return;
452
- }
453
- if (*pi->cur < '0' || '9' < *pi->cur) {
454
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
455
- return;
456
- }
457
- }
458
- for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
459
- int d = (*pi->cur - '0');
460
-
461
- if (0 < ni.num || 0 < ni.i) {
462
- dec_cnt++;
463
- }
464
- if (INT64_MAX <= ni.div) {
465
- if (!ni.no_big) {
466
- ni.big = true;
467
- }
468
- } else {
469
- ni.num = ni.num * 10 + d;
470
- ni.div *= 10;
471
- ni.di++;
472
- if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
473
- if (!ni.no_big) {
474
- ni.big = true;
475
- }
476
- }
477
- }
478
- }
479
- }
480
- if ('e' == *pi->cur || 'E' == *pi->cur) {
481
- int eneg = 0;
482
-
483
- ni.has_exp = 1;
484
- pi->cur++;
485
- if ('-' == *pi->cur) {
486
- pi->cur++;
487
- eneg = 1;
488
- } else if ('+' == *pi->cur) {
489
- pi->cur++;
490
- }
491
- for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
492
- ni.exp = ni.exp * 10 + (*pi->cur - '0');
493
- if (EXP_MAX <= ni.exp) {
494
- ni.big = true;
495
- }
496
- }
497
- if (eneg) {
498
- ni.exp = -ni.exp;
499
- }
500
- }
501
- 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;
502
549
  }
503
550
  // Check for special reserved values for Infinity and NaN.
504
551
  if (ni.big) {
505
- if (0 == strcasecmp(INF_VAL, ni.str)) {
506
- ni.infinity = 1;
507
- } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
508
- ni.infinity = 1;
509
- ni.neg = 1;
510
- } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
511
- ni.nan = 1;
512
- }
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
+ }
513
560
  }
514
- if (BigDec == pi->options.bigdec_load) {
515
- 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;
516
567
  }
517
568
  if (0 == parent) {
518
- pi->add_num(pi, &ni);
569
+ pi->add_num(pi, &ni);
519
570
  } else {
520
- switch (parent->next) {
521
- case NEXT_ARRAY_NEW:
522
- case NEXT_ARRAY_ELEMENT:
523
- pi->array_append_num(pi, &ni);
524
- parent->next = NEXT_ARRAY_COMMA;
525
- break;
526
- case NEXT_HASH_VALUE:
527
- pi->hash_set_num(pi, parent, &ni);
528
- if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
529
- xfree((char*)parent->key);
530
- parent->key = 0;
531
- }
532
- parent->next = NEXT_HASH_COMMA;
533
- break;
534
- default:
535
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
536
- break;
537
- }
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
+ }
538
595
  }
539
596
  }
540
597
 
541
- static void
542
- array_start(ParseInfo pi) {
543
- volatile VALUE v = pi->start_array(pi);
598
+ static void array_start(ParseInfo pi) {
599
+ volatile VALUE v = pi->start_array(pi);
544
600
 
545
601
  stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
546
602
  }
547
603
 
548
- static void
549
- array_end(ParseInfo pi) {
550
- Val array = stack_pop(&pi->stack);
604
+ static void array_end(ParseInfo pi) {
605
+ Val array = stack_pop(&pi->stack);
551
606
 
552
607
  if (0 == array) {
553
- 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");
554
609
  } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
555
- 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));
556
616
  } else {
557
- pi->end_array(pi);
558
- add_value(pi, array->val);
617
+ pi->end_array(pi);
618
+ add_value(pi, array->val);
559
619
  }
560
620
  }
561
621
 
562
- static void
563
- hash_start(ParseInfo pi) {
564
- volatile VALUE v = pi->start_hash(pi);
622
+ static void hash_start(ParseInfo pi) {
623
+ volatile VALUE v = pi->start_hash(pi);
565
624
 
566
625
  stack_push(&pi->stack, v, NEXT_HASH_NEW);
567
626
  }
568
627
 
569
- static void
570
- hash_end(ParseInfo pi) {
571
- volatile Val hash = stack_peek(&pi->stack);
628
+ static void hash_end(ParseInfo pi) {
629
+ volatile Val hash = stack_peek(&pi->stack);
572
630
 
573
631
  // leave hash on stack until just before
574
632
  if (0 == hash) {
575
- 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");
576
634
  } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
577
- 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));
578
641
  } else {
579
- pi->end_hash(pi);
580
- stack_pop(&pi->stack);
581
- add_value(pi, hash->val);
642
+ pi->end_hash(pi);
643
+ stack_pop(&pi->stack);
644
+ add_value(pi, hash->val);
582
645
  }
583
646
  }
584
647
 
585
- static void
586
- comma(ParseInfo pi) {
587
- Val parent = stack_peek(&pi->stack);
648
+ static void comma(ParseInfo pi) {
649
+ Val parent = stack_peek(&pi->stack);
588
650
 
589
651
  if (0 == parent) {
590
- 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");
591
653
  } else if (NEXT_ARRAY_COMMA == parent->next) {
592
- parent->next = NEXT_ARRAY_ELEMENT;
654
+ parent->next = NEXT_ARRAY_ELEMENT;
593
655
  } else if (NEXT_HASH_COMMA == parent->next) {
594
- parent->next = NEXT_HASH_KEY;
656
+ parent->next = NEXT_HASH_KEY;
595
657
  } else {
596
- 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");
597
659
  }
598
660
  }
599
661
 
600
- static void
601
- colon(ParseInfo pi) {
602
- Val parent = stack_peek(&pi->stack);
662
+ static void colon(ParseInfo pi) {
663
+ Val parent = stack_peek(&pi->stack);
603
664
 
604
665
  if (0 != parent && NEXT_HASH_COLON == parent->next) {
605
- parent->next = NEXT_HASH_VALUE;
666
+ parent->next = NEXT_HASH_VALUE;
606
667
  } else {
607
- 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");
608
669
  }
609
670
  }
610
671
 
611
- void
612
- oj_parse2(ParseInfo pi) {
613
- int first = 1;
614
- long start = 0;
672
+ void oj_parse2(ParseInfo pi) {
673
+ int first = 1;
674
+ long start = 0;
615
675
 
616
676
  pi->cur = pi->json;
617
677
  err_init(&pi->err);
618
678
  while (1) {
619
- if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
620
- VALUE err_clas = oj_get_json_err_class("NestingError");
621
-
622
- oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
623
- pi->err_class = err_clas;
624
- return;
625
- }
626
- next_non_white(pi);
627
- if (!first && '\0' != *pi->cur) {
628
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document");
629
- }
630
-
631
- // If no tokens are consumed (i.e. empty string), throw a parse error
632
- // this is the behavior of JSON.parse in both Ruby and JS.
633
- if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) {
634
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
635
- }
636
-
637
- switch (*pi->cur++) {
638
- case '{':
639
- hash_start(pi);
640
- break;
641
- case '}':
642
- hash_end(pi);
643
- break;
644
- case ':':
645
- colon(pi);
646
- break;
647
- case '[':
648
- array_start(pi);
649
- break;
650
- case ']':
651
- array_end(pi);
652
- break;
653
- case ',':
654
- comma(pi);
655
- break;
656
- case '"':
657
- read_str(pi);
658
- break;
659
- //case '+':
660
- case '+':
661
- if (CompatMode == pi->options.mode) {
662
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
663
- return;
664
- }
665
- pi->cur--;
666
- read_num(pi);
667
- break;
668
- case '-':
669
- case '0':
670
- case '1':
671
- case '2':
672
- case '3':
673
- case '4':
674
- case '5':
675
- case '6':
676
- case '7':
677
- case '8':
678
- case '9':
679
- pi->cur--;
680
- read_num(pi);
681
- break;
682
- case 'I':
683
- case 'N':
684
- if (Yes == pi->options.allow_nan) {
685
- pi->cur--;
686
- read_num(pi);
687
- } else {
688
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
689
- }
690
- break;
691
- case 't':
692
- read_true(pi);
693
- break;
694
- case 'f':
695
- read_false(pi);
696
- break;
697
- case 'n':
698
- if ('u' == *pi->cur) {
699
- read_null(pi);
700
- } else {
701
- pi->cur--;
702
- read_num(pi);
703
- }
704
- break;
705
- case '/':
706
- skip_comment(pi);
707
- if (first) {
708
- continue;
709
- }
710
- break;
711
- case '\0':
712
- pi->cur--;
713
- return;
714
- default:
715
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
716
- return;
717
- }
718
- if (err_has(&pi->err)) {
719
- return;
720
- }
721
- if (stack_empty(&pi->stack)) {
722
- if (Qundef != pi->proc) {
723
- VALUE args[3];
724
- long len = (pi->cur - pi->json) - start;
725
-
726
- *args = stack_head_val(&pi->stack);
727
- args[1] = LONG2NUM(start);
728
- args[2] = LONG2NUM(len);
729
-
730
- if (Qnil == pi->proc) {
731
- rb_yield_values2(3, args);
732
- } else {
733
- rb_proc_call_with_block(pi->proc, 3, args, Qnil);
734
- }
735
- } else if (!pi->has_callbacks) {
736
- first = 0;
737
- }
738
- start = pi->cur - pi->json;
739
- }
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
+ }
740
794
  }
741
795
  }
742
796
 
743
- static VALUE
744
- rescue_big_decimal(VALUE str, VALUE ignore) {
797
+ static VALUE rescue_big_decimal(VALUE str, VALUE ignore) {
745
798
  rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
746
799
  return Qnil;
747
800
  }
748
801
 
749
- static VALUE
750
- parse_big_decimal(VALUE str) {
802
+ static VALUE parse_big_decimal(VALUE str) {
751
803
  return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
752
804
  }
753
805
 
754
- static long double exp_plus[] = {
755
- 1.0,
756
- 1.0e1,
757
- 1.0e2,
758
- 1.0e3,
759
- 1.0e4,
760
- 1.0e5,
761
- 1.0e6,
762
- 1.0e7,
763
- 1.0e8,
764
- 1.0e9,
765
- 1.0e10,
766
- 1.0e11,
767
- 1.0e12,
768
- 1.0e13,
769
- 1.0e14,
770
- 1.0e15,
771
- 1.0e16,
772
- 1.0e17,
773
- 1.0e18,
774
- 1.0e19,
775
- 1.0e20,
776
- 1.0e21,
777
- 1.0e22,
778
- 1.0e23,
779
- 1.0e24,
780
- 1.0e25,
781
- 1.0e26,
782
- 1.0e27,
783
- 1.0e28,
784
- 1.0e29,
785
- 1.0e30,
786
- 1.0e31,
787
- 1.0e32,
788
- 1.0e33,
789
- 1.0e34,
790
- 1.0e35,
791
- 1.0e36,
792
- 1.0e37,
793
- 1.0e38,
794
- 1.0e39,
795
- 1.0e40,
796
- 1.0e41,
797
- 1.0e42,
798
- 1.0e43,
799
- 1.0e44,
800
- 1.0e45,
801
- 1.0e46,
802
- 1.0e47,
803
- 1.0e48,
804
- 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,
805
812
  };
806
813
 
807
814
  VALUE
808
815
  oj_num_as_value(NumInfo ni) {
809
- volatile VALUE rnum = Qnil;
816
+ volatile VALUE rnum = Qnil;
810
817
 
811
818
  if (ni->infinity) {
812
- if (ni->neg) {
813
- rnum = rb_float_new(-OJ_INFINITY);
814
- } else {
815
- rnum = rb_float_new(OJ_INFINITY);
816
- }
819
+ if (ni->neg) {
820
+ rnum = rb_float_new(-OJ_INFINITY);
821
+ } else {
822
+ rnum = rb_float_new(OJ_INFINITY);
823
+ }
817
824
  } else if (ni->nan) {
818
- rnum = rb_float_new(0.0/0.0);
819
- } else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum
820
- if (ni->big) {
821
- if (256 > ni->len) {
822
- char buf[256];
823
-
824
- memcpy(buf, ni->str, ni->len);
825
- buf[ni->len] = '\0';
826
- rnum = rb_cstr_to_inum(buf, 10, 0);
827
- } else {
828
- char *buf = ALLOC_N(char, ni->len + 1);
829
-
830
- memcpy(buf, ni->str, ni->len);
831
- buf[ni->len] = '\0';
832
- rnum = rb_cstr_to_inum(buf, 10, 0);
833
- xfree(buf);
834
- }
835
- } else {
836
- if (ni->neg) {
837
- rnum = rb_ll2inum(-ni->i);
838
- } else {
839
- rnum = rb_ll2inum(ni->i);
840
- }
841
- }
842
- } else { // decimal
843
- if (ni->big) {
844
- volatile VALUE bd = rb_str_new(ni->str, ni->len);
845
-
846
- rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
847
- if (ni->no_big) {
848
- rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
849
- }
850
- } else if (FastDec == ni->bigdec_load) {
851
- long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
852
- int x = (int)((int64_t)ni->exp - ni->di);
853
-
854
- if (0 < x) {
855
- if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
856
- ld *= exp_plus[x];
857
- } else {
858
- ld *= powl(10.0, x);
859
- }
860
- } else if (x < 0) {
861
- if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
862
- ld /= exp_plus[-x];
863
- } else {
864
- ld /= powl(10.0, -x);
865
- }
866
- }
867
- if (ni->neg) {
868
- ld = -ld;
869
- }
870
- rnum = rb_float_new((double)ld);
871
- } else if (RubyDec == ni->bigdec_load) {
872
- volatile VALUE sv = rb_str_new(ni->str, ni->len);
873
-
874
- rnum = rb_funcall(sv, rb_intern("to_f"), 0);
875
- } else {
876
- char *end;
877
- double d = strtod(ni->str, &end);
878
-
879
- if ((long)ni->len != (long)(end - ni->str)) {
880
- rb_raise(oj_parse_error_class, "Invalid float");
881
- }
882
- rnum = rb_float_new(d);
883
- }
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
+ }
884
891
  }
885
892
  return rnum;
886
893
  }
887
894
 
888
- void
889
- oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...) {
890
- va_list ap;
891
- char msg[256];
892
- char *p = msg;
893
- char *end = p + sizeof(msg) - 2;
894
- char *start;
895
- 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;
896
907
 
897
908
  va_start(ap, format);
898
909
  p += vsnprintf(msg, sizeof(msg) - 1, format, ap);
899
910
  va_end(ap);
900
911
  pi->err.clas = err_clas;
901
912
  if (p + 3 < end) {
902
- *p++ = ' ';
903
- *p++ = '(';
904
- *p++ = 'a';
905
- *p++ = 'f';
906
- *p++ = 't';
907
- *p++ = 'e';
908
- *p++ = 'r';
909
- *p++ = ' ';
910
- start = p;
911
- for (vp = pi->stack.head; vp < pi->stack.tail; vp++) {
912
- if (end <= p + 1 + vp->klen) {
913
- break;
914
- }
915
- if (NULL != vp->key) {
916
- if (start < p) {
917
- *p++ = '.';
918
- }
919
- memcpy(p, vp->key, vp->klen);
920
- p += vp->klen;
921
- } else {
922
- if (RUBY_T_ARRAY == rb_type(vp->val)) {
923
- if (end <= p + 12) {
924
- break;
925
- }
926
- p += snprintf(p, end - p, "[%ld]", RARRAY_LEN(vp->val));
927
- }
928
- }
929
- }
930
- *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++ = ')';
931
942
  }
932
943
  *p = '\0';
933
944
  if (0 == pi->json) {
934
- 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);
935
953
  } else {
936
- _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);
937
955
  }
938
956
  }
939
957
 
940
- static VALUE
941
- protect_parse(VALUE pip) {
958
+ static VALUE protect_parse(VALUE pip) {
942
959
  oj_parse2((ParseInfo)pip);
943
960
 
944
961
  return Qnil;
@@ -946,102 +963,102 @@ protect_parse(VALUE pip) {
946
963
 
947
964
  extern int oj_utf8_index;
948
965
 
949
- static void
950
- oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
951
- 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));
952
968
 
953
969
  if (rb_utf8_encoding() != enc) {
954
- *inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding());
970
+ *inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding());
955
971
  }
956
- pi->json = rb_string_value_ptr((VALUE*)inputp);
957
- pi->end = pi->json + RSTRING_LEN(*inputp);
972
+ pi->json = rb_string_value_ptr((VALUE *)inputp);
973
+ pi->end = pi->json + RSTRING_LEN(*inputp);
958
974
  }
959
975
 
960
976
  VALUE
961
977
  oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
962
- char *buf = 0;
963
- volatile VALUE input;
964
- volatile VALUE wrapped_stack;
965
- volatile VALUE result = Qnil;
966
- int line = 0;
967
- 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;
968
984
 
969
985
  if (argc < 1) {
970
- rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
986
+ rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
971
987
  }
972
988
  input = argv[0];
973
989
  if (2 <= argc) {
974
- if (T_HASH == rb_type(argv[1])) {
975
- oj_parse_options(argv[1], &pi->options);
976
- } else if (3 <= argc && T_HASH == rb_type(argv[2])) {
977
- oj_parse_options(argv[2], &pi->options);
978
- }
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
+ }
979
995
  }
980
996
  if (yieldOk && rb_block_given_p()) {
981
- pi->proc = Qnil;
997
+ pi->proc = Qnil;
982
998
  } else {
983
- pi->proc = Qundef;
999
+ pi->proc = Qundef;
984
1000
  }
985
1001
  if (0 != json) {
986
- pi->json = json;
987
- pi->end = json + len;
988
- free_json = 1;
1002
+ pi->json = json;
1003
+ pi->end = json + len;
1004
+ free_json = 1;
989
1005
  } else if (T_STRING == rb_type(input)) {
990
- if (CompatMode == pi->options.mode) {
991
- if (No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
992
- rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
993
- }
994
- }
995
- 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);
996
1012
  } else if (Qnil == input) {
997
- if (Yes == pi->options.nilnil) {
998
- return Qnil;
999
- } else {
1000
- rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
1001
- }
1013
+ if (Yes == pi->options.nilnil) {
1014
+ return Qnil;
1015
+ } else {
1016
+ rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
1017
+ }
1002
1018
  } else {
1003
- VALUE clas = rb_obj_class(input);
1004
- volatile VALUE s;
1019
+ VALUE clas = rb_obj_class(input);
1020
+ volatile VALUE s;
1005
1021
 
1006
- if (oj_stringio_class == clas) {
1007
- s = rb_funcall2(input, oj_string_id, 0, 0);
1008
- 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);
1009
1025
  #if !IS_WINDOWS
1010
- } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
1011
- int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
1012
- ssize_t cnt;
1013
- size_t len = lseek(fd, 0, SEEK_END);
1014
-
1015
- lseek(fd, 0, SEEK_SET);
1016
- buf = ALLOC_N(char, len + 1);
1017
- pi->json = buf;
1018
- pi->end = buf + len;
1019
- if (0 >= (cnt = read(fd, (char*)pi->json, len)) || cnt != (ssize_t)len) {
1020
- if (0 != buf) {
1021
- xfree(buf);
1022
- }
1023
- rb_raise(rb_eIOError, "failed to read from IO Object.");
1024
- }
1025
- ((char*)pi->json)[len] = '\0';
1026
- /* skip UTF-8 BOM if present */
1027
- if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
1028
- pi->cur += 3;
1029
- }
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
+ }
1030
1047
  #endif
1031
- } else if (rb_respond_to(input, oj_read_id)) {
1032
- // use stream parser instead
1033
- return oj_pi_sparse(argc, argv, pi, 0);
1034
- } else {
1035
- rb_raise(rb_eArgError, "parse() expected a String or IO Object.");
1036
- }
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
+ }
1037
1054
  }
1038
1055
  if (Yes == pi->options.circular) {
1039
- pi->circ_array = oj_circ_array_new();
1056
+ pi->circ_array = oj_circ_array_new();
1040
1057
  } else {
1041
- pi->circ_array = 0;
1058
+ pi->circ_array = 0;
1042
1059
  }
1043
1060
  if (No == pi->options.allow_gc) {
1044
- rb_gc_disable();
1061
+ rb_gc_disable();
1045
1062
  }
1046
1063
  // GC can run at any time. When it runs any Object created by C will be
1047
1064
  // freed. We protect against this by wrapping the value stack in a ruby
@@ -1050,116 +1067,116 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1050
1067
  wrapped_stack = oj_stack_init(&pi->stack);
1051
1068
  rb_protect(protect_parse, (VALUE)pi, &line);
1052
1069
  if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
1053
- if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1054
- oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
1055
- }
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
+ }
1056
1074
  }
1057
- result = stack_head_val(&pi->stack);
1075
+ result = stack_head_val(&pi->stack);
1058
1076
  DATA_PTR(wrapped_stack) = 0;
1059
1077
  if (No == pi->options.allow_gc) {
1060
- rb_gc_enable();
1078
+ rb_gc_enable();
1061
1079
  }
1062
1080
  if (!err_has(&pi->err)) {
1063
- // If the stack is not empty then the JSON terminated early.
1064
- Val v;
1065
- VALUE err_class = oj_parse_error_class;
1066
-
1067
- if (0 != line) {
1068
- VALUE ec = rb_obj_class(rb_errinfo());
1069
-
1070
- if (rb_eArgError != ec && 0 != ec) {
1071
- err_class = ec;
1072
- }
1073
- if (rb_eIOError != ec) {
1074
- goto CLEANUP;
1075
- }
1076
- }
1077
- if (NULL != (v = stack_peek(&pi->stack))) {
1078
- switch (v->next) {
1079
- case NEXT_ARRAY_NEW:
1080
- case NEXT_ARRAY_ELEMENT:
1081
- case NEXT_ARRAY_COMMA:
1082
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
1083
- break;
1084
- case NEXT_HASH_NEW:
1085
- case NEXT_HASH_KEY:
1086
- case NEXT_HASH_COLON:
1087
- case NEXT_HASH_VALUE:
1088
- case NEXT_HASH_COMMA:
1089
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
1090
- break;
1091
- default:
1092
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
1093
- }
1094
- }
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
+ }
1095
1112
  }
1096
1113
  CLEANUP:
1097
1114
  // proceed with cleanup
1098
1115
  if (0 != pi->circ_array) {
1099
- oj_circ_array_free(pi->circ_array);
1116
+ oj_circ_array_free(pi->circ_array);
1100
1117
  }
1101
1118
  if (0 != buf) {
1102
- xfree(buf);
1119
+ xfree(buf);
1103
1120
  } else if (free_json) {
1104
- xfree(json);
1121
+ xfree(json);
1105
1122
  }
1106
1123
  stack_cleanup(&pi->stack);
1107
1124
  if (pi->str_rx.head != oj_default_options.str_rx.head) {
1108
- oj_rxclass_cleanup(&pi->str_rx);
1125
+ oj_rxclass_cleanup(&pi->str_rx);
1109
1126
  }
1110
1127
  if (err_has(&pi->err)) {
1111
- rb_set_errinfo(Qnil);
1112
- if (Qnil != pi->err_class) {
1113
- pi->err.clas = pi->err_class;
1114
- }
1115
- if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
1116
- // The json gem requires the error message be UTF-8 encoded. In
1117
- // additional the complete JSON source must be returned. There
1118
- // does not seem to be a size limit.
1119
- VALUE msg = oj_encode(rb_str_new2(pi->err.msg));
1120
- VALUE args[1];
1121
-
1122
- if (NULL != pi->json) {
1123
- msg = rb_str_append(msg, oj_encode(rb_str_new2(" in '")));
1124
- msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
1125
- }
1126
- args[0] = msg;
1127
- if (pi->err.clas == oj_parse_error_class) {
1128
- // The error was an Oj::ParseError so change to a JSON::ParserError.
1129
- pi->err.clas = oj_json_parser_error_class;
1130
- }
1131
- rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
1132
- } else {
1133
- oj_err_raise(&pi->err);
1134
- }
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 && 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
+ }
1135
1152
  } else if (0 != line) {
1136
- rb_jump_tag(line);
1153
+ rb_jump_tag(line);
1137
1154
  }
1138
1155
  if (pi->options.quirks_mode == No) {
1139
- switch (rb_type(result)) {
1140
- case T_NIL:
1141
- case T_TRUE:
1142
- case T_FALSE:
1143
- case T_FIXNUM:
1144
- case T_FLOAT:
1145
- case T_CLASS:
1146
- case T_STRING:
1147
- case T_SYMBOL: {
1148
- struct _err err;
1149
-
1150
- if (Qnil == pi->err_class) {
1151
- err.clas = oj_parse_error_class;
1152
- } else {
1153
- err.clas = pi->err_class;
1154
- }
1155
- snprintf(err.msg, sizeof(err.msg), "unexpected non-document value");
1156
- oj_err_raise(&err);
1157
- break;
1158
- }
1159
- default:
1160
- // okay
1161
- break;
1162
- }
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
+ }
1163
1180
  }
1164
1181
  return result;
1165
1182
  }