oj 3.11.0 → 3.16.5

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