oj 3.17.1 → 3.17.6
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 +87 -0
- data/ext/oj/cache.c +17 -1
- data/ext/oj/cache.h +5 -0
- data/ext/oj/circarray.c +6 -2
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +7 -5
- data/ext/oj/dump.c +27 -12
- data/ext/oj/dump.h +10 -0
- data/ext/oj/dump_compat.c +11 -4
- data/ext/oj/dump_object.c +20 -10
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/fast.c +104 -48
- data/ext/oj/intern.c +7 -2
- data/ext/oj/object.c +26 -15
- data/ext/oj/odd.c +6 -2
- data/ext/oj/oj.c +277 -26
- data/ext/oj/oj.h +6 -1
- data/ext/oj/parse.c +19 -5
- data/ext/oj/parse.h +0 -1
- data/ext/oj/parser.c +135 -37
- data/ext/oj/rails.c +180 -42
- data/ext/oj/reader.c +18 -6
- data/ext/oj/resolve.c +11 -2
- data/ext/oj/rxclass.c +17 -1
- data/ext/oj/rxclass.h +2 -1
- data/ext/oj/safe.c +63 -48
- data/ext/oj/safe.h +14 -2
- data/ext/oj/saj.c +46 -10
- data/ext/oj/sparse.c +16 -6
- data/ext/oj/stream_writer.c +16 -1
- data/ext/oj/string_writer.c +23 -7
- data/ext/oj/usual.c +23 -6
- data/ext/oj/util.c +27 -0
- data/ext/oj/util.h +2 -1
- data/ext/oj/val_stack.h +24 -5
- data/ext/oj/wab.c +14 -26
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/Custom.md +2 -3
- data/pages/InstallOptions.md +8 -6
- data/pages/Modes.md +1 -1
- data/pages/Options.md +5 -6
- data/pages/Parser.md +2 -2
- data/pages/Rails.md +6 -0
- data/pages/Security.md +21 -7
- metadata +2 -2
data/ext/oj/fast.c
CHANGED
|
@@ -80,7 +80,7 @@ static void each_leaf(Doc doc, VALUE self);
|
|
|
80
80
|
static int move_step(Doc doc, const char *path, int loc);
|
|
81
81
|
static Leaf get_doc_leaf(Doc doc, const char *path);
|
|
82
82
|
static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
|
|
83
|
-
static void each_value(Doc doc, Leaf leaf);
|
|
83
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self);
|
|
84
84
|
|
|
85
85
|
VALUE oj_doc_class = Qundef;
|
|
86
86
|
|
|
@@ -92,12 +92,35 @@ inline static void next_non_white(ParseInfo pi) {
|
|
|
92
92
|
case '\f':
|
|
93
93
|
case '\n':
|
|
94
94
|
case '\r': break;
|
|
95
|
-
case '/':
|
|
95
|
+
case '/':
|
|
96
|
+
skip_comment(pi);
|
|
97
|
+
// A comment that is not terminated by a newline ends on the null
|
|
98
|
+
// terminator. Stop here so the loop does not step past it.
|
|
99
|
+
if ('\0' == *pi->s) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
96
103
|
default: return;
|
|
97
104
|
}
|
|
98
105
|
}
|
|
99
106
|
}
|
|
100
107
|
|
|
108
|
+
inline static bool is_value_end(char c) {
|
|
109
|
+
switch (c) {
|
|
110
|
+
case '\0':
|
|
111
|
+
case ' ':
|
|
112
|
+
case '\t':
|
|
113
|
+
case '\f':
|
|
114
|
+
case '\n':
|
|
115
|
+
case '\r':
|
|
116
|
+
case '/':
|
|
117
|
+
case ',':
|
|
118
|
+
case ']':
|
|
119
|
+
case '}': return true;
|
|
120
|
+
default: return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
101
124
|
inline static char *ulong_fill(char *s, size_t num) {
|
|
102
125
|
char buf[32];
|
|
103
126
|
char *b = buf + sizeof(buf) - 1;
|
|
@@ -210,10 +233,11 @@ static void skip_comment(ParseInfo pi) {
|
|
|
210
233
|
if ('*' == *pi->s && '/' == *(pi->s + 1)) {
|
|
211
234
|
pi->s++;
|
|
212
235
|
return;
|
|
213
|
-
} else if ('\0' == *pi->s) {
|
|
214
|
-
raise_error("comment not terminated", pi->str, pi->s);
|
|
215
236
|
}
|
|
216
237
|
}
|
|
238
|
+
// The loop only ends on the null terminator so the comment was never
|
|
239
|
+
// closed.
|
|
240
|
+
raise_error("comment not terminated", pi->str, pi->s);
|
|
217
241
|
} else if ('/' == *pi->s) {
|
|
218
242
|
for (; 1; pi->s++) {
|
|
219
243
|
switch (*pi->s) {
|
|
@@ -455,27 +479,42 @@ static Leaf read_num(ParseInfo pi) {
|
|
|
455
479
|
char *start = pi->s;
|
|
456
480
|
int type = T_FIXNUM;
|
|
457
481
|
Leaf leaf;
|
|
482
|
+
int dcnt = 0;
|
|
483
|
+
int ecnt = 1;
|
|
458
484
|
|
|
459
|
-
|
|
485
|
+
// read_next() sends a leading '+' here as well, and Oj.load() takes one.
|
|
486
|
+
if ('-' == *pi->s || '+' == *pi->s) {
|
|
460
487
|
pi->s++;
|
|
461
488
|
}
|
|
462
489
|
// digits
|
|
463
490
|
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
491
|
+
dcnt++;
|
|
464
492
|
}
|
|
465
493
|
if ('.' == *pi->s) {
|
|
466
494
|
type = T_FLOAT;
|
|
467
495
|
pi->s++;
|
|
468
496
|
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
497
|
+
dcnt++;
|
|
469
498
|
}
|
|
470
499
|
}
|
|
471
500
|
if ('e' == *pi->s || 'E' == *pi->s) {
|
|
501
|
+
// An exponent makes it a float whether or not a '.' was seen. Without
|
|
502
|
+
// this leaf_fixnum_value() stops reading at the 'e' and the exponent is
|
|
503
|
+
// dropped.
|
|
504
|
+
type = T_FLOAT;
|
|
472
505
|
pi->s++;
|
|
473
506
|
if ('-' == *pi->s || '+' == *pi->s) {
|
|
474
507
|
pi->s++;
|
|
475
508
|
}
|
|
476
|
-
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
509
|
+
for (ecnt = 0; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
510
|
+
ecnt++;
|
|
477
511
|
}
|
|
478
512
|
}
|
|
513
|
+
// A float is converted with rb_cstr_to_dbl(), which has to be given
|
|
514
|
+
// something it can convert.
|
|
515
|
+
if (T_FLOAT == type && (0 == dcnt || 0 == ecnt || !is_value_end(*pi->s))) {
|
|
516
|
+
raise_error("invalid number", pi->str, pi->s);
|
|
517
|
+
}
|
|
479
518
|
leaf = leaf_new(pi->doc, type);
|
|
480
519
|
leaf->str = start;
|
|
481
520
|
|
|
@@ -662,7 +701,11 @@ static void doc_free(Doc doc) {
|
|
|
662
701
|
static VALUE protect_open_proc(VALUE x) {
|
|
663
702
|
ParseInfo pi = (ParseInfo)x;
|
|
664
703
|
|
|
665
|
-
pi->doc->data
|
|
704
|
+
pi->doc->data = read_next(pi); // parse
|
|
705
|
+
// read_obj() and read_array() terminate each value where it ends. The top
|
|
706
|
+
// level value has no closing delimiter to do that on, so a number leaf runs
|
|
707
|
+
// to the end of the document unless it is terminated here.
|
|
708
|
+
*pi->s = '\0';
|
|
666
709
|
*pi->doc->where = pi->doc->data;
|
|
667
710
|
pi->doc->where = pi->doc->where_path;
|
|
668
711
|
if (rb_block_given_p()) {
|
|
@@ -710,21 +753,23 @@ static void mark_doc(void *ptr) {
|
|
|
710
753
|
}
|
|
711
754
|
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
|
712
755
|
static void compact_leaf(Leaf leaf) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
756
|
+
if (NULL != leaf) {
|
|
757
|
+
switch (leaf->value_type) {
|
|
758
|
+
case COL_VAL:
|
|
759
|
+
if (NULL != leaf->elements) {
|
|
760
|
+
Leaf first = leaf->elements->next;
|
|
761
|
+
Leaf e = first;
|
|
718
762
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
763
|
+
do {
|
|
764
|
+
compact_leaf(e);
|
|
765
|
+
e = e->next;
|
|
766
|
+
} while (e != first);
|
|
767
|
+
}
|
|
768
|
+
break;
|
|
769
|
+
case RUBY_VAL: leaf->value = rb_gc_location(leaf->value); break;
|
|
726
770
|
|
|
727
|
-
|
|
771
|
+
default: break;
|
|
772
|
+
}
|
|
728
773
|
}
|
|
729
774
|
}
|
|
730
775
|
|
|
@@ -790,14 +835,11 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
|
790
835
|
doc->self = self;
|
|
791
836
|
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
|
792
837
|
if (given || 0 != ex) {
|
|
838
|
+
// The doc is detached from its wrapper so the GC will not free it.
|
|
839
|
+
// doc_free() releases both the doc and its json buffer (doc->json), so
|
|
840
|
+
// the caller must not free json separately.
|
|
793
841
|
DATA_PTR(doc->self) = NULL;
|
|
794
|
-
// TBD is this needed?
|
|
795
|
-
/*
|
|
796
842
|
doc_free(pi.doc);
|
|
797
|
-
if (0 != ex) { // will jump so caller will not free
|
|
798
|
-
OJ_R_FREE(json);
|
|
799
|
-
}
|
|
800
|
-
*/
|
|
801
843
|
} else {
|
|
802
844
|
result = doc->self;
|
|
803
845
|
}
|
|
@@ -865,7 +907,7 @@ static bool key_match(const char *pat, const char *key, int plen) {
|
|
|
865
907
|
static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
866
908
|
Leaf leaf = *lp;
|
|
867
909
|
|
|
868
|
-
if (MAX_STACK <= lp - stack) {
|
|
910
|
+
if (MAX_STACK <= (lp + 1) - stack) {
|
|
869
911
|
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
870
912
|
}
|
|
871
913
|
if ('\0' != *path) {
|
|
@@ -946,6 +988,7 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
|
946
988
|
|
|
947
989
|
doc->where++;
|
|
948
990
|
if (MAX_STACK <= doc->where - doc->where_path) {
|
|
991
|
+
doc->where--;
|
|
949
992
|
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
950
993
|
}
|
|
951
994
|
do {
|
|
@@ -957,11 +1000,14 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
|
957
1000
|
}
|
|
958
1001
|
} else {
|
|
959
1002
|
rb_yield(self);
|
|
1003
|
+
if (NULL == DATA_PTR(self)) {
|
|
1004
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1005
|
+
}
|
|
960
1006
|
}
|
|
961
1007
|
}
|
|
962
1008
|
|
|
963
1009
|
static int move_step(Doc doc, const char *path, int loc) {
|
|
964
|
-
if (MAX_STACK <= doc->where - doc->where_path) {
|
|
1010
|
+
if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
|
|
965
1011
|
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
966
1012
|
}
|
|
967
1013
|
if ('\0' == *path) {
|
|
@@ -969,8 +1015,9 @@ static int move_step(Doc doc, const char *path, int loc) {
|
|
|
969
1015
|
} else {
|
|
970
1016
|
Leaf leaf;
|
|
971
1017
|
|
|
1018
|
+
// A document with no root (empty or comment only JSON) has no leaf to
|
|
1019
|
+
// step from so the path can not be located.
|
|
972
1020
|
if (0 == doc->where || 0 == (leaf = *doc->where)) {
|
|
973
|
-
printf("*** Internal error at %s\n", path);
|
|
974
1021
|
return loc;
|
|
975
1022
|
}
|
|
976
1023
|
if ('.' == *path && '.' == *(path + 1)) {
|
|
@@ -1050,19 +1097,22 @@ static int move_step(Doc doc, const char *path, int loc) {
|
|
|
1050
1097
|
return loc;
|
|
1051
1098
|
}
|
|
1052
1099
|
|
|
1053
|
-
static void each_value(Doc doc, Leaf leaf) {
|
|
1100
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self) {
|
|
1054
1101
|
if (COL_VAL == leaf->value_type) {
|
|
1055
1102
|
if (0 != leaf->elements) {
|
|
1056
1103
|
Leaf first = leaf->elements->next;
|
|
1057
1104
|
Leaf e = first;
|
|
1058
1105
|
|
|
1059
1106
|
do {
|
|
1060
|
-
each_value(doc, e);
|
|
1107
|
+
each_value(doc, e, self);
|
|
1061
1108
|
e = e->next;
|
|
1062
1109
|
} while (e != first);
|
|
1063
1110
|
}
|
|
1064
1111
|
} else {
|
|
1065
1112
|
rb_yield(leaf_value(doc, leaf));
|
|
1113
|
+
if (NULL == DATA_PTR(self)) {
|
|
1114
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1115
|
+
}
|
|
1066
1116
|
}
|
|
1067
1117
|
}
|
|
1068
1118
|
|
|
@@ -1098,12 +1148,7 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
|
1098
1148
|
|
|
1099
1149
|
memcpy(json, StringValuePtr(str), len);
|
|
1100
1150
|
obj = parse_json(clas, json, given);
|
|
1101
|
-
//
|
|
1102
|
-
/*
|
|
1103
|
-
if (given) {
|
|
1104
|
-
OJ_R_FREE(json);
|
|
1105
|
-
}
|
|
1106
|
-
*/
|
|
1151
|
+
// json is owned by the doc and freed by doc_free(); do not free it here.
|
|
1107
1152
|
return obj;
|
|
1108
1153
|
}
|
|
1109
1154
|
|
|
@@ -1135,7 +1180,9 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
|
1135
1180
|
int given = rb_block_given_p();
|
|
1136
1181
|
|
|
1137
1182
|
path = StringValuePtr(filename);
|
|
1138
|
-
|
|
1183
|
+
// Open in binary mode. On Windows a text mode read translates CRLF into LF
|
|
1184
|
+
// so fewer bytes are read than the file size reported by ftell().
|
|
1185
|
+
if (0 == (f = fopen(path, "rb"))) {
|
|
1139
1186
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
|
1140
1187
|
}
|
|
1141
1188
|
fseek(f, 0, SEEK_END);
|
|
@@ -1153,12 +1200,7 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
|
1153
1200
|
fclose(f);
|
|
1154
1201
|
json[len] = '\0';
|
|
1155
1202
|
obj = parse_json(clas, json, given);
|
|
1156
|
-
//
|
|
1157
|
-
/*
|
|
1158
|
-
if (given) {
|
|
1159
|
-
OJ_R_FREE(json);
|
|
1160
|
-
}
|
|
1161
|
-
*/
|
|
1203
|
+
// json is owned by the doc and freed by doc_free(); do not free it here.
|
|
1162
1204
|
return obj;
|
|
1163
1205
|
}
|
|
1164
1206
|
|
|
@@ -1257,10 +1299,14 @@ static VALUE doc_path(VALUE self) {
|
|
|
1257
1299
|
* #=> nil
|
|
1258
1300
|
*/
|
|
1259
1301
|
static VALUE doc_local_key(VALUE self) {
|
|
1260
|
-
Doc doc
|
|
1261
|
-
Leaf leaf
|
|
1262
|
-
volatile VALUE key
|
|
1302
|
+
Doc doc = self_doc(self);
|
|
1303
|
+
Leaf leaf;
|
|
1304
|
+
volatile VALUE key = Qnil;
|
|
1263
1305
|
|
|
1306
|
+
if (NULL == doc->where || NULL == *doc->where) {
|
|
1307
|
+
return Qnil;
|
|
1308
|
+
}
|
|
1309
|
+
leaf = *doc->where;
|
|
1264
1310
|
if (T_HASH == leaf->parent_type) {
|
|
1265
1311
|
key = rb_utf8_str_new_cstr(leaf->key);
|
|
1266
1312
|
} else if (T_ARRAY == leaf->parent_type) {
|
|
@@ -1415,6 +1461,9 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
|
1415
1461
|
return Qnil;
|
|
1416
1462
|
}
|
|
1417
1463
|
}
|
|
1464
|
+
if (NULL == doc->where || NULL == *doc->where) {
|
|
1465
|
+
return Qnil;
|
|
1466
|
+
}
|
|
1418
1467
|
each_leaf(doc, self);
|
|
1419
1468
|
if (0 < wlen) {
|
|
1420
1469
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
@@ -1498,12 +1547,19 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1498
1547
|
Leaf first = (*doc->where)->elements->next;
|
|
1499
1548
|
Leaf e = first;
|
|
1500
1549
|
|
|
1550
|
+
if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
|
|
1551
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
1552
|
+
}
|
|
1501
1553
|
doc->where++;
|
|
1502
1554
|
do {
|
|
1503
1555
|
*doc->where = e;
|
|
1504
1556
|
rb_yield(self);
|
|
1557
|
+
if (NULL == DATA_PTR(self)) {
|
|
1558
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1559
|
+
}
|
|
1505
1560
|
e = e->next;
|
|
1506
1561
|
} while (e != first);
|
|
1562
|
+
doc->where--;
|
|
1507
1563
|
}
|
|
1508
1564
|
if (0 < wlen) {
|
|
1509
1565
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
@@ -1547,7 +1603,7 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
|
1547
1603
|
path = StringValuePtr(*argv);
|
|
1548
1604
|
}
|
|
1549
1605
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
|
1550
|
-
each_value(doc, leaf);
|
|
1606
|
+
each_value(doc, leaf, self);
|
|
1551
1607
|
}
|
|
1552
1608
|
}
|
|
1553
1609
|
return Qnil;
|
data/ext/oj/intern.c
CHANGED
|
@@ -69,7 +69,7 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
|
69
69
|
memcpy(b + 1, str, len);
|
|
70
70
|
b[len + 1] = '\0';
|
|
71
71
|
}
|
|
72
|
-
id = rb_intern3(
|
|
72
|
+
id = rb_intern3(b, len + 1, oj_utf8_encoding);
|
|
73
73
|
OJ_R_FREE(b);
|
|
74
74
|
return id;
|
|
75
75
|
}
|
|
@@ -97,6 +97,8 @@ static const rb_data_type_t oj_cache_type = {
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
void oj_hash_init(void) {
|
|
100
|
+
oj_hash_seed_init();
|
|
101
|
+
|
|
100
102
|
VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
|
|
101
103
|
rb_undef_alloc_func(cache_class);
|
|
102
104
|
|
|
@@ -151,7 +153,7 @@ ID oj_attr_intern(const char *key, size_t len) {
|
|
|
151
153
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
|
152
154
|
const uint8_t *end = key + len;
|
|
153
155
|
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
|
154
|
-
uint64_t h = (uint64_t)len;
|
|
156
|
+
uint64_t h = (uint64_t)len ^ oj_hash_seed;
|
|
155
157
|
uint64_t k;
|
|
156
158
|
|
|
157
159
|
while (key < endless) {
|
|
@@ -188,6 +190,9 @@ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define
|
|
|
188
190
|
|
|
189
191
|
if (rb_const_defined_at(mod, ci)) {
|
|
190
192
|
clas = rb_const_get_at(mod, ci);
|
|
193
|
+
if (!RB_TYPE_P(clas, T_CLASS) && !RB_TYPE_P(clas, T_MODULE)) {
|
|
194
|
+
clas = Qundef;
|
|
195
|
+
}
|
|
191
196
|
} else if (auto_define) {
|
|
192
197
|
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
|
193
198
|
} else {
|
data/ext/oj/object.c
CHANGED
|
@@ -31,7 +31,7 @@ inline static long read_long(const char *str, size_t len) {
|
|
|
31
31
|
static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
32
32
|
volatile VALUE rkey;
|
|
33
33
|
|
|
34
|
-
if (':' == k1) {
|
|
34
|
+
if (':' == k1 && 0 < kval->klen) {
|
|
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) {
|
|
@@ -54,7 +54,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
|
54
54
|
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
|
55
55
|
long i = read_long(str + 2, len - 2);
|
|
56
56
|
|
|
57
|
-
if (0
|
|
57
|
+
if (0 >= i) {
|
|
58
58
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
|
|
59
59
|
return Qnil;
|
|
60
60
|
}
|
|
@@ -207,7 +207,7 @@ oj_parse_xml_time(const char *str, int len) {
|
|
|
207
207
|
|
|
208
208
|
static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
|
|
209
209
|
const char *key = kval->key;
|
|
210
|
-
|
|
210
|
+
size_t klen = kval->klen;
|
|
211
211
|
|
|
212
212
|
if (2 == klen) {
|
|
213
213
|
switch (key[1]) {
|
|
@@ -230,7 +230,12 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
|
230
230
|
parent->odd_args = oj_odd_alloc_args(odd);
|
|
231
231
|
break;
|
|
232
232
|
}
|
|
233
|
-
case 'm':
|
|
233
|
+
case 'm':
|
|
234
|
+
if (0 == len) {
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
|
238
|
+
break;
|
|
234
239
|
case 's': parent->val = rb_utf8_str_new(str, len); break;
|
|
235
240
|
case 'c': // class
|
|
236
241
|
{
|
|
@@ -319,20 +324,26 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
|
319
324
|
e1 = *RARRAY_CONST_PTR(value);
|
|
320
325
|
// check for anonymous Struct
|
|
321
326
|
if (T_ARRAY == rb_type(e1)) {
|
|
322
|
-
|
|
323
|
-
|
|
327
|
+
// Build the member-name list in a GC-managed Ruby array. Using a
|
|
328
|
+
// fixed C buffer (VALUE args[1024]) here overflowed the stack when
|
|
329
|
+
// the JSON supplied more than 1024 member names.
|
|
330
|
+
volatile VALUE names = rb_ary_new2(RARRAY_LEN(e1));
|
|
324
331
|
size_t i;
|
|
325
332
|
size_t cnt = RARRAY_LEN(e1);
|
|
326
333
|
|
|
327
334
|
for (i = 0; i < cnt; i++) {
|
|
328
|
-
|
|
329
|
-
args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
|
|
335
|
+
rb_ary_push(names, rb_funcall(RARRAY_AREF(e1, i), oj_to_sym_id, 0));
|
|
330
336
|
}
|
|
331
|
-
sc =
|
|
337
|
+
sc = rb_apply(rb_cStruct, oj_new_id, names);
|
|
332
338
|
} else {
|
|
333
339
|
// If struct is not defined then we let this fail and raise an exception.
|
|
334
340
|
sc = oj_name2struct(pi, *RARRAY_CONST_PTR(value), rb_eArgError);
|
|
335
341
|
}
|
|
342
|
+
if (Qundef == sc || Qnil == sc) {
|
|
343
|
+
// oj_name2struct already recorded the error; do not pass an
|
|
344
|
+
// unresolved (Qundef) class on to rb_obj_alloc/rb_class_new_instance.
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
336
347
|
if (sc == rb_cRange) {
|
|
337
348
|
parent->val = rb_class_new_instance((int)(len - 1), RARRAY_CONST_PTR(value) + 1, rb_cRange);
|
|
338
349
|
} else {
|
|
@@ -389,7 +400,7 @@ void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
|
|
389
400
|
|
|
390
401
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
391
402
|
const char *key = kval->key;
|
|
392
|
-
|
|
403
|
+
size_t klen = kval->klen;
|
|
393
404
|
Val parent = stack_peek(&pi->stack);
|
|
394
405
|
volatile VALUE rval = Qnil;
|
|
395
406
|
|
|
@@ -431,7 +442,7 @@ WHICH_TYPE:
|
|
|
431
442
|
if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
|
|
432
443
|
char buf[256];
|
|
433
444
|
|
|
434
|
-
if (
|
|
445
|
+
if (sizeof(buf) - 1 <= klen) {
|
|
435
446
|
klen = sizeof(buf) - 2;
|
|
436
447
|
}
|
|
437
448
|
memcpy(buf, key, klen);
|
|
@@ -460,7 +471,7 @@ WHICH_TYPE:
|
|
|
460
471
|
|
|
461
472
|
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
|
462
473
|
const char *key = kval->key;
|
|
463
|
-
|
|
474
|
+
size_t klen = kval->klen;
|
|
464
475
|
Val parent = stack_peek(&pi->stack);
|
|
465
476
|
volatile VALUE rval = Qnil;
|
|
466
477
|
|
|
@@ -500,7 +511,7 @@ WHICH_TYPE:
|
|
|
500
511
|
if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
|
|
501
512
|
char buf[256];
|
|
502
513
|
|
|
503
|
-
if (
|
|
514
|
+
if (sizeof(buf) - 1 <= klen) {
|
|
504
515
|
klen = sizeof(buf) - 2;
|
|
505
516
|
}
|
|
506
517
|
memcpy(buf, key, klen);
|
|
@@ -529,7 +540,7 @@ WHICH_TYPE:
|
|
|
529
540
|
|
|
530
541
|
static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
|
531
542
|
const char *key = kval->key;
|
|
532
|
-
|
|
543
|
+
size_t klen = kval->klen;
|
|
533
544
|
Val parent = stack_peek(&pi->stack);
|
|
534
545
|
|
|
535
546
|
WHICH_TYPE:
|
|
@@ -585,7 +596,7 @@ WHICH_TYPE:
|
|
|
585
596
|
} else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
|
|
586
597
|
char buf[256];
|
|
587
598
|
|
|
588
|
-
if (
|
|
599
|
+
if (sizeof(buf) - 1 <= klen) {
|
|
589
600
|
klen = sizeof(buf) - 2;
|
|
590
601
|
}
|
|
591
602
|
memcpy(buf, key, klen);
|
data/ext/oj/odd.c
CHANGED
|
@@ -166,7 +166,11 @@ Odd oj_get_oddc(const char *classname, size_t len) {
|
|
|
166
166
|
if (len == odd->clen && 0 == strncmp(classname, odd->classname, len)) {
|
|
167
167
|
return odd;
|
|
168
168
|
}
|
|
169
|
-
|
|
169
|
+
// The module test needs a "::" after the module name, so the name has
|
|
170
|
+
// to be shorter than what it is compared against. Without that the
|
|
171
|
+
// comparison and the character after it both run past len.
|
|
172
|
+
if (odd->is_module && odd->clen < len && 0 == strncmp(odd->classname, classname, odd->clen) &&
|
|
173
|
+
':' == classname[odd->clen]) {
|
|
170
174
|
return odd;
|
|
171
175
|
}
|
|
172
176
|
}
|
|
@@ -195,7 +199,7 @@ int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
|
|
|
195
199
|
int i;
|
|
196
200
|
|
|
197
201
|
for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i; i--, np++, vp++) {
|
|
198
|
-
if (
|
|
202
|
+
if (klen == strlen(*np) && 0 == memcmp(key, *np, klen)) {
|
|
199
203
|
*vp = value;
|
|
200
204
|
return 0;
|
|
201
205
|
}
|