oj 3.9.2 → 3.10.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/oj/buf.h +2 -30
- data/ext/oj/cache8.h +1 -29
- data/ext/oj/circarray.c +4 -8
- data/ext/oj/circarray.h +1 -4
- data/ext/oj/code.c +3 -6
- data/ext/oj/code.h +1 -4
- data/ext/oj/compat.c +6 -9
- data/ext/oj/custom.c +8 -7
- data/ext/oj/dump.c +33 -26
- data/ext/oj/dump.h +1 -4
- data/ext/oj/dump_compat.c +9 -14
- data/ext/oj/dump_leaf.c +2 -5
- data/ext/oj/dump_object.c +19 -15
- data/ext/oj/dump_strict.c +7 -9
- data/ext/oj/encode.h +1 -29
- data/ext/oj/err.c +1 -4
- data/ext/oj/err.h +1 -29
- data/ext/oj/extconf.rb +5 -0
- data/ext/oj/fast.c +14 -42
- data/ext/oj/hash.c +4 -32
- data/ext/oj/hash.h +1 -29
- data/ext/oj/hash_test.c +1 -29
- data/ext/oj/mimic_json.c +28 -10
- data/ext/oj/object.c +4 -6
- data/ext/oj/odd.c +1 -4
- data/ext/oj/odd.h +1 -4
- data/ext/oj/oj.c +74 -38
- data/ext/oj/oj.h +9 -7
- data/ext/oj/parse.c +127 -52
- data/ext/oj/parse.h +4 -5
- data/ext/oj/rails.c +38 -8
- data/ext/oj/rails.h +1 -4
- data/ext/oj/reader.c +5 -8
- data/ext/oj/reader.h +2 -5
- data/ext/oj/resolve.c +1 -4
- data/ext/oj/resolve.h +1 -4
- data/ext/oj/rxclass.c +3 -6
- data/ext/oj/rxclass.h +1 -4
- data/ext/oj/saj.c +6 -9
- data/ext/oj/scp.c +1 -4
- data/ext/oj/sparse.c +31 -26
- data/ext/oj/stream_writer.c +4 -9
- data/ext/oj/strict.c +3 -6
- data/ext/oj/string_writer.c +1 -4
- data/ext/oj/trace.c +5 -8
- data/ext/oj/trace.h +1 -4
- data/ext/oj/util.c +1 -1
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +1 -29
- data/ext/oj/val_stack.h +1 -29
- data/ext/oj/wab.c +10 -13
- data/lib/oj/mimic.rb +45 -1
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +0 -8
- data/pages/Modes.md +1 -1
- data/pages/Options.md +15 -11
- data/pages/Rails.md +60 -21
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +68 -60
- data/test/activesupport5/encoding_test.rb +111 -96
- data/test/activesupport5/encoding_test_cases.rb +33 -25
- data/test/activesupport5/test_helper.rb +43 -21
- data/test/activesupport5/time_zone_test_helpers.rb +18 -3
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -0
- data/test/bar.rb +21 -11
- data/test/baz.rb +16 -0
- data/test/foo.rb +39 -8
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +14 -8
- data/test/test_custom.rb +36 -6
- data/test/test_integer_range.rb +1 -2
- data/test/test_object.rb +12 -3
- data/test/test_rails.rb +35 -0
- data/test/test_strict.rb +24 -1
- data/test/test_various.rb +42 -64
- data/test/tests.rb +1 -0
- metadata +29 -7
data/ext/oj/oj.c
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2012, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2012 Peter Ohler. All rights reserved.
|
5
2
|
|
6
3
|
#include <stdlib.h>
|
7
4
|
#include <errno.h>
|
@@ -91,6 +88,7 @@ VALUE oj_slash_string;
|
|
91
88
|
VALUE oj_allow_nan_sym;
|
92
89
|
VALUE oj_array_class_sym;
|
93
90
|
VALUE oj_create_additions_sym;
|
91
|
+
VALUE oj_decimal_class_sym;
|
94
92
|
VALUE oj_hash_class_sym;
|
95
93
|
VALUE oj_indent_sym;
|
96
94
|
VALUE oj_object_class_sym;
|
@@ -115,10 +113,12 @@ static VALUE custom_sym;
|
|
115
113
|
static VALUE empty_string_sym;
|
116
114
|
static VALUE escape_mode_sym;
|
117
115
|
static VALUE integer_range_sym;
|
116
|
+
static VALUE fast_sym;
|
118
117
|
static VALUE float_prec_sym;
|
119
118
|
static VALUE float_sym;
|
120
119
|
static VALUE huge_sym;
|
121
120
|
static VALUE ignore_sym;
|
121
|
+
static VALUE ignore_under_sym;
|
122
122
|
static VALUE json_sym;
|
123
123
|
static VALUE match_string_sym;
|
124
124
|
static VALUE mode_sym;
|
@@ -181,8 +181,10 @@ struct _options oj_default_options = {
|
|
181
181
|
Yes, // allow_nan
|
182
182
|
No, // trace
|
183
183
|
No, // safe
|
184
|
-
|
185
|
-
|
184
|
+
false, // sec_prec_set
|
185
|
+
No, // ignore_under
|
186
|
+
0, // int_range_min
|
187
|
+
0, // int_range_max
|
186
188
|
oj_json_class, // create_id
|
187
189
|
10, // create_id_len
|
188
190
|
9, // sec_prec
|
@@ -227,7 +229,7 @@ struct _options oj_default_options = {
|
|
227
229
|
* - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and dump modes to use for JSON
|
228
230
|
* - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
|
229
231
|
* - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
|
230
|
-
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
|
232
|
+
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits. :float should be the same as ruby. :fast may require rounding but is must faster.
|
231
233
|
* - *:create_id* [_String_|_nil_] create id for json compatible object encoding, default is 'json_class'
|
232
234
|
* - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on load.
|
233
235
|
* - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the seconds portion of time
|
@@ -251,6 +253,7 @@ struct _options oj_default_options = {
|
|
251
253
|
* - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
|
252
254
|
* - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
|
253
255
|
* - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
|
256
|
+
* - *:ignore_under* [Boolean] if true then attributes that start with _ are ignored when dumping in object or custom mode.
|
254
257
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
255
258
|
* - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off)
|
256
259
|
* - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default is false (safe is off)
|
@@ -286,6 +289,7 @@ get_def_opts(VALUE self) {
|
|
286
289
|
rb_hash_aset(opts, oj_trace_sym, (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
|
287
290
|
rb_hash_aset(opts, oj_safe_sym, (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
|
288
291
|
rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
|
292
|
+
rb_hash_aset(opts, ignore_under_sym, (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
|
289
293
|
switch (oj_default_options.mode) {
|
290
294
|
case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
|
291
295
|
case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
|
@@ -297,16 +301,16 @@ get_def_opts(VALUE self) {
|
|
297
301
|
default: rb_hash_aset(opts, mode_sym, object_sym); break;
|
298
302
|
}
|
299
303
|
|
300
|
-
if (oj_default_options.
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
else {
|
309
|
-
|
304
|
+
if (oj_default_options.int_range_max != 0 || oj_default_options.int_range_min != 0) {
|
305
|
+
VALUE range = rb_obj_alloc(rb_cRange);
|
306
|
+
VALUE min = LONG2FIX(oj_default_options.int_range_min);
|
307
|
+
VALUE max = LONG2FIX(oj_default_options.int_range_max);
|
308
|
+
|
309
|
+
rb_ivar_set(range, oj_begin_id, min);
|
310
|
+
rb_ivar_set(range, oj_end_id, max);
|
311
|
+
rb_hash_aset(opts, integer_range_sym, range);
|
312
|
+
} else {
|
313
|
+
rb_hash_aset(opts, integer_range_sym, Qnil);
|
310
314
|
}
|
311
315
|
switch (oj_default_options.escape_mode) {
|
312
316
|
case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
|
@@ -326,6 +330,7 @@ get_def_opts(VALUE self) {
|
|
326
330
|
switch (oj_default_options.bigdec_load) {
|
327
331
|
case BigDec: rb_hash_aset(opts, bigdecimal_load_sym, bigdecimal_sym);break;
|
328
332
|
case FloatDec: rb_hash_aset(opts, bigdecimal_load_sym, float_sym); break;
|
333
|
+
case FastDec: rb_hash_aset(opts, bigdecimal_load_sym, fast_sym); break;
|
329
334
|
case AutoDec:
|
330
335
|
default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
|
331
336
|
}
|
@@ -398,6 +403,7 @@ get_def_opts(VALUE self) {
|
|
398
403
|
* - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
|
399
404
|
* - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
|
400
405
|
* - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
|
406
|
+
* - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when dumping in object or custom mode.
|
401
407
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
402
408
|
* - *:trace* [_Boolean_] turn trace on or off.
|
403
409
|
* - *:safe* [_Boolean_] turn safe mimic on or off.
|
@@ -431,6 +437,7 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
431
437
|
{ oj_allow_nan_sym, &copts->allow_nan },
|
432
438
|
{ oj_trace_sym, &copts->trace },
|
433
439
|
{ oj_safe_sym, &copts->safe },
|
440
|
+
{ ignore_under_sym, &copts->ignore_under },
|
434
441
|
{ oj_create_additions_sym, &copts->create_ok },
|
435
442
|
{ Qnil, 0 }
|
436
443
|
};
|
@@ -506,8 +513,12 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
506
513
|
n = NUM2INT(v);
|
507
514
|
if (0 > n) {
|
508
515
|
n = 0;
|
516
|
+
copts->sec_prec_set = false;
|
509
517
|
} else if (9 < n) {
|
510
518
|
n = 9;
|
519
|
+
copts->sec_prec_set = true;
|
520
|
+
} else {
|
521
|
+
copts->sec_prec_set = true;
|
511
522
|
}
|
512
523
|
copts->sec_prec = n;
|
513
524
|
}
|
@@ -563,12 +574,27 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
563
574
|
copts->bigdec_load = BigDec;
|
564
575
|
} else if (float_sym == v) {
|
565
576
|
copts->bigdec_load = FloatDec;
|
577
|
+
} else if (fast_sym == v) {
|
578
|
+
copts->bigdec_load = FastDec;
|
566
579
|
} else if (auto_sym == v || Qfalse == v) {
|
567
580
|
copts->bigdec_load = AutoDec;
|
568
581
|
} else {
|
569
582
|
rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
|
570
583
|
}
|
571
584
|
}
|
585
|
+
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) {
|
586
|
+
v = rb_hash_lookup(ropts, oj_decimal_class_sym);
|
587
|
+
if (rb_cFloat == v) {
|
588
|
+
copts->bigdec_load = FloatDec;
|
589
|
+
} else if (oj_bigdecimal_class == v) {
|
590
|
+
copts->bigdec_load = BigDec;
|
591
|
+
} else if (Qnil == v) {
|
592
|
+
copts->bigdec_load = AutoDec;
|
593
|
+
} else {
|
594
|
+
rb_raise(rb_eArgError, ":decimal_class must be BigDecimal, Float, or nil.");
|
595
|
+
}
|
596
|
+
}
|
597
|
+
|
572
598
|
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, create_id_sym)) {
|
573
599
|
v = rb_hash_lookup(ropts, create_id_sym);
|
574
600
|
if (Qnil == v) {
|
@@ -738,24 +764,26 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
738
764
|
}
|
739
765
|
}
|
740
766
|
if (Qnil != (v = rb_hash_lookup(ropts, integer_range_sym))) {
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
767
|
+
if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
|
768
|
+
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
769
|
+
VALUE max = rb_funcall(v, oj_end_id, 0);
|
770
|
+
|
771
|
+
if (TYPE(min) != T_FIXNUM || TYPE(max) != T_FIXNUM) {
|
772
|
+
rb_raise(rb_eArgError, ":integer_range range bounds is not Fixnum.");
|
773
|
+
}
|
774
|
+
|
775
|
+
copts->int_range_min = FIX2LONG(min);
|
776
|
+
copts->int_range_max = FIX2LONG(max);
|
777
|
+
} else if (Qfalse != v) {
|
778
|
+
rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
|
779
|
+
}
|
754
780
|
}
|
755
781
|
}
|
756
782
|
|
757
783
|
static int
|
758
|
-
match_string_cb(VALUE key, VALUE value,
|
784
|
+
match_string_cb(VALUE key, VALUE value, VALUE rx) {
|
785
|
+
RxClass rc = (RxClass)rx;
|
786
|
+
|
759
787
|
if (T_CLASS != rb_type(value)) {
|
760
788
|
rb_raise(rb_eArgError, "for :match_string, the hash values must be a Class.");
|
761
789
|
}
|
@@ -790,7 +818,7 @@ oj_parse_opt_match_string(RxClass rc, VALUE ropts) {
|
|
790
818
|
}
|
791
819
|
|
792
820
|
/* Document-method: load
|
793
|
-
* call-seq: load(json, options) { _|_obj, start, len_|_ }
|
821
|
+
* call-seq: load(json, options={}) { _|_obj, start, len_|_ }
|
794
822
|
*
|
795
823
|
* Parses a JSON document String into a Object, Hash, Array, String, Fixnum,
|
796
824
|
* Float, true, false, or nil according to the default mode or the mode
|
@@ -874,7 +902,7 @@ load(int argc, VALUE *argv, VALUE self) {
|
|
874
902
|
}
|
875
903
|
|
876
904
|
/* Document-method: load_file
|
877
|
-
* call-seq: load_file(path, options) { _|_obj, start, len_|_ }
|
905
|
+
* call-seq: load_file(path, options={}) { _|_obj, start, len_|_ }
|
878
906
|
*
|
879
907
|
* Parses a JSON document String into a Object, Hash, Array, String, Fixnum,
|
880
908
|
* Float, true, false, or nil according to the default mode or the mode
|
@@ -954,11 +982,13 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
954
982
|
}
|
955
983
|
switch (mode) {
|
956
984
|
case StrictMode:
|
985
|
+
case NullMode:
|
957
986
|
oj_set_strict_callbacks(&pi);
|
958
987
|
return oj_pi_sparse(argc, argv, &pi, fd);
|
959
|
-
case NullMode:
|
960
|
-
case CompatMode:
|
961
988
|
case CustomMode:
|
989
|
+
oj_set_custom_callbacks(&pi);
|
990
|
+
return oj_pi_sparse(argc, argv, &pi, fd);
|
991
|
+
case CompatMode:
|
962
992
|
case RailsMode:
|
963
993
|
oj_set_compat_callbacks(&pi);
|
964
994
|
return oj_pi_sparse(argc, argv, &pi, fd);
|
@@ -1030,7 +1060,7 @@ safe_load(VALUE self, VALUE doc) {
|
|
1030
1060
|
*/
|
1031
1061
|
|
1032
1062
|
/* Document-method: dump
|
1033
|
-
* call-seq: dump(obj, options)
|
1063
|
+
* call-seq: dump(obj, options={})
|
1034
1064
|
*
|
1035
1065
|
* Dumps an Object (obj) to a string.
|
1036
1066
|
* - *obj* [_Object_] Object to serialize as an JSON document String
|
@@ -1052,6 +1082,9 @@ dump(int argc, VALUE *argv, VALUE self) {
|
|
1052
1082
|
if (2 == argc) {
|
1053
1083
|
oj_parse_options(argv[1], &copts);
|
1054
1084
|
}
|
1085
|
+
if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) {
|
1086
|
+
copts.escape_mode = JSONEsc;
|
1087
|
+
}
|
1055
1088
|
out.buf = buf;
|
1056
1089
|
out.end = buf + sizeof(buf) - 10;
|
1057
1090
|
out.allocated = false;
|
@@ -1125,7 +1158,7 @@ to_json(int argc, VALUE *argv, VALUE self) {
|
|
1125
1158
|
}
|
1126
1159
|
|
1127
1160
|
/* Document-method: to_file
|
1128
|
-
* call-seq: to_file(file_path, obj, options)
|
1161
|
+
* call-seq: to_file(file_path, obj, options={})
|
1129
1162
|
*
|
1130
1163
|
* Dumps an Object to the specified file.
|
1131
1164
|
* - *file* [_String_] _path file path to write the JSON document to
|
@@ -1148,7 +1181,7 @@ to_file(int argc, VALUE *argv, VALUE self) {
|
|
1148
1181
|
}
|
1149
1182
|
|
1150
1183
|
/* Document-method: to_stream
|
1151
|
-
* call-seq: to_stream(io, obj, options)
|
1184
|
+
* call-seq: to_stream(io, obj, options={})
|
1152
1185
|
*
|
1153
1186
|
* Dumps an Object to the specified IO stream.
|
1154
1187
|
* - *io* [_IO_] IO stream to write the JSON document to
|
@@ -1636,10 +1669,12 @@ Init_oj() {
|
|
1636
1669
|
empty_string_sym = ID2SYM(rb_intern("empty_string")); rb_gc_register_address(&empty_string_sym);
|
1637
1670
|
escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym);
|
1638
1671
|
integer_range_sym = ID2SYM(rb_intern("integer_range")); rb_gc_register_address(&integer_range_sym);
|
1672
|
+
fast_sym = ID2SYM(rb_intern("fast")); rb_gc_register_address(&fast_sym);
|
1639
1673
|
float_prec_sym = ID2SYM(rb_intern("float_precision")); rb_gc_register_address(&float_prec_sym);
|
1640
1674
|
float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym);
|
1641
1675
|
huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym);
|
1642
1676
|
ignore_sym = ID2SYM(rb_intern("ignore")); rb_gc_register_address(&ignore_sym);
|
1677
|
+
ignore_under_sym = ID2SYM(rb_intern("ignore_under")); rb_gc_register_address(&ignore_under_sym);
|
1643
1678
|
json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym);
|
1644
1679
|
match_string_sym = ID2SYM(rb_intern("match_string")); rb_gc_register_address(&match_string_sym);
|
1645
1680
|
mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
|
@@ -1653,6 +1688,7 @@ Init_oj() {
|
|
1653
1688
|
oj_array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&oj_array_nl_sym);
|
1654
1689
|
oj_ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&oj_ascii_only_sym);
|
1655
1690
|
oj_create_additions_sym = ID2SYM(rb_intern("create_additions"));rb_gc_register_address(&oj_create_additions_sym);
|
1691
|
+
oj_decimal_class_sym = ID2SYM(rb_intern("decimal_class")); rb_gc_register_address(&oj_decimal_class_sym);
|
1656
1692
|
oj_hash_class_sym = ID2SYM(rb_intern("hash_class")); rb_gc_register_address(&oj_hash_class_sym);
|
1657
1693
|
oj_indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&oj_indent_sym);
|
1658
1694
|
oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting")); rb_gc_register_address(&oj_max_nesting_sym);
|
data/ext/oj/oj.h
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2011, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2011 Peter Ohler. All rights reserved.
|
5
2
|
|
6
3
|
#ifndef OJ_H
|
7
4
|
#define OJ_H
|
@@ -77,7 +74,9 @@ typedef enum {
|
|
77
74
|
typedef enum {
|
78
75
|
BigDec = 'b',
|
79
76
|
FloatDec = 'f',
|
80
|
-
AutoDec = 'a'
|
77
|
+
AutoDec = 'a',
|
78
|
+
FastDec = 'F',
|
79
|
+
RubyDec = 'r',
|
81
80
|
} BigLoad;
|
82
81
|
|
83
82
|
typedef enum {
|
@@ -149,8 +148,10 @@ typedef struct _options {
|
|
149
148
|
char allow_nan; // YEsyNo for parsing only
|
150
149
|
char trace; // YesNo
|
151
150
|
char safe; // YesNo
|
152
|
-
|
153
|
-
|
151
|
+
char sec_prec_set; // boolean (0 or 1)
|
152
|
+
char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes
|
153
|
+
int64_t int_range_min; // dump numbers below as string
|
154
|
+
int64_t int_range_max; // dump numbers above as string
|
154
155
|
const char *create_id; // 0 or string
|
155
156
|
size_t create_id_len; // length of create_id
|
156
157
|
int sec_prec; // second precision when dumping time
|
@@ -309,6 +310,7 @@ extern VALUE oj_array_class_sym;
|
|
309
310
|
extern VALUE oj_array_nl_sym;
|
310
311
|
extern VALUE oj_ascii_only_sym;
|
311
312
|
extern VALUE oj_create_additions_sym;
|
313
|
+
extern VALUE oj_decimal_class_sym;
|
312
314
|
extern VALUE oj_hash_class_sym;
|
313
315
|
extern VALUE oj_indent_sym;
|
314
316
|
extern VALUE oj_max_nesting_sym;
|
data/ext/oj/parse.c
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2013, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2013 Peter Ohler. All rights reserved.
|
5
2
|
|
6
3
|
#include <stdlib.h>
|
7
4
|
#include <stdio.h>
|
@@ -215,18 +212,6 @@ read_escaped_str(ParseInfo pi, const char *start) {
|
|
215
212
|
case '"': buf_append(&buf, '"'); break;
|
216
213
|
case '/': buf_append(&buf, '/'); break;
|
217
214
|
case '\\': buf_append(&buf, '\\'); break;
|
218
|
-
case '\'':
|
219
|
-
// The json gem claims this is not an error despite the
|
220
|
-
// ECMA-404 indicating it is not valid.
|
221
|
-
if (CompatMode == pi->options.mode) {
|
222
|
-
buf_append(&buf, '\'');
|
223
|
-
} else {
|
224
|
-
pi->cur = s;
|
225
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
226
|
-
buf_cleanup(&buf);
|
227
|
-
return;
|
228
|
-
}
|
229
|
-
break;
|
230
215
|
case 'u':
|
231
216
|
s++;
|
232
217
|
if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) {
|
@@ -266,6 +251,12 @@ read_escaped_str(ParseInfo pi, const char *start) {
|
|
266
251
|
}
|
267
252
|
break;
|
268
253
|
default:
|
254
|
+
// The json gem claims this is not an error despite the
|
255
|
+
// ECMA-404 indicating it is not valid.
|
256
|
+
if (CompatMode == pi->options.mode) {
|
257
|
+
buf_append(&buf, *s);
|
258
|
+
break;
|
259
|
+
}
|
269
260
|
pi->cur = s;
|
270
261
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
271
262
|
buf_cleanup(&buf);
|
@@ -393,13 +384,18 @@ read_num(ParseInfo pi) {
|
|
393
384
|
ni.infinity = 0;
|
394
385
|
ni.nan = 0;
|
395
386
|
ni.neg = 0;
|
396
|
-
ni.
|
397
|
-
ni.no_big = (FloatDec == pi->options.bigdec_load);
|
387
|
+
ni.has_exp = 0;
|
388
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
|
389
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
398
390
|
|
399
391
|
if ('-' == *pi->cur) {
|
400
392
|
pi->cur++;
|
401
393
|
ni.neg = 1;
|
402
394
|
} else if ('+' == *pi->cur) {
|
395
|
+
if (StrictMode == pi->options.mode) {
|
396
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
397
|
+
return;
|
398
|
+
}
|
403
399
|
pi->cur++;
|
404
400
|
}
|
405
401
|
if ('I' == *pi->cur) {
|
@@ -446,8 +442,14 @@ read_num(ParseInfo pi) {
|
|
446
442
|
if ('.' == *pi->cur) {
|
447
443
|
pi->cur++;
|
448
444
|
// A trailing . is not a valid decimal but if encountered allow it
|
449
|
-
// except when mimicing the JSON gem.
|
450
|
-
if (CompatMode == pi->options.mode) {
|
445
|
+
// except when mimicing the JSON gem or in strict mode.
|
446
|
+
if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
|
447
|
+
int pos = (int)(pi->cur - ni.str);
|
448
|
+
|
449
|
+
if (1 == pos || (2 == pos && ni.neg)) {
|
450
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
451
|
+
return;
|
452
|
+
}
|
451
453
|
if (*pi->cur < '0' || '9' < *pi->cur) {
|
452
454
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
453
455
|
return;
|
@@ -459,18 +461,26 @@ read_num(ParseInfo pi) {
|
|
459
461
|
if (0 < ni.num || 0 < ni.i) {
|
460
462
|
dec_cnt++;
|
461
463
|
}
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
464
|
+
if (INT64_MAX <= ni.div) {
|
465
|
+
if (!ni.no_big) {
|
466
|
+
ni.big = true;
|
467
|
+
}
|
468
|
+
} else {
|
469
|
+
ni.num = ni.num * 10 + d;
|
470
|
+
ni.div *= 10;
|
471
|
+
ni.di++;
|
472
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
473
|
+
if (!ni.no_big) {
|
474
|
+
ni.big = true;
|
475
|
+
}
|
476
|
+
}
|
467
477
|
}
|
468
478
|
}
|
469
479
|
}
|
470
480
|
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
471
481
|
int eneg = 0;
|
472
482
|
|
473
|
-
ni.
|
483
|
+
ni.has_exp = 1;
|
474
484
|
pi->cur++;
|
475
485
|
if ('-' == *pi->cur) {
|
476
486
|
pi->cur++;
|
@@ -481,7 +491,7 @@ read_num(ParseInfo pi) {
|
|
481
491
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
482
492
|
ni.exp = ni.exp * 10 + (*pi->cur - '0');
|
483
493
|
if (EXP_MAX <= ni.exp) {
|
484
|
-
ni.big =
|
494
|
+
ni.big = true;
|
485
495
|
}
|
486
496
|
}
|
487
497
|
if (eneg) {
|
@@ -731,7 +741,7 @@ oj_parse2(ParseInfo pi) {
|
|
731
741
|
}
|
732
742
|
|
733
743
|
static VALUE
|
734
|
-
rescue_big_decimal(VALUE str) {
|
744
|
+
rescue_big_decimal(VALUE str, VALUE ignore) {
|
735
745
|
rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
|
736
746
|
return Qnil;
|
737
747
|
}
|
@@ -741,6 +751,59 @@ parse_big_decimal(VALUE str) {
|
|
741
751
|
return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
|
742
752
|
}
|
743
753
|
|
754
|
+
static long double exp_plus[] = {
|
755
|
+
1.0,
|
756
|
+
1.0e1,
|
757
|
+
1.0e2,
|
758
|
+
1.0e3,
|
759
|
+
1.0e4,
|
760
|
+
1.0e5,
|
761
|
+
1.0e6,
|
762
|
+
1.0e7,
|
763
|
+
1.0e8,
|
764
|
+
1.0e9,
|
765
|
+
1.0e10,
|
766
|
+
1.0e11,
|
767
|
+
1.0e12,
|
768
|
+
1.0e13,
|
769
|
+
1.0e14,
|
770
|
+
1.0e15,
|
771
|
+
1.0e16,
|
772
|
+
1.0e17,
|
773
|
+
1.0e18,
|
774
|
+
1.0e19,
|
775
|
+
1.0e20,
|
776
|
+
1.0e21,
|
777
|
+
1.0e22,
|
778
|
+
1.0e23,
|
779
|
+
1.0e24,
|
780
|
+
1.0e25,
|
781
|
+
1.0e26,
|
782
|
+
1.0e27,
|
783
|
+
1.0e28,
|
784
|
+
1.0e29,
|
785
|
+
1.0e30,
|
786
|
+
1.0e31,
|
787
|
+
1.0e32,
|
788
|
+
1.0e33,
|
789
|
+
1.0e34,
|
790
|
+
1.0e35,
|
791
|
+
1.0e36,
|
792
|
+
1.0e37,
|
793
|
+
1.0e38,
|
794
|
+
1.0e39,
|
795
|
+
1.0e40,
|
796
|
+
1.0e41,
|
797
|
+
1.0e42,
|
798
|
+
1.0e43,
|
799
|
+
1.0e44,
|
800
|
+
1.0e45,
|
801
|
+
1.0e46,
|
802
|
+
1.0e47,
|
803
|
+
1.0e48,
|
804
|
+
1.0e49,
|
805
|
+
};
|
806
|
+
|
744
807
|
VALUE
|
745
808
|
oj_num_as_value(NumInfo ni) {
|
746
809
|
volatile VALUE rnum = Qnil;
|
@@ -753,7 +816,7 @@ oj_num_as_value(NumInfo ni) {
|
|
753
816
|
}
|
754
817
|
} else if (ni->nan) {
|
755
818
|
rnum = rb_float_new(0.0/0.0);
|
756
|
-
} else if (1 == ni->div && 0 == ni->exp) { // fixnum
|
819
|
+
} else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum
|
757
820
|
if (ni->big) {
|
758
821
|
if (256 > ni->len) {
|
759
822
|
char buf[256];
|
@@ -784,33 +847,39 @@ oj_num_as_value(NumInfo ni) {
|
|
784
847
|
if (ni->no_big) {
|
785
848
|
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
786
849
|
}
|
787
|
-
} else {
|
788
|
-
|
789
|
-
long double d = (long double)ni->i * (long double)ni->div + (long double)ni->num;
|
850
|
+
} else if (FastDec == ni->bigdec_load) {
|
851
|
+
long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
|
790
852
|
int x = (int)((int64_t)ni->exp - ni->di);
|
791
853
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
799
|
-
if (ni->no_big) {
|
800
|
-
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
801
|
-
}
|
802
|
-
} else {
|
803
|
-
d = roundl(d);
|
804
|
-
if (0 < x) {
|
805
|
-
d *= powl(10.0L, x);
|
806
|
-
} else if (0 > x) {
|
807
|
-
d /= powl(10.0L, -x);
|
854
|
+
if (0 < x) {
|
855
|
+
if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
856
|
+
ld *= exp_plus[x];
|
857
|
+
} else {
|
858
|
+
ld *= powl(10.0, x);
|
808
859
|
}
|
809
|
-
|
810
|
-
|
860
|
+
} else if (x < 0) {
|
861
|
+
if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
862
|
+
ld /= exp_plus[-x];
|
863
|
+
} else {
|
864
|
+
ld /= powl(10.0, -x);
|
811
865
|
}
|
812
|
-
rnum = rb_float_new((double)d);
|
813
866
|
}
|
867
|
+
if (ni->neg) {
|
868
|
+
ld = -ld;
|
869
|
+
}
|
870
|
+
rnum = rb_float_new((double)ld);
|
871
|
+
} else if (RubyDec == ni->bigdec_load) {
|
872
|
+
volatile VALUE sv = rb_str_new(ni->str, ni->len);
|
873
|
+
|
874
|
+
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
875
|
+
} else {
|
876
|
+
char *end;
|
877
|
+
double d = strtod(ni->str, &end);
|
878
|
+
|
879
|
+
if ((long)ni->len != (long)(end - ni->str)) {
|
880
|
+
rb_raise(oj_parse_error_class, "Invalid float");
|
881
|
+
}
|
882
|
+
rnum = rb_float_new(d);
|
814
883
|
}
|
815
884
|
}
|
816
885
|
return rnum;
|
@@ -832,6 +901,12 @@ oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const
|
|
832
901
|
if (p + 3 < end) {
|
833
902
|
*p++ = ' ';
|
834
903
|
*p++ = '(';
|
904
|
+
*p++ = 'a';
|
905
|
+
*p++ = 'f';
|
906
|
+
*p++ = 't';
|
907
|
+
*p++ = 'e';
|
908
|
+
*p++ = 'r';
|
909
|
+
*p++ = ' ';
|
835
910
|
start = p;
|
836
911
|
for (vp = pi->stack.head; vp < pi->stack.tail; vp++) {
|
837
912
|
if (end <= p + 1 + vp->klen) {
|
@@ -1050,7 +1125,7 @@ CLEANUP:
|
|
1050
1125
|
}
|
1051
1126
|
args[0] = msg;
|
1052
1127
|
if (pi->err.clas == oj_parse_error_class) {
|
1053
|
-
// The error was an Oj::ParseError so change to a JSON::
|
1128
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
1054
1129
|
pi->err.clas = oj_json_parser_error_class;
|
1055
1130
|
}
|
1056
1131
|
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
data/ext/oj/parse.h
CHANGED
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2011, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2011 Peter Ohler. All rights reserved.
|
5
2
|
|
6
3
|
#ifndef OJ_PARSE_H
|
7
4
|
#define OJ_PARSE_H
|
@@ -31,8 +28,9 @@ typedef struct _numInfo {
|
|
31
28
|
int infinity;
|
32
29
|
int nan;
|
33
30
|
int neg;
|
34
|
-
int
|
31
|
+
int has_exp;
|
35
32
|
int no_big;
|
33
|
+
int bigdec_load;
|
36
34
|
} *NumInfo;
|
37
35
|
|
38
36
|
typedef struct _parseInfo {
|
@@ -80,6 +78,7 @@ extern VALUE oj_num_as_value(NumInfo ni);
|
|
80
78
|
extern void oj_set_strict_callbacks(ParseInfo pi);
|
81
79
|
extern void oj_set_object_callbacks(ParseInfo pi);
|
82
80
|
extern void oj_set_compat_callbacks(ParseInfo pi);
|
81
|
+
extern void oj_set_custom_callbacks(ParseInfo pi);
|
83
82
|
extern void oj_set_wab_callbacks(ParseInfo pi);
|
84
83
|
|
85
84
|
extern void oj_sparse2(ParseInfo pi);
|