oj 3.7.12

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