oj 3.13.7 → 3.13.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +9 -0
- data/ext/oj/custom.c +4 -4
- data/ext/oj/dump.c +63 -88
- data/ext/oj/dump.h +14 -1
- data/ext/oj/dump_compat.c +1 -1
- data/ext/oj/dump_object.c +46 -39
- data/ext/oj/dump_strict.c +2 -2
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/fast.c +13 -3
- data/ext/oj/intern.c +7 -1
- data/ext/oj/mimic_json.c +48 -59
- data/ext/oj/object.c +27 -46
- data/ext/oj/oj.c +109 -153
- data/ext/oj/oj.h +1 -0
- data/ext/oj/parse.c +9 -1
- data/ext/oj/rails.c +5 -5
- data/ext/oj/usual.c +4 -2
- data/ext/oj/wab.c +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Rails.md +12 -0
- data/test/bug.rb +16 -0
- data/test/foo.rb +71 -7
- data/test/test_fast.rb +37 -7
- data/test/test_saj.rb +1 -1
- data/test/test_various.rb +27 -2
- data/test/tests.rb +0 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcb5f80ad6384640d44889424c39f91ee2db778b17c91b9505b5b3b4c280abf1
|
4
|
+
data.tar.gz: 85b70200f48f46019ecf1020ca8e1b8ea604bca1161120b3747a8aeac2903682
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f96776be4f9431b160f1d9f588e8688fb7e0c4a431c58a10fa43a71f5a6f95781456287f40db5dfba03bb69350946ad36f246d0b59c196f9dc95218f51005f7a
|
7
|
+
data.tar.gz: e106b88134f86d82b9740f3e836ecb2aaa4af7ad643b96a4600eaa09392ba5f630c402101a6fb476823c41bc127b5c3d9625c6900a033cf6f9830ca01e57d459
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.13.11 - 2022-01-05
|
4
|
+
|
5
|
+
- Fixed write blocking failures on writes to a slow stream with larger writes.
|
6
|
+
|
7
|
+
## 3.13.10 - 2021-12-12
|
8
|
+
|
9
|
+
- Fixed Oj::Doc re-entrant issue with each_child.
|
10
|
+
- Fixed each_child on empty Oj::Doc.
|
11
|
+
|
12
|
+
## 3.13.9 - 2021-10-06
|
13
|
+
|
14
|
+
- Fix mimic JSON load so that it honors the `:symbolize_names` option.
|
15
|
+
|
16
|
+
## 3.13.8 - 2021-09-27
|
17
|
+
|
18
|
+
- Fix `Oj::Doc` behaviour for inexisting path.
|
19
|
+
```ruby
|
20
|
+
Oj::Doc.open('{"foo":1}') do |doc|
|
21
|
+
doc.fetch('/foo/bar') # used to give `1`, now gives `nil`
|
22
|
+
doc.exists?('/foo/bar') # used to give `true`, now gives `false`
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
- Fix `Oj::Parser` handling of BigDecimal. `snprint()` does not handle `%Lg` correctly but `sprintf()` does.
|
27
|
+
|
3
28
|
## 3.13.7 - 2021-09-16
|
4
29
|
|
5
30
|
- The JSON gem allows invalid unicode so Oj, when mimicing JSON now
|
data/README.md
CHANGED
@@ -43,6 +43,15 @@ or in Bundler:
|
|
43
43
|
gem 'oj'
|
44
44
|
```
|
45
45
|
|
46
|
+
## Rails and json quickstart
|
47
|
+
|
48
|
+
See the Quickstart sections of the [Rails](pages/Rails.md) and [json](pages/JsonGem.md) docs.
|
49
|
+
|
50
|
+
## multi_json
|
51
|
+
|
52
|
+
Code which uses [multi_json](https://github.com/intridea/multi_json)
|
53
|
+
will automatically prefer Oj if it is installed.
|
54
|
+
|
46
55
|
## Support
|
47
56
|
|
48
57
|
[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).
|
data/ext/oj/custom.c
CHANGED
@@ -282,7 +282,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
282
282
|
Out out = (Out)ov;
|
283
283
|
int depth = out->depth;
|
284
284
|
|
285
|
-
if (
|
285
|
+
if (dump_ignore(out->opts, value)) {
|
286
286
|
return ST_CONTINUE;
|
287
287
|
}
|
288
288
|
if (out->omit_nil && Qnil == value) {
|
@@ -577,7 +577,7 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
|
577
577
|
size_t size;
|
578
578
|
const char *attr;
|
579
579
|
|
580
|
-
if (
|
580
|
+
if (dump_ignore(out->opts, value)) {
|
581
581
|
return ST_CONTINUE;
|
582
582
|
}
|
583
583
|
if (out->omit_nil && Qnil == value) {
|
@@ -749,7 +749,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
749
749
|
} else {
|
750
750
|
fill_indent(out, d2);
|
751
751
|
}
|
752
|
-
oj_dump_custom_val(
|
752
|
+
oj_dump_custom_val(RARRAY_AREF(a, i), d2, out, true);
|
753
753
|
if (i < cnt) {
|
754
754
|
*out->cur++ = ',';
|
755
755
|
}
|
@@ -833,7 +833,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
833
833
|
v = rb_struct_aref(obj, INT2FIX(i));
|
834
834
|
#endif
|
835
835
|
if (ma != Qnil) {
|
836
|
-
volatile VALUE s = rb_sym2str(
|
836
|
+
volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
|
837
837
|
|
838
838
|
name = RSTRING_PTR(s);
|
839
839
|
len = (int)RSTRING_LEN(s);
|
data/ext/oj/dump.c
CHANGED
@@ -10,6 +10,9 @@
|
|
10
10
|
#include <stdlib.h>
|
11
11
|
#include <string.h>
|
12
12
|
#include <unistd.h>
|
13
|
+
#if !IS_WINDOWS
|
14
|
+
#include <poll.h>
|
15
|
+
#endif
|
13
16
|
|
14
17
|
#include "cache8.h"
|
15
18
|
#include "odd.h"
|
@@ -113,49 +116,39 @@ static char rails_friendly_chars[256] = "\
|
|
113
116
|
11111111111111111111111111111111";
|
114
117
|
|
115
118
|
static void raise_strict(VALUE obj) {
|
116
|
-
rb_raise(rb_eTypeError,
|
117
|
-
"Failed to dump %s Object to JSON in strict mode.",
|
118
|
-
rb_class2name(rb_obj_class(obj)));
|
119
|
+
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.", rb_class2name(rb_obj_class(obj)));
|
119
120
|
}
|
120
121
|
|
121
|
-
inline static size_t
|
122
|
+
inline static size_t calculate_string_size(const uint8_t *str, size_t len, const char *table) {
|
122
123
|
size_t size = 0;
|
123
124
|
size_t i = len;
|
124
125
|
|
125
|
-
for (;
|
126
|
-
size +=
|
126
|
+
for (; 3 < i; i -= 4) {
|
127
|
+
size += table[*str++];
|
128
|
+
size += table[*str++];
|
129
|
+
size += table[*str++];
|
130
|
+
size += table[*str++];
|
131
|
+
}
|
132
|
+
for (; 0 < i; i--) {
|
133
|
+
size += table[*str++];
|
127
134
|
}
|
128
135
|
return size - len * (size_t)'0';
|
129
136
|
}
|
130
137
|
|
131
|
-
inline static size_t
|
132
|
-
|
133
|
-
|
138
|
+
inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
|
139
|
+
return calculate_string_size(str, len, newline_friendly_chars);
|
140
|
+
}
|
134
141
|
|
135
|
-
|
136
|
-
|
137
|
-
}
|
138
|
-
return size - len * (size_t)'0';
|
142
|
+
inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
143
|
+
return calculate_string_size(str, len, hibit_friendly_chars);
|
139
144
|
}
|
140
145
|
|
141
146
|
inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
|
142
|
-
|
143
|
-
size_t i = len;
|
144
|
-
|
145
|
-
for (; 0 < i; str++, i--) {
|
146
|
-
size += ascii_friendly_chars[*str];
|
147
|
-
}
|
148
|
-
return size - len * (size_t)'0';
|
147
|
+
return calculate_string_size(str, len, ascii_friendly_chars);
|
149
148
|
}
|
150
149
|
|
151
150
|
inline static size_t xss_friendly_size(const uint8_t *str, size_t len) {
|
152
|
-
|
153
|
-
size_t i = len;
|
154
|
-
|
155
|
-
for (; 0 < i; str++, i--) {
|
156
|
-
size += xss_friendly_chars[*str];
|
157
|
-
}
|
158
|
-
return size - len * (size_t)'0';
|
151
|
+
return calculate_string_size(str, len, xss_friendly_chars);
|
159
152
|
}
|
160
153
|
|
161
154
|
inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
|
@@ -188,13 +181,7 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
188
181
|
}
|
189
182
|
|
190
183
|
inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
191
|
-
|
192
|
-
size_t i = len;
|
193
|
-
|
194
|
-
for (; 0 < i; str++, i--) {
|
195
|
-
size += rails_friendly_chars[*str];
|
196
|
-
}
|
197
|
-
return size - len * (size_t)'0';
|
184
|
+
return calculate_string_size(str, len, rails_friendly_chars);
|
198
185
|
}
|
199
186
|
|
200
187
|
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
@@ -535,14 +522,7 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
535
522
|
}
|
536
523
|
if ((0 == nsec && !out->opts->sec_prec_set) || 0 == out->opts->sec_prec) {
|
537
524
|
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
538
|
-
int len = sprintf(buf,
|
539
|
-
"%04d-%02d-%02dT%02d:%02d:%02dZ",
|
540
|
-
ti.year,
|
541
|
-
ti.mon,
|
542
|
-
ti.day,
|
543
|
-
ti.hour,
|
544
|
-
ti.min,
|
545
|
-
ti.sec);
|
525
|
+
int len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
|
546
526
|
oj_dump_cstr(buf, len, 0, 0, out);
|
547
527
|
} else {
|
548
528
|
int len = sprintf(buf,
|
@@ -574,18 +554,7 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
574
554
|
if (9 > out->opts->sec_prec) {
|
575
555
|
format[32] = '0' + out->opts->sec_prec;
|
576
556
|
}
|
577
|
-
len = sprintf(buf,
|
578
|
-
format,
|
579
|
-
ti.year,
|
580
|
-
ti.mon,
|
581
|
-
ti.day,
|
582
|
-
ti.hour,
|
583
|
-
ti.min,
|
584
|
-
ti.sec,
|
585
|
-
(long)nsec,
|
586
|
-
tzsign,
|
587
|
-
tzhour,
|
588
|
-
tzmin);
|
557
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin);
|
589
558
|
oj_dump_cstr(buf, len, 0, 0, out);
|
590
559
|
}
|
591
560
|
}
|
@@ -666,6 +635,21 @@ void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
|
666
635
|
}
|
667
636
|
}
|
668
637
|
|
638
|
+
static void write_ready(int fd) {
|
639
|
+
struct pollfd pp;
|
640
|
+
int i;
|
641
|
+
|
642
|
+
pp.fd = fd;
|
643
|
+
pp.events = POLLERR | POLLOUT;
|
644
|
+
pp.revents = 0;
|
645
|
+
if (0 >= (i = poll(&pp, 1, 5000))) {
|
646
|
+
if (0 == i || EAGAIN == errno) {
|
647
|
+
rb_raise(rb_eIOError, "write timed out");
|
648
|
+
}
|
649
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
650
|
+
}
|
651
|
+
}
|
652
|
+
|
669
653
|
void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
670
654
|
char buf[4096];
|
671
655
|
struct _out out;
|
@@ -685,13 +669,24 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
685
669
|
if (oj_stringio_class == clas) {
|
686
670
|
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
687
671
|
#if !IS_WINDOWS
|
688
|
-
} else if (rb_respond_to(stream, oj_fileno_id) &&
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
672
|
+
} else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
|
673
|
+
0 != (fd = FIX2INT(s))) {
|
674
|
+
ssize_t cnt;
|
675
|
+
ssize_t total = 0;
|
676
|
+
|
677
|
+
while (true) {
|
678
|
+
if (0 > (cnt = write(fd, out.buf + total, size - total))) {
|
679
|
+
if (EAGAIN != errno) {
|
680
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
681
|
+
break;
|
682
|
+
}
|
683
|
+
}
|
684
|
+
total += cnt;
|
685
|
+
if (size <= total) {
|
686
|
+
// Completed
|
687
|
+
break;
|
693
688
|
}
|
694
|
-
|
689
|
+
write_ready(fd);
|
695
690
|
}
|
696
691
|
#endif
|
697
692
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
@@ -835,8 +830,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
835
830
|
for (; str < end; str++) {
|
836
831
|
switch (cmap[(uint8_t)*str]) {
|
837
832
|
case '1':
|
838
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
839
|
-
check_start <= str) {
|
833
|
+
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && check_start <= str) {
|
840
834
|
if (0 != (0x80 & (uint8_t)*str)) {
|
841
835
|
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
842
836
|
check_start = check_unicode(str, end, orig);
|
@@ -860,11 +854,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
860
854
|
}
|
861
855
|
break;
|
862
856
|
case '3': // Unicode
|
863
|
-
if (0xe2 == (uint8_t)*str &&
|
864
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
857
|
+
if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
865
858
|
2 <= end - str) {
|
866
|
-
if (0x80 == (uint8_t)str[1] &&
|
867
|
-
(0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
859
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
868
860
|
str = dump_unicode(str, end, out, orig);
|
869
861
|
} else {
|
870
862
|
check_start = check_unicode(str, end, orig);
|
@@ -883,10 +875,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
883
875
|
dump_hex((uint8_t)*str, out);
|
884
876
|
} else {
|
885
877
|
if (0xe2 == (uint8_t)*str &&
|
886
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
887
|
-
2
|
888
|
-
if (0x80 == (uint8_t)str[1] &&
|
889
|
-
(0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
878
|
+
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) {
|
879
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
890
880
|
str = dump_unicode(str, end, out, orig);
|
891
881
|
} else {
|
892
882
|
check_start = check_unicode(str, end, orig);
|
@@ -902,8 +892,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
902
892
|
}
|
903
893
|
*out->cur++ = '"';
|
904
894
|
}
|
905
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
906
|
-
0
|
895
|
+
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 0 < str - orig &&
|
896
|
+
0 != (0x80 & *(str - 1))) {
|
907
897
|
uint8_t c = (uint8_t) * (str - 1);
|
908
898
|
int i;
|
909
899
|
int scnt = (int)(str - orig);
|
@@ -1064,8 +1054,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1064
1054
|
int cnt = (int)RSTRING_LEN(rs);
|
1065
1055
|
bool dump_as_string = false;
|
1066
1056
|
|
1067
|
-
if (out->opts->int_range_max != 0 ||
|
1068
|
-
out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1057
|
+
if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1069
1058
|
dump_as_string = true;
|
1070
1059
|
assure_size(out, cnt + 2);
|
1071
1060
|
*out->cur++ = '"';
|
@@ -1225,17 +1214,3 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
1225
1214
|
}
|
1226
1215
|
return cnt;
|
1227
1216
|
}
|
1228
|
-
|
1229
|
-
bool oj_dump_ignore(Options opts, VALUE obj) {
|
1230
|
-
if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) {
|
1231
|
-
VALUE *vp = opts->ignore;
|
1232
|
-
VALUE clas = rb_obj_class(obj);
|
1233
|
-
|
1234
|
-
for (; Qnil != *vp; vp++) {
|
1235
|
-
if (clas == *vp) {
|
1236
|
-
return true;
|
1237
|
-
}
|
1238
|
-
}
|
1239
|
-
}
|
1240
|
-
return false;
|
1241
|
-
}
|
data/ext/oj/dump.h
CHANGED
@@ -50,7 +50,6 @@ extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
|
|
50
50
|
|
51
51
|
extern int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format);
|
52
52
|
|
53
|
-
extern bool oj_dump_ignore(Options opts, VALUE obj);
|
54
53
|
extern time_t oj_sec_from_time_hard_way(VALUE obj);
|
55
54
|
|
56
55
|
inline static void assure_size(Out out, size_t len) {
|
@@ -69,6 +68,20 @@ inline static void fill_indent(Out out, int cnt) {
|
|
69
68
|
}
|
70
69
|
}
|
71
70
|
|
71
|
+
inline static bool dump_ignore(Options opts, VALUE obj) {
|
72
|
+
if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) {
|
73
|
+
VALUE *vp = opts->ignore;
|
74
|
+
VALUE clas = rb_obj_class(obj);
|
75
|
+
|
76
|
+
for (; Qnil != *vp; vp++) {
|
77
|
+
if (clas == *vp) {
|
78
|
+
return true;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
return false;
|
83
|
+
}
|
84
|
+
|
72
85
|
inline static void dump_ulong(unsigned long num, Out out) {
|
73
86
|
char buf[32];
|
74
87
|
char *b = buf + sizeof(buf) - 1;
|
data/ext/oj/dump_compat.c
CHANGED
@@ -182,7 +182,7 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
182
182
|
} else {
|
183
183
|
fill_indent(out, d2);
|
184
184
|
}
|
185
|
-
oj_dump_compat_val(
|
185
|
+
oj_dump_compat_val(RARRAY_AREF(a, i), d2, out, true);
|
186
186
|
if (i < cnt) {
|
187
187
|
*out->cur++ = ',';
|
188
188
|
}
|
data/ext/oj/dump_object.c
CHANGED
@@ -157,7 +157,7 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
|
|
157
157
|
} else {
|
158
158
|
fill_indent(out, d2);
|
159
159
|
}
|
160
|
-
oj_dump_obj_val(
|
160
|
+
oj_dump_obj_val(RARRAY_AREF(a, i), d2, out);
|
161
161
|
if (i < cnt) {
|
162
162
|
*out->cur++ = ',';
|
163
163
|
}
|
@@ -218,7 +218,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
218
218
|
int depth = out->depth;
|
219
219
|
long size = depth * out->indent + 1;
|
220
220
|
|
221
|
-
if (
|
221
|
+
if (dump_ignore(out->opts, value)) {
|
222
222
|
return ST_CONTINUE;
|
223
223
|
}
|
224
224
|
if (out->omit_nil && Qnil == value) {
|
@@ -226,47 +226,54 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
226
226
|
}
|
227
227
|
assure_size(out, size);
|
228
228
|
fill_indent(out, depth);
|
229
|
-
|
229
|
+
switch (rb_type(key)) {
|
230
|
+
case T_STRING:
|
230
231
|
dump_str_class(key, Qundef, depth, out);
|
231
232
|
*out->cur++ = ':';
|
232
233
|
oj_dump_obj_val(value, depth, out);
|
233
|
-
|
234
|
+
break;
|
235
|
+
|
236
|
+
case T_SYMBOL:
|
234
237
|
dump_sym(key, 0, out, false);
|
235
238
|
*out->cur++ = ':';
|
236
239
|
oj_dump_obj_val(value, depth, out);
|
237
|
-
|
238
|
-
int d2 = depth + 1;
|
239
|
-
long s2 = size + out->indent + 1;
|
240
|
-
int i;
|
241
|
-
int started = 0;
|
242
|
-
uint8_t b;
|
240
|
+
break;
|
243
241
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
242
|
+
default:
|
243
|
+
{
|
244
|
+
int d2 = depth + 1;
|
245
|
+
long s2 = size + out->indent + 1;
|
246
|
+
int i;
|
247
|
+
int started = 0;
|
248
|
+
uint8_t b;
|
249
|
+
|
250
|
+
assure_size(out, s2 + 15);
|
251
|
+
*out->cur++ = '"';
|
252
|
+
*out->cur++ = '^';
|
253
|
+
*out->cur++ = '#';
|
254
|
+
out->hash_cnt++;
|
255
|
+
for (i = 28; 0 <= i; i -= 4) {
|
256
|
+
b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
|
257
|
+
if ('\0' != b) {
|
258
|
+
started = 1;
|
259
|
+
}
|
260
|
+
if (started) {
|
261
|
+
*out->cur++ = hex_chars[b];
|
262
|
+
}
|
256
263
|
}
|
264
|
+
*out->cur++ = '"';
|
265
|
+
*out->cur++ = ':';
|
266
|
+
*out->cur++ = '[';
|
267
|
+
fill_indent(out, d2);
|
268
|
+
oj_dump_obj_val(key, d2, out);
|
269
|
+
assure_size(out, s2);
|
270
|
+
*out->cur++ = ',';
|
271
|
+
fill_indent(out, d2);
|
272
|
+
oj_dump_obj_val(value, d2, out);
|
273
|
+
assure_size(out, size);
|
274
|
+
fill_indent(out, depth);
|
275
|
+
*out->cur++ = ']';
|
257
276
|
}
|
258
|
-
*out->cur++ = '"';
|
259
|
-
*out->cur++ = ':';
|
260
|
-
*out->cur++ = '[';
|
261
|
-
fill_indent(out, d2);
|
262
|
-
oj_dump_obj_val(key, d2, out);
|
263
|
-
assure_size(out, s2);
|
264
|
-
*out->cur++ = ',';
|
265
|
-
fill_indent(out, d2);
|
266
|
-
oj_dump_obj_val(value, d2, out);
|
267
|
-
assure_size(out, size);
|
268
|
-
fill_indent(out, depth);
|
269
|
-
*out->cur++ = ']';
|
270
277
|
}
|
271
278
|
out->depth = depth;
|
272
279
|
*out->cur++ = ',';
|
@@ -342,7 +349,7 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
|
342
349
|
size_t size = depth * out->indent + 1;
|
343
350
|
const char *attr = rb_id2name(key);
|
344
351
|
|
345
|
-
if (
|
352
|
+
if (dump_ignore(out->opts, value)) {
|
346
353
|
return ST_CONTINUE;
|
347
354
|
}
|
348
355
|
if (out->omit_nil && Qnil == value) {
|
@@ -605,7 +612,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
605
612
|
}
|
606
613
|
value = rb_ivar_get(obj, vid);
|
607
614
|
|
608
|
-
if (
|
615
|
+
if (dump_ignore(out->opts, value)) {
|
609
616
|
continue;
|
610
617
|
}
|
611
618
|
if (out->omit_nil && Qnil == value) {
|
@@ -694,7 +701,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
694
701
|
|
695
702
|
*out->cur++ = '[';
|
696
703
|
for (i = 0; i < cnt; i++) {
|
697
|
-
volatile VALUE s = rb_sym2str(
|
704
|
+
volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
|
698
705
|
|
699
706
|
name = RSTRING_PTR(s);
|
700
707
|
len = (int)RSTRING_LEN(s);
|
@@ -730,7 +737,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
730
737
|
|
731
738
|
for (i = 0; i < cnt; i++) {
|
732
739
|
v = RSTRUCT_GET(obj, i);
|
733
|
-
if (
|
740
|
+
if (dump_ignore(out->opts, v)) {
|
734
741
|
v = Qnil;
|
735
742
|
}
|
736
743
|
assure_size(out, size);
|
@@ -748,7 +755,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
748
755
|
for (i = 0; i < slen; i++) {
|
749
756
|
assure_size(out, size);
|
750
757
|
fill_indent(out, d3);
|
751
|
-
if (
|
758
|
+
if (dump_ignore(out->opts, v)) {
|
752
759
|
v = Qnil;
|
753
760
|
}
|
754
761
|
oj_dump_obj_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true);
|
data/ext/oj/dump_strict.c
CHANGED
@@ -153,9 +153,9 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
153
153
|
fill_indent(out, d2);
|
154
154
|
}
|
155
155
|
if (NullMode == out->opts->mode) {
|
156
|
-
oj_dump_null_val(
|
156
|
+
oj_dump_null_val(RARRAY_AREF(a, i), d2, out);
|
157
157
|
} else {
|
158
|
-
oj_dump_strict_val(
|
158
|
+
oj_dump_strict_val(RARRAY_AREF(a, i), d2, out);
|
159
159
|
}
|
160
160
|
if (i < cnt) {
|
161
161
|
*out->cur++ = ',';
|
data/ext/oj/encoder.c
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
// Copyright (c) 2011, 2022 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
|
+
|
4
|
+
#include "oj.h"
|
5
|
+
|
6
|
+
typedef struct _encoder {
|
7
|
+
int indent; // indention for dump, default 2
|
8
|
+
char circular; // YesNo
|
9
|
+
char escape_mode; // Escape_Mode
|
10
|
+
char mode; // Mode
|
11
|
+
char time_format; // TimeFormat
|
12
|
+
char bigdec_as_num; // YesNo
|
13
|
+
char to_hash; // YesNo
|
14
|
+
char to_json; // YesNo
|
15
|
+
char as_json; // YesNo
|
16
|
+
char raw_json; // YesNo
|
17
|
+
char trace; // YesNo
|
18
|
+
char sec_prec_set; // boolean (0 or 1)
|
19
|
+
char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes
|
20
|
+
int64_t int_range_min; // dump numbers below as string
|
21
|
+
int64_t int_range_max; // dump numbers above as string
|
22
|
+
const char* create_id; // 0 or string
|
23
|
+
size_t create_id_len; // length of create_id
|
24
|
+
int sec_prec; // second precision when dumping time
|
25
|
+
char float_prec; // float precision, linked to float_fmt
|
26
|
+
char float_fmt[7]; // float format for dumping, if empty use Ruby
|
27
|
+
struct _dumpOpts dump_opts;
|
28
|
+
struct _rxClass str_rx;
|
29
|
+
VALUE* ignore; // Qnil terminated array of classes or NULL
|
30
|
+
} * Encoder;
|
31
|
+
|
32
|
+
/*
|
33
|
+
rb_define_module_function(Oj, "encode", encode, -1);
|
34
|
+
rb_define_module_function(Oj, "to_file", to_file, -1); // or maybe just write
|
35
|
+
rb_define_module_function(Oj, "to_stream", to_stream, -1);
|
36
|
+
*/
|
37
|
+
|
38
|
+
// write(to, obj)
|
39
|
+
// if to is a string then open file
|
40
|
+
// else if stream then write to stream
|
41
|
+
// handle non-blocking
|
42
|
+
|
43
|
+
// should each mode have a different encoder or use delegates like the parser?
|
data/ext/oj/fast.c
CHANGED
@@ -771,7 +771,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
771
771
|
pi.doc = doc;
|
772
772
|
#if IS_WINDOWS
|
773
773
|
// assume a 1M stack and give half to ruby
|
774
|
-
pi.stack_min = (void*)((char*)&pi - (512 * 1024));
|
774
|
+
pi.stack_min = (void *)((char *)&pi - (512 * 1024));
|
775
775
|
#else
|
776
776
|
{
|
777
777
|
struct rlimit lim;
|
@@ -879,6 +879,10 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
879
879
|
}
|
880
880
|
} else if (NULL == leaf->elements) {
|
881
881
|
leaf = NULL;
|
882
|
+
} else if (STR_VAL == leaf->value_type || RUBY_VAL == leaf->value_type) {
|
883
|
+
// We are trying to get a children of a leaf, which
|
884
|
+
// doesn't exist.
|
885
|
+
leaf = NULL;
|
882
886
|
} else if (COL_VAL == leaf->value_type) {
|
883
887
|
Leaf first = leaf->elements->next;
|
884
888
|
Leaf e = first;
|
@@ -1373,8 +1377,8 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
|
|
1373
1377
|
* Returns true if the value at the location identified by the path exists.
|
1374
1378
|
* @param [String] path path to the location
|
1375
1379
|
* @example
|
1376
|
-
* Oj::Doc.open('[1,2]') { |doc| doc.exists('/1') } #=> true
|
1377
|
-
* Oj::Doc.open('[1,2]') { |doc| doc.exists('/3') } #=> false
|
1380
|
+
* Oj::Doc.open('[1,2]') { |doc| doc.exists?('/1') } #=> true
|
1381
|
+
* Oj::Doc.open('[1,2]') { |doc| doc.exists?('/3') } #=> false
|
1378
1382
|
*/
|
1379
1383
|
static VALUE doc_exists(VALUE self, VALUE str) {
|
1380
1384
|
Doc doc;
|
@@ -1488,6 +1492,7 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1488
1492
|
Doc doc = self_doc(self);
|
1489
1493
|
const char *path = 0;
|
1490
1494
|
size_t wlen;
|
1495
|
+
Leaf * where_orig = doc->where;
|
1491
1496
|
|
1492
1497
|
wlen = doc->where - doc->where_path;
|
1493
1498
|
if (0 < wlen) {
|
@@ -1504,9 +1509,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1504
1509
|
if (0 < wlen) {
|
1505
1510
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1506
1511
|
}
|
1512
|
+
doc->where = where_orig;
|
1507
1513
|
return Qnil;
|
1508
1514
|
}
|
1509
1515
|
}
|
1516
|
+
if (NULL == doc->where || NULL == *doc->where) {
|
1517
|
+
return Qnil;
|
1518
|
+
}
|
1510
1519
|
if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) {
|
1511
1520
|
Leaf first = (*doc->where)->elements->next;
|
1512
1521
|
Leaf e = first;
|
@@ -1521,6 +1530,7 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1521
1530
|
if (0 < wlen) {
|
1522
1531
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1523
1532
|
}
|
1533
|
+
doc->where = where_orig;
|
1524
1534
|
}
|
1525
1535
|
return Qnil;
|
1526
1536
|
}
|