json 2.8.1 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,19 +26,6 @@ static const char deprecated_create_additions_warning[] =
26
26
  "and will be removed in 3.0, use JSON.unsafe_load or explicitly "
27
27
  "pass `create_additions: true`";
28
28
 
29
- #ifndef HAVE_RB_GC_MARK_LOCATIONS
30
- // For TruffleRuby
31
- void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
32
- {
33
- VALUE *value = start;
34
-
35
- while (value < end) {
36
- rb_gc_mark(*value);
37
- value++;
38
- }
39
- }
40
- #endif
41
-
42
29
  #ifndef HAVE_RB_HASH_BULK_INSERT
43
30
  // For TruffleRuby
44
31
  void rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
@@ -264,7 +251,10 @@ static inline void rvalue_stack_pop(rvalue_stack *stack, long count)
264
251
  static void rvalue_stack_mark(void *ptr)
265
252
  {
266
253
  rvalue_stack *stack = (rvalue_stack *)ptr;
267
- rb_gc_mark_locations(stack->ptr, stack->ptr + stack->head);
254
+ long index;
255
+ for (index = 0; index < stack->head; index++) {
256
+ rb_gc_mark(stack->ptr[index]);
257
+ }
268
258
  }
269
259
 
270
260
  static void rvalue_stack_free(void *ptr)
@@ -392,6 +382,7 @@ typedef struct JSON_ParserStruct {
392
382
  VALUE decimal_class;
393
383
  VALUE match_string;
394
384
  FBuffer fbuffer;
385
+ int in_array;
395
386
  int max_nesting;
396
387
  bool allow_nan;
397
388
  bool allow_trailing_comma;
@@ -420,8 +411,7 @@ static const rb_data_type_t JSON_Parser_type;
420
411
  static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
421
412
  static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
422
413
  static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
423
- static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
424
- static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
414
+ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result);
425
415
  static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
426
416
 
427
417
 
@@ -627,11 +617,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
627
617
  raise_parse_error("unexpected token at '%s'", p);
628
618
  }
629
619
  }
630
- np = JSON_parse_float(json, fpc, pe, result);
631
- if (np != NULL) {
632
- fexec np;
633
- }
634
- np = JSON_parse_integer(json, fpc, pe, result);
620
+ np = JSON_parse_number(json, fpc, pe, result);
635
621
  if (np != NULL) {
636
622
  fexec np;
637
623
  }
@@ -640,7 +626,9 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
640
626
 
641
627
  action parse_array {
642
628
  char *np;
629
+ json->in_array++;
643
630
  np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
631
+ json->in_array--;
644
632
  if (np == NULL) { fhold; fbreak; } else fexec np;
645
633
  }
646
634
 
@@ -716,15 +704,8 @@ static inline VALUE fast_parse_integer(char *p, char *pe)
716
704
  return LL2NUM(memo);
717
705
  }
718
706
 
719
- static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
707
+ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result)
720
708
  {
721
- int cs = EVIL;
722
-
723
- %% write init;
724
- json->memo = p;
725
- %% write exec;
726
-
727
- if (cs >= JSON_integer_first_final) {
728
709
  long len = p - json->memo;
729
710
  if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
730
711
  *result = fast_parse_integer(json->memo, p);
@@ -735,9 +716,6 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
735
716
  *result = rb_cstr2inum(FBUFFER_PTR(&json->fbuffer), 10);
736
717
  }
737
718
  return p + 1;
738
- } else {
739
- return NULL;
740
- }
741
719
  }
742
720
 
743
721
  %%{
@@ -747,22 +725,28 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
747
725
  write data;
748
726
 
749
727
  action exit { fhold; fbreak; }
728
+ action isFloat { is_float = true; }
750
729
 
751
730
  main := '-'? (
752
- (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
753
- | (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
754
- ) (^[0-9Ee.\-]? @exit );
731
+ (('0' | [1-9][0-9]*)
732
+ ((('.' [0-9]+ ([Ee] [+\-]?[0-9]+)?) |
733
+ ([Ee] [+\-]?[0-9]+)) > isFloat)?
734
+ ) (^[0-9Ee.\-]? @exit ));
755
735
  }%%
756
736
 
757
- static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
737
+ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result)
758
738
  {
759
739
  int cs = EVIL;
740
+ bool is_float = false;
760
741
 
761
742
  %% write init;
762
743
  json->memo = p;
763
744
  %% write exec;
764
745
 
765
746
  if (cs >= JSON_float_first_final) {
747
+ if (!is_float) {
748
+ return JSON_decode_integer(json, p, result);
749
+ }
766
750
  VALUE mod = Qnil;
767
751
  ID method_id = 0;
768
752
  if (json->decimal_class) {
@@ -906,7 +890,7 @@ static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringE
906
890
  {
907
891
  size_t bufferSize = stringEnd - string;
908
892
 
909
- if (is_name) {
893
+ if (is_name && json->in_array) {
910
894
  VALUE cached_key;
911
895
  if (RB_UNLIKELY(symbolize)) {
912
896
  cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
@@ -929,7 +913,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE
929
913
  int unescape_len;
930
914
  char buf[4];
931
915
 
932
- if (is_name) {
916
+ if (is_name && json->in_array) {
933
917
  VALUE cached_key;
934
918
  if (RB_UNLIKELY(symbolize)) {
935
919
  cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
@@ -1355,8 +1339,10 @@ static void JSON_mark(void *ptr)
1355
1339
  rb_gc_mark(json->match_string);
1356
1340
  rb_gc_mark(json->stack_handle);
1357
1341
 
1358
- const VALUE *name_cache_entries = &json->name_cache.entries[0];
1359
- rb_gc_mark_locations(name_cache_entries, name_cache_entries + json->name_cache.length);
1342
+ long index;
1343
+ for (index = 0; index < json->name_cache.length; index++) {
1344
+ rb_gc_mark(json->name_cache.entries[index]);
1345
+ }
1360
1346
  }
1361
1347
 
1362
1348
  static void JSON_free(void *ptr)
data/lib/json/common.rb CHANGED
@@ -1,4 +1,5 @@
1
- #frozen_string_literal: true
1
+ # frozen_string_literal: true
2
+
2
3
  require 'json/version'
3
4
 
4
5
  module JSON
@@ -25,7 +26,7 @@ module JSON
25
26
  elsif object.respond_to?(:to_str)
26
27
  str = object.to_str
27
28
  if str.is_a?(String)
28
- return JSON.parse(object.to_str, opts)
29
+ return JSON.parse(str, opts)
29
30
  end
30
31
  end
31
32
 
@@ -142,7 +143,23 @@ module JSON
142
143
  # :startdoc:
143
144
 
144
145
  # This exception is raised if a generator or unparser error occurs.
145
- class GeneratorError < JSONError; end
146
+ class GeneratorError < JSONError
147
+ attr_reader :invalid_object
148
+
149
+ def initialize(message, invalid_object = nil)
150
+ super(message)
151
+ @invalid_object = invalid_object
152
+ end
153
+
154
+ def detailed_message(...)
155
+ if @invalid_object.nil?
156
+ super
157
+ else
158
+ "#{super}\nInvalid object: #{@invalid_object.inspect}"
159
+ end
160
+ end
161
+ end
162
+
146
163
  # For backwards compatibility
147
164
  UnparserError = GeneratorError # :nodoc:
148
165
 
@@ -230,8 +247,8 @@ module JSON
230
247
  # parse(File.read(path), opts)
231
248
  #
232
249
  # See method #parse.
233
- def load_file(filespec, opts = {})
234
- parse(File.read(filespec), opts)
250
+ def load_file(filespec, opts = nil)
251
+ parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
235
252
  end
236
253
 
237
254
  # :call-seq:
@@ -242,7 +259,7 @@ module JSON
242
259
  #
243
260
  # See method #parse!
244
261
  def load_file!(filespec, opts = {})
245
- parse!(File.read(filespec), opts)
262
+ parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
246
263
  end
247
264
 
248
265
  # :call-seq:
@@ -285,7 +302,7 @@ module JSON
285
302
  if State === opts
286
303
  opts.generate(obj)
287
304
  else
288
- State.generate(obj, opts)
305
+ State.generate(obj, opts, nil)
289
306
  end
290
307
  end
291
308
 
@@ -410,6 +427,10 @@ module JSON
410
427
  #
411
428
  # Returns the Ruby objects created by parsing the given +source+.
412
429
  #
430
+ # BEWARE: This method is meant to serialise data from trusted user input,
431
+ # like from your own database server or clients under your control, it could
432
+ # be dangerous to allow untrusted users to pass JSON sources into it.
433
+ #
413
434
  # - Argument +source+ must be, or be convertible to, a \String:
414
435
  # - If +source+ responds to instance method +to_str+,
415
436
  # <tt>source.to_str</tt> becomes the source.
@@ -424,9 +445,6 @@ module JSON
424
445
  # - Argument +proc+, if given, must be a \Proc that accepts one argument.
425
446
  # It will be called recursively with each result (depth-first order).
426
447
  # See details below.
427
- # BEWARE: This method is meant to serialise data from trusted user input,
428
- # like from your own database server or clients under your control, it could
429
- # be dangerous to allow untrusted users to pass JSON sources into it.
430
448
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
431
449
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
432
450
  # The default options can be changed via method JSON.unsafe_load_default_options=.
@@ -563,6 +581,16 @@ module JSON
563
581
  #
564
582
  # Returns the Ruby objects created by parsing the given +source+.
565
583
  #
584
+ # BEWARE: This method is meant to serialise data from trusted user input,
585
+ # like from your own database server or clients under your control, it could
586
+ # be dangerous to allow untrusted users to pass JSON sources into it.
587
+ # If you must use it, use JSON.unsafe_load instead to make it clear.
588
+ #
589
+ # Since JSON version 2.8.0, `load` emits a deprecation warning when a
590
+ # non native type is deserialized, without `create_additions` being explicitly
591
+ # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
592
+ # by default.
593
+ #
566
594
  # - Argument +source+ must be, or be convertible to, a \String:
567
595
  # - If +source+ responds to instance method +to_str+,
568
596
  # <tt>source.to_str</tt> becomes the source.
@@ -577,10 +605,6 @@ module JSON
577
605
  # - Argument +proc+, if given, must be a \Proc that accepts one argument.
578
606
  # It will be called recursively with each result (depth-first order).
579
607
  # See details below.
580
- # BEWARE: This method is meant to serialise data from trusted user input,
581
- # like from your own database server or clients under your control, it could
582
- # be dangerous to allow untrusted users to pass JSON sources into it.
583
- # If you must use it, use JSON.unsafe_load instead to make it clear.
584
608
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
585
609
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
586
610
  # The default options can be changed via method JSON.load_default_options=.
@@ -793,18 +817,15 @@ module JSON
793
817
  opts = opts.merge(:max_nesting => limit) if limit
794
818
  opts = merge_dump_options(opts, **kwargs) if kwargs
795
819
 
796
- result = begin
797
- generate(obj, opts)
820
+ begin
821
+ if State === opts
822
+ opts.generate(obj, anIO)
823
+ else
824
+ State.generate(obj, opts, anIO)
825
+ end
798
826
  rescue JSON::NestingError
799
827
  raise ArgumentError, "exceed depth limit"
800
828
  end
801
-
802
- if anIO.nil?
803
- result
804
- else
805
- anIO.write result
806
- anIO
807
- end
808
829
  end
809
830
 
810
831
  # Encodes string using String.encode.
@@ -47,6 +47,17 @@ module JSON
47
47
 
48
48
  alias_method :merge, :configure
49
49
 
50
+ # call-seq:
51
+ # generate(obj) -> String
52
+ # generate(obj, anIO) -> anIO
53
+ #
54
+ # Generates a valid JSON document from object +obj+ and returns the
55
+ # result. If no valid JSON document can be created this method raises a
56
+ # GeneratorError exception.
57
+ def generate(obj, io = nil)
58
+ _generate(obj, io)
59
+ end
60
+
50
61
  # call-seq: to_h
51
62
  #
52
63
  # Returns the configuration instance variables as a hash, that can be
@@ -62,8 +62,8 @@ module JSON
62
62
  string
63
63
  end
64
64
 
65
- def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
66
- string = string.b
65
+ def utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
66
+ string = original_string.b
67
67
  map = script_safe ? SCRIPT_SAFE_MAP : MAP
68
68
  string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
69
69
  string.gsub!(/(
@@ -74,7 +74,7 @@ module JSON
74
74
  )+ |
75
75
  [\x80-\xc1\xf5-\xff] # invalid
76
76
  )/nx) { |c|
77
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
77
+ c.size == 1 and raise GeneratorError.new("invalid utf8 byte: '#{c}'", original_string)
78
78
  s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0]
79
79
  s.force_encoding(::Encoding::BINARY)
80
80
  s.gsub!(/.{4}/n, '\\\\u\&')
@@ -83,7 +83,7 @@ module JSON
83
83
  string.force_encoding(::Encoding::UTF_8)
84
84
  string
85
85
  rescue => e
86
- raise GeneratorError.wrap(e)
86
+ raise GeneratorError.new(e.message, original_string)
87
87
  end
88
88
 
89
89
  def valid_utf8?(string)
@@ -96,8 +96,14 @@ module JSON
96
96
  # This class is used to create State instances, that are use to hold data
97
97
  # while generating a JSON text from a Ruby data structure.
98
98
  class State
99
- def self.generate(obj, opts = nil)
100
- new(opts).generate(obj)
99
+ def self.generate(obj, opts = nil, io = nil)
100
+ string = new(opts).generate(obj)
101
+ if io
102
+ io.write(string)
103
+ io
104
+ else
105
+ string
106
+ end
101
107
  end
102
108
 
103
109
  # Creates a State object from _opts_, which ought to be Hash to create
@@ -300,8 +306,10 @@ module JSON
300
306
  else
301
307
  result = obj.to_json(self)
302
308
  end
303
- JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError,
304
- "source sequence #{result.inspect} is illegal/malformed utf-8"
309
+ JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
310
+ "source sequence #{result.inspect} is illegal/malformed utf-8",
311
+ obj
312
+ )
305
313
  result
306
314
  end
307
315
 
@@ -358,10 +366,10 @@ module JSON
358
366
  begin
359
367
  string = string.encode(::Encoding::UTF_8)
360
368
  rescue Encoding::UndefinedConversionError => error
361
- raise GeneratorError, error.message
369
+ raise GeneratorError.new(error.message, string)
362
370
  end
363
371
  end
364
- raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?
372
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding?
365
373
 
366
374
  if /["\\\x0-\x1f]/n.match?(string)
367
375
  buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
@@ -397,7 +405,7 @@ module JSON
397
405
  # special method #to_json was defined for some object.
398
406
  def to_json(state = nil, *)
399
407
  if state && State.from_state(state).strict?
400
- raise GeneratorError, "#{self.class} not allowed in JSON"
408
+ raise GeneratorError.new("#{self.class} not allowed in JSON", self)
401
409
  else
402
410
  to_s.to_json
403
411
  end
@@ -448,7 +456,7 @@ module JSON
448
456
 
449
457
  result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
450
458
  if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
451
- raise GeneratorError, "#{value.class} not allowed in JSON"
459
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
452
460
  elsif value.respond_to?(:to_json)
453
461
  result << value.to_json(state)
454
462
  else
@@ -501,7 +509,7 @@ module JSON
501
509
  result << delim unless first
502
510
  result << state.indent * depth if indent
503
511
  if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
504
- raise GeneratorError, "#{value.class} not allowed in JSON"
512
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
505
513
  elsif value.respond_to?(:to_json)
506
514
  result << value.to_json(state)
507
515
  else
@@ -530,13 +538,13 @@ module JSON
530
538
  if state.allow_nan?
531
539
  to_s
532
540
  else
533
- raise GeneratorError, "#{self} not allowed in JSON"
541
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
534
542
  end
535
543
  when nan?
536
544
  if state.allow_nan?
537
545
  to_s
538
546
  else
539
- raise GeneratorError, "#{self} not allowed in JSON"
547
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
540
548
  end
541
549
  else
542
550
  to_s
@@ -552,7 +560,7 @@ module JSON
552
560
  state = State.from_state(state)
553
561
  if encoding == ::Encoding::UTF_8
554
562
  unless valid_encoding?
555
- raise GeneratorError, "source sequence is illegal/malformed utf-8"
563
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
556
564
  end
557
565
  string = self
558
566
  else
@@ -564,7 +572,7 @@ module JSON
564
572
  %("#{JSON::TruffleRuby::Generator.utf8_to_json(string, state.script_safe)}")
565
573
  end
566
574
  rescue Encoding::UndefinedConversionError => error
567
- raise ::JSON::GeneratorError, error.message
575
+ raise ::JSON::GeneratorError.new(error.message, self)
568
576
  end
569
577
 
570
578
  # Module that holds the extending methods if, the String module is
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.8.1'
4
+ VERSION = '2.9.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-06 00:00:00.000000000 Z
11
+ date: 2024-12-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This is a JSON implementation as a Ruby extension in C.
14
14
  email: flori@ping.de