oj 3.16.16 → 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 +30 -0
- data/README.md +0 -16
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +7 -2
- data/ext/oj/dump.c +113 -37
- data/ext/oj/dump.h +2 -0
- data/ext/oj/dump_compat.c +5 -0
- data/ext/oj/dump_object.c +5 -0
- data/ext/oj/dump_strict.c +13 -8
- data/ext/oj/fast.c +36 -16
- data/ext/oj/intern.c +1 -1
- data/ext/oj/mimic_json.c +3 -0
- data/ext/oj/oj.c +162 -1
- data/ext/oj/oj.h +55 -52
- data/ext/oj/parse.c +40 -12
- data/ext/oj/parser.c +112 -43
- data/ext/oj/rails.c +15 -15
- 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 +10 -2
- data/ext/oj/simd.h +25 -0
- data/ext/oj/sparse.c +6 -3
- data/ext/oj/usual.c +18 -5
- data/ext/oj/wab.c +1 -1
- data/lib/oj/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7458dcdf494ef6b1b283ca86d51fba0b3102ecf5cec13f43682878c01708c80
|
|
4
|
+
data.tar.gz: ab8099b8b275aa5acab45a012bbc96ef0c860e041be2c4ae7d6f7cd331da1755
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60d445fd27bbea120359c21d0c1b0ac1d4fbbd678c8fd28efe620706d382a2f0cc434645967c9bac0b6d08d1065fe99dc4b15e2623d98ca0e15a61eb591a993b
|
|
7
|
+
data.tar.gz: b7736fd3a7b27f98ef3e4df05464000849403ff33a3f82ecd6d8c51b40d0c2753d23ed14c078eb26506d504de991e35ebe68e5703225c80aab6ebbd28b7a80dc
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 3.17.3 - 2026-06-04
|
|
4
|
+
|
|
5
|
+
- Fixed issue in intern.c and fast.c.
|
|
6
|
+
|
|
7
|
+
## 3.17.2 - 2026-05-27
|
|
8
|
+
|
|
9
|
+
- Fixed multiple issues related to extreme sizes.
|
|
10
|
+
|
|
11
|
+
## 3.17.1 - 2026-05-15
|
|
12
|
+
|
|
13
|
+
- Fixed "quoted string not terminated" error.
|
|
14
|
+
|
|
15
|
+
## 3.17.0 - 2026-04-19
|
|
16
|
+
|
|
17
|
+
- A "safe" parser has been added as a variation of the Oj:Parser thanks to @meinac.
|
|
18
|
+
|
|
19
|
+
## 3.16.17 - 2026-04-12
|
|
20
|
+
|
|
21
|
+
- Rails optimize for Hash and Array now overrides `as_json` for those
|
|
22
|
+
classes. Note that when either is optimized with `Oj.optimize_rails`
|
|
23
|
+
the `Array.as_json` and `Hash.as_json` will not be called.
|
|
24
|
+
|
|
25
|
+
- Add support for the rails encoder `:only` and `:except` options.
|
|
26
|
+
|
|
27
|
+
- Handle unterminated strings in usual parser (#1002)
|
|
28
|
+
|
|
29
|
+
- Fix read() not handling partial reads for large files (#1004)
|
|
30
|
+
|
|
31
|
+
- Raise error for incomplete primitive literals (#1005)
|
|
32
|
+
|
|
3
33
|
## 3.16.16 - 2026-03-13
|
|
4
34
|
|
|
5
35
|
- Not closed arrays and objects are reported corrected in the usual parser.
|
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/compat.c
CHANGED
|
@@ -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);
|
|
@@ -910,7 +915,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
|
910
915
|
volatile VALUE rkey = oj_calc_hash_key(pi, kval);
|
|
911
916
|
|
|
912
917
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
913
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
918
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
914
919
|
|
|
915
920
|
if (Qnil != clas) {
|
|
916
921
|
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
@@ -1015,7 +1020,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
|
1015
1020
|
volatile VALUE rstr = rb_utf8_str_new(str, len);
|
|
1016
1021
|
|
|
1017
1022
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
1018
|
-
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str,
|
|
1023
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
|
|
1019
1024
|
|
|
1020
1025
|
if (Qnil != clas) {
|
|
1021
1026
|
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
data/ext/oj/dump.c
CHANGED
|
@@ -40,7 +40,7 @@ static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
|
|
40
40
|
static const char hex_chars[17] = "0123456789abcdef";
|
|
41
41
|
|
|
42
42
|
// JSON standard except newlines are no escaped
|
|
43
|
-
static char newline_friendly_chars[
|
|
43
|
+
static char newline_friendly_chars[257] = "\
|
|
44
44
|
66666666221622666666666666666666\
|
|
45
45
|
11211111111111111111111111111111\
|
|
46
46
|
11111111111111111111111111112111\
|
|
@@ -51,7 +51,7 @@ static char newline_friendly_chars[256] = "\
|
|
|
51
51
|
11111111111111111111111111111111";
|
|
52
52
|
|
|
53
53
|
// JSON standard
|
|
54
|
-
static char hibit_friendly_chars[
|
|
54
|
+
static char hibit_friendly_chars[257] = "\
|
|
55
55
|
66666666222622666666666666666666\
|
|
56
56
|
11211111111111111111111111111111\
|
|
57
57
|
11111111111111111111111111112111\
|
|
@@ -62,7 +62,7 @@ static char hibit_friendly_chars[256] = "\
|
|
|
62
62
|
11111111111111111111111111111111";
|
|
63
63
|
|
|
64
64
|
// JSON standard but escape forward slashes `/`
|
|
65
|
-
static char slash_friendly_chars[
|
|
65
|
+
static char slash_friendly_chars[257] = "\
|
|
66
66
|
66666666222622666666666666666666\
|
|
67
67
|
11211111111111121111111111111111\
|
|
68
68
|
11111111111111111111111111112111\
|
|
@@ -74,7 +74,7 @@ static char slash_friendly_chars[256] = "\
|
|
|
74
74
|
|
|
75
75
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
|
76
76
|
// bytes per character in the output. That makes this conservative.
|
|
77
|
-
static char ascii_friendly_chars[
|
|
77
|
+
static char ascii_friendly_chars[257] = "\
|
|
78
78
|
66666666222622666666666666666666\
|
|
79
79
|
11211111111111111111111111111111\
|
|
80
80
|
11111111111111111111111111112111\
|
|
@@ -85,7 +85,7 @@ static char ascii_friendly_chars[256] = "\
|
|
|
85
85
|
33333333333333333333333333333333";
|
|
86
86
|
|
|
87
87
|
// XSS safe mode
|
|
88
|
-
static char xss_friendly_chars[
|
|
88
|
+
static char xss_friendly_chars[257] = "\
|
|
89
89
|
66666666222622666666666666666666\
|
|
90
90
|
11211161111111121111111111116161\
|
|
91
91
|
11111111111111111111111111112111\
|
|
@@ -96,7 +96,7 @@ static char xss_friendly_chars[256] = "\
|
|
|
96
96
|
33333333333333333333333333333333";
|
|
97
97
|
|
|
98
98
|
// JSON XSS combo
|
|
99
|
-
static char hixss_friendly_chars[
|
|
99
|
+
static char hixss_friendly_chars[257] = "\
|
|
100
100
|
66666666222622666666666666666666\
|
|
101
101
|
11211111111111111111111111111111\
|
|
102
102
|
11111111111111111111111111112111\
|
|
@@ -107,7 +107,7 @@ static char hixss_friendly_chars[256] = "\
|
|
|
107
107
|
11611111111111111111111111111111";
|
|
108
108
|
|
|
109
109
|
// Rails XSS combo
|
|
110
|
-
static char rails_xss_friendly_chars[
|
|
110
|
+
static char rails_xss_friendly_chars[257] = "\
|
|
111
111
|
66666666222622666666666666666666\
|
|
112
112
|
11211161111111111111111111116161\
|
|
113
113
|
11111111111111111111111111112111\
|
|
@@ -118,7 +118,7 @@ static char rails_xss_friendly_chars[256] = "\
|
|
|
118
118
|
11611111111111111111111111111111";
|
|
119
119
|
|
|
120
120
|
// Rails HTML non-escape
|
|
121
|
-
static char rails_friendly_chars[
|
|
121
|
+
static char rails_friendly_chars[257] = "\
|
|
122
122
|
66666666222622666666666666666666\
|
|
123
123
|
11211111111111111111111111111111\
|
|
124
124
|
11111111111111111111111111112111\
|
|
@@ -257,7 +257,30 @@ inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
|
|
257
257
|
size += tmp;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
#ifdef HAVE_FAST_MEMCPY
|
|
261
|
+
size_t total = 0;
|
|
262
|
+
if (len - i > 4) {
|
|
263
|
+
size += (len - i);
|
|
264
|
+
unsigned char buf[sizeof(uint8x16_t)];
|
|
265
|
+
memset(buf, ' ', sizeof(buf));
|
|
266
|
+
fast_memcpy16(buf, str, len - i);
|
|
267
|
+
|
|
268
|
+
uint8x16_t chunk = vld1q_u8((const unsigned char *)buf);
|
|
269
|
+
uint8x16_t tmp1 = vqtbl4q_u8(hibit_friendly_chars_neon[0], chunk);
|
|
270
|
+
uint8x16_t tmp2 = vqtbl4q_u8(hibit_friendly_chars_neon[1], veorq_u8(chunk, vdupq_n_u8(0x40)));
|
|
271
|
+
uint8x16_t result = vorrq_u8(tmp1, tmp2);
|
|
272
|
+
uint8_t tmp = vaddvq_u8(result);
|
|
273
|
+
|
|
274
|
+
size += tmp;
|
|
275
|
+
|
|
276
|
+
total = size;
|
|
277
|
+
} else {
|
|
278
|
+
total = size + calculate_string_size(str, len - i, hibit_friendly_chars);
|
|
279
|
+
}
|
|
280
|
+
#else
|
|
260
281
|
size_t total = size + calculate_string_size(str, len - i, hibit_friendly_chars);
|
|
282
|
+
#endif
|
|
283
|
+
|
|
261
284
|
return total;
|
|
262
285
|
#elif defined(HAVE_SIMD_SSE4_2)
|
|
263
286
|
if (SIMD_Impl == SIMD_SSE42) {
|
|
@@ -967,11 +990,12 @@ typedef struct _neon_match_result {
|
|
|
967
990
|
uint8x16_t needs_escape;
|
|
968
991
|
bool has_some_hibit;
|
|
969
992
|
bool do_unicode_validation;
|
|
993
|
+
uint64_t escape_mask;
|
|
970
994
|
} neon_match_result;
|
|
971
995
|
|
|
972
996
|
static inline FORCE_INLINE neon_match_result
|
|
973
997
|
neon_update(const char *str, uint8x16x4_t *cmap_neon, int neon_table_size, bool do_unicode_validation, bool has_hi) {
|
|
974
|
-
neon_match_result result = {.has_some_hibit = false, .do_unicode_validation = false};
|
|
998
|
+
neon_match_result result = {.has_some_hibit = false, .do_unicode_validation = false, .escape_mask = 0};
|
|
975
999
|
|
|
976
1000
|
uint8x16_t chunk = vld1q_u8((const unsigned char *)str);
|
|
977
1001
|
uint8x16_t tmp1 = vqtbl4q_u8(cmap_neon[0], chunk);
|
|
@@ -987,6 +1011,9 @@ neon_update(const char *str, uint8x16x4_t *cmap_neon, int neon_table_size, bool
|
|
|
987
1011
|
result.has_some_hibit = vmaxvq_u8(has_some_hibit) != 0;
|
|
988
1012
|
result.do_unicode_validation = has_hi && do_unicode_validation && result.has_some_hibit;
|
|
989
1013
|
}
|
|
1014
|
+
const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(vmvnq_u8(vceqq_u8(result.needs_escape, vdupq_n_u8(0)))), 4);
|
|
1015
|
+
const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
|
|
1016
|
+
result.escape_mask = mask & 0x8888888888888888ull;
|
|
990
1017
|
return result;
|
|
991
1018
|
}
|
|
992
1019
|
|
|
@@ -1189,7 +1216,16 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
1189
1216
|
if (is_sym) {
|
|
1190
1217
|
*out->cur++ = ':';
|
|
1191
1218
|
}
|
|
1219
|
+
#ifdef HAVE_FAST_MEMCPY
|
|
1220
|
+
if (cnt <= 16) {
|
|
1221
|
+
fast_memcpy16(out->cur, str, cnt);
|
|
1222
|
+
out->cur += size;
|
|
1223
|
+
} else {
|
|
1224
|
+
APPEND_CHARS(out->cur, str, cnt);
|
|
1225
|
+
}
|
|
1226
|
+
#else
|
|
1192
1227
|
APPEND_CHARS(out->cur, str, cnt);
|
|
1228
|
+
#endif
|
|
1193
1229
|
*out->cur++ = '"';
|
|
1194
1230
|
} else {
|
|
1195
1231
|
const char *end = str + cnt;
|
|
@@ -1223,6 +1259,17 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
1223
1259
|
#endif
|
|
1224
1260
|
|
|
1225
1261
|
#ifdef HAVE_SIMD_NEON
|
|
1262
|
+
|
|
1263
|
+
#ifdef HAVE_FAST_MEMCPY
|
|
1264
|
+
#define APPEND_CHARS_SMALL(dst, src, length) \
|
|
1265
|
+
fast_memcpy16((dst), (src), (length)); \
|
|
1266
|
+
(dst) += (length);
|
|
1267
|
+
#define MEMCPY16 fast_memcpy16
|
|
1268
|
+
#else
|
|
1269
|
+
#define APPEND_CHARS_SMALL(dst, src, length) APPEND_CHARS(dst, str, length);
|
|
1270
|
+
#define MEMCPY16 memcpy
|
|
1271
|
+
#endif
|
|
1272
|
+
|
|
1226
1273
|
if (use_simd) {
|
|
1227
1274
|
while (str < end) {
|
|
1228
1275
|
const char *chunk_ptr = NULL;
|
|
@@ -1231,8 +1278,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
1231
1278
|
chunk_start = str;
|
|
1232
1279
|
chunk_end = str + sizeof(uint8x16_t);
|
|
1233
1280
|
} else if ((end - str) >= SIMD_MINIMUM_THRESHOLD) {
|
|
1234
|
-
memset(out->cur, '
|
|
1235
|
-
|
|
1281
|
+
memset(out->cur, ' ', sizeof(uint8x16_t));
|
|
1282
|
+
MEMCPY16(out->cur, str, (end - str));
|
|
1236
1283
|
chunk_ptr = out->cur;
|
|
1237
1284
|
chunk_start = str;
|
|
1238
1285
|
chunk_end = end;
|
|
@@ -1244,32 +1291,22 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
1244
1291
|
neon_table_size,
|
|
1245
1292
|
do_unicode_validation,
|
|
1246
1293
|
has_hi);
|
|
1247
|
-
if ((result.do_unicode_validation) ||
|
|
1294
|
+
if ((result.do_unicode_validation) || result.escape_mask != 0) {
|
|
1248
1295
|
SEARCH_FLUSH;
|
|
1249
|
-
|
|
1250
|
-
|
|
1296
|
+
bool process_each = result.do_unicode_validation;
|
|
1297
|
+
uint8x16_t actions = vaddq_u8(result.needs_escape, vdupq_n_u8('1'));
|
|
1251
1298
|
vst1q_u8((unsigned char *)matches, actions);
|
|
1252
|
-
bool process_each = result.do_unicode_validation || (num_matches > sizeof(uint8x16_t) / 2);
|
|
1253
1299
|
// If no byte in this chunk had the high bit set then we can skip
|
|
1254
1300
|
// all of the '1' bytes by directly copying them to the output.
|
|
1255
1301
|
if (!process_each) {
|
|
1256
|
-
while (
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1302
|
+
while (result.escape_mask) {
|
|
1303
|
+
int esc_pos = OJ_CTZ64(result.escape_mask) >> 2;
|
|
1304
|
+
long run_len = esc_pos - (str - chunk_start);
|
|
1305
|
+
if (run_len > 0) {
|
|
1306
|
+
APPEND_CHARS_SMALL(out->cur, str, run_len);
|
|
1307
|
+
str += run_len;
|
|
1261
1308
|
}
|
|
1262
|
-
|
|
1263
|
-
if (str >= chunk_end) {
|
|
1264
|
-
break;
|
|
1265
|
-
}
|
|
1266
|
-
str = process_character(action, str, end, out, orig, do_unicode_validation, &check_start);
|
|
1267
|
-
str++;
|
|
1268
|
-
}
|
|
1269
|
-
} else {
|
|
1270
|
-
while (str < chunk_end) {
|
|
1271
|
-
long match_index = str - chunk_start;
|
|
1272
|
-
str = process_character(matches[match_index],
|
|
1309
|
+
str = process_character(matches[esc_pos],
|
|
1273
1310
|
str,
|
|
1274
1311
|
end,
|
|
1275
1312
|
out,
|
|
@@ -1277,6 +1314,23 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
1277
1314
|
do_unicode_validation,
|
|
1278
1315
|
&check_start);
|
|
1279
1316
|
str++;
|
|
1317
|
+
result.escape_mask &= result.escape_mask - 1;
|
|
1318
|
+
}
|
|
1319
|
+
if (str < chunk_end) {
|
|
1320
|
+
APPEND_CHARS_SMALL(out->cur, str, chunk_end - str);
|
|
1321
|
+
str = chunk_end;
|
|
1322
|
+
}
|
|
1323
|
+
} else {
|
|
1324
|
+
while (str < chunk_end) {
|
|
1325
|
+
long match_index = str - chunk_start;
|
|
1326
|
+
str = process_character(matches[match_index],
|
|
1327
|
+
str,
|
|
1328
|
+
end,
|
|
1329
|
+
out,
|
|
1330
|
+
orig,
|
|
1331
|
+
do_unicode_validation,
|
|
1332
|
+
&check_start);
|
|
1333
|
+
str++;
|
|
1280
1334
|
}
|
|
1281
1335
|
}
|
|
1282
1336
|
cursor = str;
|
|
@@ -1317,12 +1371,12 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
1317
1371
|
while (str < chunk_end) {
|
|
1318
1372
|
long match_index = str - chunk_start;
|
|
1319
1373
|
str = process_character(matches[match_index],
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1374
|
+
str,
|
|
1375
|
+
end,
|
|
1376
|
+
out,
|
|
1377
|
+
orig,
|
|
1378
|
+
do_unicode_validation,
|
|
1379
|
+
&check_start);
|
|
1326
1380
|
str++;
|
|
1327
1381
|
}
|
|
1328
1382
|
cursor = str;
|
|
@@ -1687,3 +1741,25 @@ size_t oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const c
|
|
|
1687
1741
|
}
|
|
1688
1742
|
return cnt;
|
|
1689
1743
|
}
|
|
1744
|
+
|
|
1745
|
+
bool oj_key_skip(VALUE key, const char *only, const char *except) {
|
|
1746
|
+
const char *skey;
|
|
1747
|
+
|
|
1748
|
+
switch (rb_type(key)) {
|
|
1749
|
+
case RUBY_T_STRING: skey = StringValueCStr(key); break;
|
|
1750
|
+
case RUBY_T_SYMBOL: skey = rb_id2name(rb_sym2id(key)); break;
|
|
1751
|
+
default: skey = NULL; break;
|
|
1752
|
+
}
|
|
1753
|
+
if (NULL != skey && '\0' != *skey) {
|
|
1754
|
+
size_t size = strlen(skey);
|
|
1755
|
+
char *buf = alloca(size + 3);
|
|
1756
|
+
|
|
1757
|
+
buf[0] = ':';
|
|
1758
|
+
strcpy(buf + 1, skey);
|
|
1759
|
+
buf[size + 1] = ':';
|
|
1760
|
+
buf[size + 2] = '\0';
|
|
1761
|
+
|
|
1762
|
+
return ((NULL != only && NULL == strstr(only, buf)) || (NULL != except && NULL != strstr(except, buf)));
|
|
1763
|
+
}
|
|
1764
|
+
return NULL != only;
|
|
1765
|
+
}
|
data/ext/oj/dump.h
CHANGED
|
@@ -62,6 +62,8 @@ extern size_t oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d,
|
|
|
62
62
|
|
|
63
63
|
extern time_t oj_sec_from_time_hard_way(VALUE obj);
|
|
64
64
|
|
|
65
|
+
extern bool oj_key_skip(VALUE key, const char *only, const char *except);
|
|
66
|
+
|
|
65
67
|
inline static void assure_size(Out out, size_t len) {
|
|
66
68
|
if (out->end - out->cur <= (long)len) {
|
|
67
69
|
oj_grow_out(out, len);
|
data/ext/oj/dump_compat.c
CHANGED
|
@@ -605,6 +605,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
605
605
|
if (out->omit_nil && Qnil == value) {
|
|
606
606
|
return ST_CONTINUE;
|
|
607
607
|
}
|
|
608
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
609
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
610
|
+
return ST_CONTINUE;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
608
613
|
if (!out->opts->dump_opts.use) {
|
|
609
614
|
assure_size(out, depth * out->indent + 1);
|
|
610
615
|
fill_indent(out, depth);
|
data/ext/oj/dump_object.c
CHANGED
|
@@ -210,6 +210,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
210
210
|
if (out->omit_nil && Qnil == value) {
|
|
211
211
|
return ST_CONTINUE;
|
|
212
212
|
}
|
|
213
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
214
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
215
|
+
return ST_CONTINUE;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
213
218
|
assure_size(out, size);
|
|
214
219
|
fill_indent(out, depth);
|
|
215
220
|
switch (rb_type(key)) {
|
data/ext/oj/dump_strict.c
CHANGED
|
@@ -193,14 +193,19 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
193
193
|
if (out->omit_nil && Qnil == value) {
|
|
194
194
|
return ST_CONTINUE;
|
|
195
195
|
}
|
|
196
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
197
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
198
|
+
return ST_CONTINUE;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
196
201
|
if (!out->opts->dump_opts.use) {
|
|
197
202
|
size = depth * out->indent + 1;
|
|
198
203
|
assure_size(out, size);
|
|
199
204
|
fill_indent(out, depth);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
205
|
+
switch (rtype) {
|
|
206
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
207
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
208
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
204
209
|
}
|
|
205
210
|
*out->cur++ = ':';
|
|
206
211
|
} else {
|
|
@@ -215,10 +220,10 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
215
220
|
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
223
|
+
switch (rtype) {
|
|
224
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
225
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
226
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
222
227
|
}
|
|
223
228
|
size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
224
229
|
assure_size(out, size);
|
data/ext/oj/fast.c
CHANGED
|
@@ -80,21 +80,10 @@ static void each_leaf(Doc doc, VALUE self);
|
|
|
80
80
|
static int move_step(Doc doc, const char *path, int loc);
|
|
81
81
|
static Leaf get_doc_leaf(Doc doc, const char *path);
|
|
82
82
|
static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
|
|
83
|
-
static void each_value(Doc doc, Leaf leaf);
|
|
83
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self);
|
|
84
84
|
|
|
85
85
|
VALUE oj_doc_class = Qundef;
|
|
86
86
|
|
|
87
|
-
// This is only for CentOS 5.4 with Ruby 1.9.3-p0.
|
|
88
|
-
#ifndef HAVE_STPCPY
|
|
89
|
-
char *stpcpy(char *dest, const char *src) {
|
|
90
|
-
size_t cnt = strlen(src);
|
|
91
|
-
|
|
92
|
-
strcpy(dest, src);
|
|
93
|
-
|
|
94
|
-
return dest + cnt;
|
|
95
|
-
}
|
|
96
|
-
#endif
|
|
97
|
-
|
|
98
87
|
inline static void next_non_white(ParseInfo pi) {
|
|
99
88
|
for (; 1; pi->s++) {
|
|
100
89
|
switch (*pi->s) {
|
|
@@ -246,6 +235,19 @@ static void skip_comment(ParseInfo pi) {
|
|
|
246
235
|
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
247
236
|
#endif
|
|
248
237
|
|
|
238
|
+
static void validate_integer_size(size_t limit, char *head, char *tail) {
|
|
239
|
+
size_t total = (size_t)(tail - head);
|
|
240
|
+
bool has_sign = (head[0] == '-' || head[0] == '+');
|
|
241
|
+
size_t digit_count = total - (has_sign ? 1 : 0);
|
|
242
|
+
|
|
243
|
+
if (digit_count > limit) {
|
|
244
|
+
rb_raise(oj_parse_error_class,
|
|
245
|
+
"integer exceeds :max_integer_digits (%lu > %lu)",
|
|
246
|
+
(unsigned long)digit_count,
|
|
247
|
+
(unsigned long)limit);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
249
251
|
static void leaf_fixnum_value(Leaf leaf) {
|
|
250
252
|
char *s = leaf->str;
|
|
251
253
|
int64_t n = 0;
|
|
@@ -265,7 +267,12 @@ static void leaf_fixnum_value(Leaf leaf) {
|
|
|
265
267
|
}
|
|
266
268
|
}
|
|
267
269
|
if (big) {
|
|
268
|
-
|
|
270
|
+
size_t limit = oj_default_options.max_integer_digits;
|
|
271
|
+
char c = *s;
|
|
272
|
+
|
|
273
|
+
if (0 < limit) {
|
|
274
|
+
validate_integer_size(limit, leaf->str, s);
|
|
275
|
+
}
|
|
269
276
|
|
|
270
277
|
*s = '\0';
|
|
271
278
|
leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
|
|
@@ -950,6 +957,9 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
|
950
957
|
}
|
|
951
958
|
} else {
|
|
952
959
|
rb_yield(self);
|
|
960
|
+
if (NULL == DATA_PTR(self)) {
|
|
961
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
962
|
+
}
|
|
953
963
|
}
|
|
954
964
|
}
|
|
955
965
|
|
|
@@ -1043,19 +1053,22 @@ static int move_step(Doc doc, const char *path, int loc) {
|
|
|
1043
1053
|
return loc;
|
|
1044
1054
|
}
|
|
1045
1055
|
|
|
1046
|
-
static void each_value(Doc doc, Leaf leaf) {
|
|
1056
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self) {
|
|
1047
1057
|
if (COL_VAL == leaf->value_type) {
|
|
1048
1058
|
if (0 != leaf->elements) {
|
|
1049
1059
|
Leaf first = leaf->elements->next;
|
|
1050
1060
|
Leaf e = first;
|
|
1051
1061
|
|
|
1052
1062
|
do {
|
|
1053
|
-
each_value(doc, e);
|
|
1063
|
+
each_value(doc, e, self);
|
|
1054
1064
|
e = e->next;
|
|
1055
1065
|
} while (e != first);
|
|
1056
1066
|
}
|
|
1057
1067
|
} else {
|
|
1058
1068
|
rb_yield(leaf_value(doc, leaf));
|
|
1069
|
+
if (NULL == DATA_PTR(self)) {
|
|
1070
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1071
|
+
}
|
|
1059
1072
|
}
|
|
1060
1073
|
}
|
|
1061
1074
|
|
|
@@ -1491,12 +1504,19 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1491
1504
|
Leaf first = (*doc->where)->elements->next;
|
|
1492
1505
|
Leaf e = first;
|
|
1493
1506
|
|
|
1507
|
+
if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
|
|
1508
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
1509
|
+
}
|
|
1494
1510
|
doc->where++;
|
|
1495
1511
|
do {
|
|
1496
1512
|
*doc->where = e;
|
|
1497
1513
|
rb_yield(self);
|
|
1514
|
+
if (NULL == DATA_PTR(self)) {
|
|
1515
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1516
|
+
}
|
|
1498
1517
|
e = e->next;
|
|
1499
1518
|
} while (e != first);
|
|
1519
|
+
doc->where--;
|
|
1500
1520
|
}
|
|
1501
1521
|
if (0 < wlen) {
|
|
1502
1522
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
@@ -1540,7 +1560,7 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
|
1540
1560
|
path = StringValuePtr(*argv);
|
|
1541
1561
|
}
|
|
1542
1562
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
|
1543
|
-
each_value(doc, leaf);
|
|
1563
|
+
each_value(doc, leaf, self);
|
|
1544
1564
|
}
|
|
1545
1565
|
}
|
|
1546
1566
|
return Qnil;
|
data/ext/oj/intern.c
CHANGED
data/ext/oj/mimic_json.c
CHANGED
|
@@ -711,6 +711,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
|
|
|
711
711
|
0, // cache_str
|
|
712
712
|
0, // int_range_min
|
|
713
713
|
0, // int_range_max
|
|
714
|
+
0, // max_integer_digits
|
|
714
715
|
oj_json_class, // create_id
|
|
715
716
|
10, // create_id_len
|
|
716
717
|
3, // sec_prec
|
|
@@ -735,6 +736,8 @@ static struct _options mimic_object_to_json_options = {0, // indent
|
|
|
735
736
|
false, // omit_nil
|
|
736
737
|
false, // omit_null_byte
|
|
737
738
|
100, // max_depth
|
|
739
|
+
NULL, // only
|
|
740
|
+
NULL, // except
|
|
738
741
|
},
|
|
739
742
|
{
|
|
740
743
|
// str_rx
|