oj 3.16.11 → 3.17.6
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 +133 -0
- data/README.md +0 -16
- data/ext/oj/cache.c +17 -1
- data/ext/oj/cache.h +5 -0
- data/ext/oj/circarray.c +6 -2
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +12 -5
- data/ext/oj/dump.c +433 -206
- data/ext/oj/dump.h +12 -0
- data/ext/oj/dump_compat.c +17 -5
- data/ext/oj/dump_object.c +25 -10
- data/ext/oj/dump_strict.c +13 -8
- data/ext/oj/extconf.rb +11 -7
- data/ext/oj/fast.c +123 -60
- data/ext/oj/intern.c +7 -2
- data/ext/oj/mimic_json.c +3 -0
- data/ext/oj/object.c +26 -15
- data/ext/oj/odd.c +6 -2
- data/ext/oj/oj.c +511 -22
- data/ext/oj/oj.h +61 -53
- data/ext/oj/parse.c +229 -30
- data/ext/oj/parse.h +0 -1
- data/ext/oj/parser.c +226 -65
- data/ext/oj/rails.c +197 -57
- data/ext/oj/reader.c +18 -6
- data/ext/oj/resolve.c +11 -2
- data/ext/oj/rxclass.c +17 -1
- data/ext/oj/rxclass.h +2 -1
- data/ext/oj/safe.c +244 -0
- data/ext/oj/safe.h +91 -0
- data/ext/oj/saj.c +56 -12
- data/ext/oj/simd.h +210 -1
- data/ext/oj/sparse.c +22 -9
- data/ext/oj/stream_writer.c +16 -1
- data/ext/oj/string_writer.c +23 -7
- data/ext/oj/usual.c +23 -6
- data/ext/oj/util.c +27 -0
- data/ext/oj/util.h +2 -1
- data/ext/oj/val_stack.h +24 -5
- data/ext/oj/wab.c +15 -27
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/Custom.md +2 -3
- data/pages/InstallOptions.md +8 -6
- data/pages/Modes.md +1 -1
- data/pages/Options.md +5 -6
- data/pages/Parser.md +2 -2
- data/pages/Rails.md +6 -0
- data/pages/Security.md +21 -7
- metadata +21 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af3a1f2b343eefacdaeb1f82d4b48fe67bece49e4aae63ad46aa878f726ae3de
|
|
4
|
+
data.tar.gz: 8cd6e1ac300706f39d434cbbba52ea780a96b761ba2090d3d3624185bc021819
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e081fafa7bd5af792fef91dc58612d6ea85bdae7b3d709bbd945773a5ad9d1feec4c88e3844aa403098c3fa267814ef61dcbba5fb4d9ee86a239eecf5b3926fa
|
|
7
|
+
data.tar.gz: 339ba6bedb36fb30a382f8cb5037053a4197d4e9364bb11f50b79ec6ec3002cdd687868e140fec1dacabdc9cfa972a45cfcd6cb8a85e4c4148cd484f56278004
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,138 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 3.17.6 - 2026-08-10
|
|
4
|
+
|
|
5
|
+
- Fixed issue #1092, where the encoder ActiveSupport 8.1 caches with `escape: false` froze the options as they stood before `set_encoder` wrote `time_precision` into them, so `to_json(escape: false)` emitted 9 fractional digits. An options hash that names no option Oj knows no longer detaches an encoder from the defaults. (#1093)
|
|
6
|
+
|
|
7
|
+
## 3.17.5 - 2026-07-31
|
|
8
|
+
|
|
9
|
+
Most of this release comes out of a security review of the C extension. There are no API changes.
|
|
10
|
+
|
|
11
|
+
### Memory safety
|
|
12
|
+
|
|
13
|
+
- Fixed hash flooding by seeding the key hash per process. The hash was decided entirely at compile time, so a document of colliding keys turned key interning into O(n^2) and left the process slow for every later parse. (#1053)
|
|
14
|
+
- Fixed a one byte buffer over-read on a document that ends with a backslash inside an unterminated string. (#1054)
|
|
15
|
+
- Fixed two length underflows that made an empty `^m` value and a key of exactly 65,536 bytes read forward until they left mapped memory. (#1055)
|
|
16
|
+
- Fixed a SEGV from type confusion in class path resolution. A name segment that resolved to something other than a class or module was dereferenced as one. (#1056)
|
|
17
|
+
- Fixed uninitialized stack memory being read into the message of an unresolved class name error. (#1057)
|
|
18
|
+
- Fixed output buffer overflows when writing indentation, where several callers of `fill_indent()` had not assured the buffer first. (#1058)
|
|
19
|
+
- Fixed the `Oj::Doc` path depth limit being checked one level too late. (#1061)
|
|
20
|
+
- Fixed the use-after-free of a key when the value stack grows. (#1062)
|
|
21
|
+
- Fixed the buffer over-read when a document ends where a key belongs. (#1063)
|
|
22
|
+
- Fixed the id from a circular reference being used unchecked. (#1064)
|
|
23
|
+
- Fixed the SEGV dumping an exception that was never raised, where the missing backtrace was read as an Array. (#1068)
|
|
24
|
+
- Fixed the stack buffer overflow writing the error location. (#1071)
|
|
25
|
+
- Fixed a read error in `Oj::Parser#file` being taken as a read of `SIZE_MAX` bytes, which wrote in front of the buffer and then reparsed it forever without checking for interrupts. (#1072)
|
|
26
|
+
- Fixed a `:float_format` too long for the 64 byte buffer copying stack bytes past the end of it into the output. (#1073)
|
|
27
|
+
- Fixed the double free of the default `create_id` when a call passes `:create_id => nil`. (#1074)
|
|
28
|
+
- Fixed the buffer over-read of an odd attribute name and the leak of its arguments. (#1075)
|
|
29
|
+
- Fixed the SEGV reading a truncated document with `Oj::Parser#file` and the descriptor it leaked. (#1076)
|
|
30
|
+
- Fixed the SEGV from a malformed number in `Oj::Doc`. (#1077)
|
|
31
|
+
- Fixed the stack exhaustion from a long key with `:only` or `:except`. (#1078)
|
|
32
|
+
- Fixed the odd module match being decided by uninitialized memory. (#1079)
|
|
33
|
+
- Fixed `:float_format` accepting directives it has no argument for. (#1083)
|
|
34
|
+
|
|
35
|
+
### Memory leaks
|
|
36
|
+
|
|
37
|
+
- Fixed the leak of an escaped hash key in the streaming parser. (#1067)
|
|
38
|
+
- Fixed the leak of the parser `create_id` when it is set a second time. (#1085)
|
|
39
|
+
- Fixed the leak of the parser when `Oj::Parser.new` or `Oj::Parser.safe` raises on an argument it does not take. (#1086)
|
|
40
|
+
|
|
41
|
+
### Parsing and dumping
|
|
42
|
+
|
|
43
|
+
- Fixed a safe parser limit of 4 being ignored. (#1065)
|
|
44
|
+
- Fixed the exponent bound being checked after it is narrowed. (#1066)
|
|
45
|
+
- Fixed a document being rejected when it opens with a number of 4093 digits or more read through a file descriptor or an IO, and the reader buffer that leaked when it grew. (#1069)
|
|
46
|
+
- Fixed the safe parser limits being dropped when an option is set after the parser is built. (#1070)
|
|
47
|
+
- Fixed the `:custom` mode dump of an exception that was never raised opening with `{,`. (#1082)
|
|
48
|
+
- Fixed the `:wab` mode time load being an offset out on Windows, where `mktime()` stood in for `timegm()` and returned -1 for any time before the epoch. (#1088)
|
|
49
|
+
- Fixed `Oj::Doc` dropping the exponent of a number written without a decimal point, so `1e3` loaded as `1`. (#1089)
|
|
50
|
+
|
|
51
|
+
### Rails
|
|
52
|
+
|
|
53
|
+
- Fixed a `to_json(only:)` or `to_json(except:)` dropping the `include_root_in_json` wrapper key and the keys added by `:methods`. (#1039)
|
|
54
|
+
- Fixed the `as_json` options reaching only the first element of a container, so `to_json(only:)`, `to_json(methods:)` and any custom `as_json(opts)` took effect on one row and nowhere else. (#1040)
|
|
55
|
+
- An encoder now reads the global optimized class table and options instead of copying them, saving about 6.7KB of malloc per `ActiveSupport::JSON.encode`, and picks up later `Oj.default_options` and `ActiveSupport::JSON::Encoding` changes. (#1049)
|
|
56
|
+
- Fixed `as_json` being handed the encoder's own options hash. ActiveSupport allows `as_json` to write into it, and ActiveSupport 8.1 caches one encoder per process, so a single such `as_json` could leave `:only` set for every later `to_json`. (#1050)
|
|
57
|
+
|
|
58
|
+
### Documentation
|
|
59
|
+
|
|
60
|
+
- Renamed the documented `:skip_null_byte` option to `:omit_null_byte`, which is the name that works. (#1041)
|
|
61
|
+
- Dropped the `--with-sse42` install option from InstallOptions.md. SIMD support is detected at runtime. (#1042)
|
|
62
|
+
- Corrected the documented minimum Ruby version from 2.4+ to 2.7+. (#1043)
|
|
63
|
+
- Corrected the Parser.md benchmark conclusions to reference `:usual` rather than `:saj`. (#1044)
|
|
64
|
+
- Corrected Custom.md and Options.md, which called `:custom` the default mode. The default is `:object`. (#1045)
|
|
65
|
+
- Corrected the documented type of the `:safe` option from String to Boolean. (#1046)
|
|
66
|
+
- Corrected Security.md, which said no methods are ever called on an Object created by a load. `exception`, `set_backtrace` and `replace` are. The page now also says which mode `Oj.load` uses. (#1080)
|
|
67
|
+
|
|
68
|
+
### Tests and CI
|
|
69
|
+
|
|
70
|
+
- Added the ActiveSupport 8 test suite. The Rakefile picked the suite by major version, so the rails_8 job had been running zero ActiveSupport tests. (#1047)
|
|
71
|
+
- Added the ActiveSupport 8.1 test suite and pinned the #985 regression. (#1051)
|
|
72
|
+
- Fixed `rake` never running the `test/test_*.rb` suite. The `Rake::TestTask` that defined `test` was commented out, so `test_all` invoked a synthesized no-op file task. (#1084)
|
|
73
|
+
- Added a job timeout to the workflows. (#1087)
|
|
74
|
+
- Removed the pre-1970 time test skips on Windows, which were left from a 32 bit Ruby limit that no longer applies. (#1090)
|
|
75
|
+
|
|
76
|
+
## 3.17.4 - 2026-07-14
|
|
77
|
+
|
|
78
|
+
- Fixed issue in fast.c where rescuing from a panic did not reset the where counter.
|
|
79
|
+
|
|
80
|
+
- Multiple fixes thanks to @Watson1978.
|
|
81
|
+
|
|
82
|
+
## 3.17.3 - 2026-06-04
|
|
83
|
+
|
|
84
|
+
- Fixed issue in intern.c and fast.c.
|
|
85
|
+
|
|
86
|
+
## 3.17.2 - 2026-05-27
|
|
87
|
+
|
|
88
|
+
- Fixed multiple issues related to extreme sizes.
|
|
89
|
+
|
|
90
|
+
## 3.17.1 - 2026-05-15
|
|
91
|
+
|
|
92
|
+
- Fixed "quoted string not terminated" error.
|
|
93
|
+
|
|
94
|
+
## 3.17.0 - 2026-04-19
|
|
95
|
+
|
|
96
|
+
- A "safe" parser has been added as a variation of the Oj:Parser thanks to @meinac.
|
|
97
|
+
|
|
98
|
+
## 3.16.17 - 2026-04-12
|
|
99
|
+
|
|
100
|
+
- Rails optimize for Hash and Array now overrides `as_json` for those
|
|
101
|
+
classes. Note that when either is optimized with `Oj.optimize_rails`
|
|
102
|
+
the `Array.as_json` and `Hash.as_json` will not be called.
|
|
103
|
+
|
|
104
|
+
- Add support for the rails encoder `:only` and `:except` options.
|
|
105
|
+
|
|
106
|
+
- Handle unterminated strings in usual parser (#1002)
|
|
107
|
+
|
|
108
|
+
- Fix read() not handling partial reads for large files (#1004)
|
|
109
|
+
|
|
110
|
+
- Raise error for incomplete primitive literals (#1005)
|
|
111
|
+
|
|
112
|
+
## 3.16.16 - 2026-03-13
|
|
113
|
+
|
|
114
|
+
- Not closed arrays and objects are reported corrected in the usual parser.
|
|
115
|
+
|
|
116
|
+
## 3.16.15 - 2026-02-05
|
|
117
|
+
|
|
118
|
+
- Fixed by putting the ostruct dependency back until a better way is found to conditionally include it.
|
|
119
|
+
|
|
120
|
+
## 3.16.14 - 2026-02-04
|
|
121
|
+
|
|
122
|
+
- Fixed SSE issue #989.
|
|
123
|
+
|
|
124
|
+
- Removed ostruct dependency.
|
|
125
|
+
|
|
126
|
+
- Removed generic object JSON gem tests.
|
|
127
|
+
|
|
128
|
+
## 3.16.13 - 2025-12-05
|
|
129
|
+
|
|
130
|
+
- Fixed rails encoding for Hash and Array subclasses.
|
|
131
|
+
|
|
132
|
+
## 3.16.12 - 2025-10-29
|
|
133
|
+
|
|
134
|
+
- Fixed dump realloc bug that occurred when using the compat mode dump options.
|
|
135
|
+
|
|
3
136
|
## 3.16.11 - 2025-05-29
|
|
4
137
|
|
|
5
138
|
- Fixed range encoding with the :circular option
|
data/README.md
CHANGED
|
@@ -46,11 +46,6 @@ gem 'oj'
|
|
|
46
46
|
|
|
47
47
|
See the Quickstart sections of the [Rails](pages/Rails.md) and [json](pages/JsonGem.md) docs.
|
|
48
48
|
|
|
49
|
-
## multi_json
|
|
50
|
-
|
|
51
|
-
Code which uses [multi_json](https://github.com/intridea/multi_json)
|
|
52
|
-
will automatically prefer Oj if it is installed.
|
|
53
|
-
|
|
54
49
|
## Support
|
|
55
50
|
|
|
56
51
|
[Get supported Oj with a Tidelift Subscription.](https://tidelift.com/subscription/pkg/rubygems-oj?utm_source=rubygems-oj&utm_medium=referral&utm_campaign=readme) Security updates are [supported](https://tidelift.com/security).
|
|
@@ -83,17 +78,6 @@ See [{file:CHANGELOG.md}](CHANGELOG.md) and [{file:RELEASE_NOTES.md}](RELEASE_NO
|
|
|
83
78
|
|
|
84
79
|
- *RubyGems* *repo*: https://rubygems.org/gems/oj
|
|
85
80
|
|
|
86
|
-
Follow [@peterohler on Twitter](http://twitter.com/peterohler) for announcements and news about the Oj gem.
|
|
87
|
-
|
|
88
|
-
#### Performance Comparisons
|
|
89
|
-
|
|
90
|
-
- [Oj Strict Mode Performance](http://www.ohler.com/dev/oj_misc/performance_strict.html) compares Oj strict mode parser performance to other JSON parsers.
|
|
91
|
-
|
|
92
|
-
- [Oj Compat Mode Performance](http://www.ohler.com/dev/oj_misc/performance_compat.html) compares Oj compat mode parser performance to other JSON parsers.
|
|
93
|
-
|
|
94
|
-
- [Oj Object Mode Performance](http://www.ohler.com/dev/oj_misc/performance_object.html) compares Oj object mode parser performance to other marshallers.
|
|
95
|
-
|
|
96
|
-
- [Oj Callback Performance](http://www.ohler.com/dev/oj_misc/performance_callback.html) compares Oj callback parser performance to other JSON parsers.
|
|
97
81
|
|
|
98
82
|
#### Links of Interest
|
|
99
83
|
|
data/ext/oj/cache.c
CHANGED
|
@@ -28,6 +28,22 @@
|
|
|
28
28
|
// almost the Murmur hash algorithm
|
|
29
29
|
#define M 0x5bd1e995
|
|
30
30
|
|
|
31
|
+
uint64_t oj_hash_seed = 0;
|
|
32
|
+
|
|
33
|
+
void oj_hash_seed_init(void) {
|
|
34
|
+
static bool seeded = false;
|
|
35
|
+
|
|
36
|
+
if (seeded) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
seeded = true;
|
|
40
|
+
#if HAVE_RB_HASH_START
|
|
41
|
+
oj_hash_seed = (uint64_t)rb_hash_start(0);
|
|
42
|
+
#else
|
|
43
|
+
oj_hash_seed = (uint64_t)NUM2LL(rb_funcall(rb_str_new_cstr("oj"), rb_intern("hash"), 0));
|
|
44
|
+
#endif
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
typedef struct _slot {
|
|
32
48
|
struct _slot *next;
|
|
33
49
|
VALUE val;
|
|
@@ -62,7 +78,7 @@ void cache_set_form(Cache c, VALUE (*form)(const char *str, size_t len)) {
|
|
|
62
78
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
|
63
79
|
const uint8_t *end = key + len;
|
|
64
80
|
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
|
65
|
-
uint64_t h = (uint64_t)len;
|
|
81
|
+
uint64_t h = (uint64_t)len ^ oj_hash_seed;
|
|
66
82
|
uint64_t k;
|
|
67
83
|
|
|
68
84
|
while (key < endless) {
|
data/ext/oj/cache.h
CHANGED
data/ext/oj/circarray.c
CHANGED
|
@@ -25,8 +25,12 @@ void oj_circ_array_free(CircArray ca) {
|
|
|
25
25
|
OJ_R_FREE(ca);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// Objects are numbered in encounter order starting at 1, so the only id that
|
|
29
|
+
// can extend the array is one past the highest already seen. Anything further
|
|
30
|
+
// is not a reference to an object the document can contain and must not be
|
|
31
|
+
// used to size an allocation.
|
|
28
32
|
void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
|
|
29
|
-
if (0 < id &&
|
|
33
|
+
if (0 != ca && 0 < id && id <= ca->cnt + 1) {
|
|
30
34
|
unsigned long i;
|
|
31
35
|
|
|
32
36
|
if (ca->size < id) {
|
|
@@ -57,7 +61,7 @@ VALUE
|
|
|
57
61
|
oj_circ_array_get(CircArray ca, unsigned long id) {
|
|
58
62
|
VALUE obj = Qnil;
|
|
59
63
|
|
|
60
|
-
if (
|
|
64
|
+
if (0 != ca && 0 < id && id <= ca->cnt) {
|
|
61
65
|
obj = ca->objs[id - 1];
|
|
62
66
|
}
|
|
63
67
|
return obj;
|
data/ext/oj/compat.c
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
16
16
|
const char *key = kval->key;
|
|
17
|
-
|
|
17
|
+
size_t klen = kval->klen;
|
|
18
18
|
Val parent = stack_peek(&pi->stack);
|
|
19
19
|
|
|
20
20
|
if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
|
|
21
|
-
*pi->options.create_id == *key && (
|
|
21
|
+
*pi->options.create_id == *key && (size_t)pi->options.create_id_len == klen &&
|
|
22
22
|
0 == strncmp(pi->options.create_id, key, klen)) {
|
|
23
23
|
parent->classname = oj_strndup(str, len);
|
|
24
24
|
parent->clen = len;
|
|
@@ -27,7 +27,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
|
27
27
|
volatile VALUE rkey = oj_calc_hash_key(pi, kval);
|
|
28
28
|
|
|
29
29
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
30
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
30
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
31
31
|
|
|
32
32
|
if (Qnil != clas) {
|
|
33
33
|
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
@@ -84,7 +84,7 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
|
|
|
84
84
|
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
|
85
85
|
|
|
86
86
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
87
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
87
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
88
88
|
|
|
89
89
|
if (Qnil != clas) {
|
|
90
90
|
pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
@@ -155,7 +155,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
|
155
155
|
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
|
156
156
|
|
|
157
157
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
158
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
158
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
159
159
|
|
|
160
160
|
if (Qnil != clas) {
|
|
161
161
|
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
data/ext/oj/custom.c
CHANGED
|
@@ -287,6 +287,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
287
287
|
if (out->omit_nil && Qnil == value) {
|
|
288
288
|
return ST_CONTINUE;
|
|
289
289
|
}
|
|
290
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
291
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
292
|
+
return ST_CONTINUE;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
290
295
|
if (!out->opts->dump_opts.use) {
|
|
291
296
|
assure_size(out, depth * out->indent + 1);
|
|
292
297
|
fill_indent(out, depth);
|
|
@@ -635,7 +640,9 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
|
635
640
|
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
|
636
641
|
volatile VALUE rv;
|
|
637
642
|
|
|
638
|
-
|
|
643
|
+
// An exception that was never raised has no instance variables, so
|
|
644
|
+
// without the class name nothing has been written since the '{'.
|
|
645
|
+
if (',' != *(out->cur - 1) && '{' != *(out->cur - 1)) {
|
|
639
646
|
*out->cur++ = ',';
|
|
640
647
|
}
|
|
641
648
|
// message
|
|
@@ -891,11 +898,11 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
891
898
|
|
|
892
899
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
893
900
|
const char *key = kval->key;
|
|
894
|
-
|
|
901
|
+
size_t klen = kval->klen;
|
|
895
902
|
Val parent = stack_peek(&pi->stack);
|
|
896
903
|
|
|
897
904
|
if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
|
|
898
|
-
*pi->options.create_id == *key && (
|
|
905
|
+
*pi->options.create_id == *key && (size_t)pi->options.create_id_len == klen &&
|
|
899
906
|
0 == strncmp(pi->options.create_id, key, klen)) {
|
|
900
907
|
parent->clas = oj_name2class(pi, str, len, false, rb_eArgError);
|
|
901
908
|
if (2 == klen && '^' == *key && 'o' == key[1]) {
|
|
@@ -910,7 +917,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
|
910
917
|
volatile VALUE rkey = oj_calc_hash_key(pi, kval);
|
|
911
918
|
|
|
912
919
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
913
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
920
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
914
921
|
|
|
915
922
|
if (Qnil != clas) {
|
|
916
923
|
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
@@ -1015,7 +1022,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
|
1015
1022
|
volatile VALUE rstr = rb_utf8_str_new(str, len);
|
|
1016
1023
|
|
|
1017
1024
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
1018
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
1025
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
1019
1026
|
|
|
1020
1027
|
if (Qnil != clas) {
|
|
1021
1028
|
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|