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/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) {
|
|
@@ -622,6 +623,7 @@ static void encoder_free(void *ptr) {
|
|
|
622
623
|
if (NULL != ptr) {
|
|
623
624
|
Encoder e = (Encoder)ptr;
|
|
624
625
|
|
|
626
|
+
oj_options_release(&e->opts);
|
|
625
627
|
if (NULL != e->ropts.table) {
|
|
626
628
|
OJ_R_FREE(e->ropts.table);
|
|
627
629
|
}
|
|
@@ -632,10 +634,19 @@ static void encoder_free(void *ptr) {
|
|
|
632
634
|
static void encoder_mark(void *ptr) {
|
|
633
635
|
if (NULL != ptr) {
|
|
634
636
|
Encoder e = (Encoder)ptr;
|
|
637
|
+
int i;
|
|
635
638
|
|
|
639
|
+
oj_options_mark(&e->opts);
|
|
636
640
|
if (Qnil != e->arg) {
|
|
637
641
|
rb_gc_mark(e->arg);
|
|
638
642
|
}
|
|
643
|
+
// The optimized classes in the encoder table are not reachable from
|
|
644
|
+
// anywhere else once optimize() is called on the encoder itself.
|
|
645
|
+
for (i = 0; i < e->ropts.len; i++) {
|
|
646
|
+
if (Qnil != e->ropts.table[i].clas) {
|
|
647
|
+
rb_gc_mark(e->ropts.table[i].clas);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
639
650
|
}
|
|
640
651
|
}
|
|
641
652
|
|
|
@@ -660,13 +671,21 @@ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
|
|
|
660
671
|
Encoder e = OJ_R_ALLOC(struct _encoder);
|
|
661
672
|
|
|
662
673
|
e->opts = oj_default_options;
|
|
663
|
-
|
|
674
|
+
// Detach from the match_string regexps owned by the defaults before the
|
|
675
|
+
// options are parsed so that a :match_string option builds a chain of its
|
|
676
|
+
// own that is freed with the encoder.
|
|
677
|
+
e->opts.str_rx.head = NULL;
|
|
678
|
+
e->opts.str_rx.tail = NULL;
|
|
664
679
|
copy_opts(&ropts, &e->ropts);
|
|
665
680
|
|
|
666
681
|
if (1 <= argc && Qnil != *argv) {
|
|
667
|
-
oj_parse_options(*argv, &e->opts);
|
|
668
682
|
e->arg = *argv;
|
|
683
|
+
} else {
|
|
684
|
+
e->arg = rb_hash_new();
|
|
669
685
|
}
|
|
686
|
+
oj_parse_options(e->arg, &e->opts);
|
|
687
|
+
oj_options_take_ownership(&e->opts);
|
|
688
|
+
|
|
670
689
|
return TypedData_Wrap_Struct(encoder_class, &oj_encoder_type, e);
|
|
671
690
|
}
|
|
672
691
|
|
|
@@ -917,7 +936,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
|
|
|
917
936
|
if (Yes == copts.circular) {
|
|
918
937
|
oj_cache8_new(&out.circ_cache);
|
|
919
938
|
}
|
|
920
|
-
|
|
939
|
+
|
|
921
940
|
rb_protect(protect_dump, (VALUE)&oo, &line);
|
|
922
941
|
|
|
923
942
|
if (0 == line) {
|
|
@@ -933,8 +952,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
|
|
|
933
952
|
if (0 == out.buf) {
|
|
934
953
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
935
954
|
}
|
|
936
|
-
rstr =
|
|
937
|
-
rstr = oj_encode(rstr);
|
|
955
|
+
rstr = rb_utf8_str_new_cstr(out.buf);
|
|
938
956
|
}
|
|
939
957
|
if (Yes == copts.circular) {
|
|
940
958
|
oj_cache8_delete(out.circ_cache);
|
|
@@ -1101,6 +1119,8 @@ static VALUE rails_set_decoder(VALUE self) {
|
|
|
1101
1119
|
} else {
|
|
1102
1120
|
json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
|
|
1103
1121
|
}
|
|
1122
|
+
|
|
1123
|
+
rb_global_variable(&oj_json_parser_error_class);
|
|
1104
1124
|
if (rb_const_defined_at(json, rb_intern("ParserError"))) {
|
|
1105
1125
|
oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
|
|
1106
1126
|
} else {
|
|
@@ -1172,7 +1192,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1172
1192
|
char buf[64];
|
|
1173
1193
|
char *b;
|
|
1174
1194
|
double d = rb_num2dbl(obj);
|
|
1175
|
-
|
|
1195
|
+
size_t cnt = 0;
|
|
1176
1196
|
|
|
1177
1197
|
if (0.0 == d) {
|
|
1178
1198
|
b = buf;
|
|
@@ -1193,7 +1213,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1193
1213
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
1194
1214
|
|
|
1195
1215
|
strcpy(buf, RSTRING_PTR(rstr));
|
|
1196
|
-
cnt =
|
|
1216
|
+
cnt = RSTRING_LEN(rstr);
|
|
1197
1217
|
}
|
|
1198
1218
|
}
|
|
1199
1219
|
assure_size(out, cnt);
|
|
@@ -1205,7 +1225,8 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1205
1225
|
|
|
1206
1226
|
static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
1207
1227
|
size_t size;
|
|
1208
|
-
|
|
1228
|
+
size_t i;
|
|
1229
|
+
size_t cnt;
|
|
1209
1230
|
int d2 = depth + 1;
|
|
1210
1231
|
|
|
1211
1232
|
if (Yes == out->opts->circular) {
|
|
@@ -1214,12 +1235,11 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
|
1214
1235
|
return;
|
|
1215
1236
|
}
|
|
1216
1237
|
}
|
|
1217
|
-
|
|
1218
|
-
if (as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
|
|
1238
|
+
if (!oj_rails_array_opt && as_ok && rb_respond_to(a, oj_as_json_id)) {
|
|
1219
1239
|
dump_as_json(a, depth, out, false);
|
|
1220
1240
|
return;
|
|
1221
1241
|
}
|
|
1222
|
-
cnt =
|
|
1242
|
+
cnt = RARRAY_LEN(a);
|
|
1223
1243
|
*out->cur++ = '[';
|
|
1224
1244
|
size = 2;
|
|
1225
1245
|
assure_size(out, size);
|
|
@@ -1282,18 +1302,19 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
1282
1302
|
if (out->omit_nil && Qnil == value) {
|
|
1283
1303
|
return ST_CONTINUE;
|
|
1284
1304
|
}
|
|
1285
|
-
if (
|
|
1286
|
-
|
|
1287
|
-
|
|
1305
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
1306
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
1307
|
+
return ST_CONTINUE;
|
|
1308
|
+
}
|
|
1288
1309
|
}
|
|
1289
1310
|
if (!out->opts->dump_opts.use) {
|
|
1290
1311
|
size = depth * out->indent + 1;
|
|
1291
1312
|
assure_size(out, size);
|
|
1292
1313
|
fill_indent(out, depth);
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1314
|
+
switch (rtype) {
|
|
1315
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
1316
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
1317
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
1297
1318
|
}
|
|
1298
1319
|
*out->cur++ = ':';
|
|
1299
1320
|
} else {
|
|
@@ -1308,10 +1329,10 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
1308
1329
|
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
|
1309
1330
|
}
|
|
1310
1331
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1332
|
+
switch (rtype) {
|
|
1333
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
1334
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
1335
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
1315
1336
|
}
|
|
1316
1337
|
size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
1317
1338
|
assure_size(out, size);
|
|
@@ -1340,7 +1361,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1340
1361
|
return;
|
|
1341
1362
|
}
|
|
1342
1363
|
}
|
|
1343
|
-
if (
|
|
1364
|
+
if (!oj_rails_hash_opt && as_ok && rb_respond_to(obj, oj_as_json_id)) {
|
|
1344
1365
|
dump_as_json(obj, depth, out, false);
|
|
1345
1366
|
return;
|
|
1346
1367
|
}
|
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
|
|
|
@@ -164,8 +164,14 @@ static VALUE partial_io_cb(VALUE rbuf) {
|
|
|
164
164
|
}
|
|
165
165
|
str = StringValuePtr(rstr);
|
|
166
166
|
cnt = RSTRING_LEN(rstr);
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
if (cnt > (size_t)(reader->end - reader->tail)) {
|
|
168
|
+
// A misbehaving IO returned more than the requested number of bytes.
|
|
169
|
+
// Copying it in with strcpy() would overflow the reader buffer.
|
|
170
|
+
rb_raise(rb_eIOError, "read returned more than the requested number of bytes");
|
|
171
|
+
}
|
|
172
|
+
memcpy(reader->tail, str, cnt);
|
|
173
|
+
reader->tail[cnt] = '\0';
|
|
174
|
+
reader->read_end = reader->tail + cnt;
|
|
169
175
|
|
|
170
176
|
return Qtrue;
|
|
171
177
|
}
|
|
@@ -184,8 +190,14 @@ static VALUE io_cb(VALUE rbuf) {
|
|
|
184
190
|
}
|
|
185
191
|
str = StringValuePtr(rstr);
|
|
186
192
|
cnt = RSTRING_LEN(rstr);
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
if (cnt > (size_t)(reader->end - reader->tail)) {
|
|
194
|
+
// A misbehaving IO returned more than the requested number of bytes.
|
|
195
|
+
// Copying it in with strcpy() would overflow the reader buffer.
|
|
196
|
+
rb_raise(rb_eIOError, "read returned more than the requested number of bytes");
|
|
197
|
+
}
|
|
198
|
+
memcpy(reader->tail, str, cnt);
|
|
199
|
+
reader->tail[cnt] = '\0';
|
|
200
|
+
reader->read_end = reader->tail + cnt;
|
|
189
201
|
|
|
190
202
|
return Qtrue;
|
|
191
203
|
}
|
data/ext/oj/rxclass.c
CHANGED
|
@@ -96,7 +96,7 @@ int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
VALUE
|
|
99
|
-
oj_rxclass_match(RxClass rc, const char *str,
|
|
99
|
+
oj_rxclass_match(RxClass rc, const char *str, size_t len) {
|
|
100
100
|
RxC rxc;
|
|
101
101
|
char buf[4096];
|
|
102
102
|
|
|
@@ -142,3 +142,19 @@ void oj_rxclass_copy(RxClass src, RxClass dest) {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
|
|
146
|
+
// Add the Ruby objects in the chain to an array. The regexps and the classes
|
|
147
|
+
// can be referenced from nowhere else, as with a default match_string option,
|
|
148
|
+
// and are collected unless something holds onto them.
|
|
149
|
+
void oj_rxclass_keep(RxClass rc, VALUE keep) {
|
|
150
|
+
RxC rxc;
|
|
151
|
+
|
|
152
|
+
for (rxc = rc->head; NULL != rxc; rxc = rxc->next) {
|
|
153
|
+
if (Qnil != rxc->rrx) {
|
|
154
|
+
rb_ary_push(keep, rxc->rrx);
|
|
155
|
+
}
|
|
156
|
+
if (Qnil != rxc->clas) {
|
|
157
|
+
rb_ary_push(keep, rxc->clas);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
data/ext/oj/rxclass.h
CHANGED
|
@@ -19,8 +19,9 @@ 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
|
+
extern void oj_rxclass_keep(RxClass rc, VALUE keep);
|
|
25
26
|
|
|
26
27
|
#endif /* OJ_RXCLASS_H */
|
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;
|