oj 3.13.14 → 3.13.22
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 +32 -0
- data/README.md +2 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +34 -53
- data/ext/oj/dump.c +24 -13
- data/ext/oj/dump_compat.c +5 -10
- data/ext/oj/dump_object.c +5 -60
- data/ext/oj/dump_strict.c +5 -5
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +15 -13
- data/ext/oj/intern.c +6 -9
- data/ext/oj/introspect.c +96 -0
- data/ext/oj/mimic_json.c +18 -8
- data/ext/oj/object.c +42 -41
- data/ext/oj/oj.c +27 -4
- data/ext/oj/oj.h +4 -1
- data/ext/oj/parse.c +111 -76
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +61 -4
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +5 -10
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/strict.c +13 -13
- data/ext/oj/usual.c +82 -129
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +15 -20
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/test/bar.rb +3 -1
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +3 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +3 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +8 -3
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -0
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +7 -107
data/ext/oj/dump_object.c
CHANGED
@@ -315,7 +315,6 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
|
|
315
315
|
*out->cur = '\0';
|
316
316
|
}
|
317
317
|
|
318
|
-
#ifdef HAVE_RB_IVAR_FOREACH
|
319
318
|
static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
320
319
|
Out out = (Out)ov;
|
321
320
|
int depth = out->depth;
|
@@ -358,7 +357,6 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
|
358
357
|
|
359
358
|
return ST_CONTINUE;
|
360
359
|
}
|
361
|
-
#endif
|
362
360
|
|
363
361
|
static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
364
362
|
dump_hash_class(obj, rb_obj_class(obj), depth, out);
|
@@ -510,19 +508,8 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
510
508
|
default: break;
|
511
509
|
}
|
512
510
|
{
|
513
|
-
int cnt;
|
514
|
-
|
515
|
-
cnt = (int)rb_ivar_count(obj);
|
516
|
-
#else
|
517
|
-
volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
|
518
|
-
VALUE * np = RARRAY_PTR(vars);
|
519
|
-
ID vid;
|
520
|
-
const char * attr;
|
521
|
-
int i;
|
522
|
-
int first = 1;
|
523
|
-
|
524
|
-
cnt = (int)RARRAY_LEN(vars);
|
525
|
-
#endif
|
511
|
+
int cnt = (int)rb_ivar_count(obj);
|
512
|
+
|
526
513
|
if (Qundef != clas && 0 < cnt) {
|
527
514
|
*out->cur++ = ',';
|
528
515
|
}
|
@@ -535,52 +522,10 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
535
522
|
}
|
536
523
|
}
|
537
524
|
out->depth = depth + 1;
|
538
|
-
#ifdef HAVE_RB_IVAR_FOREACH
|
539
525
|
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
540
526
|
if (',' == *(out->cur - 1)) {
|
541
527
|
out->cur--; // backup to overwrite last comma
|
542
528
|
}
|
543
|
-
#else
|
544
|
-
size = d2 * out->indent + 1;
|
545
|
-
for (i = cnt; 0 < i; i--, np++) {
|
546
|
-
VALUE value;
|
547
|
-
|
548
|
-
vid = rb_to_id(*np);
|
549
|
-
attr = rb_id2name(vid);
|
550
|
-
if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
|
551
|
-
continue;
|
552
|
-
}
|
553
|
-
value = rb_ivar_get(obj, vid);
|
554
|
-
|
555
|
-
if (dump_ignore(out->opts, value)) {
|
556
|
-
continue;
|
557
|
-
}
|
558
|
-
if (out->omit_nil && Qnil == value) {
|
559
|
-
continue;
|
560
|
-
}
|
561
|
-
if (first) {
|
562
|
-
first = 0;
|
563
|
-
} else {
|
564
|
-
*out->cur++ = ',';
|
565
|
-
}
|
566
|
-
assure_size(out, size);
|
567
|
-
fill_indent(out, d2);
|
568
|
-
if ('@' == *attr) {
|
569
|
-
attr++;
|
570
|
-
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
571
|
-
} else {
|
572
|
-
char buf[32];
|
573
|
-
|
574
|
-
*buf = '~';
|
575
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
576
|
-
buf[sizeof(buf) - 1] = '\0';
|
577
|
-
oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
|
578
|
-
}
|
579
|
-
*out->cur++ = ':';
|
580
|
-
oj_dump_obj_val(value, d2, out);
|
581
|
-
assure_size(out, 2);
|
582
|
-
}
|
583
|
-
#endif
|
584
529
|
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
585
530
|
volatile VALUE rv;
|
586
531
|
|
@@ -737,7 +682,7 @@ static DumpFunc obj_funcs[] = {
|
|
737
682
|
void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
738
683
|
int type = rb_type(obj);
|
739
684
|
|
740
|
-
if (Yes == out->opts->trace) {
|
685
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
741
686
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
742
687
|
}
|
743
688
|
if (MAX_DEPTH < depth) {
|
@@ -748,14 +693,14 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
|
748
693
|
|
749
694
|
if (NULL != f) {
|
750
695
|
f(obj, depth, out, false);
|
751
|
-
if (Yes == out->opts->trace) {
|
696
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
752
697
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
753
698
|
}
|
754
699
|
return;
|
755
700
|
}
|
756
701
|
}
|
757
702
|
oj_dump_nil(Qnil, depth, out, false);
|
758
|
-
if (Yes == out->opts->trace) {
|
703
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
759
704
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
760
705
|
}
|
761
706
|
}
|
data/ext/oj/dump_strict.c
CHANGED
@@ -338,7 +338,7 @@ static DumpFunc strict_funcs[] = {
|
|
338
338
|
void oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
339
339
|
int type = rb_type(obj);
|
340
340
|
|
341
|
-
if (Yes == out->opts->trace) {
|
341
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
342
342
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
343
343
|
}
|
344
344
|
if (MAX_DEPTH < depth) {
|
@@ -349,7 +349,7 @@ void oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
|
349
349
|
|
350
350
|
if (NULL != f) {
|
351
351
|
f(obj, depth, out, false);
|
352
|
-
if (Yes == out->opts->trace) {
|
352
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
353
353
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
354
354
|
}
|
355
355
|
return;
|
@@ -386,7 +386,7 @@ static DumpFunc null_funcs[] = {
|
|
386
386
|
void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
387
387
|
int type = rb_type(obj);
|
388
388
|
|
389
|
-
if (Yes == out->opts->trace) {
|
389
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
390
390
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
391
391
|
}
|
392
392
|
if (MAX_DEPTH < depth) {
|
@@ -397,14 +397,14 @@ void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
|
397
397
|
|
398
398
|
if (NULL != f) {
|
399
399
|
f(obj, depth, out, false);
|
400
|
-
if (Yes == out->opts->trace) {
|
400
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
401
401
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
402
402
|
}
|
403
403
|
return;
|
404
404
|
}
|
405
405
|
}
|
406
406
|
oj_dump_nil(Qnil, depth, out, false);
|
407
|
-
if (Yes == out->opts->trace) {
|
407
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
408
408
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
409
409
|
}
|
410
410
|
}
|
data/ext/oj/extconf.rb
CHANGED
@@ -23,14 +23,10 @@ dflags = {
|
|
23
23
|
'RSTRUCT_LEN_RETURNS_INTEGER_OBJECT' => ('ruby' == type && '2' == version[0] && '4' == version[1] && '1' >= version[2]) ? 1 : 0,
|
24
24
|
}
|
25
25
|
|
26
|
-
have_func('rb_time_timespec')
|
27
|
-
have_func('rb_ivar_count')
|
28
|
-
have_func('rb_ivar_foreach')
|
29
26
|
# Support for compaction.
|
30
27
|
have_func('rb_gc_mark_movable')
|
31
28
|
have_func('stpcpy')
|
32
29
|
have_func('pthread_mutex_init')
|
33
|
-
have_func('rb_enc_associate')
|
34
30
|
have_func('rb_enc_interned_str')
|
35
31
|
have_func('rb_ext_ractor_safe', 'ruby.h')
|
36
32
|
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
@@ -38,6 +34,11 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
|
|
38
34
|
|
39
35
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
40
36
|
|
37
|
+
if with_config('--with-sse42')
|
38
|
+
$CPPFLAGS += ' -msse4.2'
|
39
|
+
dflags['OJ_USE_SSE4_2'] = 1
|
40
|
+
end
|
41
|
+
|
41
42
|
dflags.each do |k,v|
|
42
43
|
if v.nil?
|
43
44
|
$CPPFLAGS += " -D#{k}"
|
data/ext/oj/fast.c
CHANGED
@@ -677,21 +677,23 @@ static void free_doc_cb(void *x) {
|
|
677
677
|
}
|
678
678
|
|
679
679
|
static void mark_leaf(Leaf leaf) {
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
680
|
+
if (NULL != leaf) {
|
681
|
+
switch (leaf->value_type) {
|
682
|
+
case COL_VAL:
|
683
|
+
if (NULL != leaf->elements) {
|
684
|
+
Leaf first = leaf->elements->next;
|
685
|
+
Leaf e = first;
|
685
686
|
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
687
|
+
do {
|
688
|
+
mark_leaf(e);
|
689
|
+
e = e->next;
|
690
|
+
} while (e != first);
|
691
|
+
}
|
692
|
+
break;
|
693
|
+
case RUBY_VAL: mark(leaf->value); break;
|
693
694
|
|
694
|
-
|
695
|
+
default: break;
|
696
|
+
}
|
695
697
|
}
|
696
698
|
}
|
697
699
|
|
data/ext/oj/intern.c
CHANGED
@@ -37,13 +37,10 @@ typedef struct _hash {
|
|
37
37
|
struct _hash class_hash;
|
38
38
|
struct _hash attr_hash;
|
39
39
|
|
40
|
-
static struct _cache *str_cache = NULL;
|
41
40
|
static VALUE str_cache_obj;
|
42
41
|
|
43
|
-
static struct _cache *sym_cache = NULL;
|
44
42
|
static VALUE sym_cache_obj;
|
45
43
|
|
46
|
-
static struct _cache *attr_cache = NULL;
|
47
44
|
static VALUE attr_cache_obj;
|
48
45
|
|
49
46
|
static VALUE form_str(const char *str, size_t len) {
|
@@ -93,15 +90,15 @@ void oj_hash_init(void) {
|
|
93
90
|
rb_gc_register_address(&cache_class);
|
94
91
|
rb_undef_alloc_func(cache_class);
|
95
92
|
|
96
|
-
str_cache = cache_create(0, form_str, true, true);
|
93
|
+
struct _cache *str_cache = cache_create(0, form_str, true, true);
|
97
94
|
str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
|
98
95
|
rb_gc_register_address(&str_cache_obj);
|
99
96
|
|
100
|
-
sym_cache = cache_create(0, form_sym, true, true);
|
97
|
+
struct _cache *sym_cache = cache_create(0, form_sym, true, true);
|
101
98
|
sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
|
102
99
|
rb_gc_register_address(&sym_cache_obj);
|
103
100
|
|
104
|
-
attr_cache
|
101
|
+
struct _cache *attr_cache = cache_create(0, form_attr, false, true);
|
105
102
|
attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
|
106
103
|
rb_gc_register_address(&attr_cache_obj);
|
107
104
|
|
@@ -122,18 +119,18 @@ oj_str_intern(const char *key, size_t len) {
|
|
122
119
|
#if HAVE_RB_ENC_INTERNED_STR && 0
|
123
120
|
return rb_enc_interned_str(key, len, rb_utf8_encoding());
|
124
121
|
#else
|
125
|
-
return cache_intern(
|
122
|
+
return cache_intern(DATA_PTR(str_cache_obj), key, len);
|
126
123
|
#endif
|
127
124
|
}
|
128
125
|
|
129
126
|
VALUE
|
130
127
|
oj_sym_intern(const char *key, size_t len) {
|
131
|
-
|
128
|
+
return cache_intern(DATA_PTR(sym_cache_obj), key, len);
|
132
129
|
}
|
133
130
|
|
134
131
|
ID
|
135
132
|
oj_attr_intern(const char *key, size_t len) {
|
136
|
-
|
133
|
+
return cache_intern(DATA_PTR(attr_cache_obj), key, len);
|
137
134
|
}
|
138
135
|
|
139
136
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
data/ext/oj/introspect.c
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
#include "cache.h"
|
3
|
+
#include "oj.h"
|
4
|
+
#include "parser.h"
|
5
|
+
#include "usual.h"
|
6
|
+
|
7
|
+
#define BYTE_OFFSETS_STACK_INC_SIZE 256
|
8
|
+
|
9
|
+
VALUE mod = Qnil;
|
10
|
+
|
11
|
+
typedef struct _introspect {
|
12
|
+
struct _usual usual;
|
13
|
+
void (*start)(struct _ojParser *p);
|
14
|
+
void (*free)(struct _ojParser *p);
|
15
|
+
void (*mark)(struct _ojParser *p);
|
16
|
+
void (*open_object)(struct _ojParser *p);
|
17
|
+
void (*close_object)(struct _ojParser *p);
|
18
|
+
|
19
|
+
int len;
|
20
|
+
int cur;
|
21
|
+
long *stack;
|
22
|
+
|
23
|
+
} * Introspect;
|
24
|
+
|
25
|
+
static void dfree(ojParser p) {
|
26
|
+
Introspect d = (Introspect)p->ctx;
|
27
|
+
|
28
|
+
xfree(d->stack);
|
29
|
+
// As with the mark() function, this function should still work.
|
30
|
+
d->free(p);
|
31
|
+
}
|
32
|
+
|
33
|
+
static void start(ojParser p) {
|
34
|
+
Introspect d = (Introspect)p->ctx;
|
35
|
+
|
36
|
+
d->start(p);
|
37
|
+
|
38
|
+
d->stack = ALLOC_N(long, BYTE_OFFSETS_STACK_INC_SIZE);
|
39
|
+
d->len = BYTE_OFFSETS_STACK_INC_SIZE;
|
40
|
+
d->cur = 0;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void open_object(ojParser p) {
|
44
|
+
Introspect d = (Introspect)p->ctx;
|
45
|
+
|
46
|
+
d->open_object(p);
|
47
|
+
|
48
|
+
// TBD add offset
|
49
|
+
}
|
50
|
+
|
51
|
+
static void close_object(ojParser p) {
|
52
|
+
Introspect d = (Introspect)p->ctx;
|
53
|
+
|
54
|
+
d->close_object(p);
|
55
|
+
|
56
|
+
// TBD set offset on hash
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE new_parser(VALUE self, VALUE ropts) {
|
60
|
+
volatile VALUE pv = oj_parser_new();
|
61
|
+
ojParser p = (ojParser)DATA_PTR(pv);
|
62
|
+
Introspect d = ALLOC(struct _introspect);
|
63
|
+
|
64
|
+
oj_init_usual(p, &d->usual);
|
65
|
+
|
66
|
+
// Set the options before switching to the Introspect delegate.
|
67
|
+
p->ctx = (void *)d;
|
68
|
+
|
69
|
+
d->free = p->free;
|
70
|
+
p->free = dfree;
|
71
|
+
|
72
|
+
d->start = p->start;
|
73
|
+
p->start = start;
|
74
|
+
|
75
|
+
// We are cheating with the mark, free, and options functions. Since
|
76
|
+
// struct _usual is the first member of struct _introspect the cast to
|
77
|
+
// Usual in the usual.c mark() function should still work just fine.
|
78
|
+
|
79
|
+
d->open_object = p->funcs[TOP_FUN].open_object;
|
80
|
+
p->funcs[TOP_FUN].open_object = open_object;
|
81
|
+
|
82
|
+
d->close_object = p->funcs[TOP_FUN].close_object;
|
83
|
+
p->funcs[TOP_FUN].close_object = close_object;
|
84
|
+
|
85
|
+
Check_Type(ropts, T_HASH);
|
86
|
+
oj_parser_set_option(p, ropts);
|
87
|
+
|
88
|
+
return pv;
|
89
|
+
}
|
90
|
+
|
91
|
+
void Init_introspect(void) {
|
92
|
+
mod = rb_define_module("Introspect");
|
93
|
+
rb_gc_register_address(&mod);
|
94
|
+
|
95
|
+
rb_define_module_function(mod, "parser", new_parser, 1);
|
96
|
+
}
|
data/ext/oj/mimic_json.c
CHANGED
@@ -388,6 +388,10 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
388
388
|
VALUE active_hack[1];
|
389
389
|
|
390
390
|
if (Qundef == state_class) {
|
391
|
+
rb_warn(
|
392
|
+
"Oj::Rails.mimic_JSON was called implicitly. "
|
393
|
+
"Call it explicitly beforehand if you want to remove this warning."
|
394
|
+
);
|
391
395
|
oj_define_mimic_json(0, NULL, Qnil);
|
392
396
|
}
|
393
397
|
active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
|
@@ -481,6 +485,10 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
|
|
481
485
|
rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
|
482
486
|
}
|
483
487
|
if (Qundef == state_class) {
|
488
|
+
rb_warn(
|
489
|
+
"Oj::Rails.mimic_JSON was called implicitly. "
|
490
|
+
"Call it explicitly beforehand if you want to remove this warning."
|
491
|
+
);
|
484
492
|
oj_define_mimic_json(0, NULL, Qnil);
|
485
493
|
}
|
486
494
|
rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
|
@@ -536,14 +544,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
|
|
536
544
|
}
|
537
545
|
} else if (oj_decimal_class_sym == k) {
|
538
546
|
pi->options.compat_bigdec = (oj_bigdecimal_class == v);
|
539
|
-
} else if (oj_max_nesting_sym == k) {
|
540
|
-
if (Qtrue == v) {
|
541
|
-
pi->max_depth = 100;
|
542
|
-
} else if (Qfalse == v || Qnil == v) {
|
543
|
-
pi->max_depth = 0;
|
544
|
-
} else if (T_FIXNUM == rb_type(v)) {
|
545
|
-
pi->max_depth = NUM2INT(v);
|
546
|
-
}
|
547
547
|
}
|
548
548
|
return ST_CONTINUE;
|
549
549
|
}
|
@@ -573,11 +573,21 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
573
573
|
pi.max_depth = 100;
|
574
574
|
|
575
575
|
if (Qnil != ropts) {
|
576
|
+
VALUE v;
|
577
|
+
|
576
578
|
if (T_HASH != rb_type(ropts)) {
|
577
579
|
rb_raise(rb_eArgError, "options must be a hash.");
|
578
580
|
}
|
579
581
|
|
580
582
|
rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
|
583
|
+
v = rb_hash_lookup(ropts, oj_max_nesting_sym);
|
584
|
+
if (Qtrue == v) {
|
585
|
+
pi.max_depth = 100;
|
586
|
+
} else if (Qfalse == v || Qnil == v) {
|
587
|
+
pi.max_depth = 0;
|
588
|
+
} else if (T_FIXNUM == rb_type(v)) {
|
589
|
+
pi.max_depth = NUM2INT(v);
|
590
|
+
}
|
581
591
|
oj_parse_opt_match_string(&pi.options.str_rx, ropts);
|
582
592
|
if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
|
583
593
|
rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
|
data/ext/oj/object.c
CHANGED
@@ -67,9 +67,9 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
67
67
|
|
68
68
|
// The much faster approach (4x faster)
|
69
69
|
static int parse_num(const char *str, const char *end, int cnt) {
|
70
|
-
int
|
70
|
+
int n = 0;
|
71
71
|
char c;
|
72
|
-
int
|
72
|
+
int i;
|
73
73
|
|
74
74
|
for (i = cnt; 0 < i; i--, str++) {
|
75
75
|
c = *str;
|
@@ -83,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
|
|
83
83
|
|
84
84
|
VALUE
|
85
85
|
oj_parse_xml_time(const char *str, int len) {
|
86
|
-
VALUE
|
86
|
+
VALUE args[8];
|
87
87
|
const char *end = str + len;
|
88
|
-
int
|
88
|
+
int n;
|
89
89
|
|
90
90
|
// year
|
91
91
|
if (0 > (n = parse_num(str, end, 4))) {
|
@@ -269,19 +269,10 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
269
269
|
// match the expected value.
|
270
270
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
271
271
|
} else if (ni->has_exp) {
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
sec_as_time(t, &ti);
|
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);
|
284
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
272
|
+
struct timespec ts;
|
273
|
+
ts.tv_sec = ni->i;
|
274
|
+
ts.tv_nsec = nsec;
|
275
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
285
276
|
} else {
|
286
277
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
287
278
|
}
|
@@ -333,26 +324,30 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
333
324
|
// If struct is not defined then we let this fail and raise an exception.
|
334
325
|
sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
|
335
326
|
}
|
336
|
-
|
337
|
-
|
338
|
-
|
327
|
+
if (sc == rb_cRange) {
|
328
|
+
parent->val = rb_class_new_instance(len - 1, RARRAY_PTR(value) + 1, rb_cRange);
|
329
|
+
} else {
|
330
|
+
// Create a properly initialized struct instance without calling the initialize method.
|
331
|
+
parent->val = rb_obj_alloc(sc);
|
332
|
+
// If the JSON array has more entries than the struct class allows, we record an error.
|
339
333
|
#ifdef RSTRUCT_LEN
|
340
334
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
341
335
|
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
342
336
|
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
343
|
-
|
337
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
344
338
|
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
345
339
|
#else
|
346
|
-
|
340
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
347
341
|
#endif
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
342
|
+
// MRI >= 1.9
|
343
|
+
if (len - 1 > slen) {
|
344
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
345
|
+
} else {
|
346
|
+
int i;
|
353
347
|
|
354
|
-
|
355
|
-
|
348
|
+
for (i = 0; i < len - 1; i++) {
|
349
|
+
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
|
350
|
+
}
|
356
351
|
}
|
357
352
|
}
|
358
353
|
return 1;
|
@@ -374,11 +369,17 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
374
369
|
}
|
375
370
|
|
376
371
|
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
377
|
-
|
372
|
+
if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
373
|
+
parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
|
374
|
+
} else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
375
|
+
rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
|
376
|
+
} else {
|
377
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
378
|
+
}
|
378
379
|
}
|
379
380
|
|
380
381
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
381
|
-
const char
|
382
|
+
const char *key = kval->key;
|
382
383
|
int klen = kval->klen;
|
383
384
|
Val parent = stack_peek(&pi->stack);
|
384
385
|
volatile VALUE rval = Qnil;
|
@@ -445,13 +446,13 @@ WHICH_TYPE:
|
|
445
446
|
rb_class2name(rb_obj_class(parent->val)));
|
446
447
|
return;
|
447
448
|
}
|
448
|
-
if (Yes == pi->options.trace) {
|
449
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
449
450
|
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
450
451
|
}
|
451
452
|
}
|
452
453
|
|
453
454
|
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
454
|
-
const char
|
455
|
+
const char *key = kval->key;
|
455
456
|
int klen = kval->klen;
|
456
457
|
Val parent = stack_peek(&pi->stack);
|
457
458
|
volatile VALUE rval = Qnil;
|
@@ -516,7 +517,7 @@ WHICH_TYPE:
|
|
516
517
|
rb_class2name(rb_obj_class(parent->val)));
|
517
518
|
return;
|
518
519
|
}
|
519
|
-
if (Yes == pi->options.trace) {
|
520
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
520
521
|
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
|
521
522
|
}
|
522
523
|
}
|
@@ -602,13 +603,13 @@ WHICH_TYPE:
|
|
602
603
|
rb_class2name(rb_obj_class(parent->val)));
|
603
604
|
return;
|
604
605
|
}
|
605
|
-
if (Yes == pi->options.trace) {
|
606
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
606
607
|
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
|
607
608
|
}
|
608
609
|
}
|
609
610
|
|
610
611
|
static VALUE start_hash(ParseInfo pi) {
|
611
|
-
if (Yes == pi->options.trace) {
|
612
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
612
613
|
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
613
614
|
}
|
614
615
|
return Qnil;
|
@@ -626,7 +627,7 @@ static void end_hash(ParseInfo pi) {
|
|
626
627
|
oj_odd_free(oa);
|
627
628
|
parent->odd_args = NULL;
|
628
629
|
}
|
629
|
-
if (Yes == pi->options.trace) {
|
630
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
630
631
|
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
631
632
|
}
|
632
633
|
}
|
@@ -654,7 +655,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
654
655
|
}
|
655
656
|
rval = str_to_value(pi, str, len, orig);
|
656
657
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
657
|
-
if (Yes == pi->options.trace) {
|
658
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
658
659
|
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
659
660
|
}
|
660
661
|
}
|
@@ -663,21 +664,21 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
|
|
663
664
|
volatile VALUE rval = oj_num_as_value(ni);
|
664
665
|
|
665
666
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
666
|
-
if (Yes == pi->options.trace) {
|
667
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
667
668
|
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
668
669
|
}
|
669
670
|
}
|
670
671
|
|
671
672
|
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
672
673
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
673
|
-
if (Yes == pi->options.trace) {
|
674
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
674
675
|
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
675
676
|
}
|
676
677
|
}
|
677
678
|
|
678
679
|
static void add_num(ParseInfo pi, NumInfo ni) {
|
679
680
|
pi->stack.head->val = oj_num_as_value(ni);
|
680
|
-
if (Yes == pi->options.trace) {
|
681
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
681
682
|
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
682
683
|
}
|
683
684
|
}
|