oj 3.16.3 → 3.17.4
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 +99 -0
- data/README.md +0 -16
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +17 -11
- data/ext/oj/dump.c +619 -88
- data/ext/oj/dump.h +9 -2
- data/ext/oj/dump_compat.c +16 -9
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +52 -27
- data/ext/oj/dump_strict.c +20 -14
- data/ext/oj/extconf.rb +11 -9
- data/ext/oj/fast.c +90 -65
- data/ext/oj/intern.c +1 -1
- data/ext/oj/mimic_json.c +14 -8
- data/ext/oj/object.c +18 -12
- data/ext/oj/oj.c +426 -11
- data/ext/oj/oj.h +60 -52
- data/ext/oj/parse.c +252 -48
- data/ext/oj/parse.h +0 -1
- data/ext/oj/parser.c +179 -47
- data/ext/oj/parser.h +4 -2
- data/ext/oj/rails.c +57 -36
- data/ext/oj/reader.c +17 -5
- data/ext/oj/rxclass.c +17 -1
- data/ext/oj/rxclass.h +2 -1
- data/ext/oj/safe.c +230 -0
- data/ext/oj/safe.h +79 -0
- data/ext/oj/saj.c +55 -20
- data/ext/oj/scp.c +3 -6
- data/ext/oj/simd.h +219 -0
- data/ext/oj/sparse.c +15 -3
- data/ext/oj/stream_writer.c +19 -14
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +26 -14
- data/ext/oj/usual.c +37 -35
- data/ext/oj/wab.c +5 -4
- data/lib/oj/mimic.rb +1 -5
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +1 -1
- metadata +22 -100
- data/test/_test_active.rb +0 -75
- data/test/_test_active_mimic.rb +0 -95
- data/test/_test_mimic_rails.rb +0 -123
- data/test/activerecord/result_test.rb +0 -31
- data/test/activesupport6/abstract_unit.rb +0 -44
- data/test/activesupport6/decoding_test.rb +0 -133
- data/test/activesupport6/encoding_test.rb +0 -507
- data/test/activesupport6/encoding_test_cases.rb +0 -98
- data/test/activesupport6/test_common.rb +0 -17
- data/test/activesupport6/test_helper.rb +0 -163
- data/test/activesupport6/time_zone_test_helpers.rb +0 -39
- data/test/activesupport7/abstract_unit.rb +0 -49
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -486
- data/test/activesupport7/encoding_test_cases.rb +0 -104
- data/test/activesupport7/time_zone_test_helpers.rb +0 -47
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -14
- data/test/helper.rb +0 -39
- data/test/isolated/shared.rb +0 -309
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -155
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -21
- data/test/json_gem/json_fixtures_test.rb +0 -36
- data/test/json_gem/json_generator_test.rb +0 -413
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -477
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -30
- data/test/mem.rb +0 -34
- data/test/perf.rb +0 -102
- data/test/perf_compat.rb +0 -128
- data/test/perf_dump.rb +0 -50
- data/test/perf_fast.rb +0 -162
- data/test/perf_file.rb +0 -62
- data/test/perf_object.rb +0 -134
- data/test/perf_once.rb +0 -59
- data/test/perf_parser.rb +0 -183
- data/test/perf_saj.rb +0 -101
- data/test/perf_scp.rb +0 -140
- data/test/perf_simple.rb +0 -289
- data/test/perf_strict.rb +0 -137
- data/test/perf_wab.rb +0 -129
- data/test/prec.rb +0 -23
- data/test/sample/change.rb +0 -13
- data/test/sample/dir.rb +0 -18
- data/test/sample/doc.rb +0 -35
- data/test/sample/file.rb +0 -47
- data/test/sample/group.rb +0 -15
- data/test/sample/hasprops.rb +0 -15
- data/test/sample/layer.rb +0 -11
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -9
- data/test/sample/shape.rb +0 -34
- data/test/sample/text.rb +0 -19
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -567
- data/test/test_custom.rb +0 -555
- data/test/test_debian.rb +0 -50
- data/test/test_fast.rb +0 -526
- data/test/test_file.rb +0 -250
- data/test/test_gc.rb +0 -60
- data/test/test_generate.rb +0 -21
- data/test/test_hash.rb +0 -39
- data/test/test_integer_range.rb +0 -72
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1030
- data/test/test_parser.rb +0 -11
- data/test/test_parser_debug.rb +0 -27
- data/test/test_parser_saj.rb +0 -337
- data/test/test_parser_usual.rb +0 -227
- data/test/test_rails.rb +0 -35
- data/test/test_saj.rb +0 -188
- data/test/test_scp.rb +0 -431
- data/test/test_strict.rb +0 -441
- data/test/test_various.rb +0 -801
- data/test/test_wab.rb +0 -311
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -33
- data/test/tests_mimic.rb +0 -23
- data/test/tests_mimic_addition.rb +0 -16
data/ext/oj/fast.c
CHANGED
|
@@ -40,7 +40,7 @@ typedef struct _doc {
|
|
|
40
40
|
Leaf *where; // points to current location
|
|
41
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
|
42
42
|
char *json;
|
|
43
|
-
unsigned long size;
|
|
43
|
+
unsigned long size; // number of leaves/branches in the doc
|
|
44
44
|
VALUE self;
|
|
45
45
|
Batch batches;
|
|
46
46
|
struct _batch batch0;
|
|
@@ -80,21 +80,10 @@ 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
|
|
|
87
|
-
// This is only for CentOS 5.4 with Ruby 1.9.3-p0.
|
|
88
|
-
#ifndef HAVE_STPCPY
|
|
89
|
-
char *stpcpy(char *dest, const char *src) {
|
|
90
|
-
size_t cnt = strlen(src);
|
|
91
|
-
|
|
92
|
-
strcpy(dest, src);
|
|
93
|
-
|
|
94
|
-
return dest + cnt;
|
|
95
|
-
}
|
|
96
|
-
#endif
|
|
97
|
-
|
|
98
87
|
inline static void next_non_white(ParseInfo pi) {
|
|
99
88
|
for (; 1; pi->s++) {
|
|
100
89
|
switch (*pi->s) {
|
|
@@ -103,7 +92,14 @@ inline static void next_non_white(ParseInfo pi) {
|
|
|
103
92
|
case '\f':
|
|
104
93
|
case '\n':
|
|
105
94
|
case '\r': break;
|
|
106
|
-
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;
|
|
107
103
|
default: return;
|
|
108
104
|
}
|
|
109
105
|
}
|
|
@@ -193,8 +189,7 @@ static VALUE leaf_value(Doc doc, Leaf leaf) {
|
|
|
193
189
|
case T_FIXNUM: leaf_fixnum_value(leaf); break;
|
|
194
190
|
case T_FLOAT: leaf_float_value(leaf); break;
|
|
195
191
|
case T_STRING:
|
|
196
|
-
leaf->value =
|
|
197
|
-
leaf->value = oj_encode(leaf->value);
|
|
192
|
+
leaf->value = rb_utf8_str_new_cstr(leaf->str);
|
|
198
193
|
leaf->value_type = RUBY_VAL;
|
|
199
194
|
break;
|
|
200
195
|
case T_ARRAY: return leaf_array_value(doc, leaf); break;
|
|
@@ -222,10 +217,11 @@ static void skip_comment(ParseInfo pi) {
|
|
|
222
217
|
if ('*' == *pi->s && '/' == *(pi->s + 1)) {
|
|
223
218
|
pi->s++;
|
|
224
219
|
return;
|
|
225
|
-
} else if ('\0' == *pi->s) {
|
|
226
|
-
raise_error("comment not terminated", pi->str, pi->s);
|
|
227
220
|
}
|
|
228
221
|
}
|
|
222
|
+
// The loop only ends on the null terminator so the comment was never
|
|
223
|
+
// closed.
|
|
224
|
+
raise_error("comment not terminated", pi->str, pi->s);
|
|
229
225
|
} else if ('/' == *pi->s) {
|
|
230
226
|
for (; 1; pi->s++) {
|
|
231
227
|
switch (*pi->s) {
|
|
@@ -247,6 +243,19 @@ static void skip_comment(ParseInfo pi) {
|
|
|
247
243
|
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
248
244
|
#endif
|
|
249
245
|
|
|
246
|
+
static void validate_integer_size(size_t limit, char *head, char *tail) {
|
|
247
|
+
size_t total = (size_t)(tail - head);
|
|
248
|
+
bool has_sign = (head[0] == '-' || head[0] == '+');
|
|
249
|
+
size_t digit_count = total - (has_sign ? 1 : 0);
|
|
250
|
+
|
|
251
|
+
if (digit_count > limit) {
|
|
252
|
+
rb_raise(oj_parse_error_class,
|
|
253
|
+
"integer exceeds :max_integer_digits (%lu > %lu)",
|
|
254
|
+
(unsigned long)digit_count,
|
|
255
|
+
(unsigned long)limit);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
250
259
|
static void leaf_fixnum_value(Leaf leaf) {
|
|
251
260
|
char *s = leaf->str;
|
|
252
261
|
int64_t n = 0;
|
|
@@ -266,7 +275,12 @@ static void leaf_fixnum_value(Leaf leaf) {
|
|
|
266
275
|
}
|
|
267
276
|
}
|
|
268
277
|
if (big) {
|
|
269
|
-
|
|
278
|
+
size_t limit = oj_default_options.max_integer_digits;
|
|
279
|
+
char c = *s;
|
|
280
|
+
|
|
281
|
+
if (0 < limit) {
|
|
282
|
+
validate_integer_size(limit, leaf->str, s);
|
|
283
|
+
}
|
|
270
284
|
|
|
271
285
|
*s = '\0';
|
|
272
286
|
leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
|
|
@@ -309,8 +323,7 @@ static VALUE leaf_hash_value(Doc doc, Leaf leaf) {
|
|
|
309
323
|
volatile VALUE key;
|
|
310
324
|
|
|
311
325
|
do {
|
|
312
|
-
key =
|
|
313
|
-
key = oj_encode(key);
|
|
326
|
+
key = rb_utf8_str_new_cstr(e->key);
|
|
314
327
|
rb_hash_aset(h, key, leaf_value(doc, e));
|
|
315
328
|
e = e->next;
|
|
316
329
|
} while (e != first);
|
|
@@ -573,7 +586,7 @@ static char *read_quoted_value(ParseInfo pi) {
|
|
|
573
586
|
char *h = pi->s; // head
|
|
574
587
|
char *t = h; // tail
|
|
575
588
|
|
|
576
|
-
h++;
|
|
589
|
+
h++; // skip quote character
|
|
577
590
|
t++;
|
|
578
591
|
value = h;
|
|
579
592
|
for (; '"' != *h; h++, t++) {
|
|
@@ -705,21 +718,23 @@ static void mark_doc(void *ptr) {
|
|
|
705
718
|
}
|
|
706
719
|
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
|
707
720
|
static void compact_leaf(Leaf leaf) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
721
|
+
if (NULL != leaf) {
|
|
722
|
+
switch (leaf->value_type) {
|
|
723
|
+
case COL_VAL:
|
|
724
|
+
if (NULL != leaf->elements) {
|
|
725
|
+
Leaf first = leaf->elements->next;
|
|
726
|
+
Leaf e = first;
|
|
713
727
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
728
|
+
do {
|
|
729
|
+
compact_leaf(e);
|
|
730
|
+
e = e->next;
|
|
731
|
+
} while (e != first);
|
|
732
|
+
}
|
|
733
|
+
break;
|
|
734
|
+
case RUBY_VAL: leaf->value = rb_gc_location(leaf->value); break;
|
|
721
735
|
|
|
722
|
-
|
|
736
|
+
default: break;
|
|
737
|
+
}
|
|
723
738
|
}
|
|
724
739
|
}
|
|
725
740
|
|
|
@@ -765,7 +780,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
|
765
780
|
pi.s = pi.str;
|
|
766
781
|
doc_init(doc);
|
|
767
782
|
pi.doc = doc;
|
|
768
|
-
#if IS_WINDOWS
|
|
783
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
|
769
784
|
// assume a 1M stack and give half to ruby
|
|
770
785
|
pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
|
|
771
786
|
#else
|
|
@@ -785,14 +800,11 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
|
785
800
|
doc->self = self;
|
|
786
801
|
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
|
787
802
|
if (given || 0 != ex) {
|
|
803
|
+
// The doc is detached from its wrapper so the GC will not free it.
|
|
804
|
+
// doc_free() releases both the doc and its json buffer (doc->json), so
|
|
805
|
+
// the caller must not free json separately.
|
|
788
806
|
DATA_PTR(doc->self) = NULL;
|
|
789
|
-
// TBD is this needed?
|
|
790
|
-
/*
|
|
791
807
|
doc_free(pi.doc);
|
|
792
|
-
if (0 != ex) { // will jump so caller will not free
|
|
793
|
-
OJ_R_FREE(json);
|
|
794
|
-
}
|
|
795
|
-
*/
|
|
796
808
|
} else {
|
|
797
809
|
result = doc->self;
|
|
798
810
|
}
|
|
@@ -941,6 +953,7 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
|
941
953
|
|
|
942
954
|
doc->where++;
|
|
943
955
|
if (MAX_STACK <= doc->where - doc->where_path) {
|
|
956
|
+
doc->where--;
|
|
944
957
|
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
945
958
|
}
|
|
946
959
|
do {
|
|
@@ -952,6 +965,9 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
|
952
965
|
}
|
|
953
966
|
} else {
|
|
954
967
|
rb_yield(self);
|
|
968
|
+
if (NULL == DATA_PTR(self)) {
|
|
969
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
970
|
+
}
|
|
955
971
|
}
|
|
956
972
|
}
|
|
957
973
|
|
|
@@ -964,8 +980,9 @@ static int move_step(Doc doc, const char *path, int loc) {
|
|
|
964
980
|
} else {
|
|
965
981
|
Leaf leaf;
|
|
966
982
|
|
|
983
|
+
// A document with no root (empty or comment only JSON) has no leaf to
|
|
984
|
+
// step from so the path can not be located.
|
|
967
985
|
if (0 == doc->where || 0 == (leaf = *doc->where)) {
|
|
968
|
-
printf("*** Internal error at %s\n", path);
|
|
969
986
|
return loc;
|
|
970
987
|
}
|
|
971
988
|
if ('.' == *path && '.' == *(path + 1)) {
|
|
@@ -1045,19 +1062,22 @@ static int move_step(Doc doc, const char *path, int loc) {
|
|
|
1045
1062
|
return loc;
|
|
1046
1063
|
}
|
|
1047
1064
|
|
|
1048
|
-
static void each_value(Doc doc, Leaf leaf) {
|
|
1065
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self) {
|
|
1049
1066
|
if (COL_VAL == leaf->value_type) {
|
|
1050
1067
|
if (0 != leaf->elements) {
|
|
1051
1068
|
Leaf first = leaf->elements->next;
|
|
1052
1069
|
Leaf e = first;
|
|
1053
1070
|
|
|
1054
1071
|
do {
|
|
1055
|
-
each_value(doc, e);
|
|
1072
|
+
each_value(doc, e, self);
|
|
1056
1073
|
e = e->next;
|
|
1057
1074
|
} while (e != first);
|
|
1058
1075
|
}
|
|
1059
1076
|
} else {
|
|
1060
1077
|
rb_yield(leaf_value(doc, leaf));
|
|
1078
|
+
if (NULL == DATA_PTR(self)) {
|
|
1079
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1080
|
+
}
|
|
1061
1081
|
}
|
|
1062
1082
|
}
|
|
1063
1083
|
|
|
@@ -1088,17 +1108,12 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
|
1088
1108
|
int given = rb_block_given_p();
|
|
1089
1109
|
|
|
1090
1110
|
Check_Type(str, T_STRING);
|
|
1091
|
-
len =
|
|
1111
|
+
len = RSTRING_LEN(str) + 1;
|
|
1092
1112
|
json = OJ_R_ALLOC_N(char, len);
|
|
1093
1113
|
|
|
1094
1114
|
memcpy(json, StringValuePtr(str), len);
|
|
1095
1115
|
obj = parse_json(clas, json, given);
|
|
1096
|
-
//
|
|
1097
|
-
/*
|
|
1098
|
-
if (given) {
|
|
1099
|
-
OJ_R_FREE(json);
|
|
1100
|
-
}
|
|
1101
|
-
*/
|
|
1116
|
+
// json is owned by the doc and freed by doc_free(); do not free it here.
|
|
1102
1117
|
return obj;
|
|
1103
1118
|
}
|
|
1104
1119
|
|
|
@@ -1130,7 +1145,9 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
|
1130
1145
|
int given = rb_block_given_p();
|
|
1131
1146
|
|
|
1132
1147
|
path = StringValuePtr(filename);
|
|
1133
|
-
|
|
1148
|
+
// Open in binary mode. On Windows a text mode read translates CRLF into LF
|
|
1149
|
+
// so fewer bytes are read than the file size reported by ftell().
|
|
1150
|
+
if (0 == (f = fopen(path, "rb"))) {
|
|
1134
1151
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
|
1135
1152
|
}
|
|
1136
1153
|
fseek(f, 0, SEEK_END);
|
|
@@ -1148,12 +1165,7 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
|
1148
1165
|
fclose(f);
|
|
1149
1166
|
json[len] = '\0';
|
|
1150
1167
|
obj = parse_json(clas, json, given);
|
|
1151
|
-
//
|
|
1152
|
-
/*
|
|
1153
|
-
if (given) {
|
|
1154
|
-
OJ_R_FREE(json);
|
|
1155
|
-
}
|
|
1156
|
-
*/
|
|
1168
|
+
// json is owned by the doc and freed by doc_free(); do not free it here.
|
|
1157
1169
|
return obj;
|
|
1158
1170
|
}
|
|
1159
1171
|
|
|
@@ -1252,13 +1264,16 @@ static VALUE doc_path(VALUE self) {
|
|
|
1252
1264
|
* #=> nil
|
|
1253
1265
|
*/
|
|
1254
1266
|
static VALUE doc_local_key(VALUE self) {
|
|
1255
|
-
Doc doc
|
|
1256
|
-
Leaf leaf
|
|
1257
|
-
volatile VALUE key
|
|
1267
|
+
Doc doc = self_doc(self);
|
|
1268
|
+
Leaf leaf;
|
|
1269
|
+
volatile VALUE key = Qnil;
|
|
1258
1270
|
|
|
1271
|
+
if (NULL == doc->where || NULL == *doc->where) {
|
|
1272
|
+
return Qnil;
|
|
1273
|
+
}
|
|
1274
|
+
leaf = *doc->where;
|
|
1259
1275
|
if (T_HASH == leaf->parent_type) {
|
|
1260
|
-
key =
|
|
1261
|
-
key = oj_encode(key);
|
|
1276
|
+
key = rb_utf8_str_new_cstr(leaf->key);
|
|
1262
1277
|
} else if (T_ARRAY == leaf->parent_type) {
|
|
1263
1278
|
key = LONG2NUM(leaf->index);
|
|
1264
1279
|
}
|
|
@@ -1411,6 +1426,9 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
|
1411
1426
|
return Qnil;
|
|
1412
1427
|
}
|
|
1413
1428
|
}
|
|
1429
|
+
if (NULL == doc->where || NULL == *doc->where) {
|
|
1430
|
+
return Qnil;
|
|
1431
|
+
}
|
|
1414
1432
|
each_leaf(doc, self);
|
|
1415
1433
|
if (0 < wlen) {
|
|
1416
1434
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
@@ -1494,12 +1512,19 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1494
1512
|
Leaf first = (*doc->where)->elements->next;
|
|
1495
1513
|
Leaf e = first;
|
|
1496
1514
|
|
|
1515
|
+
if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
|
|
1516
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
1517
|
+
}
|
|
1497
1518
|
doc->where++;
|
|
1498
1519
|
do {
|
|
1499
1520
|
*doc->where = e;
|
|
1500
1521
|
rb_yield(self);
|
|
1522
|
+
if (NULL == DATA_PTR(self)) {
|
|
1523
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1524
|
+
}
|
|
1501
1525
|
e = e->next;
|
|
1502
1526
|
} while (e != first);
|
|
1527
|
+
doc->where--;
|
|
1503
1528
|
}
|
|
1504
1529
|
if (0 < wlen) {
|
|
1505
1530
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
@@ -1543,7 +1568,7 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
|
1543
1568
|
path = StringValuePtr(*argv);
|
|
1544
1569
|
}
|
|
1545
1570
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
|
1546
|
-
each_value(doc, leaf);
|
|
1571
|
+
each_value(doc, leaf, self);
|
|
1547
1572
|
}
|
|
1548
1573
|
}
|
|
1549
1574
|
return Qnil;
|
data/ext/oj/intern.c
CHANGED
data/ext/oj/mimic_json.c
CHANGED
|
@@ -246,8 +246,7 @@ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
|
|
|
246
246
|
if (0 == out.buf) {
|
|
247
247
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
248
248
|
}
|
|
249
|
-
rstr =
|
|
250
|
-
rstr = oj_encode(rstr);
|
|
249
|
+
rstr = rb_utf8_str_new_cstr(out.buf);
|
|
251
250
|
if (2 <= argc && Qnil != argv[1] && rb_respond_to(argv[1], oj_write_id)) {
|
|
252
251
|
VALUE io = argv[1];
|
|
253
252
|
VALUE args[1];
|
|
@@ -396,8 +395,7 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
|
396
395
|
if (0 == out.buf) {
|
|
397
396
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
398
397
|
}
|
|
399
|
-
rstr =
|
|
400
|
-
rstr = oj_encode(rstr);
|
|
398
|
+
rstr = rb_utf8_str_new_cstr(out.buf);
|
|
401
399
|
|
|
402
400
|
oj_out_free(&out);
|
|
403
401
|
|
|
@@ -713,6 +711,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
|
|
|
713
711
|
0, // cache_str
|
|
714
712
|
0, // int_range_min
|
|
715
713
|
0, // int_range_max
|
|
714
|
+
0, // max_integer_digits
|
|
716
715
|
oj_json_class, // create_id
|
|
717
716
|
10, // create_id_len
|
|
718
717
|
3, // sec_prec
|
|
@@ -737,6 +736,8 @@ static struct _options mimic_object_to_json_options = {0, // indent
|
|
|
737
736
|
false, // omit_nil
|
|
738
737
|
false, // omit_null_byte
|
|
739
738
|
100, // max_depth
|
|
739
|
+
NULL, // only
|
|
740
|
+
NULL, // except
|
|
740
741
|
},
|
|
741
742
|
{
|
|
742
743
|
// str_rx
|
|
@@ -768,8 +769,7 @@ static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
|
|
|
768
769
|
if (NULL == out.buf) {
|
|
769
770
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
770
771
|
}
|
|
771
|
-
rstr =
|
|
772
|
-
rstr = oj_encode(rstr);
|
|
772
|
+
rstr = rb_utf8_str_new_cstr(out.buf);
|
|
773
773
|
|
|
774
774
|
oj_out_free(&out);
|
|
775
775
|
|
|
@@ -837,11 +837,15 @@ void oj_mimic_json_methods(VALUE json) {
|
|
|
837
837
|
} else {
|
|
838
838
|
json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
|
|
839
839
|
}
|
|
840
|
+
|
|
841
|
+
rb_global_variable(&oj_json_parser_error_class);
|
|
840
842
|
if (rb_const_defined_at(json, rb_intern("ParserError"))) {
|
|
841
843
|
oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
|
|
842
844
|
} else {
|
|
843
845
|
oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
|
|
844
846
|
}
|
|
847
|
+
|
|
848
|
+
rb_global_variable(&oj_json_generator_error_class);
|
|
845
849
|
if (rb_const_defined_at(json, rb_intern("GeneratorError"))) {
|
|
846
850
|
oj_json_generator_error_class = rb_const_get(json, rb_intern("GeneratorError"));
|
|
847
851
|
} else {
|
|
@@ -867,8 +871,8 @@ void oj_mimic_json_methods(VALUE json) {
|
|
|
867
871
|
rb_require("oj/state");
|
|
868
872
|
}
|
|
869
873
|
// Pull in the JSON::State mimic file.
|
|
874
|
+
rb_global_variable(&state_class);
|
|
870
875
|
state_class = rb_const_get_at(generator, rb_intern("State"));
|
|
871
|
-
rb_gc_register_mark_object(state_class);
|
|
872
876
|
}
|
|
873
877
|
|
|
874
878
|
/* Document-module: JSON
|
|
@@ -905,7 +909,9 @@ oj_define_mimic_json(int argc, VALUE *argv, VALUE self) {
|
|
|
905
909
|
}
|
|
906
910
|
oj_mimic_json_methods(json);
|
|
907
911
|
|
|
908
|
-
|
|
912
|
+
if (!rb_const_defined(rb_cObject, rb_intern("ActiveSupport"))) {
|
|
913
|
+
rb_define_method(rb_cObject, "to_json", mimic_object_to_json, -1);
|
|
914
|
+
}
|
|
909
915
|
|
|
910
916
|
rb_gv_set("$VERBOSE", verbose);
|
|
911
917
|
|
data/ext/oj/object.c
CHANGED
|
@@ -305,7 +305,7 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
|
305
305
|
|
|
306
306
|
static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
|
|
307
307
|
if (T_ARRAY == rb_type(value)) {
|
|
308
|
-
|
|
308
|
+
size_t len = RARRAY_LEN(value);
|
|
309
309
|
|
|
310
310
|
if (2 == klen && 'u' == key[1]) {
|
|
311
311
|
volatile VALUE sc;
|
|
@@ -319,21 +319,28 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
|
319
319
|
e1 = *RARRAY_CONST_PTR(value);
|
|
320
320
|
// check for anonymous Struct
|
|
321
321
|
if (T_ARRAY == rb_type(e1)) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
// Build the member-name list in a GC-managed Ruby array. Using a
|
|
323
|
+
// fixed C buffer (VALUE args[1024]) here overflowed the stack when
|
|
324
|
+
// the JSON supplied more than 1024 member names.
|
|
325
|
+
volatile VALUE names = rb_ary_new2(RARRAY_LEN(e1));
|
|
326
|
+
size_t i;
|
|
327
|
+
size_t cnt = RARRAY_LEN(e1);
|
|
325
328
|
|
|
326
329
|
for (i = 0; i < cnt; i++) {
|
|
327
|
-
|
|
328
|
-
args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
|
|
330
|
+
rb_ary_push(names, rb_funcall(RARRAY_AREF(e1, i), oj_to_sym_id, 0));
|
|
329
331
|
}
|
|
330
|
-
sc =
|
|
332
|
+
sc = rb_apply(rb_cStruct, oj_new_id, names);
|
|
331
333
|
} else {
|
|
332
334
|
// If struct is not defined then we let this fail and raise an exception.
|
|
333
335
|
sc = oj_name2struct(pi, *RARRAY_CONST_PTR(value), rb_eArgError);
|
|
334
336
|
}
|
|
337
|
+
if (Qundef == sc || Qnil == sc) {
|
|
338
|
+
// oj_name2struct already recorded the error; do not pass an
|
|
339
|
+
// unresolved (Qundef) class on to rb_obj_alloc/rb_class_new_instance.
|
|
340
|
+
return 1;
|
|
341
|
+
}
|
|
335
342
|
if (sc == rb_cRange) {
|
|
336
|
-
parent->val = rb_class_new_instance(len - 1, RARRAY_CONST_PTR(value) + 1, rb_cRange);
|
|
343
|
+
parent->val = rb_class_new_instance((int)(len - 1), RARRAY_CONST_PTR(value) + 1, rb_cRange);
|
|
337
344
|
} else {
|
|
338
345
|
// Create a properly initialized struct instance without calling the initialize method.
|
|
339
346
|
parent->val = rb_obj_alloc(sc);
|
|
@@ -348,10 +355,10 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
|
348
355
|
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
|
349
356
|
#endif
|
|
350
357
|
// MRI >= 1.9
|
|
351
|
-
if (len - 1 > slen) {
|
|
358
|
+
if (len - 1 > (size_t)slen) {
|
|
352
359
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
|
353
360
|
} else {
|
|
354
|
-
|
|
361
|
+
size_t i;
|
|
355
362
|
|
|
356
363
|
for (i = 0; i < len - 1; i++) {
|
|
357
364
|
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_CONST_PTR(value)[i + 1]);
|
|
@@ -698,9 +705,8 @@ oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
|
|
698
705
|
|
|
699
706
|
if (T_STRING == rb_type(*argv)) {
|
|
700
707
|
return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
|
|
701
|
-
} else {
|
|
702
|
-
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
703
708
|
}
|
|
709
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
704
710
|
}
|
|
705
711
|
|
|
706
712
|
VALUE
|