oj 3.16.1 → 3.16.4

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