oj 3.7.4 → 3.13.21

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1352 -0
  3. data/README.md +29 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +809 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1070 -1087
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +525 -593
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1325 -986
  36. data/ext/oj/oj.h +333 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1557 -0
  40. data/ext/oj/parser.h +91 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +602 -0
  51. data/ext/oj/scp.c +88 -113
  52. data/ext/oj/sparse.c +787 -709
  53. data/ext/oj/stream_writer.c +133 -159
  54. data/ext/oj/strict.c +127 -118
  55. data/ext/oj/string_writer.c +230 -249
  56. data/ext/oj/trace.c +34 -41
  57. data/ext/oj/trace.h +19 -19
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +59 -67
  62. data/ext/oj/val_stack.h +91 -129
  63. data/ext/oj/validate.c +46 -0
  64. data/ext/oj/wab.c +342 -353
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +5 -4
  67. data/lib/oj/error.rb +1 -1
  68. data/lib/oj/json.rb +1 -1
  69. data/lib/oj/mimic.rb +48 -14
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/state.rb +8 -7
  72. data/lib/oj/version.rb +2 -2
  73. data/lib/oj.rb +0 -8
  74. data/pages/Compatibility.md +1 -1
  75. data/pages/JsonGem.md +15 -0
  76. data/pages/Modes.md +53 -46
  77. data/pages/Options.md +72 -11
  78. data/pages/Parser.md +309 -0
  79. data/pages/Rails.md +73 -22
  80. data/pages/Security.md +1 -1
  81. data/test/activerecord/result_test.rb +7 -2
  82. data/test/activesupport5/abstract_unit.rb +45 -0
  83. data/test/activesupport5/decoding_test.rb +68 -60
  84. data/test/activesupport5/encoding_test.rb +111 -96
  85. data/test/activesupport5/encoding_test_cases.rb +33 -25
  86. data/test/activesupport5/test_helper.rb +43 -21
  87. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  88. data/test/activesupport6/abstract_unit.rb +44 -0
  89. data/test/activesupport6/decoding_test.rb +133 -0
  90. data/test/activesupport6/encoding_test.rb +507 -0
  91. data/test/activesupport6/encoding_test_cases.rb +98 -0
  92. data/test/activesupport6/test_common.rb +17 -0
  93. data/test/activesupport6/test_helper.rb +163 -0
  94. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  95. data/test/activesupport7/abstract_unit.rb +49 -0
  96. data/test/activesupport7/decoding_test.rb +125 -0
  97. data/test/activesupport7/encoding_test.rb +486 -0
  98. data/test/activesupport7/encoding_test_cases.rb +104 -0
  99. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  100. data/test/bar.rb +6 -12
  101. data/test/baz.rb +16 -0
  102. data/test/bug.rb +16 -0
  103. data/test/foo.rb +69 -75
  104. data/test/helper.rb +16 -0
  105. data/test/json_gem/json_common_interface_test.rb +8 -3
  106. data/test/json_gem/json_generator_test.rb +18 -4
  107. data/test/json_gem/json_parser_test.rb +9 -0
  108. data/test/json_gem/test_helper.rb +12 -0
  109. data/test/mem.rb +33 -0
  110. data/test/perf.rb +1 -1
  111. data/test/perf_dump.rb +50 -0
  112. data/test/perf_once.rb +58 -0
  113. data/test/perf_parser.rb +189 -0
  114. data/test/perf_scp.rb +11 -10
  115. data/test/perf_strict.rb +17 -23
  116. data/test/prec.rb +23 -0
  117. data/test/sample_json.rb +1 -1
  118. data/test/test_compat.rb +46 -10
  119. data/test/test_custom.rb +147 -8
  120. data/test/test_fast.rb +62 -2
  121. data/test/test_file.rb +25 -2
  122. data/test/test_gc.rb +13 -0
  123. data/test/test_generate.rb +21 -0
  124. data/test/test_hash.rb +11 -1
  125. data/test/test_integer_range.rb +7 -2
  126. data/test/test_object.rb +85 -9
  127. data/test/test_parser.rb +27 -0
  128. data/test/test_parser_saj.rb +335 -0
  129. data/test/test_parser_usual.rb +217 -0
  130. data/test/test_rails.rb +35 -0
  131. data/test/test_saj.rb +1 -1
  132. data/test/test_scp.rb +5 -5
  133. data/test/test_strict.rb +26 -1
  134. data/test/test_various.rb +87 -65
  135. data/test/test_wab.rb +2 -0
  136. data/test/test_writer.rb +19 -2
  137. data/test/tests.rb +1 -1
  138. data/test/zoo.rb +13 -0
  139. metadata +60 -110
  140. data/ext/oj/hash.c +0 -163
  141. data/ext/oj/hash.h +0 -46
  142. data/ext/oj/hash_test.c +0 -512
data/ext/oj/sparse.c CHANGED
@@ -1,784 +1,854 @@
1
- /* sparse.c
2
- * Copyright (c) 2013, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2013 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
5
3
 
6
- #include <stdlib.h>
4
+ #include <math.h>
7
5
  #include <stdio.h>
6
+ #include <stdlib.h>
8
7
  #include <string.h>
9
8
  #include <unistd.h>
10
- #include <math.h>
11
9
 
12
- #include "oj.h"
10
+ #include "buf.h"
13
11
  #include "encode.h"
12
+ #include "intern.h" // for oj_strndup()
13
+ #include "oj.h"
14
14
  #include "parse.h"
15
- #include "buf.h"
16
- #include "hash.h" // for oj_strndup()
17
15
  #include "val_stack.h"
18
16
 
19
17
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
- #define OJ_INFINITY (1.0/0.0)
18
+ #define OJ_INFINITY (1.0 / 0.0)
21
19
 
22
20
  #ifdef RUBINIUS_RUBY
23
- #define NUM_MAX 0x07FFFFFF
21
+ #define NUM_MAX 0x07FFFFFF
24
22
  #else
25
- #define NUM_MAX (FIXNUM_MAX >> 8)
23
+ #define NUM_MAX (FIXNUM_MAX >> 8)
26
24
  #endif
27
- #define EXP_MAX 100000
28
- #define DEC_MAX 15
25
+ #define EXP_MAX 100000
26
+ #define DEC_MAX 15
29
27
 
30
- static void
31
- skip_comment(ParseInfo pi) {
32
- char c = reader_get(&pi->rd);
28
+ static void skip_comment(ParseInfo pi) {
29
+ char c = reader_get(&pi->rd);
33
30
 
34
31
  if ('*' == c) {
35
- while ('\0' != (c = reader_get(&pi->rd))) {
36
- if ('*' == c) {
37
- c = reader_get(&pi->rd);
38
- if ('/' == c) {
39
- return;
40
- }
41
- }
42
- }
32
+ while ('\0' != (c = reader_get(&pi->rd))) {
33
+ if ('*' == c) {
34
+ c = reader_get(&pi->rd);
35
+ if ('/' == c) {
36
+ return;
37
+ }
38
+ }
39
+ }
43
40
  } else if ('/' == c) {
44
- while ('\0' != (c = reader_get(&pi->rd))) {
45
- switch (c) {
46
- case '\n':
47
- case '\r':
48
- case '\f':
49
- case '\0':
50
- return;
51
- default:
52
- break;
53
- }
54
- }
41
+ while ('\0' != (c = reader_get(&pi->rd))) {
42
+ switch (c) {
43
+ case '\n':
44
+ case '\r':
45
+ case '\f':
46
+ case '\0': return;
47
+ default: break;
48
+ }
49
+ }
55
50
  } else {
56
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
51
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
57
52
  }
58
53
  if ('\0' == c) {
59
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
60
- return;
54
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
55
+ return;
61
56
  }
62
57
  }
63
58
 
64
- static void
65
- add_value(ParseInfo pi, VALUE rval) {
66
- Val parent = stack_peek(&pi->stack);
59
+ static void add_value(ParseInfo pi, VALUE rval) {
60
+ Val parent = stack_peek(&pi->stack);
67
61
 
68
- if (0 == parent) { // simple add
69
- pi->add_value(pi, rval);
62
+ if (0 == parent) { // simple add
63
+ pi->add_value(pi, rval);
70
64
  } else {
71
- switch (parent->next) {
72
- case NEXT_ARRAY_NEW:
73
- case NEXT_ARRAY_ELEMENT:
74
- pi->array_append_value(pi, rval);
75
- parent->next = NEXT_ARRAY_COMMA;
76
- break;
77
- case NEXT_HASH_VALUE:
78
- pi->hash_set_value(pi, parent, rval);
79
- if (parent->kalloc) {
80
- xfree((char*)parent->key);
81
- }
82
- parent->key = 0;
83
- parent->kalloc = 0;
84
- parent->next = NEXT_HASH_COMMA;
85
- break;
86
- case NEXT_HASH_NEW:
87
- case NEXT_HASH_KEY:
88
- case NEXT_HASH_COMMA:
89
- case NEXT_NONE:
90
- case NEXT_ARRAY_COMMA:
91
- case NEXT_HASH_COLON:
92
- default:
93
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
94
- break;
95
- }
65
+ switch (parent->next) {
66
+ case NEXT_ARRAY_NEW:
67
+ case NEXT_ARRAY_ELEMENT:
68
+ pi->array_append_value(pi, rval);
69
+ parent->next = NEXT_ARRAY_COMMA;
70
+ break;
71
+ case NEXT_HASH_VALUE:
72
+ pi->hash_set_value(pi, parent, rval);
73
+ if (parent->kalloc) {
74
+ xfree((char *)parent->key);
75
+ }
76
+ parent->key = 0;
77
+ parent->kalloc = 0;
78
+ parent->next = NEXT_HASH_COMMA;
79
+ break;
80
+ case NEXT_HASH_NEW:
81
+ case NEXT_HASH_KEY:
82
+ case NEXT_HASH_COMMA:
83
+ case NEXT_NONE:
84
+ case NEXT_ARRAY_COMMA:
85
+ case NEXT_HASH_COLON:
86
+ default:
87
+ oj_set_error_at(pi,
88
+ oj_parse_error_class,
89
+ __FILE__,
90
+ __LINE__,
91
+ "expected %s",
92
+ oj_stack_next_string(parent->next));
93
+ break;
94
+ }
96
95
  }
97
96
  }
98
97
 
99
- static void
100
- add_num_value(ParseInfo pi, NumInfo ni) {
101
- Val parent = stack_peek(&pi->stack);
98
+ static void add_num_value(ParseInfo pi, NumInfo ni) {
99
+ Val parent = stack_peek(&pi->stack);
102
100
 
103
101
  if (0 == parent) {
104
- pi->add_num(pi, ni);
102
+ pi->add_num(pi, ni);
105
103
  } else {
106
- switch (parent->next) {
107
- case NEXT_ARRAY_NEW:
108
- case NEXT_ARRAY_ELEMENT:
109
- pi->array_append_num(pi, ni);
110
- parent->next = NEXT_ARRAY_COMMA;
111
- break;
112
- case NEXT_HASH_VALUE:
113
- pi->hash_set_num(pi, parent, ni);
114
- if (parent->kalloc) {
115
- xfree((char*)parent->key);
116
- }
117
- parent->key = 0;
118
- parent->kalloc = 0;
119
- parent->next = NEXT_HASH_COMMA;
120
- break;
121
- default:
122
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
123
- break;
124
- }
104
+ switch (parent->next) {
105
+ case NEXT_ARRAY_NEW:
106
+ case NEXT_ARRAY_ELEMENT:
107
+ pi->array_append_num(pi, ni);
108
+ parent->next = NEXT_ARRAY_COMMA;
109
+ break;
110
+ case NEXT_HASH_VALUE:
111
+ pi->hash_set_num(pi, parent, ni);
112
+ if (parent->kalloc) {
113
+ xfree((char *)parent->key);
114
+ }
115
+ parent->key = 0;
116
+ parent->kalloc = 0;
117
+ parent->next = NEXT_HASH_COMMA;
118
+ break;
119
+ default:
120
+ oj_set_error_at(pi,
121
+ oj_parse_error_class,
122
+ __FILE__,
123
+ __LINE__,
124
+ "expected %s",
125
+ oj_stack_next_string(parent->next));
126
+ break;
127
+ }
125
128
  }
126
129
  }
127
130
 
128
- static void
129
- read_true(ParseInfo pi) {
131
+ static void read_true(ParseInfo pi) {
130
132
  if (0 == reader_expect(&pi->rd, "rue")) {
131
- add_value(pi, Qtrue);
133
+ add_value(pi, Qtrue);
132
134
  } else {
133
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
135
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
134
136
  }
135
137
  }
136
138
 
137
- static void
138
- read_false(ParseInfo pi) {
139
+ static void read_false(ParseInfo pi) {
139
140
  if (0 == reader_expect(&pi->rd, "alse")) {
140
- add_value(pi, Qfalse);
141
+ add_value(pi, Qfalse);
141
142
  } else {
142
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
143
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
143
144
  }
144
145
  }
145
146
 
146
- static uint32_t
147
- read_hex(ParseInfo pi) {
148
- uint32_t b = 0;
149
- int i;
150
- char c;
147
+ static uint32_t read_hex(ParseInfo pi) {
148
+ uint32_t b = 0;
149
+ int i;
150
+ char c;
151
151
 
152
152
  for (i = 0; i < 4; i++) {
153
- c = reader_get(&pi->rd);
154
- b = b << 4;
155
- if ('0' <= c && c <= '9') {
156
- b += c - '0';
157
- } else if ('A' <= c && c <= 'F') {
158
- b += c - 'A' + 10;
159
- } else if ('a' <= c && c <= 'f') {
160
- b += c - 'a' + 10;
161
- } else {
162
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
163
- return 0;
164
- }
153
+ c = reader_get(&pi->rd);
154
+ b = b << 4;
155
+ if ('0' <= c && c <= '9') {
156
+ b += c - '0';
157
+ } else if ('A' <= c && c <= 'F') {
158
+ b += c - 'A' + 10;
159
+ } else if ('a' <= c && c <= 'f') {
160
+ b += c - 'a' + 10;
161
+ } else {
162
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
163
+ return 0;
164
+ }
165
165
  }
166
166
  return b;
167
167
  }
168
168
 
169
- static void
170
- unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
169
+ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
171
170
  if (0x0000007F >= code) {
172
- buf_append(buf, (char)code);
171
+ buf_append(buf, (char)code);
173
172
  } else if (0x000007FF >= code) {
174
- buf_append(buf, 0xC0 | (code >> 6));
175
- buf_append(buf, 0x80 | (0x3F & code));
173
+ buf_append(buf, 0xC0 | (code >> 6));
174
+ buf_append(buf, 0x80 | (0x3F & code));
176
175
  } else if (0x0000FFFF >= code) {
177
- buf_append(buf, 0xE0 | (code >> 12));
178
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
179
- buf_append(buf, 0x80 | (0x3F & code));
176
+ buf_append(buf, 0xE0 | (code >> 12));
177
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
178
+ buf_append(buf, 0x80 | (0x3F & code));
180
179
  } else if (0x001FFFFF >= code) {
181
- buf_append(buf, 0xF0 | (code >> 18));
182
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
183
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
184
- buf_append(buf, 0x80 | (0x3F & code));
180
+ buf_append(buf, 0xF0 | (code >> 18));
181
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
182
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
183
+ buf_append(buf, 0x80 | (0x3F & code));
185
184
  } else if (0x03FFFFFF >= code) {
186
- buf_append(buf, 0xF8 | (code >> 24));
187
- buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
188
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
189
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
190
- buf_append(buf, 0x80 | (0x3F & code));
185
+ buf_append(buf, 0xF8 | (code >> 24));
186
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
187
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
188
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
189
+ buf_append(buf, 0x80 | (0x3F & code));
191
190
  } else if (0x7FFFFFFF >= code) {
192
- buf_append(buf, 0xFC | (code >> 30));
193
- buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
194
- buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
195
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
196
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
197
- buf_append(buf, 0x80 | (0x3F & code));
191
+ buf_append(buf, 0xFC | (code >> 30));
192
+ buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
193
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
194
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
195
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
196
+ buf_append(buf, 0x80 | (0x3F & code));
198
197
  } else {
199
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
198
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
200
199
  }
201
200
  }
202
201
 
203
202
  // entered at backslash
204
- static void
205
- read_escaped_str(ParseInfo pi) {
206
- struct _Buf buf;
207
- char c;
208
- uint32_t code;
209
- Val parent = stack_peek(&pi->stack);
203
+ static void read_escaped_str(ParseInfo pi) {
204
+ struct _buf buf;
205
+ char c;
206
+ uint32_t code;
207
+ Val parent = stack_peek(&pi->stack);
210
208
 
211
209
  buf_init(&buf);
212
210
  if (pi->rd.str < pi->rd.tail) {
213
- buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
211
+ buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
214
212
  }
215
213
  while ('\"' != (c = reader_get(&pi->rd))) {
216
- if ('\0' == c) {
217
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
218
- buf_cleanup(&buf);
219
- return;
220
- } else if ('\\' == c) {
221
- c = reader_get(&pi->rd);
222
- switch (c) {
223
- case 'n': buf_append(&buf, '\n'); break;
224
- case 'r': buf_append(&buf, '\r'); break;
225
- case 't': buf_append(&buf, '\t'); break;
226
- case 'f': buf_append(&buf, '\f'); break;
227
- case 'b': buf_append(&buf, '\b'); break;
228
- case '"': buf_append(&buf, '"'); break;
229
- case '/': buf_append(&buf, '/'); break;
230
- case '\\': buf_append(&buf, '\\'); break;
231
- case '\'':
232
- // The json gem claims this is not an error despite the
233
- // ECMA-404 indicating it is not valid.
234
- if (CompatMode == pi->options.mode) {
235
- buf_append(&buf, '\'');
236
- } else {
237
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
238
- buf_cleanup(&buf);
239
- return;
240
- }
241
- break;
242
- case 'u':
243
- if (0 == (code = read_hex(pi)) && err_has(&pi->err)) {
244
- buf_cleanup(&buf);
245
- return;
246
- }
247
- if (0x0000D800 <= code && code <= 0x0000DFFF) {
248
- uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
249
- uint32_t c2;
250
- char ch2;
251
-
252
- c = reader_get(&pi->rd);
253
- ch2 = reader_get(&pi->rd);
254
- if ('\\' != c || 'u' != ch2) {
255
- if (Yes == pi->options.allow_invalid) {
256
- unicode_to_chars(pi, &buf, code);
257
- reader_backup(&pi->rd);
258
- reader_backup(&pi->rd);
259
- break;
260
- }
261
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
262
- buf_cleanup(&buf);
263
- return;
264
- }
265
- if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) {
266
- buf_cleanup(&buf);
267
- return;
268
- }
269
- c2 = (c2 - 0x0000DC00) & 0x000003FF;
270
- code = ((c1 << 10) | c2) + 0x00010000;
271
- }
272
- unicode_to_chars(pi, &buf, code);
273
- if (err_has(&pi->err)) {
274
- buf_cleanup(&buf);
275
- return;
276
- }
277
- break;
278
- default:
279
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
280
- buf_cleanup(&buf);
281
- return;
282
- }
283
- } else {
284
- buf_append(&buf, c);
285
- }
214
+ if ('\0' == c) {
215
+ oj_set_error_at(pi,
216
+ oj_parse_error_class,
217
+ __FILE__,
218
+ __LINE__,
219
+ "quoted string not terminated");
220
+ buf_cleanup(&buf);
221
+ return;
222
+ } else if ('\\' == c) {
223
+ c = reader_get(&pi->rd);
224
+ switch (c) {
225
+ case 'n': buf_append(&buf, '\n'); break;
226
+ case 'r': buf_append(&buf, '\r'); break;
227
+ case 't': buf_append(&buf, '\t'); break;
228
+ case 'f': buf_append(&buf, '\f'); break;
229
+ case 'b': buf_append(&buf, '\b'); break;
230
+ case '"': buf_append(&buf, '"'); break;
231
+ case '/': buf_append(&buf, '/'); break;
232
+ case '\\': buf_append(&buf, '\\'); break;
233
+ case 'u':
234
+ if (0 == (code = read_hex(pi)) && err_has(&pi->err)) {
235
+ buf_cleanup(&buf);
236
+ return;
237
+ }
238
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
239
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
240
+ uint32_t c2;
241
+ char ch2;
242
+
243
+ c = reader_get(&pi->rd);
244
+ ch2 = reader_get(&pi->rd);
245
+ if ('\\' != c || 'u' != ch2) {
246
+ if (Yes == pi->options.allow_invalid) {
247
+ unicode_to_chars(pi, &buf, code);
248
+ reader_backup(&pi->rd);
249
+ reader_backup(&pi->rd);
250
+ break;
251
+ }
252
+ oj_set_error_at(pi,
253
+ oj_parse_error_class,
254
+ __FILE__,
255
+ __LINE__,
256
+ "invalid escaped character");
257
+ buf_cleanup(&buf);
258
+ return;
259
+ }
260
+ if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) {
261
+ buf_cleanup(&buf);
262
+ return;
263
+ }
264
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
265
+ code = ((c1 << 10) | c2) + 0x00010000;
266
+ }
267
+ unicode_to_chars(pi, &buf, code);
268
+ if (err_has(&pi->err)) {
269
+ buf_cleanup(&buf);
270
+ return;
271
+ }
272
+ break;
273
+ default:
274
+ // The json gem claims this is not an error despite the
275
+ // ECMA-404 indicating it is not valid.
276
+ if (CompatMode == pi->options.mode) {
277
+ buf_append(&buf, c);
278
+ break;
279
+ }
280
+ oj_set_error_at(pi,
281
+ oj_parse_error_class,
282
+ __FILE__,
283
+ __LINE__,
284
+ "invalid escaped character");
285
+ buf_cleanup(&buf);
286
+ return;
287
+ }
288
+ } else {
289
+ buf_append(&buf, c);
290
+ }
286
291
  }
287
292
  if (0 == parent) {
288
- pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
293
+ pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
289
294
  } else {
290
- switch (parent->next) {
291
- case NEXT_ARRAY_NEW:
292
- case NEXT_ARRAY_ELEMENT:
293
- pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
294
- parent->next = NEXT_ARRAY_COMMA;
295
- break;
296
- case NEXT_HASH_NEW:
297
- case NEXT_HASH_KEY:
298
- if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
299
- parent->klen = buf_len(&buf);
300
- parent->key = malloc(parent->klen + 1);
301
- memcpy((char*)parent->key, buf.head, parent->klen);
302
- *(char*)(parent->key + parent->klen) = '\0';
303
- } else {
304
- parent->key = "";
305
- parent->klen = 0;
306
- }
307
- parent->k1 = *pi->rd.str;
308
- parent->next = NEXT_HASH_COLON;
309
- break;
310
- case NEXT_HASH_VALUE:
311
- pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
312
- if (parent->kalloc) {
313
- xfree((char*)parent->key);
314
- }
315
- parent->key = 0;
316
- parent->kalloc = 0;
317
- parent->next = NEXT_HASH_COMMA;
318
- break;
319
- case NEXT_HASH_COMMA:
320
- case NEXT_NONE:
321
- case NEXT_ARRAY_COMMA:
322
- case NEXT_HASH_COLON:
323
- default:
324
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
325
- break;
326
- }
295
+ switch (parent->next) {
296
+ case NEXT_ARRAY_NEW:
297
+ case NEXT_ARRAY_ELEMENT:
298
+ pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
299
+ parent->next = NEXT_ARRAY_COMMA;
300
+ break;
301
+ case NEXT_HASH_NEW:
302
+ case NEXT_HASH_KEY:
303
+ if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
304
+ parent->klen = buf_len(&buf);
305
+ parent->key = malloc(parent->klen + 1);
306
+ memcpy((char *)parent->key, buf.head, parent->klen);
307
+ *(char *)(parent->key + parent->klen) = '\0';
308
+ } else {
309
+ parent->key = "";
310
+ parent->klen = 0;
311
+ }
312
+ parent->k1 = *pi->rd.str;
313
+ parent->next = NEXT_HASH_COLON;
314
+ break;
315
+ case NEXT_HASH_VALUE:
316
+ pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
317
+ if (parent->kalloc) {
318
+ xfree((char *)parent->key);
319
+ }
320
+ parent->key = 0;
321
+ parent->kalloc = 0;
322
+ parent->next = NEXT_HASH_COMMA;
323
+ break;
324
+ case NEXT_HASH_COMMA:
325
+ case NEXT_NONE:
326
+ case NEXT_ARRAY_COMMA:
327
+ case NEXT_HASH_COLON:
328
+ default:
329
+ oj_set_error_at(pi,
330
+ oj_parse_error_class,
331
+ __FILE__,
332
+ __LINE__,
333
+ "expected %s, not a string",
334
+ oj_stack_next_string(parent->next));
335
+ break;
336
+ }
327
337
  }
328
338
  buf_cleanup(&buf);
329
339
  }
330
340
 
331
- static void
332
- read_str(ParseInfo pi) {
333
- Val parent = stack_peek(&pi->stack);
334
- char c;
341
+ static void read_str(ParseInfo pi) {
342
+ Val parent = stack_peek(&pi->stack);
343
+ char c;
335
344
 
336
345
  reader_protect(&pi->rd);
337
346
  while ('\"' != (c = reader_get(&pi->rd))) {
338
- if ('\0' == c) {
339
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
340
- return;
341
- } else if ('\\' == c) {
342
- reader_backup(&pi->rd);
343
- read_escaped_str(pi);
344
- reader_release(&pi->rd);
345
- return;
346
- }
347
- }
348
- if (0 == parent) { // simple add
349
- pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
347
+ if ('\0' == c) {
348
+ oj_set_error_at(pi,
349
+ oj_parse_error_class,
350
+ __FILE__,
351
+ __LINE__,
352
+ "quoted string not terminated");
353
+ return;
354
+ } else if ('\\' == c) {
355
+ reader_backup(&pi->rd);
356
+ read_escaped_str(pi);
357
+ reader_release(&pi->rd);
358
+ return;
359
+ }
360
+ }
361
+ if (0 == parent) { // simple add
362
+ pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
350
363
  } else {
351
- switch (parent->next) {
352
- case NEXT_ARRAY_NEW:
353
- case NEXT_ARRAY_ELEMENT:
354
- pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
355
- parent->next = NEXT_ARRAY_COMMA;
356
- break;
357
- case NEXT_HASH_NEW:
358
- case NEXT_HASH_KEY:
359
- parent->klen = pi->rd.tail - pi->rd.str - 1;
360
- if (sizeof(parent->karray) <= parent->klen) {
361
- parent->key = oj_strndup(pi->rd.str, parent->klen);
362
- parent->kalloc = 1;
363
- } else {
364
- memcpy(parent->karray, pi->rd.str, parent->klen);
365
- parent->karray[parent->klen] = '\0';
366
- parent->key = parent->karray;
367
- parent->kalloc = 0;
368
- }
369
- parent->key_val = pi->hash_key(pi, parent->key, parent->klen);
370
- parent->k1 = *pi->rd.str;
371
- parent->next = NEXT_HASH_COLON;
372
- break;
373
- case NEXT_HASH_VALUE:
374
- pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
375
- if (parent->kalloc) {
376
- xfree((char*)parent->key);
377
- }
378
- parent->key = 0;
379
- parent->kalloc = 0;
380
- parent->next = NEXT_HASH_COMMA;
381
- break;
382
- case NEXT_HASH_COMMA:
383
- case NEXT_NONE:
384
- case NEXT_ARRAY_COMMA:
385
- case NEXT_HASH_COLON:
386
- default:
387
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
388
- break;
389
- }
364
+ switch (parent->next) {
365
+ case NEXT_ARRAY_NEW:
366
+ case NEXT_ARRAY_ELEMENT:
367
+ pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
368
+ parent->next = NEXT_ARRAY_COMMA;
369
+ break;
370
+ case NEXT_HASH_NEW:
371
+ case NEXT_HASH_KEY:
372
+ parent->klen = pi->rd.tail - pi->rd.str - 1;
373
+ if (sizeof(parent->karray) <= parent->klen) {
374
+ parent->key = oj_strndup(pi->rd.str, parent->klen);
375
+ parent->kalloc = 1;
376
+ } else {
377
+ memcpy(parent->karray, pi->rd.str, parent->klen);
378
+ parent->karray[parent->klen] = '\0';
379
+ parent->key = parent->karray;
380
+ parent->kalloc = 0;
381
+ }
382
+ parent->key_val = pi->hash_key(pi, parent->key, parent->klen);
383
+ parent->k1 = *pi->rd.str;
384
+ parent->next = NEXT_HASH_COLON;
385
+ break;
386
+ case NEXT_HASH_VALUE:
387
+ pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
388
+ if (parent->kalloc) {
389
+ xfree((char *)parent->key);
390
+ }
391
+ parent->key = 0;
392
+ parent->kalloc = 0;
393
+ parent->next = NEXT_HASH_COMMA;
394
+ break;
395
+ case NEXT_HASH_COMMA:
396
+ case NEXT_NONE:
397
+ case NEXT_ARRAY_COMMA:
398
+ case NEXT_HASH_COLON:
399
+ default:
400
+ oj_set_error_at(pi,
401
+ oj_parse_error_class,
402
+ __FILE__,
403
+ __LINE__,
404
+ "expected %s, not a string",
405
+ oj_stack_next_string(parent->next));
406
+ break;
407
+ }
390
408
  }
391
409
  reader_release(&pi->rd);
392
410
  }
393
411
 
394
- static void
395
- read_num(ParseInfo pi) {
396
- struct _NumInfo ni;
397
- char c;
412
+ static void read_num(ParseInfo pi) {
413
+ struct _numInfo ni;
414
+ char c;
398
415
 
399
416
  reader_protect(&pi->rd);
400
- ni.i = 0;
401
- ni.num = 0;
402
- ni.div = 1;
403
- ni.di = 0;
404
- ni.len = 0;
405
- ni.exp = 0;
406
- ni.big = 0;
417
+ ni.i = 0;
418
+ ni.num = 0;
419
+ ni.div = 1;
420
+ ni.di = 0;
421
+ ni.len = 0;
422
+ ni.exp = 0;
423
+ ni.big = 0;
407
424
  ni.infinity = 0;
408
- ni.nan = 0;
409
- ni.neg = 0;
410
- ni.hasExp = 0;
411
- ni.no_big = (FloatDec == pi->options.bigdec_load);
425
+ ni.nan = 0;
426
+ ni.neg = 0;
427
+ ni.has_exp = 0;
428
+ if (CompatMode == pi->options.mode) {
429
+ ni.no_big = !pi->options.compat_bigdec;
430
+ ni.bigdec_load = pi->options.compat_bigdec;
431
+ } else {
432
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
433
+ RubyDec == pi->options.bigdec_load);
434
+ ni.bigdec_load = pi->options.bigdec_load;
435
+ }
436
+
412
437
  c = reader_get(&pi->rd);
413
438
  if ('-' == c) {
414
- c = reader_get(&pi->rd);
415
- ni.neg = 1;
439
+ c = reader_get(&pi->rd);
440
+ ni.neg = 1;
416
441
  } else if ('+' == c) {
417
- c = reader_get(&pi->rd);
442
+ c = reader_get(&pi->rd);
418
443
  }
419
444
  if ('I' == c) {
420
- if (No == pi->options.allow_nan) {
421
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
422
- return;
423
- } else if (0 != reader_expect(&pi->rd, "nfinity")) {
424
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
425
- return;
426
- }
427
- ni.infinity = 1;
445
+ if (No == pi->options.allow_nan) {
446
+ oj_set_error_at(pi,
447
+ oj_parse_error_class,
448
+ __FILE__,
449
+ __LINE__,
450
+ "not a number or other value");
451
+ return;
452
+ } else if (0 != reader_expect(&pi->rd, "nfinity")) {
453
+ oj_set_error_at(pi,
454
+ oj_parse_error_class,
455
+ __FILE__,
456
+ __LINE__,
457
+ "not a number or other value");
458
+ return;
459
+ }
460
+ ni.infinity = 1;
428
461
  } else {
429
- int dec_cnt = 0;
430
- bool zero1 = false;
431
-
432
- for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
433
- if (0 == ni.i && '0' == c) {
434
- zero1 = true;
435
- }
436
- if (0 < ni.i) {
437
- dec_cnt++;
438
- }
439
- if (ni.big) {
440
- ni.big++;
441
- } else {
442
- int d = (c - '0');
443
-
444
- if (0 < d) {
445
- if (zero1 && CompatMode == pi->options.mode) {
446
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
447
- return;
448
- }
449
- zero1 = false;
450
- }
451
- ni.i = ni.i * 10 + d;
452
- if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
453
- ni.big = 1;
454
- }
455
- }
456
- }
457
- if ('.' == c) {
458
- c = reader_get(&pi->rd);
459
- // A trailing . is not a valid decimal but if encountered allow it
460
- // except when mimicing the JSON gem.
461
- if (CompatMode == pi->options.mode) {
462
- if (c < '0' || '9' < c) {
463
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
464
- }
465
- }
466
- for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
467
- int d = (c - '0');
468
-
469
- if (0 < ni.num || 0 < ni.i) {
470
- dec_cnt++;
471
- }
472
- ni.num = ni.num * 10 + d;
473
- ni.div *= 10;
474
- ni.di++;
475
- if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
476
- ni.big = 1;
477
- }
478
- }
479
- }
480
- if ('e' == c || 'E' == c) {
481
- int eneg = 0;
482
-
483
- ni.hasExp = 1;
484
- c = reader_get(&pi->rd);
485
- if ('-' == c) {
486
- c = reader_get(&pi->rd);
487
- eneg = 1;
488
- } else if ('+' == c) {
489
- c = reader_get(&pi->rd);
490
- }
491
- for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
492
- ni.exp = ni.exp * 10 + (c - '0');
493
- if (EXP_MAX <= ni.exp) {
494
- ni.big = 1;
495
- }
496
- }
497
- if (eneg) {
498
- ni.exp = -ni.exp;
499
- }
500
- }
501
- ni.len = pi->rd.tail - pi->rd.str;
502
- if (0 != c) {
503
- reader_backup(&pi->rd);
504
- }
462
+ int dec_cnt = 0;
463
+ bool zero1 = false;
464
+
465
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
466
+ if (0 == ni.i && '0' == c) {
467
+ zero1 = true;
468
+ }
469
+ if (0 < ni.i) {
470
+ dec_cnt++;
471
+ }
472
+ if (ni.big) {
473
+ ni.big++;
474
+ } else {
475
+ int d = (c - '0');
476
+
477
+ if (0 < d) {
478
+ if (zero1 && CompatMode == pi->options.mode) {
479
+ oj_set_error_at(pi,
480
+ oj_parse_error_class,
481
+ __FILE__,
482
+ __LINE__,
483
+ "not a number");
484
+ return;
485
+ }
486
+ zero1 = false;
487
+ }
488
+ ni.i = ni.i * 10 + d;
489
+ if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
490
+ ni.big = 1;
491
+ }
492
+ }
493
+ }
494
+ if ('.' == c) {
495
+ c = reader_get(&pi->rd);
496
+ // A trailing . is not a valid decimal but if encountered allow it
497
+ // except when mimicking the JSON gem.
498
+ if (CompatMode == pi->options.mode) {
499
+ if (c < '0' || '9' < c) {
500
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
501
+ }
502
+ }
503
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
504
+ int d = (c - '0');
505
+
506
+ if (0 < ni.num || 0 < ni.i) {
507
+ dec_cnt++;
508
+ }
509
+ if (INT64_MAX <= ni.div) {
510
+ if (!ni.no_big) {
511
+ ni.big = true;
512
+ }
513
+ } else {
514
+ ni.num = ni.num * 10 + d;
515
+ ni.div *= 10;
516
+ ni.di++;
517
+ if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
518
+ if (!ni.no_big) {
519
+ ni.big = true;
520
+ }
521
+ }
522
+ }
523
+ }
524
+ }
525
+ if ('e' == c || 'E' == c) {
526
+ int eneg = 0;
527
+
528
+ ni.has_exp = 1;
529
+ c = reader_get(&pi->rd);
530
+ if ('-' == c) {
531
+ c = reader_get(&pi->rd);
532
+ eneg = 1;
533
+ } else if ('+' == c) {
534
+ c = reader_get(&pi->rd);
535
+ }
536
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
537
+ ni.exp = ni.exp * 10 + (c - '0');
538
+ if (EXP_MAX <= ni.exp) {
539
+ ni.big = 1;
540
+ }
541
+ }
542
+ if (eneg) {
543
+ ni.exp = -ni.exp;
544
+ }
545
+ }
546
+ ni.len = pi->rd.tail - pi->rd.str;
547
+ if (0 != c) {
548
+ reader_backup(&pi->rd);
549
+ }
505
550
  }
506
551
  ni.str = pi->rd.str;
507
552
  ni.len = pi->rd.tail - pi->rd.str;
508
553
  // Check for special reserved values for Infinity and NaN.
509
554
  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
- }
518
- }
519
- if (BigDec == pi->options.bigdec_load) {
520
- ni.big = 1;
555
+ if (0 == strcasecmp(INF_VAL, ni.str)) {
556
+ ni.infinity = 1;
557
+ } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
558
+ ni.infinity = 1;
559
+ ni.neg = 1;
560
+ } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
561
+ ni.nan = 1;
562
+ }
563
+ }
564
+ if (CompatMode == pi->options.mode) {
565
+ if (pi->options.compat_bigdec) {
566
+ ni.big = 1;
567
+ }
568
+ } else if (BigDec == pi->options.bigdec_load) {
569
+ ni.big = 1;
521
570
  }
522
571
  add_num_value(pi, &ni);
523
572
  reader_release(&pi->rd);
524
573
  }
525
574
 
526
- static void
527
- read_nan(ParseInfo pi) {
528
- struct _NumInfo ni;
529
- char c;
530
-
531
- ni.str = pi->rd.str;
532
- ni.i = 0;
533
- ni.num = 0;
534
- ni.div = 1;
535
- ni.di = 0;
536
- ni.len = 0;
537
- ni.exp = 0;
538
- ni.big = 0;
575
+ static void read_nan(ParseInfo pi) {
576
+ struct _numInfo ni;
577
+ char c;
578
+
579
+ ni.str = pi->rd.str;
580
+ ni.i = 0;
581
+ ni.num = 0;
582
+ ni.div = 1;
583
+ ni.di = 0;
584
+ ni.len = 0;
585
+ ni.exp = 0;
586
+ ni.big = 0;
539
587
  ni.infinity = 0;
540
- ni.nan = 1;
541
- ni.neg = 0;
542
- ni.no_big = (FloatDec == pi->options.bigdec_load);
588
+ ni.nan = 1;
589
+ ni.neg = 0;
590
+ if (CompatMode == pi->options.mode) {
591
+ ni.no_big = !pi->options.compat_bigdec;
592
+ ni.bigdec_load = pi->options.compat_bigdec;
593
+ } else {
594
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
595
+ RubyDec == pi->options.bigdec_load);
596
+ ni.bigdec_load = pi->options.bigdec_load;
597
+ }
543
598
 
544
- if ('a' != reader_get(&pi->rd) ||
545
- ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
546
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
547
- return;
599
+ if ('a' != reader_get(&pi->rd) || ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
600
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
601
+ return;
548
602
  }
549
- if (BigDec == pi->options.bigdec_load) {
550
- ni.big = 1;
603
+ if (CompatMode == pi->options.mode) {
604
+ if (pi->options.compat_bigdec) {
605
+ ni.big = 1;
606
+ }
607
+ } else if (BigDec == pi->options.bigdec_load) {
608
+ ni.big = 1;
551
609
  }
552
610
  add_num_value(pi, &ni);
553
611
  }
554
612
 
555
- static void
556
- array_start(ParseInfo pi) {
557
- VALUE v = pi->start_array(pi);
613
+ static void array_start(ParseInfo pi) {
614
+ VALUE v = pi->start_array(pi);
558
615
 
559
616
  stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
560
617
  }
561
618
 
562
- static void
563
- array_end(ParseInfo pi) {
564
- Val array = stack_pop(&pi->stack);
619
+ static void array_end(ParseInfo pi) {
620
+ Val array = stack_pop(&pi->stack);
565
621
 
566
622
  if (0 == array) {
567
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
623
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
568
624
  } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
569
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next));
625
+ oj_set_error_at(pi,
626
+ oj_parse_error_class,
627
+ __FILE__,
628
+ __LINE__,
629
+ "expected %s, not an array close",
630
+ oj_stack_next_string(array->next));
570
631
  } else {
571
- pi->end_array(pi);
572
- add_value(pi, array->val);
632
+ pi->end_array(pi);
633
+ add_value(pi, array->val);
573
634
  }
574
635
  }
575
636
 
576
- static void
577
- hash_start(ParseInfo pi) {
578
- volatile VALUE v = pi->start_hash(pi);
637
+ static void hash_start(ParseInfo pi) {
638
+ volatile VALUE v = pi->start_hash(pi);
579
639
 
580
640
  stack_push(&pi->stack, v, NEXT_HASH_NEW);
581
641
  }
582
642
 
583
- static void
584
- hash_end(ParseInfo pi) {
585
- volatile Val hash = stack_peek(&pi->stack);
643
+ static void hash_end(ParseInfo pi) {
644
+ volatile Val hash = stack_peek(&pi->stack);
586
645
 
587
646
  // leave hash on stack until just before
588
647
  if (0 == hash) {
589
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
648
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
590
649
  } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
591
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next));
650
+ oj_set_error_at(pi,
651
+ oj_parse_error_class,
652
+ __FILE__,
653
+ __LINE__,
654
+ "expected %s, not a hash close",
655
+ oj_stack_next_string(hash->next));
592
656
  } else {
593
- pi->end_hash(pi);
594
- stack_pop(&pi->stack);
595
- add_value(pi, hash->val);
657
+ pi->end_hash(pi);
658
+ stack_pop(&pi->stack);
659
+ add_value(pi, hash->val);
596
660
  }
597
661
  }
598
662
 
599
- static void
600
- comma(ParseInfo pi) {
601
- Val parent = stack_peek(&pi->stack);
663
+ static void comma(ParseInfo pi) {
664
+ Val parent = stack_peek(&pi->stack);
602
665
 
603
666
  if (0 == parent) {
604
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
667
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
605
668
  } else if (NEXT_ARRAY_COMMA == parent->next) {
606
- parent->next = NEXT_ARRAY_ELEMENT;
669
+ parent->next = NEXT_ARRAY_ELEMENT;
607
670
  } else if (NEXT_HASH_COMMA == parent->next) {
608
- parent->next = NEXT_HASH_KEY;
671
+ parent->next = NEXT_HASH_KEY;
609
672
  } else {
610
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
673
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
611
674
  }
612
675
  }
613
676
 
614
- static void
615
- colon(ParseInfo pi) {
616
- Val parent = stack_peek(&pi->stack);
677
+ static void colon(ParseInfo pi) {
678
+ Val parent = stack_peek(&pi->stack);
617
679
 
618
680
  if (0 != parent && NEXT_HASH_COLON == parent->next) {
619
- parent->next = NEXT_HASH_VALUE;
681
+ parent->next = NEXT_HASH_VALUE;
620
682
  } else {
621
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
683
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
622
684
  }
623
685
  }
624
686
 
625
- void
626
- oj_sparse2(ParseInfo pi) {
627
- int first = 1;
628
- char c;
629
- long start = 0;
687
+ void oj_sparse2(ParseInfo pi) {
688
+ int first = 1;
689
+ char c;
690
+ long start = 0;
630
691
 
631
692
  err_init(&pi->err);
632
693
  while (1) {
633
- if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
634
- VALUE err_clas = oj_get_json_err_class("NestingError");
635
-
636
- oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
637
- pi->err_class = err_clas;
638
- return;
639
- }
640
- c = reader_next_non_white(&pi->rd);
641
- if (!first && '\0' != c) {
642
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document");
643
- }
644
- switch (c) {
645
- case '{':
646
- hash_start(pi);
647
- break;
648
- case '}':
649
- hash_end(pi);
650
- break;
651
- case ':':
652
- colon(pi);
653
- break;
654
- case '[':
655
- array_start(pi);
656
- break;
657
- case ']':
658
- array_end(pi);
659
- break;
660
- case ',':
661
- comma(pi);
662
- break;
663
- case '"':
664
- read_str(pi);
665
- break;
666
- case '+':
667
- if (CompatMode == pi->options.mode) {
668
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
669
- return;
670
- }
671
- pi->cur--;
672
- read_num(pi);
673
- break;
674
- case '-':
675
- case '0':
676
- case '1':
677
- case '2':
678
- case '3':
679
- case '4':
680
- case '5':
681
- case '6':
682
- case '7':
683
- case '8':
684
- case '9':
685
- reader_backup(&pi->rd);
686
- read_num(pi);
687
- break;
688
- case 'I':
689
- if (Yes == pi->options.allow_nan) {
690
- reader_backup(&pi->rd);
691
- read_num(pi);
692
- } else {
693
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
694
- return;
695
- }
696
- break;
697
- case 'N':
698
- if (Yes == pi->options.allow_nan) {
699
- read_nan(pi);
700
- } else {
701
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
702
- return;
703
- }
704
- break;
705
- case 't':
706
- read_true(pi);
707
- break;
708
- case 'f':
709
- read_false(pi);
710
- break;
711
- case 'n':
712
- c = reader_get(&pi->rd);
713
- if ('u' == c) {
714
- if (0 == reader_expect(&pi->rd, "ll")) {
715
- add_value(pi, Qnil);
716
- } else {
717
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
718
- return;
719
- }
720
- } else if ('a' == c) {
721
- struct _NumInfo ni;
722
-
723
- c = reader_get(&pi->rd);
724
- if ('N' != c && 'n' != c) {
725
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
726
- return;
727
- }
728
- ni.str = pi->rd.str;
729
- ni.i = 0;
730
- ni.num = 0;
731
- ni.div = 1;
732
- ni.di = 0;
733
- ni.len = 0;
734
- ni.exp = 0;
735
- ni.big = 0;
736
- ni.infinity = 0;
737
- ni.nan = 1;
738
- ni.neg = 0;
739
- ni.no_big = (FloatDec == pi->options.bigdec_load);
740
- add_num_value(pi, &ni);
741
- } else {
742
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
743
- return;
744
- }
745
- break;
746
- case '/':
747
- skip_comment(pi);
748
- break;
749
- case '\0':
750
- return;
751
- default:
752
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character '%c' [0x%02x]", c, c);
753
- return;
754
- }
755
- if (err_has(&pi->err)) {
756
- return;
757
- }
758
- if (stack_empty(&pi->stack)) {
759
- if (Qundef != pi->proc) {
760
- VALUE args[3];
761
- long len = pi->rd.pos - start;
762
-
763
- *args = stack_head_val(&pi->stack);
764
- args[1] = LONG2NUM(start);
765
- args[2] = LONG2NUM(len);
766
-
767
- if (Qnil == pi->proc) {
768
- rb_yield_values2(3, args);
769
- } else {
770
- rb_proc_call_with_block(pi->proc, 3, args, Qnil);
771
- }
772
- } else if (!pi->has_callbacks) {
773
- first = 0;
774
- }
775
- start = pi->rd.pos;
776
- }
694
+ if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
695
+ VALUE err_clas = oj_get_json_err_class("NestingError");
696
+
697
+ oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
698
+ pi->err_class = err_clas;
699
+ return;
700
+ }
701
+ c = reader_next_non_white(&pi->rd);
702
+ if (!first && '\0' != c) {
703
+ oj_set_error_at(pi,
704
+ oj_parse_error_class,
705
+ __FILE__,
706
+ __LINE__,
707
+ "unexpected characters after the JSON document");
708
+ }
709
+ switch (c) {
710
+ case '{': hash_start(pi); break;
711
+ case '}': hash_end(pi); break;
712
+ case ':': colon(pi); break;
713
+ case '[': array_start(pi); break;
714
+ case ']': array_end(pi); break;
715
+ case ',': comma(pi); break;
716
+ case '"': read_str(pi); break;
717
+ case '+':
718
+ if (CompatMode == pi->options.mode) {
719
+ oj_set_error_at(pi,
720
+ oj_parse_error_class,
721
+ __FILE__,
722
+ __LINE__,
723
+ "unexpected character");
724
+ return;
725
+ }
726
+ pi->cur--;
727
+ read_num(pi);
728
+ break;
729
+ case '-':
730
+ case '0':
731
+ case '1':
732
+ case '2':
733
+ case '3':
734
+ case '4':
735
+ case '5':
736
+ case '6':
737
+ case '7':
738
+ case '8':
739
+ case '9':
740
+ reader_backup(&pi->rd);
741
+ read_num(pi);
742
+ break;
743
+ case 'I':
744
+ if (Yes == pi->options.allow_nan) {
745
+ reader_backup(&pi->rd);
746
+ read_num(pi);
747
+ } else {
748
+ oj_set_error_at(pi,
749
+ oj_parse_error_class,
750
+ __FILE__,
751
+ __LINE__,
752
+ "unexpected character");
753
+ return;
754
+ }
755
+ break;
756
+ case 'N':
757
+ if (Yes == pi->options.allow_nan) {
758
+ read_nan(pi);
759
+ } else {
760
+ oj_set_error_at(pi,
761
+ oj_parse_error_class,
762
+ __FILE__,
763
+ __LINE__,
764
+ "unexpected character");
765
+ return;
766
+ }
767
+ break;
768
+ case 't': read_true(pi); break;
769
+ case 'f': read_false(pi); break;
770
+ case 'n':
771
+ c = reader_get(&pi->rd);
772
+ if ('u' == c) {
773
+ if (0 == reader_expect(&pi->rd, "ll")) {
774
+ add_value(pi, Qnil);
775
+ } else {
776
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
777
+ return;
778
+ }
779
+ } else if ('a' == c) {
780
+ struct _numInfo ni;
781
+
782
+ c = reader_get(&pi->rd);
783
+ if ('N' != c && 'n' != c) {
784
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
785
+ return;
786
+ }
787
+ ni.str = pi->rd.str;
788
+ ni.i = 0;
789
+ ni.num = 0;
790
+ ni.div = 1;
791
+ ni.di = 0;
792
+ ni.len = 0;
793
+ ni.exp = 0;
794
+ ni.big = 0;
795
+ ni.infinity = 0;
796
+ ni.nan = 1;
797
+ ni.neg = 0;
798
+ if (CompatMode == pi->options.mode) {
799
+ ni.no_big = !pi->options.compat_bigdec;
800
+ ni.bigdec_load = pi->options.compat_bigdec;
801
+ } else {
802
+ ni.no_big = (FloatDec == pi->options.bigdec_load ||
803
+ FastDec == pi->options.bigdec_load ||
804
+ RubyDec == pi->options.bigdec_load);
805
+ ni.bigdec_load = pi->options.bigdec_load;
806
+ }
807
+ add_num_value(pi, &ni);
808
+ } else {
809
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
810
+ return;
811
+ }
812
+ break;
813
+ case '/': skip_comment(pi); break;
814
+ case '\0': return;
815
+ default:
816
+ oj_set_error_at(pi,
817
+ oj_parse_error_class,
818
+ __FILE__,
819
+ __LINE__,
820
+ "unexpected character '%c' [0x%02x]",
821
+ c,
822
+ c);
823
+ return;
824
+ }
825
+ if (err_has(&pi->err)) {
826
+ return;
827
+ }
828
+ if (stack_empty(&pi->stack)) {
829
+ if (Qundef != pi->proc) {
830
+ VALUE args[3];
831
+ long len = pi->rd.pos - start;
832
+
833
+ *args = stack_head_val(&pi->stack);
834
+ args[1] = LONG2NUM(start);
835
+ args[2] = LONG2NUM(len);
836
+
837
+ if (Qnil == pi->proc) {
838
+ rb_yield_values2(3, args);
839
+ } else {
840
+ rb_proc_call_with_block(pi->proc, 3, args, Qnil);
841
+ }
842
+ } else if (!pi->has_callbacks) {
843
+ first = 0;
844
+ }
845
+ start = pi->rd.pos;
846
+ // TBD break if option set to allow that
847
+ }
777
848
  }
778
849
  }
779
850
 
780
- static VALUE
781
- protect_parse(VALUE pip) {
851
+ static VALUE protect_parse(VALUE pip) {
782
852
  oj_sparse2((ParseInfo)pip);
783
853
 
784
854
  return Qnil;
@@ -786,46 +856,47 @@ protect_parse(VALUE pip) {
786
856
 
787
857
  VALUE
788
858
  oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
789
- volatile VALUE input;
790
- volatile VALUE wrapped_stack;
791
- VALUE result = Qnil;
792
- int line = 0;
859
+ volatile VALUE input;
860
+ volatile VALUE wrapped_stack;
861
+ VALUE result = Qnil;
862
+ int line = 0;
793
863
 
794
864
  if (argc < 1) {
795
- rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
865
+ rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
796
866
  }
797
867
  input = argv[0];
798
868
  if (2 <= argc) {
799
- if (T_HASH == rb_type(argv[1])) {
800
- oj_parse_options(argv[1], &pi->options);
801
- } else if (3 <= argc && T_HASH == rb_type(argv[2])) {
802
- oj_parse_options(argv[2], &pi->options);
803
- }
869
+ if (T_HASH == rb_type(argv[1])) {
870
+ oj_parse_options(argv[1], &pi->options);
871
+ } else if (3 <= argc && T_HASH == rb_type(argv[2])) {
872
+ oj_parse_options(argv[2], &pi->options);
873
+ }
804
874
  }
805
875
  if (Qnil == input) {
806
- if (Yes == pi->options.nilnil) {
807
- return Qnil;
808
- } else {
809
- rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
810
- }
811
- } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) && No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
812
- rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
876
+ if (Yes == pi->options.nilnil) {
877
+ return Qnil;
878
+ } else {
879
+ rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
880
+ }
881
+ } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
882
+ No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
883
+ rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
813
884
  }
814
885
  if (rb_block_given_p()) {
815
- pi->proc = Qnil;
886
+ pi->proc = Qnil;
816
887
  } else {
817
- pi->proc = Qundef;
888
+ pi->proc = Qundef;
818
889
  }
819
890
  oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
820
- pi->json = 0; // indicates reader is in use
891
+ pi->json = 0; // indicates reader is in use
821
892
 
822
893
  if (Yes == pi->options.circular) {
823
- pi->circ_array = oj_circ_array_new();
894
+ pi->circ_array = oj_circ_array_new();
824
895
  } else {
825
- pi->circ_array = 0;
896
+ pi->circ_array = 0;
826
897
  }
827
898
  if (No == pi->options.allow_gc) {
828
- rb_gc_disable();
899
+ rb_gc_disable();
829
900
  }
830
901
  // GC can run at any time. When it runs any Object created by C will be
831
902
  // freed. We protect against this by wrapping the value stack in a ruby
@@ -834,77 +905,84 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
834
905
  wrapped_stack = oj_stack_init(&pi->stack);
835
906
  rb_protect(protect_parse, (VALUE)pi, &line);
836
907
  if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
837
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
908
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
838
909
  }
839
- result = stack_head_val(&pi->stack);
910
+ result = stack_head_val(&pi->stack);
840
911
  DATA_PTR(wrapped_stack) = 0;
841
912
  if (No == pi->options.allow_gc) {
842
- rb_gc_enable();
913
+ rb_gc_enable();
843
914
  }
844
915
  if (!err_has(&pi->err)) {
845
- // If the stack is not empty then the JSON terminated early.
846
- Val v;
847
- VALUE err_class = oj_parse_error_class;
848
-
849
- if (0 != line) {
850
- VALUE ec = rb_obj_class(rb_errinfo());
851
-
852
- if (rb_eIOError != ec) {
853
- goto CLEANUP;
854
- }
855
- // Sometimes the class of the error is 0 which seems broken.
856
- if (rb_eArgError != ec && 0 != ec) {
857
- err_class = ec;
858
- }
859
- }
860
- if (0 != (v = stack_peek(&pi->stack))) {
861
- switch (v->next) {
862
- case NEXT_ARRAY_NEW:
863
- case NEXT_ARRAY_ELEMENT:
864
- case NEXT_ARRAY_COMMA:
865
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
866
- break;
867
- case NEXT_HASH_NEW:
868
- case NEXT_HASH_KEY:
869
- case NEXT_HASH_COLON:
870
- case NEXT_HASH_VALUE:
871
- case NEXT_HASH_COMMA:
872
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
873
- break;
874
- default:
875
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
876
- }
877
- }
916
+ // If the stack is not empty then the JSON terminated early.
917
+ Val v;
918
+ VALUE err_class = oj_parse_error_class;
919
+
920
+ if (0 != line) {
921
+ VALUE ec = rb_obj_class(rb_errinfo());
922
+
923
+ if (rb_eIOError != ec) {
924
+ goto CLEANUP;
925
+ }
926
+ // Sometimes the class of the error is 0 which seems broken.
927
+ if (rb_eArgError != ec && 0 != ec) {
928
+ err_class = ec;
929
+ }
930
+ }
931
+ if (0 != (v = stack_peek(&pi->stack))) {
932
+ switch (v->next) {
933
+ case NEXT_ARRAY_NEW:
934
+ case NEXT_ARRAY_ELEMENT:
935
+ case NEXT_ARRAY_COMMA:
936
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
937
+ break;
938
+ case NEXT_HASH_NEW:
939
+ case NEXT_HASH_KEY:
940
+ case NEXT_HASH_COLON:
941
+ case NEXT_HASH_VALUE:
942
+ case NEXT_HASH_COMMA:
943
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
944
+ break;
945
+ default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
946
+ }
947
+ }
878
948
  }
879
949
  CLEANUP:
880
950
  // proceed with cleanup
881
951
  if (0 != pi->circ_array) {
882
- oj_circ_array_free(pi->circ_array);
952
+ oj_circ_array_free(pi->circ_array);
883
953
  }
884
954
  stack_cleanup(&pi->stack);
885
955
  if (0 != fd) {
886
- close(fd);
956
+ #ifdef _WIN32
957
+ rb_w32_close(fd);
958
+ #else
959
+ close(fd);
960
+ #endif
887
961
  }
888
962
  if (err_has(&pi->err)) {
889
- rb_set_errinfo(Qnil);
890
- if (Qnil != pi->err_class && 0 != pi->err_class) {
891
- pi->err.clas = pi->err_class;
892
- }
893
- if (CompatMode == pi->options.mode) {
894
- // The json gem requires the error message be UTF-8 encoded. In
895
- // additional the complete JSON source should be returned but that
896
- // is not possible without stored all the bytes read and reading
897
- // the remaining bytes on the stream. Both seem like a very bad
898
- // idea.
899
- VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) };
900
-
901
- rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
902
- } else {
903
- oj_err_raise(&pi->err);
904
- }
905
- oj_err_raise(&pi->err);
963
+ rb_set_errinfo(Qnil);
964
+ if (Qnil != pi->err_class && 0 != pi->err_class) {
965
+ pi->err.clas = pi->err_class;
966
+ }
967
+ if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
968
+ // The json gem requires the error message be UTF-8 encoded. In
969
+ // additional the complete JSON source should be returned but that
970
+ // is not possible without stored all the bytes read and reading
971
+ // the remaining bytes on the stream. Both seem like a very bad
972
+ // idea.
973
+ VALUE args[] = {oj_encode(rb_str_new2(pi->err.msg))};
974
+
975
+ if (pi->err.clas == oj_parse_error_class) {
976
+ // The error was an Oj::ParseError so change to a JSON::ParserError.
977
+ pi->err.clas = oj_json_parser_error_class;
978
+ }
979
+ rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
980
+ } else {
981
+ oj_err_raise(&pi->err);
982
+ }
983
+ oj_err_raise(&pi->err);
906
984
  } else if (0 != line) {
907
- rb_jump_tag(line);
985
+ rb_jump_tag(line);
908
986
  }
909
987
  return result;
910
988
  }