oj 3.16.1 → 3.16.4

Sign up to get free protection for your applications and to get access to all the features.
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
  }