oj 3.13.7 → 3.13.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44e493d06f06095e80eb1af563739efca81076a8d3cfd89d02e537ada1f00a60
4
- data.tar.gz: 9502a2285781a49c8a2cec4937bb92c1b04a4c95e44b8f34fdd9a6295f0f69f4
3
+ metadata.gz: dcb5f80ad6384640d44889424c39f91ee2db778b17c91b9505b5b3b4c280abf1
4
+ data.tar.gz: 85b70200f48f46019ecf1020ca8e1b8ea604bca1161120b3747a8aeac2903682
5
5
  SHA512:
6
- metadata.gz: fa5e096b0ec018cc964c98e108967e766454d48bbfbd7a0ec55fc86aa2e4cac1d54f2b069613823d183df128ed836c95b2b3851793243985b531bbe41b045132
7
- data.tar.gz: 22a9ded2a0442a64f4ac91e3fc5b1d0be86ea6c53dd857039a92ef515a74b6e348b3587899df5e4a78550ec8e1c4c7c06986a0b8912ef90a419e6c8ac2f65450
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 (oj_dump_ignore(out->opts, value)) {
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 (oj_dump_ignore(out->opts, value)) {
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(rb_ary_entry(a, i), d2, out, true);
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(rb_ary_entry(ma, i));
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 newline_friendly_size(const uint8_t *str, size_t len) {
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 (; 0 < i; str++, i--) {
126
- size += newline_friendly_chars[*str];
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 hibit_friendly_size(const uint8_t *str, size_t len) {
132
- size_t size = 0;
133
- size_t i = len;
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
- for (; 0 < i; str++, i--) {
136
- size += hibit_friendly_chars[*str];
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
- size_t size = 0;
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
- size_t size = 0;
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
- size_t size = 0;
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
- Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && 0 != (fd = FIX2INT(s))) {
690
- if (size != write(fd, out.buf, size)) {
691
- if (out.allocated) {
692
- xfree(out.buf);
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
- rb_raise(rb_eIOError, "Write failed. [%d:%s]", errno, strerror(errno));
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 <= end - str) {
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 < str - orig && 0 != (0x80 & *(str - 1))) {
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(rb_ary_entry(a, i), d2, out, true);
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(rb_ary_entry(a, i), d2, out);
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 (oj_dump_ignore(out->opts, value)) {
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
- if (rb_type(key) == T_STRING) {
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
- } else if (rb_type(key) == T_SYMBOL) {
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
- } else {
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
- assure_size(out, s2 + 15);
245
- *out->cur++ = '"';
246
- *out->cur++ = '^';
247
- *out->cur++ = '#';
248
- out->hash_cnt++;
249
- for (i = 28; 0 <= i; i -= 4) {
250
- b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
251
- if ('\0' != b) {
252
- started = 1;
253
- }
254
- if (started) {
255
- *out->cur++ = hex_chars[b];
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 (oj_dump_ignore(out->opts, value)) {
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 (oj_dump_ignore(out->opts, value)) {
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(rb_ary_entry(ma, i));
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 (oj_dump_ignore(out->opts, v)) {
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 (oj_dump_ignore(out->opts, v)) {
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(rb_ary_entry(a, i), d2, out);
156
+ oj_dump_null_val(RARRAY_AREF(a, i), d2, out);
157
157
  } else {
158
- oj_dump_strict_val(rb_ary_entry(a, i), d2, out);
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
  }