oj 3.7.12

Sign up to get free protection for your applications and to get access to all the features.
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,363 @@
1
+ /* stream_writer.c
2
+ * Copyright (c) 2012, 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <errno.h>
7
+
8
+ #include <ruby.h>
9
+
10
+ #include "encode.h"
11
+
12
+ extern VALUE Oj;
13
+
14
+ static void
15
+ stream_writer_free(void *ptr) {
16
+ StreamWriter sw;
17
+
18
+ if (0 == ptr) {
19
+ return;
20
+ }
21
+ sw = (StreamWriter)ptr;
22
+ xfree(sw->sw.out.buf);
23
+ xfree(sw->sw.types);
24
+ xfree(ptr);
25
+ }
26
+
27
+ static void
28
+ stream_writer_reset_buf(StreamWriter sw) {
29
+ sw->sw.out.cur = sw->sw.out.buf;
30
+ *sw->sw.out.cur = '\0';
31
+ }
32
+
33
+ static void
34
+ stream_writer_write(StreamWriter sw) {
35
+ ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
36
+
37
+ switch (sw->type) {
38
+ case STRING_IO:
39
+ case STREAM_IO: {
40
+ volatile VALUE rs = rb_str_new(sw->sw.out.buf, size);
41
+
42
+ // Oddly enough, when pushing ASCII characters with UTF-8 encoding or
43
+ // even ASCII-8BIT does not change the output encoding. Pushing any
44
+ // non-ASCII no matter what the encoding changes the output encoding
45
+ // to ASCII-8BIT if it the string is not forced to UTF-8 here.
46
+ rs = oj_encode(rs);
47
+ rb_funcall(sw->stream, oj_write_id, 1, rs);
48
+ break;
49
+ }
50
+ case FILE_IO:
51
+ if (size != write(sw->fd, sw->sw.out.buf, size)) {
52
+ rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno));
53
+ }
54
+ break;
55
+ default:
56
+ rb_raise(rb_eArgError, "expected an IO Object.");
57
+ }
58
+ stream_writer_reset_buf(sw);
59
+ }
60
+
61
+ static VALUE buffer_size_sym = Qundef;
62
+
63
+ /* Document-method: new
64
+ * call-seq: new(io, options)
65
+ *
66
+ * Creates a new StreamWriter. Options are supported according the the
67
+ * specified mode or the mode in the default options. Note that if mimic_JSON
68
+ * or Oj.optimize_rails has not been called then the behavior of the modes may
69
+ * not be the same as if they were.
70
+ *
71
+ * In addition to the regular dump options for the various modes a
72
+ * _:buffer_size_ option is available. It should be set to a positive
73
+ * integer. It is considered a hint of how large the initial internal buffer
74
+ * should be and also a hint on when to flush.
75
+ *
76
+ * - *io* [_IO_] stream to write to
77
+ * - *options* [_Hash_] formating options
78
+ */
79
+ static VALUE
80
+ stream_writer_new(int argc, VALUE *argv, VALUE self) {
81
+ StreamWriterType type = STREAM_IO;
82
+ int fd = 0;
83
+ VALUE stream = argv[0];
84
+ VALUE clas = rb_obj_class(stream);
85
+ StreamWriter sw;
86
+ #if !IS_WINDOWS
87
+ VALUE s;
88
+ #endif
89
+
90
+ if (oj_stringio_class == clas) {
91
+ type = STRING_IO;
92
+ #if !IS_WINDOWS
93
+ } else if (rb_respond_to(stream, oj_fileno_id) &&
94
+ Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
95
+ 0 != (fd = FIX2INT(s))) {
96
+ type = FILE_IO;
97
+ #endif
98
+ } else if (rb_respond_to(stream, oj_write_id)) {
99
+ type = STREAM_IO;
100
+ } else {
101
+ rb_raise(rb_eArgError, "expected an IO Object.");
102
+ }
103
+ sw = ALLOC(struct _streamWriter);
104
+ if (2 == argc && T_HASH == rb_type(argv[1])) {
105
+ volatile VALUE v;
106
+ int buf_size = 0;
107
+
108
+ if (Qundef == buffer_size_sym) {
109
+ buffer_size_sym = ID2SYM(rb_intern("buffer_size")); rb_gc_register_address(&buffer_size_sym);
110
+
111
+ }
112
+ if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) {
113
+ #ifdef RUBY_INTEGER_UNIFICATION
114
+ if (rb_cInteger != rb_obj_class(v)) {
115
+ rb_raise(rb_eArgError, ":buffer size must be a Integer.");
116
+ }
117
+ #else
118
+ if (T_FIXNUM != rb_type(v)) {
119
+ rb_raise(rb_eArgError, ":buffer size must be a Integer.");
120
+ }
121
+ #endif
122
+ buf_size = FIX2INT(v);
123
+ }
124
+ oj_str_writer_init(&sw->sw, buf_size);
125
+ oj_parse_options(argv[1], &sw->sw.opts);
126
+ sw->flush_limit = buf_size;
127
+ } else {
128
+ oj_str_writer_init(&sw->sw, 4096);
129
+ sw->flush_limit = 0;
130
+ }
131
+ sw->sw.out.indent = sw->sw.opts.indent;
132
+ sw->stream = stream;
133
+ sw->type = type;
134
+ sw->fd = fd;
135
+
136
+ return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
137
+ }
138
+
139
+ /* Document-method: push_key
140
+ * call-seq: push_key(key)
141
+ *
142
+ * Pushes a key onto the JSON document. The key will be used for the next push
143
+ * if currently in a JSON object and ignored otherwise. If a key is provided on
144
+ * the next push then that new key will be ignored.
145
+ *
146
+ * - *key* [_String_] the key pending for the next push
147
+ */
148
+ static VALUE
149
+ stream_writer_push_key(VALUE self, VALUE key) {
150
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
151
+
152
+ rb_check_type(key, T_STRING);
153
+ oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
154
+ if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
155
+ stream_writer_write(sw);
156
+ }
157
+ return Qnil;
158
+ }
159
+
160
+ /* Document-method: push_object
161
+ * call-seq: push_object(key=nil)
162
+ *
163
+ * Pushes an object onto the JSON document. Future pushes will be to this object
164
+ * until a pop() is called.
165
+ *
166
+ * - *key* [_String_] the key if adding to an object in the JSON document
167
+ */
168
+ static VALUE
169
+ stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
170
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
171
+
172
+ switch (argc) {
173
+ case 0:
174
+ oj_str_writer_push_object(&sw->sw, 0);
175
+ break;
176
+ case 1:
177
+ if (Qnil == argv[0]) {
178
+ oj_str_writer_push_object(&sw->sw, 0);
179
+ } else {
180
+ rb_check_type(argv[0], T_STRING);
181
+ oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
182
+ }
183
+ break;
184
+ default:
185
+ rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
186
+ break;
187
+ }
188
+ if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
189
+ stream_writer_write(sw);
190
+ }
191
+ return Qnil;
192
+ }
193
+
194
+ /* Document-method: push_array
195
+ * call-seq: push_array(key=nil)
196
+ *
197
+ * Pushes an array onto the JSON document. Future pushes will be to this object
198
+ * until a pop() is called.
199
+ *
200
+ * - *key* [_String_] the key if adding to an object in the JSON document
201
+ */
202
+ static VALUE
203
+ stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
204
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
205
+
206
+ switch (argc) {
207
+ case 0:
208
+ oj_str_writer_push_array(&sw->sw, 0);
209
+ break;
210
+ case 1:
211
+ if (Qnil == argv[0]) {
212
+ oj_str_writer_push_array(&sw->sw, 0);
213
+ } else {
214
+ rb_check_type(argv[0], T_STRING);
215
+ oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
216
+ }
217
+ break;
218
+ default:
219
+ rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
220
+ break;
221
+ }
222
+ if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
223
+ stream_writer_write(sw);
224
+ }
225
+ return Qnil;
226
+ }
227
+
228
+ /* Document-method: push_value
229
+ * call-seq: push_value(value, key=nil)
230
+ *
231
+ * Pushes a value onto the JSON document.
232
+ * - *value* [_Object_] value to add to the JSON document
233
+ * - *key* [_String_] the key if adding to an object in the JSON document
234
+ */
235
+ static VALUE
236
+ stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
237
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
238
+
239
+ switch (argc) {
240
+ case 1:
241
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
242
+ break;
243
+ case 2:
244
+ if (Qnil == argv[1]) {
245
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
246
+ } else {
247
+ rb_check_type(argv[1], T_STRING);
248
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
249
+ }
250
+ break;
251
+ default:
252
+ rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
253
+ break;
254
+ }
255
+ if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
256
+ stream_writer_write(sw);
257
+ }
258
+ return Qnil;
259
+ }
260
+
261
+ /* Document-method: push_json
262
+ * call-seq: push_json(value, key=nil)
263
+ *
264
+ * Pushes a string onto the JSON document. The String must be a valid JSON
265
+ * encoded string. No additional checking is done to verify the validity of the
266
+ * string.
267
+ * - *value* [_Object_] value to add to the JSON document
268
+ * - *key* [_String_] the key if adding to an object in the JSON document
269
+ */
270
+ static VALUE
271
+ stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
272
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
273
+
274
+ rb_check_type(argv[0], T_STRING);
275
+ switch (argc) {
276
+ case 1:
277
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
278
+ break;
279
+ case 2:
280
+ if (Qnil == argv[1]) {
281
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
282
+ } else {
283
+ rb_check_type(argv[1], T_STRING);
284
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
285
+ }
286
+ break;
287
+ default:
288
+ rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
289
+ break;
290
+ }
291
+ if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
292
+ stream_writer_write(sw);
293
+ }
294
+ return Qnil;
295
+ }
296
+
297
+ /* Document-method: pop
298
+ * call-seq: pop()
299
+ *
300
+ * Pops up a level in the JSON document closing the array or object that is
301
+ * currently open.
302
+ */
303
+ static VALUE
304
+ stream_writer_pop(VALUE self) {
305
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
306
+
307
+ oj_str_writer_pop(&sw->sw);
308
+ if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
309
+ stream_writer_write(sw);
310
+ }
311
+ return Qnil;
312
+ }
313
+
314
+ /* Document-method: pop_all
315
+ * call-seq: pop_all()
316
+ *
317
+ * Pops all level in the JSON document closing all the array or object that is
318
+ * currently open.
319
+ */
320
+ static VALUE
321
+ stream_writer_pop_all(VALUE self) {
322
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
323
+
324
+ oj_str_writer_pop_all(&sw->sw);
325
+ stream_writer_write(sw);
326
+
327
+ return Qnil;
328
+ }
329
+
330
+ /* Document-method: flush
331
+ * call-seq: flush()
332
+ *
333
+ * Flush any remaining characters in the buffer.
334
+ */
335
+ static VALUE
336
+ stream_writer_flush(VALUE self) {
337
+ stream_writer_write((StreamWriter)DATA_PTR(self));
338
+
339
+ return Qnil;
340
+ }
341
+
342
+ /* Document-class: Oj::StreamWriter
343
+ *
344
+ * Supports building a JSON document one element at a time. Build the IO stream
345
+ * document by pushing values into the document. Pushing an array or an object
346
+ * will create that element in the JSON document and subsequent pushes will add
347
+ * the elements to that array or object until a pop() is called.
348
+ */
349
+ void
350
+ oj_stream_writer_init() {
351
+ oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
352
+ rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
353
+ rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
354
+ rb_define_method(oj_stream_writer_class, "push_object", stream_writer_push_object, -1);
355
+ rb_define_method(oj_stream_writer_class, "push_array", stream_writer_push_array, -1);
356
+ rb_define_method(oj_stream_writer_class, "push_value", stream_writer_push_value, -1);
357
+ rb_define_method(oj_stream_writer_class, "push_json", stream_writer_push_json, -1);
358
+ rb_define_method(oj_stream_writer_class, "pop", stream_writer_pop, 0);
359
+ rb_define_method(oj_stream_writer_class, "pop_all", stream_writer_pop_all, 0);
360
+ rb_define_method(oj_stream_writer_class, "flush", stream_writer_flush, 0);
361
+ }
362
+
363
+
@@ -0,0 +1,212 @@
1
+ /* strict.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 <unistd.h>
10
+
11
+ #include "oj.h"
12
+ #include "err.h"
13
+ #include "parse.h"
14
+ #include "encode.h"
15
+ #include "trace.h"
16
+
17
+ static void
18
+ hash_end(ParseInfo pi) {
19
+ if (Yes == pi->options.trace) {
20
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
21
+ }
22
+ }
23
+
24
+ static void
25
+ array_end(ParseInfo pi) {
26
+ if (Yes == pi->options.trace) {
27
+ oj_trace_parse_array_end(pi, __FILE__, __LINE__);
28
+ }
29
+ }
30
+
31
+ static VALUE
32
+ noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
33
+ return Qundef;
34
+ }
35
+
36
+ static void
37
+ add_value(ParseInfo pi, VALUE val) {
38
+ if (Yes == pi->options.trace) {
39
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
40
+ }
41
+ pi->stack.head->val = val;
42
+ }
43
+
44
+ static void
45
+ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
46
+ volatile VALUE rstr = rb_str_new(str, len);
47
+
48
+ rstr = oj_encode(rstr);
49
+ pi->stack.head->val = rstr;
50
+ if (Yes == pi->options.trace) {
51
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
52
+ }
53
+ }
54
+
55
+ static void
56
+ add_num(ParseInfo pi, NumInfo ni) {
57
+ if (ni->infinity || ni->nan) {
58
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
59
+ }
60
+ pi->stack.head->val = oj_num_as_value(ni);
61
+ if (Yes == pi->options.trace) {
62
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
63
+ }
64
+ }
65
+
66
+ static VALUE
67
+ start_hash(ParseInfo pi) {
68
+ if (Qnil != pi->options.hash_class) {
69
+ return rb_class_new_instance(0, NULL, pi->options.hash_class);
70
+ }
71
+ if (Yes == pi->options.trace) {
72
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
+ }
74
+ return rb_hash_new();
75
+ }
76
+
77
+ static VALUE
78
+ calc_hash_key(ParseInfo pi, Val parent) {
79
+ volatile VALUE rkey = parent->key_val;
80
+
81
+ if (Qundef == rkey) {
82
+ rkey = rb_str_new(parent->key, parent->klen);
83
+ }
84
+ rkey = oj_encode(rkey);
85
+ if (Yes == pi->options.sym_key) {
86
+ rkey = rb_str_intern(rkey);
87
+ }
88
+ return rkey;
89
+ }
90
+
91
+ static void
92
+ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
93
+ volatile VALUE rstr = rb_str_new(str, len);
94
+
95
+ rstr = oj_encode(rstr);
96
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
97
+ if (Yes == pi->options.trace) {
98
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
99
+ }
100
+ }
101
+
102
+ static void
103
+ hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
104
+ volatile VALUE v;
105
+
106
+ if (ni->infinity || ni->nan) {
107
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
108
+ }
109
+ v = oj_num_as_value(ni);
110
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v);
111
+ if (Yes == pi->options.trace) {
112
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
113
+ }
114
+ }
115
+
116
+ static void
117
+ hash_set_value(ParseInfo pi, Val parent, VALUE value) {
118
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
119
+ if (Yes == pi->options.trace) {
120
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
121
+ }
122
+ }
123
+
124
+ static VALUE
125
+ start_array(ParseInfo pi) {
126
+ if (Yes == pi->options.trace) {
127
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
128
+ }
129
+ return rb_ary_new();
130
+ }
131
+
132
+ static void
133
+ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
134
+ volatile VALUE rstr = rb_str_new(str, len);
135
+
136
+ rstr = oj_encode(rstr);
137
+ rb_ary_push(stack_peek(&pi->stack)->val, rstr);
138
+ if (Yes == pi->options.trace) {
139
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
140
+ }
141
+ }
142
+
143
+ static void
144
+ array_append_num(ParseInfo pi, NumInfo ni) {
145
+ volatile VALUE v;
146
+
147
+ if (ni->infinity || ni->nan) {
148
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
149
+ }
150
+ v = oj_num_as_value(ni);
151
+ rb_ary_push(stack_peek(&pi->stack)->val, v);
152
+ if (Yes == pi->options.trace) {
153
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
154
+ }
155
+ }
156
+
157
+ static void
158
+ array_append_value(ParseInfo pi, VALUE value) {
159
+ rb_ary_push(stack_peek(&pi->stack)->val, value);
160
+ if (Yes == pi->options.trace) {
161
+ oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
162
+ }
163
+ }
164
+
165
+ void
166
+ oj_set_strict_callbacks(ParseInfo pi) {
167
+ pi->start_hash = start_hash;
168
+ pi->end_hash = hash_end;
169
+ pi->hash_key = noop_hash_key;
170
+ pi->hash_set_cstr = hash_set_cstr;
171
+ pi->hash_set_num = hash_set_num;
172
+ pi->hash_set_value = hash_set_value;
173
+ pi->start_array = start_array;
174
+ pi->end_array = array_end;
175
+ pi->array_append_cstr = array_append_cstr;
176
+ pi->array_append_num = array_append_num;
177
+ pi->array_append_value = array_append_value;
178
+ pi->add_cstr = add_cstr;
179
+ pi->add_num = add_num;
180
+ pi->add_value = add_value;
181
+ pi->expect_value = 1;
182
+ }
183
+
184
+ VALUE
185
+ oj_strict_parse(int argc, VALUE *argv, VALUE self) {
186
+ struct _parseInfo pi;
187
+
188
+ parse_info_init(&pi);
189
+ pi.options = oj_default_options;
190
+ pi.handler = Qnil;
191
+ pi.err_class = Qnil;
192
+ oj_set_strict_callbacks(&pi);
193
+
194
+ if (T_STRING == rb_type(*argv)) {
195
+ return oj_pi_parse(argc, argv, &pi, 0, 0, true);
196
+ } else {
197
+ return oj_pi_sparse(argc, argv, &pi, 0);
198
+ }
199
+ }
200
+
201
+ VALUE
202
+ oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
203
+ struct _parseInfo pi;
204
+
205
+ parse_info_init(&pi);
206
+ pi.options = oj_default_options;
207
+ pi.handler = Qnil;
208
+ pi.err_class = Qnil;
209
+ oj_set_strict_callbacks(&pi);
210
+
211
+ return oj_pi_parse(argc, argv, &pi, json, len, true);
212
+ }