oj 3.13.21 → 3.13.23
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 +8 -0
- data/README.md +2 -0
- data/ext/oj/custom.c +21 -40
- data/ext/oj/fast.c +15 -13
- data/ext/oj/intern.c +6 -9
- data/ext/oj/object.c +33 -32
- data/ext/oj/oj.c +11 -3
- data/ext/oj/oj.h +3 -0
- data/ext/oj/parser.c +32 -2
- data/ext/oj/parser.h +11 -0
- data/ext/oj/saj2.c +56 -62
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/usual.c +82 -129
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Options.md +6 -0
- data/test/json_gem/json_generator_test.rb +3 -4
- data/test/json_gem/json_parser_test.rb +1 -3
- data/test/test_custom.rb +9 -10
- data/test/test_file.rb +3 -10
- data/test/test_gc.rb +0 -2
- data/test/test_integer_range.rb +0 -6
- data/test/test_object.rb +3 -48
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_scp.rb +2 -4
- data/test/test_various.rb +2 -3
- data/test/tests.rb +9 -0
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d2f8a01b7a59da7cd25ed3551065dddd9e31e5184989804d172c2e39cc769d6
|
|
4
|
+
data.tar.gz: 7211a96856ec44173fa9dcc7245e3cb2f6b7c2e22a746ef35f168126873f4c88
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee3ad5cac6cac48bcf7fdf682e69770dfee08b502735cc75b84ae1635196fdcdaf2fde021e32e6d897bdc6935e111882ddc48fa5a274fe0d98ad45c2fdf68917
|
|
7
|
+
data.tar.gz: 3e05212fa84a2bf05954ec870ac27da7c845335b411507aa0bf5e45497403cccf4c40990f0ee8cee6d21f19163f33116bb240836795482737eaa744bc5ff6d94
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 3.13.23 - 2022-11-06
|
|
4
|
+
|
|
5
|
+
- Fixed issue with Oj::Parser extension regarding GC timeing.
|
|
6
|
+
|
|
7
|
+
## 3.13.22 - 2022-11-01
|
|
8
|
+
|
|
9
|
+
- Reorganized Oj::Parser code to allow for parser extensions in C.
|
|
10
|
+
|
|
3
11
|
## 3.13.21 - 2022-08-19
|
|
4
12
|
|
|
5
13
|
- Bug parsing big numbers fixed in the SAJ parser.
|
data/README.md
CHANGED
|
@@ -109,6 +109,8 @@ Follow [@peterohler on Twitter](http://twitter.com/peterohler) for announcements
|
|
|
109
109
|
|
|
110
110
|
- *Agoo-C, a high performance C web server supporting GraphQL on GitHub*: https://github.com/ohler55/agoo-c
|
|
111
111
|
|
|
112
|
+
- *oj-introspect, an example of creating an Oj parser extension in C*: https://github.com/meinac/oj-introspect
|
|
113
|
+
|
|
112
114
|
#### Contributing
|
|
113
115
|
|
|
114
116
|
+ Provide a Pull Request off the `develop` branch.
|
data/ext/oj/custom.c
CHANGED
|
@@ -31,14 +31,14 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
|
|
|
31
31
|
|
|
32
32
|
static void dump_obj_as_str(VALUE obj, int depth, Out out) {
|
|
33
33
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
34
|
-
const char
|
|
34
|
+
const char *str = RSTRING_PTR(rstr);
|
|
35
35
|
|
|
36
36
|
oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
static void bigdecimal_dump(VALUE obj, int depth, Out out) {
|
|
40
40
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
41
|
-
const char
|
|
41
|
+
const char *str = RSTRING_PTR(rstr);
|
|
42
42
|
int len = (int)RSTRING_LEN(rstr);
|
|
43
43
|
|
|
44
44
|
if (0 == strcasecmp("Infinity", str)) {
|
|
@@ -82,8 +82,7 @@ static VALUE complex_load(VALUE clas, VALUE args) {
|
|
|
82
82
|
real_id = rb_intern("real");
|
|
83
83
|
imag_id = rb_intern("imag");
|
|
84
84
|
}
|
|
85
|
-
return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)),
|
|
86
|
-
rb_hash_aref(args, rb_id2str(imag_id)));
|
|
85
|
+
return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id)));
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
static void time_dump(VALUE obj, int depth, Out out) {
|
|
@@ -246,8 +245,7 @@ static VALUE rational_load(VALUE clas, VALUE args) {
|
|
|
246
245
|
numerator_id = rb_intern("numerator");
|
|
247
246
|
denominator_id = rb_intern("denominator");
|
|
248
247
|
}
|
|
249
|
-
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
|
|
250
|
-
rb_hash_aref(args, rb_id2str(denominator_id)));
|
|
248
|
+
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), rb_hash_aref(args, rb_id2str(denominator_id)));
|
|
251
249
|
}
|
|
252
250
|
|
|
253
251
|
static VALUE regexp_load(VALUE clas, VALUE args) {
|
|
@@ -292,8 +290,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
292
290
|
assure_size(out, depth * out->indent + 1);
|
|
293
291
|
fill_indent(out, depth);
|
|
294
292
|
} else {
|
|
295
|
-
assure_size(out,
|
|
296
|
-
depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
|
293
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
|
297
294
|
if (0 < out->opts->dump_opts.hash_size) {
|
|
298
295
|
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
|
299
296
|
}
|
|
@@ -352,9 +349,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
352
349
|
assure_size(out, depth * out->indent + 2);
|
|
353
350
|
fill_indent(out, depth);
|
|
354
351
|
} else {
|
|
355
|
-
assure_size(
|
|
356
|
-
out,
|
|
357
|
-
depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
|
352
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
|
358
353
|
if (0 < out->opts->dump_opts.hash_size) {
|
|
359
354
|
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
|
360
355
|
}
|
|
@@ -372,10 +367,10 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
372
367
|
}
|
|
373
368
|
|
|
374
369
|
static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
375
|
-
ID
|
|
376
|
-
AttrGetFunc
|
|
370
|
+
ID *idp;
|
|
371
|
+
AttrGetFunc *fp;
|
|
377
372
|
volatile VALUE v;
|
|
378
|
-
const char
|
|
373
|
+
const char *name;
|
|
379
374
|
size_t size;
|
|
380
375
|
int d2 = depth + 1;
|
|
381
376
|
|
|
@@ -384,7 +379,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
|
384
379
|
if (NULL != out->opts->create_id && Yes == out->opts->create_ok) {
|
|
385
380
|
const char *classname = rb_class2name(clas);
|
|
386
381
|
int clen = (int)strlen(classname);
|
|
387
|
-
size_t
|
|
382
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
388
383
|
|
|
389
384
|
size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
|
|
390
385
|
assure_size(out, size);
|
|
@@ -481,7 +476,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
|
481
476
|
oj_dump_raw_json(obj, depth, out);
|
|
482
477
|
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
|
483
478
|
volatile VALUE rs;
|
|
484
|
-
const char
|
|
479
|
+
const char *s;
|
|
485
480
|
int len;
|
|
486
481
|
|
|
487
482
|
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
|
@@ -521,11 +516,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
|
521
516
|
if (aj == obj) {
|
|
522
517
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
523
518
|
|
|
524
|
-
oj_dump_cstr(RSTRING_PTR(rstr),
|
|
525
|
-
(int)RSTRING_LEN(rstr),
|
|
526
|
-
false,
|
|
527
|
-
false,
|
|
528
|
-
out);
|
|
519
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
|
|
529
520
|
} else {
|
|
530
521
|
oj_dump_custom_val(aj, depth, out, true);
|
|
531
522
|
}
|
|
@@ -609,7 +600,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
|
609
600
|
assure_size(out, 2);
|
|
610
601
|
*out->cur++ = '{';
|
|
611
602
|
if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) {
|
|
612
|
-
size_t
|
|
603
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
613
604
|
const char *classname = rb_obj_classname(obj);
|
|
614
605
|
size_t len = strlen(classname);
|
|
615
606
|
|
|
@@ -911,7 +902,7 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
911
902
|
///// load functions /////
|
|
912
903
|
|
|
913
904
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
914
|
-
const char
|
|
905
|
+
const char *key = kval->key;
|
|
915
906
|
int klen = kval->klen;
|
|
916
907
|
Val parent = stack_peek(&pi->stack);
|
|
917
908
|
volatile VALUE rkey = kval->key_val;
|
|
@@ -928,14 +919,14 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
|
928
919
|
}
|
|
929
920
|
}
|
|
930
921
|
} else {
|
|
931
|
-
|
|
932
|
-
//volatile VALUE rstr = rb_utf8_str_new(str, len);
|
|
922
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
|
923
|
+
// volatile VALUE rstr = rb_utf8_str_new(str, len);
|
|
933
924
|
|
|
934
925
|
if (Qundef == rkey) {
|
|
935
926
|
if (Yes == pi->options.sym_key) {
|
|
936
927
|
rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
|
|
937
928
|
} else {
|
|
938
|
-
|
|
929
|
+
rkey = rb_utf8_str_new(key, klen);
|
|
939
930
|
}
|
|
940
931
|
}
|
|
941
932
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
@@ -1008,20 +999,10 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
|
|
1008
999
|
// match the expected value.
|
|
1009
1000
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
|
1010
1001
|
} else if (ni->has_exp) {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
sec_as_time(t, &ti);
|
|
1016
|
-
|
|
1017
|
-
args[0] = LONG2NUM(ti.year);
|
|
1018
|
-
args[1] = LONG2NUM(ti.mon);
|
|
1019
|
-
args[2] = LONG2NUM(ti.day);
|
|
1020
|
-
args[3] = LONG2NUM(ti.hour);
|
|
1021
|
-
args[4] = LONG2NUM(ti.min);
|
|
1022
|
-
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
|
1023
|
-
args[6] = LONG2NUM(ni->exp);
|
|
1024
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
1002
|
+
struct timespec ts;
|
|
1003
|
+
ts.tv_sec = ni->i;
|
|
1004
|
+
ts.tv_nsec = nsec;
|
|
1005
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
|
1025
1006
|
} else {
|
|
1026
1007
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
1027
1008
|
}
|
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/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;
|
|
@@ -451,7 +452,7 @@ WHICH_TYPE:
|
|
|
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;
|
data/ext/oj/oj.c
CHANGED
|
@@ -32,6 +32,7 @@ ID oj_array_append_id;
|
|
|
32
32
|
ID oj_array_end_id;
|
|
33
33
|
ID oj_array_start_id;
|
|
34
34
|
ID oj_as_json_id;
|
|
35
|
+
ID oj_at_id;
|
|
35
36
|
ID oj_begin_id;
|
|
36
37
|
ID oj_bigdecimal_id;
|
|
37
38
|
ID oj_end_id;
|
|
@@ -89,7 +90,9 @@ VALUE oj_array_class_sym;
|
|
|
89
90
|
VALUE oj_create_additions_sym;
|
|
90
91
|
VALUE oj_decimal_class_sym;
|
|
91
92
|
VALUE oj_hash_class_sym;
|
|
93
|
+
VALUE oj_in_sym;
|
|
92
94
|
VALUE oj_indent_sym;
|
|
95
|
+
VALUE oj_nanosecond_sym;
|
|
93
96
|
VALUE oj_object_class_sym;
|
|
94
97
|
VALUE oj_quirks_mode_sym;
|
|
95
98
|
VALUE oj_safe_sym;
|
|
@@ -240,7 +243,7 @@ struct _options oj_default_options = {
|
|
|
240
243
|
*references
|
|
241
244
|
* - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
|
|
242
245
|
* - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
|
|
243
|
-
* - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|
|
|
246
|
+
* - *:escape_mode* [_:newline_|_:json_|_:slash_|_:xss_safe_|_:ascii_|_:unicode_xss_|_nil_] determines the
|
|
244
247
|
*characters to escape
|
|
245
248
|
* - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying
|
|
246
249
|
*classes or reloading classes then don't use this)
|
|
@@ -248,7 +251,7 @@ struct _options oj_default_options = {
|
|
|
248
251
|
*to use for JSON
|
|
249
252
|
* - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
|
|
250
253
|
* - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
|
|
251
|
-
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead
|
|
254
|
+
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals as BigDecimal instead
|
|
252
255
|
*of as a Float. :auto pick the most precise for the number of digits. :float should be the same as
|
|
253
256
|
*ruby. :fast may require rounding but is must faster.
|
|
254
257
|
* - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in
|
|
@@ -929,7 +932,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
929
932
|
if (Qnil == v) {
|
|
930
933
|
return ST_CONTINUE;
|
|
931
934
|
}
|
|
932
|
-
if (
|
|
935
|
+
if (rb_obj_class(v) == rb_cRange) {
|
|
933
936
|
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
|
934
937
|
VALUE max = rb_funcall(v, oj_end_id, 0);
|
|
935
938
|
|
|
@@ -1814,6 +1817,7 @@ void Init_oj(void) {
|
|
|
1814
1817
|
oj_array_end_id = rb_intern("array_end");
|
|
1815
1818
|
oj_array_start_id = rb_intern("array_start");
|
|
1816
1819
|
oj_as_json_id = rb_intern("as_json");
|
|
1820
|
+
oj_at_id = rb_intern("at");
|
|
1817
1821
|
oj_begin_id = rb_intern("begin");
|
|
1818
1822
|
oj_bigdecimal_id = rb_intern("BigDecimal");
|
|
1819
1823
|
oj_end_id = rb_intern("end");
|
|
@@ -1961,10 +1965,14 @@ void Init_oj(void) {
|
|
|
1961
1965
|
rb_gc_register_address(&oj_decimal_class_sym);
|
|
1962
1966
|
oj_hash_class_sym = ID2SYM(rb_intern("hash_class"));
|
|
1963
1967
|
rb_gc_register_address(&oj_hash_class_sym);
|
|
1968
|
+
oj_in_sym = ID2SYM(rb_intern("in"));
|
|
1969
|
+
rb_gc_register_address(&oj_in_sym);
|
|
1964
1970
|
oj_indent_sym = ID2SYM(rb_intern("indent"));
|
|
1965
1971
|
rb_gc_register_address(&oj_indent_sym);
|
|
1966
1972
|
oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting"));
|
|
1967
1973
|
rb_gc_register_address(&oj_max_nesting_sym);
|
|
1974
|
+
oj_nanosecond_sym = ID2SYM(rb_intern("nanosecond"));
|
|
1975
|
+
rb_gc_register_address(&oj_nanosecond_sym);
|
|
1968
1976
|
oj_object_class_sym = ID2SYM(rb_intern("object_class"));
|
|
1969
1977
|
rb_gc_register_address(&oj_object_class_sym);
|
|
1970
1978
|
oj_object_nl_sym = ID2SYM(rb_intern("object_nl"));
|
data/ext/oj/oj.h
CHANGED
|
@@ -317,7 +317,9 @@ extern VALUE oj_ascii_only_sym;
|
|
|
317
317
|
extern VALUE oj_create_additions_sym;
|
|
318
318
|
extern VALUE oj_decimal_class_sym;
|
|
319
319
|
extern VALUE oj_hash_class_sym;
|
|
320
|
+
extern VALUE oj_in_sym;
|
|
320
321
|
extern VALUE oj_indent_sym;
|
|
322
|
+
extern VALUE oj_nanosecond_sym;
|
|
321
323
|
extern VALUE oj_max_nesting_sym;
|
|
322
324
|
extern VALUE oj_object_class_sym;
|
|
323
325
|
extern VALUE oj_object_nl_sym;
|
|
@@ -334,6 +336,7 @@ extern ID oj_array_append_id;
|
|
|
334
336
|
extern ID oj_array_end_id;
|
|
335
337
|
extern ID oj_array_start_id;
|
|
336
338
|
extern ID oj_as_json_id;
|
|
339
|
+
extern ID oj_at_id;
|
|
337
340
|
extern ID oj_begin_id;
|
|
338
341
|
extern ID oj_bigdecimal_id;
|
|
339
342
|
extern ID oj_end_id;
|
data/ext/oj/parser.c
CHANGED
|
@@ -1145,7 +1145,9 @@ static void parser_free(void *ptr) {
|
|
|
1145
1145
|
p = (ojParser)ptr;
|
|
1146
1146
|
buf_cleanup(&p->key);
|
|
1147
1147
|
buf_cleanup(&p->buf);
|
|
1148
|
-
p->free
|
|
1148
|
+
if (NULL != p->free) {
|
|
1149
|
+
p->free(p);
|
|
1150
|
+
}
|
|
1149
1151
|
xfree(ptr);
|
|
1150
1152
|
}
|
|
1151
1153
|
|
|
@@ -1156,7 +1158,9 @@ static void parser_mark(void *ptr) {
|
|
|
1156
1158
|
if (0 != p->reader) {
|
|
1157
1159
|
rb_gc_mark(p->reader);
|
|
1158
1160
|
}
|
|
1159
|
-
p->mark
|
|
1161
|
+
if (NULL != p->mark) {
|
|
1162
|
+
p->mark(p);
|
|
1163
|
+
}
|
|
1160
1164
|
}
|
|
1161
1165
|
}
|
|
1162
1166
|
|
|
@@ -1254,6 +1258,32 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
|
1254
1258
|
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
|
1255
1259
|
}
|
|
1256
1260
|
|
|
1261
|
+
// Create a new parser without setting the delegate. The parser is
|
|
1262
|
+
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
|
1263
|
+
// from this function. A delegate must be added before the parser can be
|
|
1264
|
+
// used. Optionally oj_parser_set_options can be called if the options are not
|
|
1265
|
+
// set directly.
|
|
1266
|
+
VALUE oj_parser_new() {
|
|
1267
|
+
ojParser p = ALLOC(struct _ojParser);
|
|
1268
|
+
|
|
1269
|
+
#if HAVE_RB_EXT_RACTOR_SAFE
|
|
1270
|
+
// This doesn't seem to do anything.
|
|
1271
|
+
rb_ext_ractor_safe(true);
|
|
1272
|
+
#endif
|
|
1273
|
+
memset(p, 0, sizeof(struct _ojParser));
|
|
1274
|
+
buf_init(&p->key);
|
|
1275
|
+
buf_init(&p->buf);
|
|
1276
|
+
p->map = value_map;
|
|
1277
|
+
|
|
1278
|
+
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// Set set the options from a hash (ropts).
|
|
1282
|
+
void oj_parser_set_option(ojParser p, VALUE ropts) {
|
|
1283
|
+
Check_Type(ropts, T_HASH);
|
|
1284
|
+
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1257
1287
|
/* Document-method: method_missing(value)
|
|
1258
1288
|
* call-seq: method_missing(value)
|
|
1259
1289
|
*
|
data/ext/oj/parser.h
CHANGED
|
@@ -88,4 +88,15 @@ typedef struct _ojParser {
|
|
|
88
88
|
bool just_one;
|
|
89
89
|
} * ojParser;
|
|
90
90
|
|
|
91
|
+
// Create a new parser without setting the delegate. The parser is
|
|
92
|
+
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
|
93
|
+
// from this function. A delegate must be added before the parser can be
|
|
94
|
+
// used. Optionally oj_parser_set_options can be called if the options are not
|
|
95
|
+
// set directly.
|
|
96
|
+
extern VALUE oj_parser_new();
|
|
97
|
+
|
|
98
|
+
// Set set the options from a hash (ropts).
|
|
99
|
+
extern void oj_parser_set_option(ojParser p, VALUE ropts);
|
|
100
|
+
|
|
101
|
+
|
|
91
102
|
#endif /* OJ_PARSER_H */
|