oj 3.9.1 → 3.16.11

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