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