oj 3.7.4 → 3.11.2

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -4
  3. data/ext/oj/buf.h +6 -34
  4. data/ext/oj/cache8.c +3 -3
  5. data/ext/oj/cache8.h +5 -33
  6. data/ext/oj/circarray.c +5 -9
  7. data/ext/oj/circarray.h +5 -8
  8. data/ext/oj/code.c +3 -6
  9. data/ext/oj/code.h +7 -10
  10. data/ext/oj/compat.c +11 -14
  11. data/ext/oj/custom.c +108 -75
  12. data/ext/oj/dump.c +132 -92
  13. data/ext/oj/dump.h +6 -7
  14. data/ext/oj/dump_compat.c +37 -34
  15. data/ext/oj/dump_leaf.c +3 -6
  16. data/ext/oj/dump_object.c +23 -17
  17. data/ext/oj/dump_strict.c +7 -9
  18. data/ext/oj/encode.h +6 -32
  19. data/ext/oj/err.c +2 -5
  20. data/ext/oj/err.h +6 -34
  21. data/ext/oj/extconf.rb +6 -0
  22. data/ext/oj/fast.c +39 -56
  23. data/ext/oj/hash.c +11 -39
  24. data/ext/oj/hash.h +5 -33
  25. data/ext/oj/hash_test.c +3 -31
  26. data/ext/oj/mimic_json.c +65 -44
  27. data/ext/oj/object.c +38 -69
  28. data/ext/oj/odd.c +18 -17
  29. data/ext/oj/odd.h +6 -9
  30. data/ext/oj/oj.c +139 -93
  31. data/ext/oj/oj.h +43 -35
  32. data/ext/oj/parse.c +164 -60
  33. data/ext/oj/parse.h +30 -31
  34. data/ext/oj/rails.c +119 -83
  35. data/ext/oj/rails.h +4 -7
  36. data/ext/oj/reader.c +5 -8
  37. data/ext/oj/reader.h +7 -10
  38. data/ext/oj/resolve.c +4 -7
  39. data/ext/oj/resolve.h +4 -7
  40. data/ext/oj/rxclass.c +8 -11
  41. data/ext/oj/rxclass.h +8 -11
  42. data/ext/oj/saj.c +9 -12
  43. data/ext/oj/scp.c +4 -7
  44. data/ext/oj/sparse.c +67 -33
  45. data/ext/oj/stream_writer.c +16 -15
  46. data/ext/oj/strict.c +9 -12
  47. data/ext/oj/string_writer.c +27 -8
  48. data/ext/oj/trace.c +5 -8
  49. data/ext/oj/trace.h +9 -12
  50. data/ext/oj/util.c +136 -0
  51. data/ext/oj/util.h +19 -0
  52. data/ext/oj/val_stack.c +28 -36
  53. data/ext/oj/val_stack.h +19 -50
  54. data/ext/oj/wab.c +29 -29
  55. data/lib/oj.rb +0 -8
  56. data/lib/oj/json.rb +1 -1
  57. data/lib/oj/mimic.rb +46 -2
  58. data/lib/oj/version.rb +2 -2
  59. data/pages/Modes.md +47 -45
  60. data/pages/Options.md +43 -10
  61. data/pages/Rails.md +60 -21
  62. data/pages/Security.md +1 -1
  63. data/test/activesupport5/abstract_unit.rb +45 -0
  64. data/test/activesupport5/decoding_test.rb +68 -60
  65. data/test/activesupport5/encoding_test.rb +111 -96
  66. data/test/activesupport5/encoding_test_cases.rb +33 -25
  67. data/test/activesupport5/test_helper.rb +43 -21
  68. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  69. data/test/activesupport6/abstract_unit.rb +44 -0
  70. data/test/activesupport6/decoding_test.rb +133 -0
  71. data/test/activesupport6/encoding_test.rb +507 -0
  72. data/test/activesupport6/encoding_test_cases.rb +98 -0
  73. data/test/activesupport6/test_common.rb +17 -0
  74. data/test/activesupport6/test_helper.rb +163 -0
  75. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  76. data/test/bar.rb +24 -6
  77. data/test/baz.rb +16 -0
  78. data/test/foo.rb +26 -57
  79. data/test/helper.rb +10 -0
  80. data/test/json_gem/json_common_interface_test.rb +8 -3
  81. data/test/json_gem/json_generator_test.rb +15 -3
  82. data/test/json_gem/test_helper.rb +8 -0
  83. data/test/prec.rb +23 -0
  84. data/test/sample_json.rb +1 -1
  85. data/test/test_compat.rb +21 -10
  86. data/test/test_custom.rb +135 -8
  87. data/test/test_integer_range.rb +1 -2
  88. data/test/test_object.rb +35 -2
  89. data/test/test_rails.rb +35 -0
  90. data/test/test_strict.rb +24 -1
  91. data/test/test_various.rb +52 -63
  92. data/test/test_writer.rb +19 -2
  93. data/test/tests.rb +1 -0
  94. data/test/zoo.rb +13 -0
  95. metadata +100 -75
data/ext/oj/hash.h CHANGED
@@ -1,39 +1,11 @@
1
- /* hash.h
2
- * Copyright (c) 2011, Peter Ohler
3
- * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
30
2
 
31
- #ifndef __OJ_HASH_H__
32
- #define __OJ_HASH_H__
3
+ #ifndef OJ_HASH_H
4
+ #define OJ_HASH_H
33
5
 
34
6
  #include "ruby.h"
35
7
 
36
- typedef struct _Hash *Hash;
8
+ typedef struct _hash *Hash;
37
9
 
38
10
  extern void oj_hash_init();
39
11
 
@@ -43,4 +15,4 @@ extern ID oj_attr_hash_get(const char *key, size_t len, ID **slotp);
43
15
  extern void oj_hash_print();
44
16
  extern char* oj_strndup(const char *s, size_t len);
45
17
 
46
- #endif /* __OJ_HASH_H__ */
18
+ #endif /* OJ_HASH_H */
data/ext/oj/hash_test.c CHANGED
@@ -1,32 +1,4 @@
1
- /* hash_test.c
2
- * Copyright (c) 2011, Peter Ohler
3
- * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
30
2
 
31
3
  // if windows, comment out the whole file. It's only a performance test.
32
4
  #ifndef _WIN32
@@ -39,12 +11,12 @@
39
11
  #define __STDC_FORMAT_MACROS
40
12
  #include <inttypes.h>
41
13
 
42
- typedef struct _StrLen {
14
+ typedef struct _strLen {
43
15
  const char *str;
44
16
  size_t len;
45
17
  } *StrLen;
46
18
 
47
- static struct _StrLen data[] = {
19
+ static struct _strLen data[] = {
48
20
  { "Gem::Version", 12 },
49
21
  { "TracePoint", 10 },
50
22
  { "Complex::compatible", 19 },
data/ext/oj/mimic_json.c CHANGED
@@ -1,14 +1,11 @@
1
- /* mimic_json.c
2
- * Copyright (c) 2012, 2017, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
5
2
 
6
3
  #include "oj.h"
7
4
  #include "encode.h"
8
5
  #include "dump.h"
9
6
  #include "parse.h"
10
7
 
11
- static VALUE symbolize_names_sym;
8
+ static VALUE symbolize_names_sym = Qundef;
12
9
 
13
10
  extern const char oj_json_class[];
14
11
 
@@ -26,30 +23,30 @@ static VALUE state_class;
26
23
  // mimic JSON documentation
27
24
 
28
25
  /* Document-module: JSON::Ext
29
- *
26
+ *
30
27
  * The Ext module is a placeholder in the mimic JSON module used for
31
28
  * compatibility only.
32
29
  */
33
30
  /* Document-class: JSON::Ext::Parser
34
- *
31
+ *
35
32
  * The JSON::Ext::Parser is a placeholder in the mimic JSON module used for
36
33
  * compatibility only.
37
34
  */
38
35
  /* Document-class: JSON::Ext::Generator
39
- *
36
+ *
40
37
  * The JSON::Ext::Generator is a placeholder in the mimic JSON module used for
41
38
  * compatibility only.
42
39
  */
43
40
 
44
41
  /* Document-method: parser=
45
42
  * call-seq: parser=(parser)
46
- *
43
+ *
47
44
  * Does nothing other than provide compatibility.
48
45
  * - *parser* [_Object_] ignored
49
46
  */
50
47
  /* Document-method: generator=
51
48
  * call-seq: generator=(generator)
52
- *
49
+ *
53
50
  * Does nothing other than provide compatibility.
54
51
  * - *generator* [_Object_] ignored
55
52
  */
@@ -167,7 +164,7 @@ oj_parse_mimic_dump_options(VALUE ropts, Options copts) {
167
164
  if (Qnil != (v = rb_hash_lookup(ropts, oj_ascii_only_sym))) {
168
165
  // generate seems to assume anything except nil and false are true.
169
166
  if (Qfalse == v) {
170
- copts->escape_mode = JXEsc; // JSONEsc;
167
+ copts->escape_mode = JXEsc;
171
168
  } else {
172
169
  copts->escape_mode = ASCIIEsc;
173
170
  }
@@ -184,9 +181,9 @@ mimic_limit_arg(VALUE a) {
184
181
 
185
182
  /* Document-method: dump
186
183
  * call-seq: dump(obj, anIO=nil, limit=nil)
187
- *
184
+ *
188
185
  * Encodes an object as a JSON String.
189
- *
186
+ *
190
187
  * - *obj* [_Object_] object to convert to encode as JSON
191
188
  * - *anIO* [_IO_] an IO that allows writing
192
189
  * - *limit* [_Fixnum_] ignored
@@ -196,9 +193,10 @@ mimic_limit_arg(VALUE a) {
196
193
  static VALUE
197
194
  mimic_dump(int argc, VALUE *argv, VALUE self) {
198
195
  char buf[4096];
199
- struct _Out out;
200
- struct _Options copts = oj_default_options;
196
+ struct _out out;
197
+ struct _options copts = oj_default_options;
201
198
  VALUE rstr;
199
+ VALUE active_hack[1];
202
200
 
203
201
  copts.str_rx.head = NULL;
204
202
  copts.str_rx.tail = NULL;
@@ -216,9 +214,10 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
216
214
  */
217
215
  copts.dump_opts.max_depth = MAX_DEPTH; // when using dump there is no limit
218
216
  out.omit_nil = copts.dump_opts.omit_nil;
217
+
219
218
  if (2 <= argc) {
220
219
  int limit;
221
-
220
+
222
221
  // The json gem take a more liberal approach to optional
223
222
  // arguments. Expected are (obj, anIO=nil, limit=nil) yet the io
224
223
  // argument can be left off completely and the 2nd argument is then
@@ -230,7 +229,15 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
230
229
  copts.dump_opts.max_depth = limit;
231
230
  }
232
231
  }
233
- oj_dump_obj_to_json(*argv, &copts, &out);
232
+ // ActiveSupport in active_support/core_ext/object/json.rb check the
233
+ // optional argument type to to_json and it the argument is a
234
+ // ::JSON::State it calls the JSON gem code otherwise it calls the active
235
+ // support encoder code. To make sure the desired branch is called a
236
+ // default ::JSON::State argument is passed in. Basically a hack to get
237
+ // around the active support hack so two wrongs make a right this time.
238
+ active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
239
+ oj_dump_obj_to_json_using_params(*argv, &copts, &out, 1, active_hack);
240
+
234
241
  if (0 == out.buf) {
235
242
  rb_raise(rb_eNoMemError, "Not enough memory.");
236
243
  }
@@ -285,11 +292,11 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
285
292
 
286
293
  /* Document-method: restore
287
294
  * call-seq: restore(source, proc=nil)
288
- *
295
+ *
289
296
  * Loads a Ruby Object from a JSON source that can be either a String or an
290
- * IO. If Proc is given or a block is providedit is called with each nested
297
+ * IO. If Proc is given or a block is provided it is called with each nested
291
298
  * element of the loaded Object.
292
- *
299
+ *
293
300
  * - *source* [_String_|IO] JSON source
294
301
  * - *proc* [_Proc_] to yield to on each element or nil
295
302
  *
@@ -298,11 +305,11 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
298
305
 
299
306
  /* Document-method: load
300
307
  * call-seq: load(source, proc=nil)
301
- *
308
+ *
302
309
  * Loads a Ruby Object from a JSON source that can be either a String or an
303
- * IO. If Proc is given or a block is providedit is called with each nested
310
+ * IO. If Proc is given or a block is provided it is called with each nested
304
311
  * element of the loaded Object.
305
- *
312
+ *
306
313
  * - *source* [_String_|IO] JSON source
307
314
  * - *proc* [_Proc_] to yield to on each element or nil
308
315
  *
@@ -330,10 +337,10 @@ mimic_load(int argc, VALUE *argv, VALUE self) {
330
337
 
331
338
  /* Document-method: []
332
339
  * call-seq: [](obj, opts={})
333
- *
340
+ *
334
341
  * If the obj argument is a String then it is assumed to be a JSON String and
335
342
  * parsed otherwise the obj is encoded as a JSON String.
336
- *
343
+ *
337
344
  * - *obj* [_String_|Hash|Array] object to convert
338
345
  * - *opts* [_Hash_] same options as either generate or parse
339
346
  *
@@ -354,9 +361,11 @@ mimic_dump_load(int argc, VALUE *argv, VALUE self) {
354
361
  static VALUE
355
362
  mimic_generate_core(int argc, VALUE *argv, Options copts) {
356
363
  char buf[4096];
357
- struct _Out out;
364
+ struct _out out;
358
365
  VALUE rstr;
359
366
 
367
+ memset(buf, 0, sizeof(buf));
368
+
360
369
  out.buf = buf;
361
370
  out.end = buf + sizeof(buf) - 10;
362
371
  out.allocated = false;
@@ -396,11 +405,11 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
396
405
 
397
406
  /* Document-method: generate
398
407
  * call-seq: generate(obj, opts=nil)
399
- *
408
+ *
400
409
  * Encode obj as a JSON String. The obj argument must be a Hash, Array, or
401
410
  * respond to to_h or to_json. Options other than those listed such as
402
411
  * +:allow_nan+ or +:max_nesting+ are ignored.
403
- *
412
+ *
404
413
  * - *obj* [_Object_|Hash|Array] object to convert to a JSON String
405
414
  * - *opts* [_Hash_] options
406
415
  * - - *:indent* [_String_] String to use for indentation.
@@ -414,7 +423,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
414
423
  */
415
424
  VALUE
416
425
  oj_mimic_generate(int argc, VALUE *argv, VALUE self) {
417
- struct _Options copts = oj_default_options;
426
+ struct _options copts = oj_default_options;
418
427
 
419
428
  copts.str_rx.head = NULL;
420
429
  copts.str_rx.tail = NULL;
@@ -432,7 +441,7 @@ oj_mimic_generate(int argc, VALUE *argv, VALUE self) {
432
441
  */
433
442
  VALUE
434
443
  oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
435
- struct _Options copts = oj_default_options;
444
+ struct _options copts = oj_default_options;
436
445
  VALUE rargs[2];
437
446
  volatile VALUE h;
438
447
 
@@ -461,7 +470,7 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
461
470
  rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
462
471
  }
463
472
  rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
464
-
473
+
465
474
  copts.str_rx.head = NULL;
466
475
  copts.str_rx.tail = NULL;
467
476
  strcpy(copts.dump_opts.indent_str, " ");
@@ -481,7 +490,7 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
481
490
 
482
491
  static VALUE
483
492
  mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
484
- struct _ParseInfo pi;
493
+ struct _parseInfo pi;
485
494
  VALUE ropts;
486
495
  VALUE args[1];
487
496
 
@@ -500,7 +509,7 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
500
509
  pi.options.create_ok = No;
501
510
  pi.options.allow_nan = (bang ? Yes : No);
502
511
  pi.options.nilnil = No;
503
- pi.options.bigdec_load = FloatDec;
512
+ pi.options.bigdec_load = RubyDec;
504
513
  pi.options.mode = CompatMode;
505
514
  pi.max_depth = 100;
506
515
 
@@ -510,6 +519,9 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
510
519
  if (T_HASH != rb_type(ropts)) {
511
520
  rb_raise(rb_eArgError, "options must be a hash.");
512
521
  }
522
+ if (Qundef == symbolize_names_sym) {
523
+ symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
524
+ }
513
525
  if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
514
526
  pi.options.sym_key = (Qtrue == v) ? Yes : No;
515
527
  }
@@ -547,6 +559,9 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
547
559
  pi.options.array_class = v;
548
560
  }
549
561
  }
562
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) {
563
+ pi.options.compat_bigdec = (oj_bigdecimal_class == rb_hash_lookup(ropts, oj_decimal_class_sym));
564
+ }
550
565
  v = rb_hash_lookup(ropts, oj_max_nesting_sym);
551
566
  if (Qtrue == v) {
552
567
  pi.max_depth = 100;
@@ -602,9 +617,9 @@ mimic_parse_bang(int argc, VALUE *argv, VALUE self) {
602
617
 
603
618
  /* Document-method: recurse_proc
604
619
  * call-seq: recurse_proc(obj, &proc)
605
- *
620
+ *
606
621
  * Yields to the proc for every element in the obj recursively.
607
- *
622
+ *
608
623
  * - *obj* [_Hash_|Array] object to walk
609
624
  * - *proc* [_Proc_] to yield to on each element
610
625
  */
@@ -631,7 +646,7 @@ mimic_set_create_id(VALUE self, VALUE id) {
631
646
  Check_Type(id, T_STRING);
632
647
 
633
648
  if (NULL != oj_default_options.create_id) {
634
- if (oj_json_class != oj_default_options.create_id && NULL != oj_default_options.create_id) {
649
+ if (oj_json_class != oj_default_options.create_id) {
635
650
  xfree((char*)oj_default_options.create_id);
636
651
  }
637
652
  oj_default_options.create_id = NULL;
@@ -660,7 +675,7 @@ mimic_create_id(VALUE self) {
660
675
  return rb_str_new_cstr(oj_json_class);
661
676
  }
662
677
 
663
- static struct _Options mimic_object_to_json_options = {
678
+ static struct _options mimic_object_to_json_options = {
664
679
  0, // indent
665
680
  No, // circular
666
681
  No, // auto_define
@@ -670,10 +685,12 @@ static struct _Options mimic_object_to_json_options = {
670
685
  No, // class_cache
671
686
  RubyTime, // time_format
672
687
  No, // bigdec_as_num
673
- FloatDec, // bigdec_load
688
+ RubyDec, // bigdec_load
689
+ false, // compat_bigdec
674
690
  No, // to_hash
675
691
  No, // to_json
676
692
  No, // as_json
693
+ No, // raw_json
677
694
  No, // nilnil
678
695
  No, // empty_string
679
696
  Yes, // allow_gc
@@ -682,12 +699,15 @@ static struct _Options mimic_object_to_json_options = {
682
699
  No, // create_ok
683
700
  No, // allow_nan
684
701
  No, // trace
685
- 0, // integer_range_min
686
- 0, // integer_range_max
702
+ No, // safe
703
+ false, // sec_prec_set
704
+ No, // ignore_under
705
+ 0, // int_range_min
706
+ 0, // int_range_max
687
707
  oj_json_class,// create_id
688
708
  10, // create_id_len
689
709
  3, // sec_prec
690
- 16, // float_prec
710
+ 0, // float_prec
691
711
  "%0.16g", // float_fmt
692
712
  Qnil, // hash_class
693
713
  Qnil, // array_class
@@ -717,9 +737,9 @@ static struct _Options mimic_object_to_json_options = {
717
737
  static VALUE
718
738
  mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
719
739
  char buf[4096];
720
- struct _Out out;
740
+ struct _out out;
721
741
  VALUE rstr;
722
- struct _Options copts = oj_default_options;
742
+ struct _options copts = oj_default_options;
723
743
 
724
744
  copts.str_rx.head = NULL;
725
745
  copts.str_rx.tail = NULL;
@@ -821,6 +841,7 @@ oj_mimic_json_methods(VALUE json) {
821
841
  }
822
842
  // Pull in the JSON::State mimic file.
823
843
  state_class = rb_const_get_at(generator, rb_intern("State"));
844
+ rb_gc_register_mark_object(state_class);
824
845
 
825
846
  symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
826
847
  }
@@ -834,7 +855,7 @@ oj_define_mimic_json(int argc, VALUE *argv, VALUE self) {
834
855
  VALUE dummy;
835
856
  VALUE verbose;
836
857
  VALUE json;
837
-
858
+
838
859
  // Either set the paths to indicate JSON has been loaded or replaces the
839
860
  // methods if it has been loaded.
840
861
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
data/ext/oj/object.c CHANGED
@@ -1,8 +1,6 @@
1
- /* object.c
2
- * Copyright (c) 2012, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
5
2
 
3
+ #include <stdint.h>
6
4
  #include <stdio.h>
7
5
  #include <time.h>
8
6
 
@@ -14,6 +12,7 @@
14
12
  #include "odd.h"
15
13
  #include "encode.h"
16
14
  #include "trace.h"
15
+ #include "util.h"
17
16
 
18
17
  inline static long
19
18
  read_long(const char *str, size_t len) {
@@ -274,7 +273,10 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
274
273
  if (2 == kval->klen) {
275
274
  switch (kval->key[1]) {
276
275
  case 't': // time as a float
277
- {
276
+ if (0 == ni->div || 9 < ni->di) {
277
+ rb_raise(rb_eArgError, "Invalid time decimal representation.");
278
+ //parent->val = rb_time_nano_new(0, 0);
279
+ } else {
278
280
  int64_t nsec = ni->num * 1000000000LL / ni->div;
279
281
 
280
282
  if (ni->neg) {
@@ -290,25 +292,20 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
290
292
  // offset and then a conversion to UTC keeps makes the time
291
293
  // match the expected value.
292
294
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
293
- } else if (ni->hasExp) {
294
- time_t t = (time_t)(ni->i + ni->exp);
295
- struct tm *st = gmtime(&t);
296
- VALUE args[8];
297
-
298
- // Windows does not support dates before 1970 so ignore
299
- // the zone and do the best we can.
300
- if (NULL == st) {
301
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
302
- } else {
303
- args[0] = LONG2NUM((long)(1900 + st->tm_year));
304
- args[1] = LONG2NUM(1 + st->tm_mon);
305
- args[2] = LONG2NUM(st->tm_mday);
306
- args[3] = LONG2NUM(st->tm_hour);
307
- args[4] = LONG2NUM(st->tm_min);
308
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
309
- args[6] = LONG2NUM(ni->exp);
310
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
311
- }
295
+ } else if (ni->has_exp) {
296
+ int64_t t = (int64_t)(ni->i + ni->exp);
297
+ struct _timeInfo ti;
298
+ VALUE args[8];
299
+
300
+ sec_as_time(t, &ti);
301
+ args[0] = LONG2NUM((long)(ti.year));
302
+ args[1] = LONG2NUM(ti.mon);
303
+ args[2] = LONG2NUM(ti.day);
304
+ args[3] = LONG2NUM(ti.hour);
305
+ args[4] = LONG2NUM(ti.min);
306
+ args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
307
+ args[6] = LONG2NUM(ni->exp);
308
+ parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
312
309
  } else {
313
310
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
314
311
  }
@@ -403,23 +400,6 @@ hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE
403
400
  return 0;
404
401
  }
405
402
 
406
- static void
407
- copy_ivars(VALUE target, VALUE src) {
408
- volatile VALUE vars = rb_funcall(src, oj_instance_variables_id, 0);
409
- volatile VALUE *np = RARRAY_PTR(vars);
410
- ID vid;
411
- int i, cnt = (int)RARRAY_LEN(vars);
412
- const char *attr;
413
-
414
- for (i = cnt; 0 < i; i--, np++) {
415
- vid = rb_to_id(*np);
416
- attr = rb_id2name(vid);
417
- if ('@' == *attr) {
418
- rb_ivar_set(target, vid, rb_ivar_get(src, vid));
419
- }
420
- }
421
- }
422
-
423
403
  void
424
404
  oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
425
405
  const char *key = kval->key;
@@ -427,19 +407,7 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
427
407
  ID var_id;
428
408
  ID *slot;
429
409
 
430
- if ('~' == *key && Qtrue == rb_obj_is_kind_of(parent->val, rb_eException)) {
431
- if (5 == klen && 0 == strncmp("~mesg", key, klen)) {
432
- VALUE args[1];
433
- volatile VALUE prev = parent->val;
434
-
435
- args[0] = value;
436
- parent->val = rb_class_new_instance(1, args, rb_class_of(parent->val));
437
- copy_ivars(parent->val, prev);
438
- } else if (3 == klen && 0 == strncmp("~bt", key, klen)) {
439
- rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
440
- }
441
- }
442
- #if HAVE_LIBPTHREAD
410
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
443
411
  pthread_mutex_lock(&oj_cache_mutex);
444
412
  #else
445
413
  rb_mutex_lock(oj_cache_mutex);
@@ -473,7 +441,7 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
473
441
  }
474
442
  *slot = var_id;
475
443
  }
476
- #if HAVE_LIBPTHREAD
444
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
477
445
  pthread_mutex_unlock(&oj_cache_mutex);
478
446
  #else
479
447
  rb_mutex_unlock(oj_cache_mutex);
@@ -491,7 +459,7 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
491
459
  WHICH_TYPE:
492
460
  switch (rb_type(parent->val)) {
493
461
  case T_NIL:
494
- parent->odd_args = 0; // make sure it is 0 in case not odd
462
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
495
463
  if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
496
464
  parent->val = rb_hash_new();
497
465
  goto WHICH_TYPE;
@@ -513,7 +481,7 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
513
481
  oj_set_obj_ivar(parent, kval, rval);
514
482
  break;
515
483
  case T_CLASS:
516
- if (0 == parent->odd_args) {
484
+ if (NULL == parent->odd_args) {
517
485
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
518
486
  return;
519
487
  } else {
@@ -549,7 +517,7 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
549
517
  WHICH_TYPE:
550
518
  switch (rb_type(parent->val)) {
551
519
  case T_NIL:
552
- parent->odd_args = 0; // make sure it is 0 in case not odd
520
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
553
521
  if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
554
522
  parent->val = rb_hash_new();
555
523
  goto WHICH_TYPE;
@@ -569,7 +537,7 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
569
537
  }
570
538
  break;
571
539
  case T_CLASS:
572
- if (0 == parent->odd_args) {
540
+ if (NULL == parent->odd_args) {
573
541
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
574
542
  return;
575
543
  } else {
@@ -604,7 +572,7 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
604
572
  WHICH_TYPE:
605
573
  switch (rb_type(parent->val)) {
606
574
  case T_NIL:
607
- parent->odd_args = 0; // make sure it is 0 in case not odd
575
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
608
576
  if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
609
577
  parent->val = rb_hash_new();
610
578
  goto WHICH_TYPE;
@@ -645,7 +613,7 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
645
613
  break;
646
614
  case T_MODULE:
647
615
  case T_CLASS:
648
- if (0 == parent->odd_args) {
616
+ if (NULL == parent->odd_args) {
649
617
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
650
618
  return;
651
619
  } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
@@ -677,17 +645,17 @@ start_hash(ParseInfo pi) {
677
645
  }
678
646
 
679
647
  static void
680
- end_hash(struct _ParseInfo *pi) {
648
+ end_hash(ParseInfo pi) {
681
649
  Val parent = stack_peek(&pi->stack);
682
650
 
683
651
  if (Qnil == parent->val) {
684
652
  parent->val = rb_hash_new();
685
- } else if (0 != parent->odd_args) {
653
+ } else if (NULL != parent->odd_args) {
686
654
  OddArgs oa = parent->odd_args;
687
655
 
688
656
  parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
689
657
  oj_odd_free(oa);
690
- parent->odd_args = 0;
658
+ parent->odd_args = NULL;
691
659
  }
692
660
  if (Yes == pi->options.trace) {
693
661
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
@@ -697,8 +665,9 @@ end_hash(struct _ParseInfo *pi) {
697
665
  static void
698
666
  array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
699
667
  volatile VALUE rval = Qnil;
700
-
701
- if (3 <= len && 0 != pi->circ_array) {
668
+
669
+ // orig lets us know whether the string was ^r1 or \u005er1
670
+ if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
702
671
  if ('i' == str[1]) {
703
672
  long i = read_long(str + 2, len - 2);
704
673
 
@@ -726,7 +695,7 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
726
695
  static void
727
696
  array_append_num(ParseInfo pi, NumInfo ni) {
728
697
  volatile VALUE rval = oj_num_as_value(ni);
729
-
698
+
730
699
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
731
700
  if (Yes == pi->options.trace) {
732
701
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
@@ -765,7 +734,7 @@ oj_set_object_callbacks(ParseInfo pi) {
765
734
 
766
735
  VALUE
767
736
  oj_object_parse(int argc, VALUE *argv, VALUE self) {
768
- struct _ParseInfo pi;
737
+ struct _parseInfo pi;
769
738
 
770
739
  parse_info_init(&pi);
771
740
  pi.options = oj_default_options;
@@ -782,7 +751,7 @@ oj_object_parse(int argc, VALUE *argv, VALUE self) {
782
751
 
783
752
  VALUE
784
753
  oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
785
- struct _ParseInfo pi;
754
+ struct _parseInfo pi;
786
755
 
787
756
  parse_info_init(&pi);
788
757
  pi.options = oj_default_options;