oj 3.16.1 → 3.16.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 +14 -0
- data/ext/oj/cache.c +4 -2
- data/ext/oj/cache.h +3 -2
- data/ext/oj/dump.c +39 -16
- data/ext/oj/extconf.rb +1 -2
- data/ext/oj/fast.c +10 -9
- data/ext/oj/intern.c +23 -6
- data/ext/oj/mimic_json.c +3 -3
- data/ext/oj/object.c +13 -5
- data/ext/oj/oj.c +131 -130
- data/ext/oj/oj.h +4 -3
- data/ext/oj/parser.c +67 -53
- data/ext/oj/parser.h +2 -2
- data/ext/oj/rails.c +23 -6
- data/ext/oj/reader.c +1 -1
- data/ext/oj/saj.c +2 -2
- data/ext/oj/stream_writer.c +35 -15
- data/ext/oj/string_writer.c +50 -16
- data/ext/oj/usual.c +20 -27
- data/ext/oj/usual.h +1 -0
- data/ext/oj/val_stack.c +13 -2
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/version.rb +1 -1
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/activesupport7/encoding_test.rb +72 -22
- data/test/foo.rb +3 -9
- data/test/json_gem/json_generator_test.rb +6 -0
- data/test/perf_dump.rb +1 -1
- data/test/prec.rb +4 -4
- data/test/test_custom.rb +2 -1
- data/test/test_object.rb +14 -0
- data/test/test_parser_debug.rb +1 -1
- data/test/test_parser_usual.rb +10 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd443226b6fbe558bd4a01e5e4e2c150149e697c22c1676007f67923b9832682
|
4
|
+
data.tar.gz: 0a46ac536c4fccaeac2bddde9ff8ef8d50343f5eeff3455b36c5bfb762aef073
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49e28b9151a1c84d9f97adcea6af90acd1141a194858f29e633bf5e2e1965bb5fab783c015e343f569692e6351ad3957059135f05eb50022b79ee799ae0a306a
|
7
|
+
data.tar.gz: 74f69e8e14c39aee7128f8b7dc23fa1fa60a8df383dec844257e67c6e7f34c58d430ac77bc06571e8d52a29f857ee0162cba8ad1e93ac8bc1f7c2ad0260a0002
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.16.4 - 2024-06-08
|
4
|
+
|
5
|
+
- Fixed Oj::Parse EOF issue on larger stream input.
|
6
|
+
|
7
|
+
## 3.16.3 - 2023-12-11
|
8
|
+
|
9
|
+
- Fixed the gemspec to allow earlier versions of the bigdecimal gem.
|
10
|
+
|
11
|
+
## 3.16.2 - 2023-12-06
|
12
|
+
|
13
|
+
- Fixed documentation formatting.
|
14
|
+
|
15
|
+
- Added option to the "usual" parser to raise an error on an empty input string.
|
16
|
+
|
3
17
|
## 3.16.1 - 2023-09-01
|
4
18
|
|
5
19
|
- Fixed exception type on number parsing. (thank you @jasonpenny)
|
data/ext/oj/cache.c
CHANGED
@@ -260,7 +260,8 @@ void cache_set_expunge_rate(Cache c, int rate) {
|
|
260
260
|
c->xrate = (uint8_t)rate;
|
261
261
|
}
|
262
262
|
|
263
|
-
void cache_free(
|
263
|
+
void cache_free(void *data) {
|
264
|
+
Cache c = (Cache)data;
|
264
265
|
uint64_t i;
|
265
266
|
|
266
267
|
for (i = 0; i < c->size; i++) {
|
@@ -276,7 +277,8 @@ void cache_free(Cache c) {
|
|
276
277
|
OJ_FREE(c);
|
277
278
|
}
|
278
279
|
|
279
|
-
void cache_mark(
|
280
|
+
void cache_mark(void *data) {
|
281
|
+
Cache c = (Cache)data;
|
280
282
|
uint64_t i;
|
281
283
|
|
282
284
|
#if !HAVE_PTHREAD_MUTEX_INIT
|
data/ext/oj/cache.h
CHANGED
@@ -10,10 +10,11 @@
|
|
10
10
|
#define CACHE_MAX_KEY 35
|
11
11
|
|
12
12
|
struct _cache;
|
13
|
+
typedef struct _cache *Cache;
|
13
14
|
|
14
15
|
extern struct _cache *cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking);
|
15
|
-
extern void cache_free(
|
16
|
-
extern void cache_mark(
|
16
|
+
extern void cache_free(void *data);
|
17
|
+
extern void cache_mark(void *data);
|
17
18
|
extern void cache_set_form(struct _cache *c, VALUE (*form)(const char *str, size_t len));
|
18
19
|
extern VALUE cache_intern(struct _cache *c, const char *key, size_t len);
|
19
20
|
extern void cache_set_expunge_rate(struct _cache *c, int rate);
|
data/ext/oj/dump.c
CHANGED
@@ -198,7 +198,18 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
198
198
|
}
|
199
199
|
|
200
200
|
inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
201
|
-
|
201
|
+
long size = 0;
|
202
|
+
size_t i = len;
|
203
|
+
uint8_t hi = 0;
|
204
|
+
|
205
|
+
for (; 0 < i; str++, i--) {
|
206
|
+
size += rails_friendly_chars[*str];
|
207
|
+
hi |= *str & 0x80;
|
208
|
+
}
|
209
|
+
if (0 == hi) {
|
210
|
+
return size - len * (size_t)'0';
|
211
|
+
}
|
212
|
+
return -(size - len * (size_t)'0');
|
202
213
|
}
|
203
214
|
|
204
215
|
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
@@ -727,8 +738,11 @@ static void debug_raise(const char *orig, size_t cnt, int line) {
|
|
727
738
|
|
728
739
|
void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
729
740
|
if (oj_string_writer_class == rb_obj_class(obj)) {
|
730
|
-
StrWriter sw
|
731
|
-
size_t len
|
741
|
+
StrWriter sw;
|
742
|
+
size_t len;
|
743
|
+
|
744
|
+
sw = oj_str_writer_unwrap(obj);
|
745
|
+
len = sw->out.cur - sw->out.buf;
|
732
746
|
|
733
747
|
if (0 < len) {
|
734
748
|
len--;
|
@@ -747,8 +761,9 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
747
761
|
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
748
762
|
size_t size;
|
749
763
|
char *cmap;
|
750
|
-
const char *orig
|
751
|
-
bool has_hi
|
764
|
+
const char *orig = str;
|
765
|
+
bool has_hi = false;
|
766
|
+
bool do_unicode_validation = false;
|
752
767
|
|
753
768
|
switch (out->opts->escape_mode) {
|
754
769
|
case NLEsc:
|
@@ -769,8 +784,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
769
784
|
size = xss_friendly_size((uint8_t *)str, cnt);
|
770
785
|
break;
|
771
786
|
case JXEsc:
|
772
|
-
cmap
|
773
|
-
size
|
787
|
+
cmap = hixss_friendly_chars;
|
788
|
+
size = hixss_friendly_size((uint8_t *)str, cnt);
|
789
|
+
do_unicode_validation = true;
|
774
790
|
break;
|
775
791
|
case RailsXEsc: {
|
776
792
|
long sz;
|
@@ -783,12 +799,22 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
783
799
|
} else {
|
784
800
|
size = (size_t)sz;
|
785
801
|
}
|
802
|
+
do_unicode_validation = true;
|
786
803
|
break;
|
787
804
|
}
|
788
|
-
case RailsEsc:
|
805
|
+
case RailsEsc: {
|
806
|
+
long sz;
|
789
807
|
cmap = rails_friendly_chars;
|
790
|
-
|
808
|
+
sz = rails_friendly_size((uint8_t *)str, cnt);
|
809
|
+
if (sz < 0) {
|
810
|
+
has_hi = true;
|
811
|
+
size = (size_t)-sz;
|
812
|
+
} else {
|
813
|
+
size = (size_t)sz;
|
814
|
+
}
|
815
|
+
do_unicode_validation = true;
|
791
816
|
break;
|
817
|
+
}
|
792
818
|
case JSONEsc:
|
793
819
|
default: cmap = hibit_friendly_chars; size = hibit_friendly_size((uint8_t *)str, cnt);
|
794
820
|
}
|
@@ -819,7 +845,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
819
845
|
for (; str < end; str++) {
|
820
846
|
switch (cmap[(uint8_t)*str]) {
|
821
847
|
case '1':
|
822
|
-
if (
|
848
|
+
if (do_unicode_validation && check_start <= str) {
|
823
849
|
if (0 != (0x80 & (uint8_t)*str)) {
|
824
850
|
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
825
851
|
check_start = check_unicode(str, end, orig);
|
@@ -843,8 +869,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
843
869
|
}
|
844
870
|
break;
|
845
871
|
case '3': // Unicode
|
846
|
-
if (0xe2 == (uint8_t)*str &&
|
847
|
-
2 <= end - str) {
|
872
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
848
873
|
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
849
874
|
str = dump_unicode(str, end, out, orig);
|
850
875
|
} else {
|
@@ -863,8 +888,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
863
888
|
APPEND_CHARS(out->cur, "\\u00", 4);
|
864
889
|
dump_hex((uint8_t)*str, out);
|
865
890
|
} else {
|
866
|
-
if (0xe2 == (uint8_t)*str &&
|
867
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) {
|
891
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
868
892
|
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
869
893
|
str = dump_unicode(str, end, out, orig);
|
870
894
|
} else {
|
@@ -881,8 +905,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
881
905
|
}
|
882
906
|
*out->cur++ = '"';
|
883
907
|
}
|
884
|
-
if (
|
885
|
-
0 != (0x80 & *(str - 1))) {
|
908
|
+
if (do_unicode_validation && 0 < str - orig && 0 != (0x80 & *(str - 1))) {
|
886
909
|
uint8_t c = (uint8_t) * (str - 1);
|
887
910
|
int i;
|
888
911
|
int scnt = (int)(str - orig);
|
data/ext/oj/extconf.rb
CHANGED
@@ -29,10 +29,9 @@ dflags = {
|
|
29
29
|
have_func('rb_gc_mark_movable')
|
30
30
|
have_func('stpcpy')
|
31
31
|
have_func('pthread_mutex_init')
|
32
|
+
have_func('getrlimit', 'sys/resource.h')
|
32
33
|
have_func('rb_enc_interned_str')
|
33
34
|
have_func('rb_ext_ractor_safe', 'ruby.h')
|
34
|
-
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
35
|
-
have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
|
36
35
|
|
37
36
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
38
37
|
|
data/ext/oj/fast.c
CHANGED
@@ -40,7 +40,7 @@ typedef struct _doc {
|
|
40
40
|
Leaf *where; // points to current location
|
41
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
42
42
|
char *json;
|
43
|
-
unsigned long size;
|
43
|
+
unsigned long size; // number of leaves/branches in the doc
|
44
44
|
VALUE self;
|
45
45
|
Batch batches;
|
46
46
|
struct _batch batch0;
|
@@ -573,7 +573,7 @@ static char *read_quoted_value(ParseInfo pi) {
|
|
573
573
|
char *h = pi->s; // head
|
574
574
|
char *t = h; // tail
|
575
575
|
|
576
|
-
h++;
|
576
|
+
h++; // skip quote character
|
577
577
|
t++;
|
578
578
|
value = h;
|
579
579
|
for (; '"' != *h; h++, t++) {
|
@@ -765,7 +765,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
765
765
|
pi.s = pi.str;
|
766
766
|
doc_init(doc);
|
767
767
|
pi.doc = doc;
|
768
|
-
#if IS_WINDOWS
|
768
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
769
769
|
// assume a 1M stack and give half to ruby
|
770
770
|
pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
|
771
771
|
#else
|
@@ -780,11 +780,10 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
780
780
|
}
|
781
781
|
}
|
782
782
|
#endif
|
783
|
-
doc->json
|
784
|
-
self
|
785
|
-
doc->self
|
786
|
-
|
787
|
-
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
783
|
+
doc->json = json;
|
784
|
+
self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
|
785
|
+
doc->self = self;
|
786
|
+
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
788
787
|
if (given || 0 != ex) {
|
789
788
|
DATA_PTR(doc->self) = NULL;
|
790
789
|
// TBD is this needed?
|
@@ -1609,7 +1608,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1609
1608
|
* Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
|
1610
1609
|
*/
|
1611
1610
|
static VALUE doc_size(VALUE self) {
|
1612
|
-
|
1611
|
+
Doc d;
|
1612
|
+
TypedData_Get_Struct(self, struct _doc, &oj_doc_type, d);
|
1613
|
+
return ULONG2NUM(d->size);
|
1613
1614
|
}
|
1614
1615
|
|
1615
1616
|
/* @overload close() => nil
|
data/ext/oj/intern.c
CHANGED
@@ -85,20 +85,31 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
85
85
|
return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
|
86
86
|
}
|
87
87
|
|
88
|
+
static const rb_data_type_t oj_cache_type = {
|
89
|
+
"Oj/cache",
|
90
|
+
{
|
91
|
+
cache_mark,
|
92
|
+
cache_free,
|
93
|
+
NULL,
|
94
|
+
},
|
95
|
+
0,
|
96
|
+
0,
|
97
|
+
};
|
98
|
+
|
88
99
|
void oj_hash_init(void) {
|
89
100
|
VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
|
90
101
|
rb_undef_alloc_func(cache_class);
|
91
102
|
|
92
103
|
struct _cache *str_cache = cache_create(0, form_str, true, true);
|
93
|
-
str_cache_obj =
|
104
|
+
str_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, str_cache);
|
94
105
|
rb_gc_register_address(&str_cache_obj);
|
95
106
|
|
96
107
|
struct _cache *sym_cache = cache_create(0, form_sym, true, true);
|
97
|
-
sym_cache_obj =
|
108
|
+
sym_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, sym_cache);
|
98
109
|
rb_gc_register_address(&sym_cache_obj);
|
99
110
|
|
100
111
|
struct _cache *attr_cache = cache_create(0, form_attr, false, true);
|
101
|
-
attr_cache_obj =
|
112
|
+
attr_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, attr_cache);
|
102
113
|
rb_gc_register_address(&attr_cache_obj);
|
103
114
|
|
104
115
|
memset(class_hash.slots, 0, sizeof(class_hash.slots));
|
@@ -118,17 +129,23 @@ oj_str_intern(const char *key, size_t len) {
|
|
118
129
|
#if HAVE_RB_ENC_INTERNED_STR && 0
|
119
130
|
return rb_enc_interned_str(key, len, rb_utf8_encoding());
|
120
131
|
#else
|
121
|
-
|
132
|
+
Cache c;
|
133
|
+
TypedData_Get_Struct(str_cache_obj, struct _cache, &oj_cache_type, c);
|
134
|
+
return cache_intern(c, key, len);
|
122
135
|
#endif
|
123
136
|
}
|
124
137
|
|
125
138
|
VALUE
|
126
139
|
oj_sym_intern(const char *key, size_t len) {
|
127
|
-
|
140
|
+
Cache c;
|
141
|
+
TypedData_Get_Struct(sym_cache_obj, struct _cache, &oj_cache_type, c);
|
142
|
+
return cache_intern(c, key, len);
|
128
143
|
}
|
129
144
|
|
130
145
|
ID oj_attr_intern(const char *key, size_t len) {
|
131
|
-
|
146
|
+
Cache c;
|
147
|
+
TypedData_Get_Struct(attr_cache_obj, struct _cache, &oj_cache_type, c);
|
148
|
+
return cache_intern(c, key, len);
|
132
149
|
}
|
133
150
|
|
134
151
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
data/ext/oj/mimic_json.c
CHANGED
@@ -425,7 +425,7 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
425
425
|
* - *:object_nl* [_String_] String placed after a JSON object
|
426
426
|
* - *:array_nl* [_String_] String placed after a JSON array
|
427
427
|
* - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters in the output.
|
428
|
-
*
|
428
|
+
* Note JSON.generate does support this even if it is not documented.
|
429
429
|
*
|
430
430
|
* Returns [_String_] generated JSON.
|
431
431
|
*/
|
@@ -605,9 +605,9 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
605
605
|
* - *source* [_String_|IO] source to parse
|
606
606
|
* - *opts* [_Hash_] options
|
607
607
|
* - *:symbolize* [Boolean] _names flag indicating JSON object keys should be Symbols instead of
|
608
|
-
*
|
608
|
+
* Strings
|
609
609
|
* - *:create_additions* [Boolean] flag indicating a key matching +create_id+ in a JSON object
|
610
|
-
*
|
610
|
+
* should trigger the creation of Ruby Object
|
611
611
|
*
|
612
612
|
* Returns [Object]
|
613
613
|
* @see create_id=
|
data/ext/oj/object.c
CHANGED
@@ -83,8 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
|
|
83
83
|
|
84
84
|
VALUE
|
85
85
|
oj_parse_xml_time(const char *str, int len) {
|
86
|
-
VALUE args[
|
87
|
-
const char *end
|
86
|
+
VALUE args[7];
|
87
|
+
const char *end = str + len;
|
88
|
+
const char *orig = str;
|
88
89
|
int n;
|
89
90
|
|
90
91
|
// year
|
@@ -144,7 +145,9 @@ oj_parse_xml_time(const char *str, int len) {
|
|
144
145
|
char c = *str++;
|
145
146
|
|
146
147
|
if ('.' == c) {
|
147
|
-
long long
|
148
|
+
unsigned long long num = 0;
|
149
|
+
unsigned long long den = 1;
|
150
|
+
const unsigned long long last_den_limit = ULLONG_MAX / 10;
|
148
151
|
|
149
152
|
for (; str < end; str++) {
|
150
153
|
c = *str;
|
@@ -152,9 +155,14 @@ oj_parse_xml_time(const char *str, int len) {
|
|
152
155
|
str++;
|
153
156
|
break;
|
154
157
|
}
|
155
|
-
|
158
|
+
if (den > last_den_limit) {
|
159
|
+
// bail to Time.parse if there are more fractional digits than a ULLONG rational can hold
|
160
|
+
return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(orig, len));
|
161
|
+
}
|
162
|
+
num = num * 10 + (c - '0');
|
163
|
+
den *= 10;
|
156
164
|
}
|
157
|
-
args[5] =
|
165
|
+
args[5] = rb_funcall(INT2NUM(n), oj_plus_id, 1, rb_rational_new(ULL2NUM(num), ULL2NUM(den)));
|
158
166
|
} else {
|
159
167
|
args[5] = rb_ll2inum(n);
|
160
168
|
}
|