oj 3.16.0 → 3.17.3
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 +107 -0
- data/README.md +0 -16
- data/ext/oj/cache.c +4 -2
- data/ext/oj/cache.h +3 -2
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +17 -11
- data/ext/oj/dump.c +624 -90
- data/ext/oj/dump.h +9 -2
- data/ext/oj/dump_compat.c +15 -9
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +32 -17
- data/ext/oj/dump_strict.c +20 -14
- data/ext/oj/extconf.rb +11 -9
- data/ext/oj/fast.c +50 -32
- data/ext/oj/intern.c +24 -7
- data/ext/oj/mimic_json.c +17 -11
- data/ext/oj/object.c +21 -13
- data/ext/oj/oj.c +387 -140
- data/ext/oj/oj.h +59 -55
- data/ext/oj/parse.c +248 -47
- data/ext/oj/parser.c +179 -89
- data/ext/oj/parser.h +4 -2
- data/ext/oj/rails.c +64 -42
- data/ext/oj/reader.c +1 -1
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/safe.c +230 -0
- data/ext/oj/safe.h +79 -0
- data/ext/oj/saj.c +15 -10
- data/ext/oj/scp.c +3 -6
- data/ext/oj/simd.h +219 -0
- data/ext/oj/sparse.c +6 -3
- data/ext/oj/stream_writer.c +38 -28
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +54 -22
- data/ext/oj/usual.c +57 -35
- data/ext/oj/usual.h +1 -0
- data/ext/oj/val_stack.c +13 -2
- 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 +36 -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 -407
- 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 -554
- 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 -1016
- 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 -217
- 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 -431
- 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/rails.c
CHANGED
|
@@ -140,7 +140,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
140
140
|
volatile VALUE v;
|
|
141
141
|
int cnt;
|
|
142
142
|
int i;
|
|
143
|
-
|
|
143
|
+
size_t len;
|
|
144
144
|
const char *name;
|
|
145
145
|
|
|
146
146
|
#ifdef RSTRUCT_LEN
|
|
@@ -161,7 +161,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
161
161
|
volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
|
|
162
162
|
|
|
163
163
|
name = RSTRING_PTR(s);
|
|
164
|
-
len =
|
|
164
|
+
len = RSTRING_LEN(s);
|
|
165
165
|
assure_size(out, size + sep_len + 6);
|
|
166
166
|
if (0 < i) {
|
|
167
167
|
*out->cur++ = ',';
|
|
@@ -205,11 +205,11 @@ static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
205
205
|
if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
|
|
206
206
|
oj_dump_nil(Qnil, depth, out, false);
|
|
207
207
|
} else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
|
|
208
|
-
oj_dump_cstr(str,
|
|
208
|
+
oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
|
|
209
209
|
} else if (Yes == out->opts->bigdec_as_num) {
|
|
210
|
-
oj_dump_raw(str,
|
|
210
|
+
oj_dump_raw(str, RSTRING_LEN(rstr), out);
|
|
211
211
|
} else {
|
|
212
|
-
oj_dump_cstr(str,
|
|
212
|
+
oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
@@ -330,14 +330,14 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
330
330
|
static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
|
|
331
331
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
332
332
|
|
|
333
|
-
oj_dump_cstr(RSTRING_PTR(rstr),
|
|
333
|
+
oj_dump_cstr(RSTRING_PTR(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
static ID parameters_id = 0;
|
|
337
337
|
|
|
338
338
|
typedef struct _strLen {
|
|
339
339
|
const char *str;
|
|
340
|
-
|
|
340
|
+
size_t len;
|
|
341
341
|
} *StrLen;
|
|
342
342
|
|
|
343
343
|
static void dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
|
|
@@ -352,10 +352,10 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
|
|
|
352
352
|
volatile VALUE v;
|
|
353
353
|
StrLen cp;
|
|
354
354
|
StrLen cols;
|
|
355
|
-
|
|
356
|
-
|
|
355
|
+
size_t i;
|
|
356
|
+
size_t cnt = RARRAY_LEN(rcols);
|
|
357
357
|
|
|
358
|
-
*ccnt = cnt;
|
|
358
|
+
*ccnt = (int)cnt;
|
|
359
359
|
cols = OJ_R_ALLOC_N(struct _strLen, cnt);
|
|
360
360
|
for (i = 0, cp = cols; i < cnt; i++, cp++) {
|
|
361
361
|
v = RARRAY_AREF(rcols, i);
|
|
@@ -363,7 +363,7 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
|
|
|
363
363
|
v = oj_safe_string_convert(v);
|
|
364
364
|
}
|
|
365
365
|
cp->str = StringValuePtr(v);
|
|
366
|
-
cp->len =
|
|
366
|
+
cp->len = RSTRING_LEN(v);
|
|
367
367
|
}
|
|
368
368
|
return cols;
|
|
369
369
|
}
|
|
@@ -424,7 +424,8 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
|
|
|
424
424
|
volatile VALUE rows;
|
|
425
425
|
StrLen cols;
|
|
426
426
|
int ccnt = 0;
|
|
427
|
-
|
|
427
|
+
size_t i;
|
|
428
|
+
size_t rcnt;
|
|
428
429
|
size_t size;
|
|
429
430
|
int d2 = depth + 1;
|
|
430
431
|
|
|
@@ -435,7 +436,7 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
|
|
|
435
436
|
out->argc = 0;
|
|
436
437
|
cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt);
|
|
437
438
|
rows = rb_ivar_get(obj, rows_id);
|
|
438
|
-
rcnt =
|
|
439
|
+
rcnt = RARRAY_LEN(rows);
|
|
439
440
|
assure_size(out, 2);
|
|
440
441
|
*out->cur++ = '[';
|
|
441
442
|
if (out->opts->dump_opts.use) {
|
|
@@ -639,6 +640,17 @@ static void encoder_mark(void *ptr) {
|
|
|
639
640
|
}
|
|
640
641
|
}
|
|
641
642
|
|
|
643
|
+
static const rb_data_type_t oj_encoder_type = {
|
|
644
|
+
"Oj/encoder",
|
|
645
|
+
{
|
|
646
|
+
encoder_mark,
|
|
647
|
+
encoder_free,
|
|
648
|
+
NULL,
|
|
649
|
+
},
|
|
650
|
+
0,
|
|
651
|
+
0,
|
|
652
|
+
};
|
|
653
|
+
|
|
642
654
|
/* Document-method: new
|
|
643
655
|
* call-seq: new(options=nil)
|
|
644
656
|
*
|
|
@@ -649,14 +661,16 @@ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
|
|
|
649
661
|
Encoder e = OJ_R_ALLOC(struct _encoder);
|
|
650
662
|
|
|
651
663
|
e->opts = oj_default_options;
|
|
652
|
-
e->arg = Qnil;
|
|
653
664
|
copy_opts(&ropts, &e->ropts);
|
|
654
665
|
|
|
655
666
|
if (1 <= argc && Qnil != *argv) {
|
|
656
|
-
oj_parse_options(*argv, &e->opts);
|
|
657
667
|
e->arg = *argv;
|
|
668
|
+
} else {
|
|
669
|
+
e->arg = rb_hash_new();
|
|
658
670
|
}
|
|
659
|
-
|
|
671
|
+
oj_parse_options(e->arg, &e->opts);
|
|
672
|
+
|
|
673
|
+
return TypedData_Wrap_Struct(encoder_class, &oj_encoder_type, e);
|
|
660
674
|
}
|
|
661
675
|
|
|
662
676
|
static VALUE resolve_classpath(const char *name) {
|
|
@@ -748,7 +762,8 @@ static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
|
|
|
748
762
|
* - *classes* [_Class_] a list of classes to optimize
|
|
749
763
|
*/
|
|
750
764
|
static VALUE encoder_optimize(int argc, VALUE *argv, VALUE self) {
|
|
751
|
-
Encoder e
|
|
765
|
+
Encoder e;
|
|
766
|
+
TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
|
|
752
767
|
|
|
753
768
|
optimize(argc, argv, &e->ropts, true);
|
|
754
769
|
|
|
@@ -804,7 +819,8 @@ rails_mimic_json(VALUE self) {
|
|
|
804
819
|
* - *classes* [_Class_] a list of classes to deoptimize
|
|
805
820
|
*/
|
|
806
821
|
static VALUE encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
|
|
807
|
-
Encoder e
|
|
822
|
+
Encoder e;
|
|
823
|
+
TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
|
|
808
824
|
|
|
809
825
|
optimize(argc, argv, &e->ropts, false);
|
|
810
826
|
|
|
@@ -833,8 +849,11 @@ static VALUE rails_deoptimize(int argc, VALUE *argv, VALUE self) {
|
|
|
833
849
|
* @return true if the class is being optimized for rails and false otherwise
|
|
834
850
|
*/
|
|
835
851
|
static VALUE encoder_optimized(VALUE self, VALUE clas) {
|
|
836
|
-
Encoder e
|
|
837
|
-
ROpt ro
|
|
852
|
+
Encoder e;
|
|
853
|
+
ROpt ro;
|
|
854
|
+
|
|
855
|
+
TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
|
|
856
|
+
ro = oj_rails_get_opt(&e->ropts, clas);
|
|
838
857
|
|
|
839
858
|
if (NULL == ro) {
|
|
840
859
|
return Qfalse;
|
|
@@ -901,7 +920,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
|
|
|
901
920
|
if (Yes == copts.circular) {
|
|
902
921
|
oj_cache8_new(&out.circ_cache);
|
|
903
922
|
}
|
|
904
|
-
|
|
923
|
+
|
|
905
924
|
rb_protect(protect_dump, (VALUE)&oo, &line);
|
|
906
925
|
|
|
907
926
|
if (0 == line) {
|
|
@@ -917,8 +936,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
|
|
|
917
936
|
if (0 == out.buf) {
|
|
918
937
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
919
938
|
}
|
|
920
|
-
rstr =
|
|
921
|
-
rstr = oj_encode(rstr);
|
|
939
|
+
rstr = rb_utf8_str_new_cstr(out.buf);
|
|
922
940
|
}
|
|
923
941
|
if (Yes == copts.circular) {
|
|
924
942
|
oj_cache8_delete(out.circ_cache);
|
|
@@ -940,7 +958,8 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
|
|
|
940
958
|
* Returns encoded object as a JSON string.
|
|
941
959
|
*/
|
|
942
960
|
static VALUE encoder_encode(VALUE self, VALUE obj) {
|
|
943
|
-
Encoder e
|
|
961
|
+
Encoder e;
|
|
962
|
+
TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
|
|
944
963
|
|
|
945
964
|
if (Qnil != e->arg) {
|
|
946
965
|
VALUE argv[1] = {e->arg};
|
|
@@ -1084,6 +1103,8 @@ static VALUE rails_set_decoder(VALUE self) {
|
|
|
1084
1103
|
} else {
|
|
1085
1104
|
json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
|
|
1086
1105
|
}
|
|
1106
|
+
|
|
1107
|
+
rb_global_variable(&oj_json_parser_error_class);
|
|
1087
1108
|
if (rb_const_defined_at(json, rb_intern("ParserError"))) {
|
|
1088
1109
|
oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
|
|
1089
1110
|
} else {
|
|
@@ -1155,7 +1176,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1155
1176
|
char buf[64];
|
|
1156
1177
|
char *b;
|
|
1157
1178
|
double d = rb_num2dbl(obj);
|
|
1158
|
-
|
|
1179
|
+
size_t cnt = 0;
|
|
1159
1180
|
|
|
1160
1181
|
if (0.0 == d) {
|
|
1161
1182
|
b = buf;
|
|
@@ -1176,7 +1197,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1176
1197
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
1177
1198
|
|
|
1178
1199
|
strcpy(buf, RSTRING_PTR(rstr));
|
|
1179
|
-
cnt =
|
|
1200
|
+
cnt = RSTRING_LEN(rstr);
|
|
1180
1201
|
}
|
|
1181
1202
|
}
|
|
1182
1203
|
assure_size(out, cnt);
|
|
@@ -1188,7 +1209,8 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1188
1209
|
|
|
1189
1210
|
static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
1190
1211
|
size_t size;
|
|
1191
|
-
|
|
1212
|
+
size_t i;
|
|
1213
|
+
size_t cnt;
|
|
1192
1214
|
int d2 = depth + 1;
|
|
1193
1215
|
|
|
1194
1216
|
if (Yes == out->opts->circular) {
|
|
@@ -1197,12 +1219,11 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
|
1197
1219
|
return;
|
|
1198
1220
|
}
|
|
1199
1221
|
}
|
|
1200
|
-
|
|
1201
|
-
if (as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
|
|
1222
|
+
if (!oj_rails_array_opt && as_ok && rb_respond_to(a, oj_as_json_id)) {
|
|
1202
1223
|
dump_as_json(a, depth, out, false);
|
|
1203
1224
|
return;
|
|
1204
1225
|
}
|
|
1205
|
-
cnt =
|
|
1226
|
+
cnt = RARRAY_LEN(a);
|
|
1206
1227
|
*out->cur++ = '[';
|
|
1207
1228
|
size = 2;
|
|
1208
1229
|
assure_size(out, size);
|
|
@@ -1265,18 +1286,19 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
1265
1286
|
if (out->omit_nil && Qnil == value) {
|
|
1266
1287
|
return ST_CONTINUE;
|
|
1267
1288
|
}
|
|
1268
|
-
if (
|
|
1269
|
-
|
|
1270
|
-
|
|
1289
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
1290
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
1291
|
+
return ST_CONTINUE;
|
|
1292
|
+
}
|
|
1271
1293
|
}
|
|
1272
1294
|
if (!out->opts->dump_opts.use) {
|
|
1273
1295
|
size = depth * out->indent + 1;
|
|
1274
1296
|
assure_size(out, size);
|
|
1275
1297
|
fill_indent(out, depth);
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1298
|
+
switch (rtype) {
|
|
1299
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
1300
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
1301
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
1280
1302
|
}
|
|
1281
1303
|
*out->cur++ = ':';
|
|
1282
1304
|
} else {
|
|
@@ -1291,10 +1313,10 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
1291
1313
|
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
|
1292
1314
|
}
|
|
1293
1315
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1316
|
+
switch (rtype) {
|
|
1317
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
1318
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
1319
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
1298
1320
|
}
|
|
1299
1321
|
size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
1300
1322
|
assure_size(out, size);
|
|
@@ -1323,7 +1345,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1323
1345
|
return;
|
|
1324
1346
|
}
|
|
1325
1347
|
}
|
|
1326
|
-
if (
|
|
1348
|
+
if (!oj_rails_hash_opt && as_ok && rb_respond_to(obj, oj_as_json_id)) {
|
|
1327
1349
|
dump_as_json(obj, depth, out, false);
|
|
1328
1350
|
return;
|
|
1329
1351
|
}
|
data/ext/oj/reader.c
CHANGED
|
@@ -101,7 +101,7 @@ int oj_reader_read(Reader reader) {
|
|
|
101
101
|
} else {
|
|
102
102
|
shift = reader->pro - reader->head - 1; // leave one character so we can backup one
|
|
103
103
|
}
|
|
104
|
-
if (0 >= shift) {
|
|
104
|
+
if (0 >= shift) { /* no space left so allocate more */
|
|
105
105
|
const char *old = reader->head;
|
|
106
106
|
size_t size = reader->end - reader->head + BUF_PAD;
|
|
107
107
|
|
data/ext/oj/rxclass.c
CHANGED
data/ext/oj/rxclass.h
CHANGED
|
@@ -19,7 +19,7 @@ typedef struct _rxClass {
|
|
|
19
19
|
extern void oj_rxclass_init(RxClass rc);
|
|
20
20
|
extern void oj_rxclass_cleanup(RxClass rc);
|
|
21
21
|
extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
|
|
22
|
-
extern VALUE oj_rxclass_match(RxClass rc, const char *str,
|
|
22
|
+
extern VALUE oj_rxclass_match(RxClass rc, const char *str, size_t len);
|
|
23
23
|
extern void oj_rxclass_copy(RxClass src, RxClass dest);
|
|
24
24
|
extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
|
|
25
25
|
|
data/ext/oj/safe.c
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
|
|
2
|
+
#include "safe.h"
|
|
3
|
+
|
|
4
|
+
static VALUE max_hash_size_sym, max_array_size_sym, max_depth_sym, max_total_elements_sym, max_hash_size_error_class,
|
|
5
|
+
max_array_size_error_class, max_depth_error_class, max_total_elements_error_class;
|
|
6
|
+
|
|
7
|
+
static void check_object_size(safe_T safe) {
|
|
8
|
+
if (NIL_P(safe->max_hash_size)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
struct _usual usual = safe->usual;
|
|
13
|
+
Col current_object_location = usual.ctail - 1;
|
|
14
|
+
|
|
15
|
+
long int number_of_items_in_stack = usual.vtail - usual.vhead;
|
|
16
|
+
long int number_of_items_in_hash = (number_of_items_in_stack - current_object_location->vi - 1) / 2;
|
|
17
|
+
|
|
18
|
+
if (safe->max_hash_size > number_of_items_in_hash) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
rb_raise(max_hash_size_error_class, "Too many object items!");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static void check_array_size(safe_T safe) {
|
|
26
|
+
if (NIL_P(safe->max_array_size)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
struct _usual usual = safe->usual;
|
|
31
|
+
Col current_object_location = usual.ctail - 1;
|
|
32
|
+
|
|
33
|
+
long int number_of_items_in_stack = usual.vtail - usual.vhead;
|
|
34
|
+
long int number_of_items_in_array = number_of_items_in_stack - current_object_location->vi - 1;
|
|
35
|
+
|
|
36
|
+
if (safe->max_array_size > number_of_items_in_array) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
rb_raise(max_array_size_error_class, "Too many array items!");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static void check_max_depth(safe_T safe, ojParser p) {
|
|
44
|
+
if (NIL_P(safe->max_depth) || safe->max_depth >= (p->depth + 1)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
rb_raise(max_depth_error_class, "JSON is too deep!");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static void check_max_total_elements(safe_T safe) {
|
|
52
|
+
/*
|
|
53
|
+
* We check if `max_total_elements` is greater than `current_elements_count`
|
|
54
|
+
* (instead of greater than or equal) because top-level elements (e.g., [],
|
|
55
|
+
* null, true) are not counted. As a result, `current_elements_count`
|
|
56
|
+
* always holds one less than the actual total.
|
|
57
|
+
*/
|
|
58
|
+
if (NIL_P(safe->max_total_elements) || safe->max_total_elements > safe->current_elements_count) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
rb_raise(max_total_elements_error_class, "Too many elements!");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static void safe_start(ojParser p) {
|
|
66
|
+
safe_T safe = (safe_T)p->ctx;
|
|
67
|
+
|
|
68
|
+
safe->current_hash_size = 0;
|
|
69
|
+
safe->current_array_size = 0;
|
|
70
|
+
safe->current_elements_count = 0;
|
|
71
|
+
|
|
72
|
+
safe->delegated_start_func(p);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static void safe_open_object(ojParser p) {
|
|
76
|
+
safe_T safe = (safe_T)p->ctx;
|
|
77
|
+
|
|
78
|
+
safe->current_hash_size++;
|
|
79
|
+
safe->current_elements_count++;
|
|
80
|
+
|
|
81
|
+
check_array_size(safe);
|
|
82
|
+
check_max_depth(safe, p);
|
|
83
|
+
check_max_total_elements(safe);
|
|
84
|
+
|
|
85
|
+
safe->delegated_open_object_func(p);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static void safe_open_array(ojParser p) {
|
|
89
|
+
safe_T safe = (safe_T)p->ctx;
|
|
90
|
+
|
|
91
|
+
safe->current_array_size++;
|
|
92
|
+
safe->current_elements_count++;
|
|
93
|
+
|
|
94
|
+
check_array_size(safe);
|
|
95
|
+
check_max_depth(safe, p);
|
|
96
|
+
check_max_total_elements(safe);
|
|
97
|
+
|
|
98
|
+
safe->delegated_open_array_func(p);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
DEFINE_DELEGATED_FUNCTION(add_null);
|
|
102
|
+
DEFINE_DELEGATED_FUNCTION(add_true);
|
|
103
|
+
DEFINE_DELEGATED_FUNCTION(add_false);
|
|
104
|
+
DEFINE_DELEGATED_FUNCTION(add_int);
|
|
105
|
+
DEFINE_DELEGATED_FUNCTION(add_float);
|
|
106
|
+
DEFINE_DELEGATED_FUNCTION(add_big);
|
|
107
|
+
DEFINE_DELEGATED_FUNCTION(add_str);
|
|
108
|
+
|
|
109
|
+
static void safe_open_object_key(ojParser p) {
|
|
110
|
+
safe_T safe = (safe_T)p->ctx;
|
|
111
|
+
|
|
112
|
+
safe->current_hash_size++;
|
|
113
|
+
safe->current_elements_count += 2;
|
|
114
|
+
|
|
115
|
+
check_object_size(safe);
|
|
116
|
+
check_max_depth(safe, p);
|
|
117
|
+
check_max_total_elements(safe);
|
|
118
|
+
|
|
119
|
+
safe->delegated_open_object_key_func(p);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static void safe_open_array_key(ojParser p) {
|
|
123
|
+
safe_T safe = (safe_T)p->ctx;
|
|
124
|
+
|
|
125
|
+
safe->current_array_size++;
|
|
126
|
+
safe->current_elements_count += 2;
|
|
127
|
+
|
|
128
|
+
check_object_size(safe);
|
|
129
|
+
check_max_depth(safe, p);
|
|
130
|
+
check_max_total_elements(safe);
|
|
131
|
+
|
|
132
|
+
safe->delegated_open_array_key_func(p);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_null);
|
|
136
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_true);
|
|
137
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_false);
|
|
138
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_int);
|
|
139
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_float);
|
|
140
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_big);
|
|
141
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_str);
|
|
142
|
+
|
|
143
|
+
void oj_init_safe_parser(ojParser p, safe_T safe, VALUE options) {
|
|
144
|
+
// Safe parser inherits all members of usual parser
|
|
145
|
+
oj_init_usual(p, &safe->usual);
|
|
146
|
+
|
|
147
|
+
safe->delegated_start_func = p->start;
|
|
148
|
+
p->start = safe_start;
|
|
149
|
+
|
|
150
|
+
Funcs f;
|
|
151
|
+
|
|
152
|
+
// Array parser functions
|
|
153
|
+
f = &p->funcs[ARRAY_FUN];
|
|
154
|
+
safe->delegated_open_object_func = f->open_object;
|
|
155
|
+
f->open_object = safe_open_object;
|
|
156
|
+
safe->delegated_open_array_func = f->open_array;
|
|
157
|
+
f->open_array = safe_open_array;
|
|
158
|
+
// The following overrides are done for counting objects
|
|
159
|
+
safe->delegated_add_null_func = f->add_null;
|
|
160
|
+
f->add_null = safe_add_null;
|
|
161
|
+
safe->delegated_add_true_func = f->add_true;
|
|
162
|
+
f->add_true = safe_add_true;
|
|
163
|
+
safe->delegated_add_false_func = f->add_false;
|
|
164
|
+
f->add_false = safe_add_false;
|
|
165
|
+
safe->delegated_add_int_func = f->add_int;
|
|
166
|
+
f->add_int = safe_add_int;
|
|
167
|
+
safe->delegated_add_float_func = f->add_float;
|
|
168
|
+
f->add_float = safe_add_float;
|
|
169
|
+
safe->delegated_add_big_func = f->add_big;
|
|
170
|
+
f->add_big = safe_add_big;
|
|
171
|
+
safe->delegated_add_str_func = f->add_str;
|
|
172
|
+
f->add_str = safe_add_str;
|
|
173
|
+
|
|
174
|
+
// Object parser functions
|
|
175
|
+
f = &p->funcs[OBJECT_FUN];
|
|
176
|
+
safe->delegated_open_object_key_func = f->open_object;
|
|
177
|
+
f->open_object = safe_open_object_key;
|
|
178
|
+
safe->delegated_open_array_key_func = f->open_array;
|
|
179
|
+
f->open_array = safe_open_array_key;
|
|
180
|
+
// The following overrides are done for counting objects
|
|
181
|
+
safe->delegated_add_null_key_func = f->add_null;
|
|
182
|
+
f->add_null = safe_add_null_key;
|
|
183
|
+
safe->delegated_add_true_key_func = f->add_true;
|
|
184
|
+
f->add_true = safe_add_true_key;
|
|
185
|
+
safe->delegated_add_false_key_func = f->add_false;
|
|
186
|
+
f->add_false = safe_add_false_key;
|
|
187
|
+
safe->delegated_add_int_key_func = f->add_int;
|
|
188
|
+
f->add_int = safe_add_int_key;
|
|
189
|
+
safe->delegated_add_float_key_func = f->add_float;
|
|
190
|
+
f->add_float = safe_add_float_key;
|
|
191
|
+
safe->delegated_add_big_key_func = f->add_big;
|
|
192
|
+
f->add_big = safe_add_big_key;
|
|
193
|
+
safe->delegated_add_str_key_func = f->add_str;
|
|
194
|
+
f->add_str = safe_add_str_key;
|
|
195
|
+
|
|
196
|
+
SET_CONFIG(max_hash_size);
|
|
197
|
+
SET_CONFIG(max_array_size);
|
|
198
|
+
SET_CONFIG(max_depth);
|
|
199
|
+
SET_CONFIG(max_total_elements);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void oj_set_parser_safe(ojParser p, VALUE options) {
|
|
203
|
+
safe_T s = OJ_R_ALLOC(struct _safe_S);
|
|
204
|
+
|
|
205
|
+
oj_init_safe_parser(p, s, options);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
void oj_safe_init(VALUE parser_class) {
|
|
209
|
+
VALUE validation_error_class = rb_define_class_under(parser_class, "ValidationError", rb_eRuntimeError);
|
|
210
|
+
|
|
211
|
+
max_hash_size_error_class = rb_define_class_under(parser_class, "HashSizeError", validation_error_class);
|
|
212
|
+
max_array_size_error_class = rb_define_class_under(parser_class, "ArraySizeError", validation_error_class);
|
|
213
|
+
max_depth_error_class = rb_define_class_under(parser_class, "DepthError", validation_error_class);
|
|
214
|
+
max_total_elements_error_class = rb_define_class_under(parser_class, "TotalElementsError", validation_error_class);
|
|
215
|
+
|
|
216
|
+
rb_gc_register_address(&max_hash_size_error_class);
|
|
217
|
+
rb_gc_register_address(&max_array_size_error_class);
|
|
218
|
+
rb_gc_register_address(&max_depth_error_class);
|
|
219
|
+
rb_gc_register_address(&max_total_elements_error_class);
|
|
220
|
+
|
|
221
|
+
max_hash_size_sym = ID2SYM(rb_intern("max_hash_size"));
|
|
222
|
+
max_array_size_sym = ID2SYM(rb_intern("max_array_size"));
|
|
223
|
+
max_depth_sym = ID2SYM(rb_intern("max_depth"));
|
|
224
|
+
max_total_elements_sym = ID2SYM(rb_intern("max_total_elements"));
|
|
225
|
+
|
|
226
|
+
rb_gc_register_address(&max_hash_size_sym);
|
|
227
|
+
rb_gc_register_address(&max_array_size_sym);
|
|
228
|
+
rb_gc_register_address(&max_depth_sym);
|
|
229
|
+
rb_gc_register_address(&max_total_elements_sym);
|
|
230
|
+
}
|
data/ext/oj/safe.h
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
|
|
3
|
+
#include "parser.h"
|
|
4
|
+
#include "usual.h"
|
|
5
|
+
|
|
6
|
+
#define SET_CONFIG(config_name) \
|
|
7
|
+
do { \
|
|
8
|
+
VALUE rb_##config_name = rb_hash_aref(options, config_name##_sym); \
|
|
9
|
+
\
|
|
10
|
+
if (RB_INTEGER_TYPE_P(rb_##config_name)) { \
|
|
11
|
+
safe->config_name = NUM2LONG(rb_##config_name); \
|
|
12
|
+
} else if (!NIL_P(rb_##config_name)) { \
|
|
13
|
+
rb_raise(rb_eArgError, "Incorrect value provided for `" #config_name "`"); \
|
|
14
|
+
} else { \
|
|
15
|
+
safe->config_name = Qnil; \
|
|
16
|
+
} \
|
|
17
|
+
} while (0);
|
|
18
|
+
|
|
19
|
+
#define DEFINE_DELEGATED_FUNCTION(function_name) \
|
|
20
|
+
static void safe_##function_name(ojParser p) { \
|
|
21
|
+
safe_T safe = (safe_T)p->ctx; \
|
|
22
|
+
\
|
|
23
|
+
safe->current_elements_count++; \
|
|
24
|
+
\
|
|
25
|
+
check_array_size(safe); \
|
|
26
|
+
check_max_total_elements(safe); \
|
|
27
|
+
\
|
|
28
|
+
safe->delegated_##function_name##_func(p); \
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#define DEFINE_DELEGATED_OBJECT_FUNCTION(function_name) \
|
|
32
|
+
static void safe_##function_name##_key(ojParser p) { \
|
|
33
|
+
safe_T safe = (safe_T)p->ctx; \
|
|
34
|
+
\
|
|
35
|
+
safe->current_elements_count += 2; \
|
|
36
|
+
\
|
|
37
|
+
check_object_size(safe); \
|
|
38
|
+
check_max_total_elements(safe); \
|
|
39
|
+
\
|
|
40
|
+
safe->delegated_##function_name##_key_func(p); \
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
typedef struct _safe_S {
|
|
44
|
+
struct _usual usual;
|
|
45
|
+
|
|
46
|
+
long int max_hash_size;
|
|
47
|
+
long int max_array_size;
|
|
48
|
+
long int max_depth;
|
|
49
|
+
long int max_total_elements;
|
|
50
|
+
long int max_json_size_bytes;
|
|
51
|
+
|
|
52
|
+
long int current_hash_size;
|
|
53
|
+
long int current_array_size;
|
|
54
|
+
long int current_elements_count;
|
|
55
|
+
|
|
56
|
+
void (*delegated_start_func)(struct _ojParser *p);
|
|
57
|
+
|
|
58
|
+
// Array functions
|
|
59
|
+
void (*delegated_open_object_func)(struct _ojParser *p);
|
|
60
|
+
void (*delegated_open_array_func)(struct _ojParser *p);
|
|
61
|
+
void (*delegated_add_null_func)(struct _ojParser *p);
|
|
62
|
+
void (*delegated_add_true_func)(struct _ojParser *p);
|
|
63
|
+
void (*delegated_add_false_func)(struct _ojParser *p);
|
|
64
|
+
void (*delegated_add_int_func)(struct _ojParser *p);
|
|
65
|
+
void (*delegated_add_float_func)(struct _ojParser *p);
|
|
66
|
+
void (*delegated_add_big_func)(struct _ojParser *p);
|
|
67
|
+
void (*delegated_add_str_func)(struct _ojParser *p);
|
|
68
|
+
|
|
69
|
+
// Object functions
|
|
70
|
+
void (*delegated_open_object_key_func)(struct _ojParser *p);
|
|
71
|
+
void (*delegated_open_array_key_func)(struct _ojParser *p);
|
|
72
|
+
void (*delegated_add_null_key_func)(struct _ojParser *p);
|
|
73
|
+
void (*delegated_add_true_key_func)(struct _ojParser *p);
|
|
74
|
+
void (*delegated_add_false_key_func)(struct _ojParser *p);
|
|
75
|
+
void (*delegated_add_int_key_func)(struct _ojParser *p);
|
|
76
|
+
void (*delegated_add_float_key_func)(struct _ojParser *p);
|
|
77
|
+
void (*delegated_add_big_key_func)(struct _ojParser *p);
|
|
78
|
+
void (*delegated_add_str_key_func)(struct _ojParser *p);
|
|
79
|
+
} *safe_T;
|