oj 3.7.4 → 3.11.2

Sign up to get free protection for your applications and to get access to all the features.
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;