oj 3.13.7 → 3.13.11
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +9 -0
- data/ext/oj/custom.c +4 -4
- data/ext/oj/dump.c +63 -88
- data/ext/oj/dump.h +14 -1
- data/ext/oj/dump_compat.c +1 -1
- data/ext/oj/dump_object.c +46 -39
- data/ext/oj/dump_strict.c +2 -2
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/fast.c +13 -3
- data/ext/oj/intern.c +7 -1
- data/ext/oj/mimic_json.c +48 -59
- data/ext/oj/object.c +27 -46
- data/ext/oj/oj.c +109 -153
- data/ext/oj/oj.h +1 -0
- data/ext/oj/parse.c +9 -1
- data/ext/oj/rails.c +5 -5
- data/ext/oj/usual.c +4 -2
- data/ext/oj/wab.c +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Rails.md +12 -0
- data/test/bug.rb +16 -0
- data/test/foo.rb +71 -7
- data/test/test_fast.rb +37 -7
- data/test/test_saj.rb +1 -1
- data/test/test_various.rb +27 -2
- data/test/tests.rb +0 -1
- metadata +5 -2
data/ext/oj/intern.c
CHANGED
@@ -186,6 +186,7 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
|
|
186
186
|
char * end = class_name + sizeof(class_name) - 1;
|
187
187
|
char * s;
|
188
188
|
const char *n = name;
|
189
|
+
size_t nlen = len;
|
189
190
|
|
190
191
|
clas = rb_cObject;
|
191
192
|
for (s = class_name; 0 < len; n++, len--) {
|
@@ -208,7 +209,12 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
|
|
208
209
|
}
|
209
210
|
*s = '\0';
|
210
211
|
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
211
|
-
|
212
|
+
if (sizeof(class_name) <= nlen) {
|
213
|
+
nlen = sizeof(class_name) - 1;
|
214
|
+
}
|
215
|
+
strncpy(class_name, name, nlen);
|
216
|
+
class_name[nlen] = '\0';
|
217
|
+
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
|
212
218
|
if (Qnil != error_class) {
|
213
219
|
pi->err_class = error_class;
|
214
220
|
}
|
data/ext/oj/mimic_json.c
CHANGED
@@ -6,8 +6,6 @@
|
|
6
6
|
#include "oj.h"
|
7
7
|
#include "parse.h"
|
8
8
|
|
9
|
-
static VALUE symbolize_names_sym = Qundef;
|
10
|
-
|
11
9
|
extern const char oj_json_class[];
|
12
10
|
|
13
11
|
VALUE oj_array_nl_sym;
|
@@ -274,7 +272,7 @@ static int mimic_walk(VALUE key, VALUE obj, VALUE proc) {
|
|
274
272
|
size_t i;
|
275
273
|
|
276
274
|
for (i = 0; i < cnt; i++) {
|
277
|
-
mimic_walk(Qnil,
|
275
|
+
mimic_walk(Qnil, RARRAY_AREF(obj, i), proc);
|
278
276
|
}
|
279
277
|
break;
|
280
278
|
}
|
@@ -501,6 +499,52 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
|
|
501
499
|
return mimic_generate_core(2, rargs, &copts);
|
502
500
|
}
|
503
501
|
|
502
|
+
static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
|
503
|
+
struct _parseInfo *pi = (struct _parseInfo *)info;
|
504
|
+
|
505
|
+
if (oj_symbolize_names_sym == k) {
|
506
|
+
pi->options.sym_key = (Qtrue == v) ? Yes : No;
|
507
|
+
} else if (oj_quirks_mode_sym == k) {
|
508
|
+
pi->options.quirks_mode = (Qtrue == v) ? Yes : No;
|
509
|
+
} else if (oj_create_additions_sym == k) {
|
510
|
+
pi->options.create_ok = (Qtrue == v) ? Yes : No;
|
511
|
+
} else if (oj_allow_nan_sym == k) {
|
512
|
+
pi->options.allow_nan = (Qtrue == v) ? Yes : No;
|
513
|
+
} else if (oj_hash_class_sym == k) {
|
514
|
+
if (Qnil == v) {
|
515
|
+
pi->options.hash_class = Qnil;
|
516
|
+
} else {
|
517
|
+
rb_check_type(v, T_CLASS);
|
518
|
+
pi->options.hash_class = v;
|
519
|
+
}
|
520
|
+
} else if (oj_object_class_sym == k) {
|
521
|
+
if (Qnil == v) {
|
522
|
+
pi->options.hash_class = Qnil;
|
523
|
+
} else {
|
524
|
+
rb_check_type(v, T_CLASS);
|
525
|
+
pi->options.hash_class = v;
|
526
|
+
}
|
527
|
+
} else if (oj_array_class_sym == k) {
|
528
|
+
if (Qnil == v) {
|
529
|
+
pi->options.array_class = Qnil;
|
530
|
+
} else {
|
531
|
+
rb_check_type(v, T_CLASS);
|
532
|
+
pi->options.array_class = v;
|
533
|
+
}
|
534
|
+
} else if (oj_decimal_class_sym == k) {
|
535
|
+
pi->options.compat_bigdec = (oj_bigdecimal_class == v);
|
536
|
+
} else if (oj_max_nesting_sym == k) {
|
537
|
+
if (Qtrue == v) {
|
538
|
+
pi->max_depth = 100;
|
539
|
+
} else if (Qfalse == v || Qnil == v) {
|
540
|
+
pi->max_depth = 0;
|
541
|
+
} else if (T_FIXNUM == rb_type(v)) {
|
542
|
+
pi->max_depth = NUM2INT(v);
|
543
|
+
}
|
544
|
+
}
|
545
|
+
return ST_CONTINUE;
|
546
|
+
}
|
547
|
+
|
504
548
|
static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
505
549
|
struct _parseInfo pi;
|
506
550
|
VALUE ropts;
|
@@ -526,63 +570,11 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
526
570
|
pi.max_depth = 100;
|
527
571
|
|
528
572
|
if (Qnil != ropts) {
|
529
|
-
VALUE v;
|
530
|
-
|
531
573
|
if (T_HASH != rb_type(ropts)) {
|
532
574
|
rb_raise(rb_eArgError, "options must be a hash.");
|
533
575
|
}
|
534
|
-
if (Qundef == symbolize_names_sym) {
|
535
|
-
symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
|
536
|
-
rb_gc_register_address(&symbolize_names_sym);
|
537
|
-
}
|
538
|
-
if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
|
539
|
-
pi.options.sym_key = (Qtrue == v) ? Yes : No;
|
540
|
-
}
|
541
|
-
if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) {
|
542
|
-
pi.options.quirks_mode = (Qtrue == v) ? Yes : No;
|
543
|
-
}
|
544
|
-
if (Qnil != (v = rb_hash_lookup(ropts, oj_create_additions_sym))) {
|
545
|
-
pi.options.create_ok = (Qtrue == v) ? Yes : No;
|
546
|
-
}
|
547
|
-
if (Qnil != (v = rb_hash_lookup(ropts, oj_allow_nan_sym))) {
|
548
|
-
pi.options.allow_nan = (Qtrue == v) ? Yes : No;
|
549
|
-
}
|
550
576
|
|
551
|
-
|
552
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
|
553
|
-
pi.options.hash_class = Qnil;
|
554
|
-
} else {
|
555
|
-
rb_check_type(v, T_CLASS);
|
556
|
-
pi.options.hash_class = v;
|
557
|
-
}
|
558
|
-
}
|
559
|
-
if (oj_hash_has_key(ropts, oj_object_class_sym)) {
|
560
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
|
561
|
-
pi.options.hash_class = Qnil;
|
562
|
-
} else {
|
563
|
-
rb_check_type(v, T_CLASS);
|
564
|
-
pi.options.hash_class = v;
|
565
|
-
}
|
566
|
-
}
|
567
|
-
if (oj_hash_has_key(ropts, oj_array_class_sym)) {
|
568
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
|
569
|
-
pi.options.array_class = Qnil;
|
570
|
-
} else {
|
571
|
-
rb_check_type(v, T_CLASS);
|
572
|
-
pi.options.array_class = v;
|
573
|
-
}
|
574
|
-
}
|
575
|
-
if (oj_hash_has_key(ropts, oj_decimal_class_sym)) {
|
576
|
-
pi.options.compat_bigdec = (oj_bigdecimal_class == rb_hash_lookup(ropts, oj_decimal_class_sym));
|
577
|
-
}
|
578
|
-
v = rb_hash_lookup(ropts, oj_max_nesting_sym);
|
579
|
-
if (Qtrue == v) {
|
580
|
-
pi.max_depth = 100;
|
581
|
-
} else if (Qfalse == v || Qnil == v) {
|
582
|
-
pi.max_depth = 0;
|
583
|
-
} else if (T_FIXNUM == rb_type(v)) {
|
584
|
-
pi.max_depth = NUM2INT(v);
|
585
|
-
}
|
577
|
+
rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
|
586
578
|
oj_parse_opt_match_string(&pi.options.str_rx, ropts);
|
587
579
|
if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
|
588
580
|
rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
|
@@ -852,9 +844,6 @@ void oj_mimic_json_methods(VALUE json) {
|
|
852
844
|
// Pull in the JSON::State mimic file.
|
853
845
|
state_class = rb_const_get_at(generator, rb_intern("State"));
|
854
846
|
rb_gc_register_mark_object(state_class);
|
855
|
-
|
856
|
-
symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
|
857
|
-
rb_gc_register_address(&symbolize_names_sym);
|
858
847
|
}
|
859
848
|
|
860
849
|
/* Document-module: JSON
|
data/ext/oj/object.c
CHANGED
@@ -35,7 +35,7 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
35
35
|
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
36
36
|
}
|
37
37
|
if (Yes == pi->options.sym_key) {
|
38
|
-
|
38
|
+
return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
|
39
39
|
}
|
40
40
|
#if HAVE_RB_ENC_INTERNED_STR
|
41
41
|
rkey = rb_enc_interned_str(kval->key, kval->klen, oj_utf8_encoding);
|
@@ -60,21 +60,16 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
60
60
|
}
|
61
61
|
rstr = oj_circ_array_get(pi->circ_array, i);
|
62
62
|
} else {
|
63
|
-
|
63
|
+
rstr = rb_utf8_str_new(str, len);
|
64
64
|
}
|
65
65
|
return rstr;
|
66
66
|
}
|
67
67
|
|
68
|
-
#if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
69
|
-
static VALUE oj_parse_xml_time(const char *str, int len) {
|
70
|
-
return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
|
71
|
-
}
|
72
|
-
#else
|
73
68
|
// The much faster approach (4x faster)
|
74
69
|
static int parse_num(const char *str, const char *end, int cnt) {
|
75
|
-
int
|
70
|
+
int n = 0;
|
76
71
|
char c;
|
77
|
-
int
|
72
|
+
int i;
|
78
73
|
|
79
74
|
for (i = cnt; 0 < i; i--, str++) {
|
80
75
|
c = *str;
|
@@ -88,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
|
|
88
83
|
|
89
84
|
VALUE
|
90
85
|
oj_parse_xml_time(const char *str, int len) {
|
91
|
-
VALUE
|
86
|
+
VALUE args[8];
|
92
87
|
const char *end = str + len;
|
93
|
-
int
|
88
|
+
int n;
|
94
89
|
|
95
90
|
// year
|
96
91
|
if (0 > (n = parse_num(str, end, 4))) {
|
@@ -201,7 +196,6 @@ oj_parse_xml_time(const char *str, int len) {
|
|
201
196
|
}
|
202
197
|
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
203
198
|
}
|
204
|
-
#endif
|
205
199
|
|
206
200
|
static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
|
207
201
|
const char *key = kval->key;
|
@@ -226,13 +220,10 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
226
220
|
}
|
227
221
|
parent->val = odd->clas;
|
228
222
|
parent->odd_args = oj_odd_alloc_args(odd);
|
229
|
-
} break;
|
230
|
-
case 'm':
|
231
|
-
parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
232
|
-
break;
|
233
|
-
case 's':
|
234
|
-
parent->val = rb_utf8_str_new(str, len);
|
235
223
|
break;
|
224
|
+
}
|
225
|
+
case 'm': parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding)); break;
|
226
|
+
case 's': parent->val = rb_utf8_str_new(str, len); break;
|
236
227
|
case 'c': // class
|
237
228
|
{
|
238
229
|
VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
|
@@ -242,7 +233,8 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
242
233
|
} else {
|
243
234
|
parent->val = clas;
|
244
235
|
}
|
245
|
-
|
236
|
+
break;
|
237
|
+
}
|
246
238
|
case 't': // time
|
247
239
|
parent->val = oj_parse_xml_time(str, (int)len);
|
248
240
|
break;
|
@@ -282,22 +274,21 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
282
274
|
VALUE args[8];
|
283
275
|
|
284
276
|
sec_as_time(t, &ti);
|
285
|
-
args[0]
|
286
|
-
args[1]
|
287
|
-
args[2]
|
288
|
-
args[3]
|
289
|
-
args[4]
|
290
|
-
args[5]
|
291
|
-
args[6]
|
277
|
+
args[0] = LONG2NUM((long)(ti.year));
|
278
|
+
args[1] = LONG2NUM(ti.mon);
|
279
|
+
args[2] = LONG2NUM(ti.day);
|
280
|
+
args[3] = LONG2NUM(ti.hour);
|
281
|
+
args[4] = LONG2NUM(ti.min);
|
282
|
+
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
283
|
+
args[6] = LONG2NUM(ni->exp);
|
292
284
|
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
293
285
|
} else {
|
294
286
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
295
287
|
}
|
296
288
|
}
|
297
289
|
break;
|
298
|
-
case 'i':
|
299
|
-
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
300
|
-
0 != pi->circ_array) { // fixnum
|
290
|
+
case 'i': // circular index
|
291
|
+
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
301
292
|
if (Qnil == parent->val) {
|
302
293
|
parent->val = rb_hash_new();
|
303
294
|
}
|
@@ -334,7 +325,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
334
325
|
int i, cnt = (int)RARRAY_LEN(e1);
|
335
326
|
|
336
327
|
for (i = 0; i < cnt; i++) {
|
337
|
-
rstr =
|
328
|
+
rstr = RARRAY_AREF(e1, i);
|
338
329
|
args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
|
339
330
|
}
|
340
331
|
sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
|
@@ -402,9 +393,7 @@ WHICH_TYPE:
|
|
402
393
|
}
|
403
394
|
break;
|
404
395
|
case T_HASH:
|
405
|
-
rb_hash_aset(parent->val,
|
406
|
-
calc_hash_key(pi, kval, parent->k1),
|
407
|
-
str_to_value(pi, str, len, orig));
|
396
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
408
397
|
break;
|
409
398
|
case T_STRING:
|
410
399
|
rval = str_to_value(pi, str, len, orig);
|
@@ -481,8 +470,8 @@ WHICH_TYPE:
|
|
481
470
|
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
482
471
|
break;
|
483
472
|
case T_OBJECT:
|
484
|
-
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg &&
|
485
|
-
|
473
|
+
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
474
|
+
0 != pi->circ_array) { // fixnum
|
486
475
|
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
487
476
|
} else {
|
488
477
|
rval = oj_num_as_value(ni);
|
@@ -559,11 +548,7 @@ WHICH_TYPE:
|
|
559
548
|
volatile VALUE *a = RARRAY_PTR(value);
|
560
549
|
|
561
550
|
if (2 != len) {
|
562
|
-
oj_set_error_at(pi,
|
563
|
-
oj_parse_error_class,
|
564
|
-
__FILE__,
|
565
|
-
__LINE__,
|
566
|
-
"invalid hash pair");
|
551
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
567
552
|
return;
|
568
553
|
}
|
569
554
|
rb_hash_aset(parent->val, *a, a[1]);
|
@@ -637,10 +622,7 @@ static void end_hash(ParseInfo pi) {
|
|
637
622
|
} else if (NULL != parent->odd_args) {
|
638
623
|
OddArgs oa = parent->odd_args;
|
639
624
|
|
640
|
-
parent->val = rb_funcall2(oa->odd->create_obj,
|
641
|
-
oa->odd->create_op,
|
642
|
-
oa->odd->attr_cnt,
|
643
|
-
oa->args);
|
625
|
+
parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
|
644
626
|
oj_odd_free(oa);
|
645
627
|
parent->odd_args = NULL;
|
646
628
|
}
|
@@ -653,8 +635,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
653
635
|
volatile VALUE rval = Qnil;
|
654
636
|
|
655
637
|
// orig lets us know whether the string was ^r1 or \u005er1
|
656
|
-
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] &&
|
657
|
-
0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
638
|
+
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
658
639
|
if ('i' == str[1]) {
|
659
640
|
long i = read_long(str + 2, len - 2);
|
660
641
|
|