oj 3.16.6 → 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 +81 -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 +592 -81
- 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 +10 -7
- data/ext/oj/fast.c +40 -23
- data/ext/oj/intern.c +1 -1
- data/ext/oj/mimic_json.c +11 -7
- data/ext/oj/object.c +8 -8
- data/ext/oj/oj.c +256 -10
- data/ext/oj/oj.h +55 -52
- data/ext/oj/parse.c +243 -46
- data/ext/oj/parser.c +113 -37
- data/ext/oj/parser.h +2 -0
- data/ext/oj/rails.c +41 -36
- 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 +13 -8
- 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 +3 -13
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +5 -7
- data/ext/oj/usual.c +20 -7
- data/ext/oj/wab.c +5 -4
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +1 -1
- metadata +22 -114
- 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 -542
- 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 -52
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -536
- 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 -26
- 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 -251
- 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/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;
|
|
@@ -321,19 +321,20 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
|
321
321
|
if (T_ARRAY == rb_type(e1)) {
|
|
322
322
|
VALUE args[1024];
|
|
323
323
|
volatile VALUE rstr;
|
|
324
|
-
|
|
324
|
+
size_t i;
|
|
325
|
+
size_t cnt = RARRAY_LEN(e1);
|
|
325
326
|
|
|
326
327
|
for (i = 0; i < cnt; i++) {
|
|
327
328
|
rstr = RARRAY_AREF(e1, i);
|
|
328
329
|
args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
|
|
329
330
|
}
|
|
330
|
-
sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
|
|
331
|
+
sc = rb_funcall2(rb_cStruct, oj_new_id, (int)cnt, args);
|
|
331
332
|
} else {
|
|
332
333
|
// If struct is not defined then we let this fail and raise an exception.
|
|
333
334
|
sc = oj_name2struct(pi, *RARRAY_CONST_PTR(value), rb_eArgError);
|
|
334
335
|
}
|
|
335
336
|
if (sc == rb_cRange) {
|
|
336
|
-
parent->val = rb_class_new_instance(len - 1, RARRAY_CONST_PTR(value) + 1, rb_cRange);
|
|
337
|
+
parent->val = rb_class_new_instance((int)(len - 1), RARRAY_CONST_PTR(value) + 1, rb_cRange);
|
|
337
338
|
} else {
|
|
338
339
|
// Create a properly initialized struct instance without calling the initialize method.
|
|
339
340
|
parent->val = rb_obj_alloc(sc);
|
|
@@ -348,10 +349,10 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
|
348
349
|
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
|
349
350
|
#endif
|
|
350
351
|
// MRI >= 1.9
|
|
351
|
-
if (len - 1 > slen) {
|
|
352
|
+
if (len - 1 > (size_t)slen) {
|
|
352
353
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
|
353
354
|
} else {
|
|
354
|
-
|
|
355
|
+
size_t i;
|
|
355
356
|
|
|
356
357
|
for (i = 0; i < len - 1; i++) {
|
|
357
358
|
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_CONST_PTR(value)[i + 1]);
|
|
@@ -698,9 +699,8 @@ oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
|
|
698
699
|
|
|
699
700
|
if (T_STRING == rb_type(*argv)) {
|
|
700
701
|
return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
|
|
701
|
-
} else {
|
|
702
|
-
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
703
702
|
}
|
|
703
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
VALUE
|
data/ext/oj/oj.c
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
#include "odd.h"
|
|
19
19
|
#include "parse.h"
|
|
20
20
|
#include "rails.h"
|
|
21
|
+
#include "simd.h"
|
|
22
|
+
|
|
23
|
+
#define MAX_INDENT 16
|
|
21
24
|
|
|
22
25
|
typedef struct _yesNoOpt {
|
|
23
26
|
VALUE sym;
|
|
@@ -119,7 +122,9 @@ static VALUE create_id_sym;
|
|
|
119
122
|
static VALUE custom_sym;
|
|
120
123
|
static VALUE empty_string_sym;
|
|
121
124
|
static VALUE escape_mode_sym;
|
|
125
|
+
static VALUE except_sym;
|
|
122
126
|
static VALUE integer_range_sym;
|
|
127
|
+
static VALUE max_integer_digits_sym;
|
|
123
128
|
static VALUE fast_sym;
|
|
124
129
|
static VALUE float_prec_sym;
|
|
125
130
|
static VALUE float_format_sym;
|
|
@@ -137,6 +142,7 @@ static VALUE null_sym;
|
|
|
137
142
|
static VALUE object_sym;
|
|
138
143
|
static VALUE omit_null_byte_sym;
|
|
139
144
|
static VALUE omit_nil_sym;
|
|
145
|
+
static VALUE only_sym;
|
|
140
146
|
static VALUE rails_sym;
|
|
141
147
|
static VALUE raise_sym;
|
|
142
148
|
static VALUE ruby_sym;
|
|
@@ -166,6 +172,8 @@ pthread_mutex_t oj_cache_mutex;
|
|
|
166
172
|
VALUE oj_cache_mutex = Qnil;
|
|
167
173
|
#endif
|
|
168
174
|
|
|
175
|
+
SIMD_Implementation SIMD_Impl = SIMD_NONE;
|
|
176
|
+
|
|
169
177
|
extern void oj_parser_init();
|
|
170
178
|
|
|
171
179
|
const char oj_json_class[] = "json_class";
|
|
@@ -201,6 +209,7 @@ struct _options oj_default_options = {
|
|
|
201
209
|
0, // cache_str
|
|
202
210
|
0, // int_range_min
|
|
203
211
|
0, // int_range_max
|
|
212
|
+
0, // max_integer_digits
|
|
204
213
|
oj_json_class, // create_id
|
|
205
214
|
10, // create_id_len
|
|
206
215
|
9, // sec_prec
|
|
@@ -225,6 +234,8 @@ struct _options oj_default_options = {
|
|
|
225
234
|
false, // omit_nil
|
|
226
235
|
false, // omit_null_byte
|
|
227
236
|
MAX_DEPTH, // max_depth
|
|
237
|
+
NULL, // only
|
|
238
|
+
NULL, // except
|
|
228
239
|
},
|
|
229
240
|
{
|
|
230
241
|
// str_rx
|
|
@@ -235,6 +246,22 @@ struct _options oj_default_options = {
|
|
|
235
246
|
NULL,
|
|
236
247
|
};
|
|
237
248
|
|
|
249
|
+
static VALUE only_array_from_string(const char *str) {
|
|
250
|
+
volatile VALUE a = Qnil;
|
|
251
|
+
|
|
252
|
+
if (NULL != str && 2 < strlen(str)) {
|
|
253
|
+
str++;
|
|
254
|
+
char *cp;
|
|
255
|
+
|
|
256
|
+
a = rb_ary_new();
|
|
257
|
+
while (NULL != (cp = strchr(str, ':'))) {
|
|
258
|
+
rb_ary_push(a, rb_id2sym(rb_intern2(str, cp - str)));
|
|
259
|
+
str = cp + 1;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return a;
|
|
263
|
+
}
|
|
264
|
+
|
|
238
265
|
/* Document-method: default_options()
|
|
239
266
|
* call-seq: default_options()
|
|
240
267
|
*
|
|
@@ -311,10 +338,17 @@ struct _options oj_default_options = {
|
|
|
311
338
|
* - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less
|
|
312
339
|
* than this are cached)
|
|
313
340
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
|
341
|
+
* - *:max_integer_digits* [_Fixnum_] Maximum number of decimal digits allowed in a
|
|
342
|
+
* parsed integer. When the limit is exceeded a parse error is raised. 0 (the
|
|
343
|
+
* default) disables the limit. Setting a reasonable limit is recommended when
|
|
344
|
+
* parsing untrusted input to mitigate CPU-DoS attacks. Only applies to the
|
|
345
|
+
* legacy parsers (Oj.load, Oj::Doc, JSON.parse mimic); Oj::Parser is unaffected.
|
|
314
346
|
* - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false
|
|
315
347
|
* (trace is off)
|
|
316
348
|
* - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default
|
|
317
349
|
* is false (safe is off)
|
|
350
|
+
* - *:only* [_nil,_|_Array_] A list of the fields to encode. All others are skipped.
|
|
351
|
+
* - *:except* [_nil,_|_Array_] A list of the fields to not encode. All others are encoded.
|
|
318
352
|
*
|
|
319
353
|
* Return [_Hash_] all current option settings.
|
|
320
354
|
*/
|
|
@@ -423,6 +457,7 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
423
457
|
} else {
|
|
424
458
|
rb_hash_aset(opts, integer_range_sym, Qnil);
|
|
425
459
|
}
|
|
460
|
+
rb_hash_aset(opts, max_integer_digits_sym, LONG2NUM((long)oj_default_options.max_integer_digits));
|
|
426
461
|
switch (oj_default_options.escape_mode) {
|
|
427
462
|
case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
|
|
428
463
|
case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
|
|
@@ -480,6 +515,9 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
480
515
|
rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class);
|
|
481
516
|
rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class);
|
|
482
517
|
|
|
518
|
+
rb_hash_aset(opts, only_sym, only_array_from_string(oj_default_options.dump_opts.only));
|
|
519
|
+
rb_hash_aset(opts, except_sym, only_array_from_string(oj_default_options.dump_opts.except));
|
|
520
|
+
|
|
483
521
|
if (NULL == oj_default_options.ignore) {
|
|
484
522
|
rb_hash_aset(opts, ignore_sym, Qnil);
|
|
485
523
|
} else {
|
|
@@ -563,6 +601,8 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
563
601
|
* - *:cache_keys* [_Boolean_] if true then hash keys are cached
|
|
564
602
|
* - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less than this are cached)
|
|
565
603
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
|
604
|
+
* - *:max_integer_digits* [_Fixnum_] Maximum decimal digits in a parsed integer
|
|
605
|
+
* (0 = unlimited). Use to mitigate CPU-DoS via huge integer values in JSON.
|
|
566
606
|
* - *:trace* [_Boolean_] turn trace on or off.
|
|
567
607
|
* - *:safe* [_Boolean_] turn safe mimic on or off.
|
|
568
608
|
*/
|
|
@@ -622,6 +662,95 @@ bool set_yesno_options(VALUE key, VALUE value, Options copts) {
|
|
|
622
662
|
return false;
|
|
623
663
|
}
|
|
624
664
|
|
|
665
|
+
static const char *make_only_value(VALUE v) {
|
|
666
|
+
switch (rb_type(v)) {
|
|
667
|
+
case RUBY_T_NIL:
|
|
668
|
+
case RUBY_T_NONE: return NULL;
|
|
669
|
+
case RUBY_T_ARRAY: {
|
|
670
|
+
long len = rb_array_len(v);
|
|
671
|
+
long i;
|
|
672
|
+
long size = 0;
|
|
673
|
+
char *buf;
|
|
674
|
+
char *bp;
|
|
675
|
+
|
|
676
|
+
for (i = 0; i < len; i++) {
|
|
677
|
+
VALUE x = rb_ary_entry(v, i);
|
|
678
|
+
|
|
679
|
+
switch (rb_type(x)) {
|
|
680
|
+
case RUBY_T_SYMBOL:
|
|
681
|
+
size += strlen(rb_id2name(rb_sym2id(x)));
|
|
682
|
+
size++;
|
|
683
|
+
break;
|
|
684
|
+
case RUBY_T_STRING:
|
|
685
|
+
size += strlen(StringValueCStr(x));
|
|
686
|
+
size++;
|
|
687
|
+
break;
|
|
688
|
+
default: rb_raise(rb_eArgError, ":only and :except must be nil, symbol, string, or array."); break;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if (0 == size) {
|
|
692
|
+
return NULL;
|
|
693
|
+
}
|
|
694
|
+
buf = OJ_R_ALLOC_N(char, size + 2);
|
|
695
|
+
bp = buf;
|
|
696
|
+
*bp++ = ':';
|
|
697
|
+
for (i = 0; i < len; i++) {
|
|
698
|
+
VALUE x = rb_ary_entry(v, i);
|
|
699
|
+
const char *str;
|
|
700
|
+
|
|
701
|
+
switch (rb_type(x)) {
|
|
702
|
+
case RUBY_T_SYMBOL:
|
|
703
|
+
str = rb_id2name(rb_sym2id(x));
|
|
704
|
+
size = strlen(str);
|
|
705
|
+
memcpy(bp, str, size);
|
|
706
|
+
bp += size;
|
|
707
|
+
*bp++ = ':';
|
|
708
|
+
break;
|
|
709
|
+
case RUBY_T_STRING:
|
|
710
|
+
str = StringValueCStr(x);
|
|
711
|
+
size = strlen(str);
|
|
712
|
+
memcpy(bp, str, size);
|
|
713
|
+
bp += size;
|
|
714
|
+
*bp++ = ':';
|
|
715
|
+
break;
|
|
716
|
+
default:
|
|
717
|
+
// ignore
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
*bp = '\0';
|
|
722
|
+
|
|
723
|
+
return buf;
|
|
724
|
+
}
|
|
725
|
+
case RUBY_T_STRING: {
|
|
726
|
+
const char *str = StringValueCStr(v);
|
|
727
|
+
size_t size = strlen(str);
|
|
728
|
+
char *buf = OJ_R_ALLOC_N(char, size + 3);
|
|
729
|
+
|
|
730
|
+
buf[0] = ':';
|
|
731
|
+
strcpy(buf + 1, str);
|
|
732
|
+
buf[size + 1] = ':';
|
|
733
|
+
buf[size + 2] = '\0';
|
|
734
|
+
|
|
735
|
+
return buf;
|
|
736
|
+
}
|
|
737
|
+
case RUBY_T_SYMBOL: {
|
|
738
|
+
const char *str = rb_id2name(rb_sym2id(v));
|
|
739
|
+
size_t size = strlen(str);
|
|
740
|
+
char *buf = OJ_R_ALLOC_N(char, size + 3);
|
|
741
|
+
|
|
742
|
+
buf[0] = ':';
|
|
743
|
+
strcpy(buf + 1, str);
|
|
744
|
+
buf[size + 1] = ':';
|
|
745
|
+
buf[size + 2] = '\0';
|
|
746
|
+
|
|
747
|
+
return buf;
|
|
748
|
+
}
|
|
749
|
+
default: rb_raise(rb_eArgError, ":only and zzz :except must be nil, symbol, string, or array."); break;
|
|
750
|
+
}
|
|
751
|
+
return NULL;
|
|
752
|
+
}
|
|
753
|
+
|
|
625
754
|
static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
626
755
|
Options copts = (Options)opts;
|
|
627
756
|
size_t len;
|
|
@@ -639,7 +768,10 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
639
768
|
case T_FIXNUM:
|
|
640
769
|
copts->dump_opts.indent_size = 0;
|
|
641
770
|
*copts->dump_opts.indent_str = '\0';
|
|
642
|
-
|
|
771
|
+
if (MAX_INDENT < FIX2INT(v)) {
|
|
772
|
+
rb_raise(rb_eArgError, "indent is limited to %d characters.", MAX_INDENT);
|
|
773
|
+
}
|
|
774
|
+
copts->indent = FIX2INT(v);
|
|
643
775
|
break;
|
|
644
776
|
case T_STRING:
|
|
645
777
|
if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
|
|
@@ -923,12 +1055,12 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
923
1055
|
OJ_R_FREE(copts->ignore);
|
|
924
1056
|
copts->ignore = NULL;
|
|
925
1057
|
if (Qnil != v) {
|
|
926
|
-
|
|
1058
|
+
size_t cnt;
|
|
927
1059
|
|
|
928
1060
|
rb_check_type(v, T_ARRAY);
|
|
929
|
-
cnt =
|
|
1061
|
+
cnt = RARRAY_LEN(v);
|
|
930
1062
|
if (0 < cnt) {
|
|
931
|
-
|
|
1063
|
+
size_t i;
|
|
932
1064
|
|
|
933
1065
|
copts->ignore = OJ_R_ALLOC_N(VALUE, cnt + 1);
|
|
934
1066
|
for (i = 0; i < cnt; i++) {
|
|
@@ -954,6 +1086,20 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
954
1086
|
} else if (Qfalse != v) {
|
|
955
1087
|
rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
|
|
956
1088
|
}
|
|
1089
|
+
} else if (max_integer_digits_sym == k) {
|
|
1090
|
+
if (Qnil == v || Qfalse == v) {
|
|
1091
|
+
copts->max_integer_digits = 0;
|
|
1092
|
+
} else if (T_FIXNUM == rb_type(v)) {
|
|
1093
|
+
long n = FIX2LONG(v);
|
|
1094
|
+
|
|
1095
|
+
if (n < 0) {
|
|
1096
|
+
rb_raise(rb_eArgError, ":max_integer_digits must be >= 0.");
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
copts->max_integer_digits = (size_t)n;
|
|
1100
|
+
} else {
|
|
1101
|
+
rb_raise(rb_eArgError, ":max_integer_digits must be a non-negative Integer.");
|
|
1102
|
+
}
|
|
957
1103
|
} else if (symbol_keys_sym == k || oj_symbolize_names_sym == k) {
|
|
958
1104
|
if (Qnil == v) {
|
|
959
1105
|
return ST_CONTINUE;
|
|
@@ -973,11 +1119,23 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
973
1119
|
}
|
|
974
1120
|
} else if (float_format_sym == k) {
|
|
975
1121
|
rb_check_type(v, T_STRING);
|
|
976
|
-
if (6 <
|
|
1122
|
+
if (6 < RSTRING_LEN(v)) {
|
|
977
1123
|
rb_raise(rb_eArgError, ":float_format must be 6 bytes or less.");
|
|
978
1124
|
}
|
|
979
1125
|
strncpy(copts->float_fmt, RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
|
|
980
1126
|
copts->float_fmt[RSTRING_LEN(v)] = '\0';
|
|
1127
|
+
} else if (only_sym == k) {
|
|
1128
|
+
if (NULL != copts->dump_opts.only) {
|
|
1129
|
+
OJ_R_FREE((void *)copts->dump_opts.only);
|
|
1130
|
+
copts->dump_opts.only = NULL;
|
|
1131
|
+
}
|
|
1132
|
+
copts->dump_opts.only = make_only_value(v);
|
|
1133
|
+
} else if (except_sym == k) {
|
|
1134
|
+
if (NULL != copts->dump_opts.except) {
|
|
1135
|
+
OJ_R_FREE((void *)copts->dump_opts.except);
|
|
1136
|
+
copts->dump_opts.except = NULL;
|
|
1137
|
+
}
|
|
1138
|
+
copts->dump_opts.except = make_only_value(v);
|
|
981
1139
|
}
|
|
982
1140
|
return ST_CONTINUE;
|
|
983
1141
|
}
|
|
@@ -1188,7 +1346,7 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
|
|
|
1188
1346
|
OJ_FREE(wide_path);
|
|
1189
1347
|
}
|
|
1190
1348
|
#else
|
|
1191
|
-
fd
|
|
1349
|
+
fd = open(path, O_RDONLY);
|
|
1192
1350
|
#endif
|
|
1193
1351
|
if (0 == fd) {
|
|
1194
1352
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
|
@@ -1277,8 +1435,7 @@ static VALUE dump_body(VALUE a) {
|
|
|
1277
1435
|
if (0 == arg->out->buf) {
|
|
1278
1436
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
1279
1437
|
}
|
|
1280
|
-
rstr =
|
|
1281
|
-
rstr = oj_encode(rstr);
|
|
1438
|
+
rstr = rb_utf8_str_new_cstr(arg->out->buf);
|
|
1282
1439
|
|
|
1283
1440
|
return rstr;
|
|
1284
1441
|
}
|
|
@@ -1378,8 +1535,7 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
|
|
|
1378
1535
|
if (0 == out.buf) {
|
|
1379
1536
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
|
1380
1537
|
}
|
|
1381
|
-
rstr =
|
|
1382
|
-
rstr = oj_encode(rstr);
|
|
1538
|
+
rstr = rb_utf8_str_new_cstr(out.buf);
|
|
1383
1539
|
|
|
1384
1540
|
oj_out_free(&out);
|
|
1385
1541
|
|
|
@@ -1781,6 +1937,78 @@ static VALUE mem_report(VALUE self) {
|
|
|
1781
1937
|
*
|
|
1782
1938
|
* - *:wab* specifically for WAB data exchange.
|
|
1783
1939
|
*/
|
|
1940
|
+
|
|
1941
|
+
// =============================================================================
|
|
1942
|
+
// Runtime SIMD CPU detection
|
|
1943
|
+
// Cross-platform support for Windows (MSVC), Linux, and macOS (GCC/Clang)
|
|
1944
|
+
// =============================================================================
|
|
1945
|
+
SIMD_Implementation oj_get_simd_implementation(void) {
|
|
1946
|
+
#ifdef HAVE_SIMD_X86
|
|
1947
|
+
// x86/x86_64 runtime detection
|
|
1948
|
+
|
|
1949
|
+
#if defined(_MSC_VER)
|
|
1950
|
+
// MSVC: Use __cpuid intrinsic
|
|
1951
|
+
int cpu_info[4];
|
|
1952
|
+
__cpuid(cpu_info, 1);
|
|
1953
|
+
|
|
1954
|
+
// Check for SSE4.2 (bit 20 of ECX)
|
|
1955
|
+
if (cpu_info[2] & (1 << 20)) {
|
|
1956
|
+
return SIMD_SSE42;
|
|
1957
|
+
}
|
|
1958
|
+
// Check for SSE2 (bit 26 of EDX)
|
|
1959
|
+
if (cpu_info[3] & (1 << 26)) {
|
|
1960
|
+
return SIMD_SSE2;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
1964
|
+
// GCC/Clang: Use __builtin_cpu_supports if available
|
|
1965
|
+
#if defined(__has_builtin)
|
|
1966
|
+
#if __has_builtin(__builtin_cpu_supports)
|
|
1967
|
+
#define OJ_HAS_BUILTIN_CPU_SUPPORTS 1
|
|
1968
|
+
#endif
|
|
1969
|
+
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
|
1970
|
+
// GCC 4.8+ has __builtin_cpu_supports
|
|
1971
|
+
#define OJ_HAS_BUILTIN_CPU_SUPPORTS 1
|
|
1972
|
+
#endif
|
|
1973
|
+
|
|
1974
|
+
#ifdef OJ_HAS_BUILTIN_CPU_SUPPORTS
|
|
1975
|
+
#ifdef HAVE_SIMD_SSE4_2
|
|
1976
|
+
if (__builtin_cpu_supports("sse4.2")) {
|
|
1977
|
+
return SIMD_SSE42;
|
|
1978
|
+
}
|
|
1979
|
+
#endif
|
|
1980
|
+
#ifdef HAVE_SIMD_SSE2
|
|
1981
|
+
if (__builtin_cpu_supports("sse2")) {
|
|
1982
|
+
return SIMD_SSE2;
|
|
1983
|
+
}
|
|
1984
|
+
#endif
|
|
1985
|
+
#else
|
|
1986
|
+
// Fallback: Use CPUID instruction directly
|
|
1987
|
+
unsigned int eax, ebx, ecx, edx;
|
|
1988
|
+
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
|
|
1989
|
+
// Check for SSE4.2 (bit 20 of ECX)
|
|
1990
|
+
if (ecx & (1 << 20)) {
|
|
1991
|
+
return SIMD_SSE42;
|
|
1992
|
+
}
|
|
1993
|
+
// Check for SSE2 (bit 26 of EDX)
|
|
1994
|
+
if (edx & (1 << 26)) {
|
|
1995
|
+
return SIMD_SSE2;
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
#endif // OJ_HAS_BUILTIN_CPU_SUPPORTS
|
|
1999
|
+
|
|
2000
|
+
#endif // _MSC_VER vs GCC/Clang
|
|
2001
|
+
|
|
2002
|
+
#endif // HAVE_SIMD_X86
|
|
2003
|
+
|
|
2004
|
+
#ifdef HAVE_SIMD_NEON
|
|
2005
|
+
// ARM NEON is always available on ARM64 and detected at compile time
|
|
2006
|
+
return SIMD_NEON;
|
|
2007
|
+
#endif
|
|
2008
|
+
|
|
2009
|
+
return SIMD_NONE;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
1784
2012
|
void Init_oj(void) {
|
|
1785
2013
|
int err = 0;
|
|
1786
2014
|
|
|
@@ -1954,6 +2182,8 @@ void Init_oj(void) {
|
|
|
1954
2182
|
rb_gc_register_address(&escape_mode_sym);
|
|
1955
2183
|
integer_range_sym = ID2SYM(rb_intern("integer_range"));
|
|
1956
2184
|
rb_gc_register_address(&integer_range_sym);
|
|
2185
|
+
max_integer_digits_sym = ID2SYM(rb_intern("max_integer_digits"));
|
|
2186
|
+
rb_gc_register_address(&max_integer_digits_sym);
|
|
1957
2187
|
fast_sym = ID2SYM(rb_intern("fast"));
|
|
1958
2188
|
rb_gc_register_address(&fast_sym);
|
|
1959
2189
|
float_format_sym = ID2SYM(rb_intern("float_format"));
|
|
@@ -2060,6 +2290,10 @@ void Init_oj(void) {
|
|
|
2060
2290
|
rb_gc_register_address(&xmlschema_sym);
|
|
2061
2291
|
xss_safe_sym = ID2SYM(rb_intern("xss_safe"));
|
|
2062
2292
|
rb_gc_register_address(&xss_safe_sym);
|
|
2293
|
+
only_sym = ID2SYM(rb_intern("only"));
|
|
2294
|
+
rb_gc_register_address(&only_sym);
|
|
2295
|
+
except_sym = ID2SYM(rb_intern("except"));
|
|
2296
|
+
rb_gc_register_address(&except_sym);
|
|
2063
2297
|
|
|
2064
2298
|
oj_slash_string = rb_str_new2("/");
|
|
2065
2299
|
rb_gc_register_address(&oj_slash_string);
|
|
@@ -2081,6 +2315,18 @@ void Init_oj(void) {
|
|
|
2081
2315
|
#endif
|
|
2082
2316
|
oj_init_doc();
|
|
2083
2317
|
|
|
2318
|
+
SIMD_Impl = oj_get_simd_implementation();
|
|
2319
|
+
|
|
2084
2320
|
oj_parser_init();
|
|
2085
2321
|
oj_scanner_init();
|
|
2322
|
+
|
|
2323
|
+
#ifdef HAVE_SIMD_NEON
|
|
2324
|
+
initialize_neon();
|
|
2325
|
+
#endif /* HAVE_SIMD_NEON */
|
|
2326
|
+
|
|
2327
|
+
#ifdef HAVE_SIMD_SSE4_2
|
|
2328
|
+
if (SIMD_Impl == SIMD_SSE42) {
|
|
2329
|
+
initialize_sse42();
|
|
2330
|
+
}
|
|
2331
|
+
#endif /* HAVE_SIMD_SSE4_2 */
|
|
2086
2332
|
}
|
data/ext/oj/oj.h
CHANGED
|
@@ -104,61 +104,64 @@ typedef enum {
|
|
|
104
104
|
} StreamWriterType;
|
|
105
105
|
|
|
106
106
|
typedef struct _dumpOpts {
|
|
107
|
-
bool
|
|
108
|
-
char
|
|
109
|
-
char
|
|
110
|
-
char
|
|
111
|
-
char
|
|
112
|
-
char
|
|
113
|
-
uint8_t
|
|
114
|
-
uint8_t
|
|
115
|
-
uint8_t
|
|
116
|
-
uint8_t
|
|
117
|
-
uint8_t
|
|
118
|
-
char
|
|
119
|
-
bool
|
|
120
|
-
bool
|
|
121
|
-
int
|
|
107
|
+
bool use;
|
|
108
|
+
char indent_str[16];
|
|
109
|
+
char before_sep[16];
|
|
110
|
+
char after_sep[16];
|
|
111
|
+
char hash_nl[16];
|
|
112
|
+
char array_nl[16];
|
|
113
|
+
uint8_t indent_size;
|
|
114
|
+
uint8_t before_size;
|
|
115
|
+
uint8_t after_size;
|
|
116
|
+
uint8_t hash_size;
|
|
117
|
+
uint8_t array_size;
|
|
118
|
+
char nan_dump; // NanDump
|
|
119
|
+
bool omit_nil;
|
|
120
|
+
bool omit_null_byte;
|
|
121
|
+
int max_depth;
|
|
122
|
+
const char *only;
|
|
123
|
+
const char *except;
|
|
122
124
|
} *DumpOpts;
|
|
123
125
|
|
|
124
126
|
typedef struct _options {
|
|
125
|
-
int indent;
|
|
126
|
-
char circular;
|
|
127
|
-
char auto_define;
|
|
128
|
-
char sym_key;
|
|
129
|
-
char escape_mode;
|
|
130
|
-
char mode;
|
|
131
|
-
char class_cache;
|
|
132
|
-
char time_format;
|
|
133
|
-
char bigdec_as_num;
|
|
134
|
-
char bigdec_load;
|
|
135
|
-
char compat_bigdec;
|
|
136
|
-
char to_hash;
|
|
137
|
-
char to_json;
|
|
138
|
-
char as_json;
|
|
139
|
-
char raw_json;
|
|
140
|
-
char nilnil;
|
|
141
|
-
char empty_string;
|
|
142
|
-
char allow_gc;
|
|
143
|
-
char quirks_mode;
|
|
144
|
-
char allow_invalid;
|
|
145
|
-
char create_ok;
|
|
146
|
-
char allow_nan;
|
|
147
|
-
char trace;
|
|
148
|
-
char safe;
|
|
149
|
-
char sec_prec_set;
|
|
150
|
-
char ignore_under;
|
|
151
|
-
char cache_keys;
|
|
152
|
-
char cache_str;
|
|
153
|
-
int64_t int_range_min;
|
|
154
|
-
int64_t int_range_max;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
char
|
|
160
|
-
|
|
161
|
-
VALUE
|
|
127
|
+
int indent; // indention for dump, default 2
|
|
128
|
+
char circular; // YesNo
|
|
129
|
+
char auto_define; // YesNo
|
|
130
|
+
char sym_key; // YesNo
|
|
131
|
+
char escape_mode; // Escape_Mode
|
|
132
|
+
char mode; // Mode
|
|
133
|
+
char class_cache; // YesNo
|
|
134
|
+
char time_format; // TimeFormat
|
|
135
|
+
char bigdec_as_num; // YesNo
|
|
136
|
+
char bigdec_load; // BigLoad
|
|
137
|
+
char compat_bigdec; // boolean (0 or 1)
|
|
138
|
+
char to_hash; // YesNo
|
|
139
|
+
char to_json; // YesNo
|
|
140
|
+
char as_json; // YesNo
|
|
141
|
+
char raw_json; // YesNo
|
|
142
|
+
char nilnil; // YesNo
|
|
143
|
+
char empty_string; // YesNo
|
|
144
|
+
char allow_gc; // allow GC during parse
|
|
145
|
+
char quirks_mode; // allow single JSON values instead of documents
|
|
146
|
+
char allow_invalid; // YesNo - allow invalid unicode
|
|
147
|
+
char create_ok; // YesNo allow create_id
|
|
148
|
+
char allow_nan; // YesNo for parsing only
|
|
149
|
+
char trace; // YesNo
|
|
150
|
+
char safe; // YesNo
|
|
151
|
+
char sec_prec_set; // boolean (0 or 1)
|
|
152
|
+
char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes
|
|
153
|
+
char cache_keys; // YesNo
|
|
154
|
+
char cache_str; // string short than or equal to this are cache
|
|
155
|
+
int64_t int_range_min; // dump numbers below as string
|
|
156
|
+
int64_t int_range_max; // dump numbers above as string
|
|
157
|
+
size_t max_integer_digits; // 0 = unlimited; max decimal digits for parsed integers
|
|
158
|
+
const char *create_id; // 0 or string
|
|
159
|
+
size_t create_id_len; // length of create_id
|
|
160
|
+
int sec_prec; // second precision when dumping time
|
|
161
|
+
char float_prec; // float precision, linked to float_fmt
|
|
162
|
+
char float_fmt[7]; // float format for dumping, if empty use Ruby
|
|
163
|
+
VALUE hash_class; // class to use in place of Hash on load
|
|
164
|
+
VALUE array_class; // class to use in place of Array on load
|
|
162
165
|
struct _dumpOpts dump_opts;
|
|
163
166
|
struct _rxClass str_rx;
|
|
164
167
|
VALUE *ignore; // Qnil terminated array of classes or NULL
|