json 2.18.1 → 2.19.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 +4 -4
- data/CHANGES.md +29 -0
- data/ext/json/ext/fbuffer/fbuffer.h +17 -15
- data/ext/json/ext/generator/extconf.rb +2 -0
- data/ext/json/ext/generator/generator.c +57 -303
- data/ext/json/ext/json.h +15 -0
- data/ext/json/ext/parser/extconf.rb +4 -0
- data/ext/json/ext/parser/parser.c +111 -74
- data/ext/json/ext/simd/simd.h +0 -10
- data/lib/json/common.rb +41 -10
- data/lib/json/ext/generator/state.rb +1 -1
- data/lib/json/truffle_ruby/generator.rb +21 -9
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +14 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48a111e63867f6bb2c0cb1b2740a898f3102bc07ac196136e26ca9b68f510f89
|
|
4
|
+
data.tar.gz: 2f760d8afae80555c483afaaa8bead26f045d26c394cc07843a85deaff7fdd40
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6387b2c483c8f4d7ed304f33a3553a2fde78c04efeff7ae32a1e952380df92d6df87b543c22832907b007f758f09bd2f80ef4db0b5753e46fdf73f0e264e9e02
|
|
7
|
+
data.tar.gz: c3c855b9e460768f83516914580c10854ea2b28ee73976e311ce55a0d2265576f65a23c41cccc47c7443d79883658962d1cf923880685d555b3af1ba0ebcb056
|
data/CHANGES.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
### Unreleased
|
|
4
4
|
|
|
5
|
+
### 2026-04-19 (2.19.4)
|
|
6
|
+
|
|
7
|
+
* Fix parsing of out of range floats (very large exponents that lead ot either `0.0` or `Inf`).
|
|
8
|
+
|
|
9
|
+
### 2026-03-25 (2.19.3)
|
|
10
|
+
|
|
11
|
+
* Fix handling of unescaped control characters preceeded by a backslash.
|
|
12
|
+
|
|
13
|
+
### 2026-03-18 (2.19.2)
|
|
14
|
+
|
|
15
|
+
* Fix a format string injection vulnerability in `JSON.parse(doc, allow_duplicate_key: false)`. `CVE-2026-33210`.
|
|
16
|
+
|
|
17
|
+
### 2026-03-08 (2.19.1)
|
|
18
|
+
|
|
19
|
+
* Fix a compiler dependent GC bug introduced in `2.18.0`.
|
|
20
|
+
|
|
21
|
+
### 2026-03-06 (2.19.0)
|
|
22
|
+
|
|
23
|
+
* Fix `allow_blank` parsing option to no longer allow invalid types (e.g. `load([], allow_blank: true)` now raise a type error).
|
|
24
|
+
* Add `allow_invalid_escape` parsing option to ignore backslashes that aren't followed by one of the valid escape characters.
|
|
25
|
+
|
|
5
26
|
### 2026-02-03 (2.18.1)
|
|
6
27
|
|
|
7
28
|
* Fix a potential crash in very specific circumstance if GC triggers during a call to `to_json`
|
|
@@ -11,6 +32,10 @@
|
|
|
11
32
|
|
|
12
33
|
* Add `:allow_control_characters` parser options, to allow JSON strings containing unescaped ASCII control characters (e.g. newlines).
|
|
13
34
|
|
|
35
|
+
### 2026-03-18 (2.17.1.2) - Security Backport
|
|
36
|
+
|
|
37
|
+
* Fix a format string injection vulnerability in `JSON.parse(doc, allow_duplicate_key: false)`. `CVE-2026-33210`.
|
|
38
|
+
|
|
14
39
|
### 2025-12-04 (2.17.1)
|
|
15
40
|
|
|
16
41
|
* Fix a regression in parsing of unicode surogate pairs (`\uXX\uXX`) that could cause an invalid string to be returned.
|
|
@@ -37,6 +62,10 @@
|
|
|
37
62
|
* Optimized numbers parsing using SWAR (thanks to Scott Myron).
|
|
38
63
|
* Optimized parsing of pretty printed documents using SWAR (thanks to Scott Myron).
|
|
39
64
|
|
|
65
|
+
### 2026-03-18 (2.15.2.1) - Security Backport
|
|
66
|
+
|
|
67
|
+
* Fix a format string injection vulnerability in `JSON.parse(doc, allow_duplicate_key: false)`. `CVE-2026-33210`.
|
|
68
|
+
|
|
40
69
|
### 2025-10-25 (2.15.2)
|
|
41
70
|
|
|
42
71
|
* Fix `JSON::Coder` to have one dedicated depth counter per invocation.
|
|
@@ -11,11 +11,11 @@ enum fbuffer_type {
|
|
|
11
11
|
|
|
12
12
|
typedef struct FBufferStruct {
|
|
13
13
|
enum fbuffer_type type;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
size_t initial_length;
|
|
15
|
+
size_t len;
|
|
16
|
+
size_t capa;
|
|
17
17
|
#if JSON_DEBUG
|
|
18
|
-
|
|
18
|
+
size_t requested;
|
|
19
19
|
#endif
|
|
20
20
|
char *ptr;
|
|
21
21
|
VALUE io;
|
|
@@ -32,12 +32,12 @@ typedef struct FBufferStruct {
|
|
|
32
32
|
|
|
33
33
|
static void fbuffer_free(FBuffer *fb);
|
|
34
34
|
static void fbuffer_clear(FBuffer *fb);
|
|
35
|
-
static void fbuffer_append(FBuffer *fb, const char *newstr,
|
|
35
|
+
static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len);
|
|
36
36
|
static void fbuffer_append_long(FBuffer *fb, long number);
|
|
37
37
|
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
|
|
38
38
|
static VALUE fbuffer_finalize(FBuffer *fb);
|
|
39
39
|
|
|
40
|
-
static void fbuffer_stack_init(FBuffer *fb,
|
|
40
|
+
static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size)
|
|
41
41
|
{
|
|
42
42
|
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
|
|
43
43
|
if (stack_buffer) {
|
|
@@ -50,7 +50,7 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
|
|
|
50
50
|
#endif
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
static inline void fbuffer_consumed(FBuffer *fb,
|
|
53
|
+
static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
|
|
54
54
|
{
|
|
55
55
|
#if JSON_DEBUG
|
|
56
56
|
if (consumed > fb->requested) {
|
|
@@ -79,7 +79,7 @@ static void fbuffer_flush(FBuffer *fb)
|
|
|
79
79
|
fbuffer_clear(fb);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
static void fbuffer_realloc(FBuffer *fb,
|
|
82
|
+
static void fbuffer_realloc(FBuffer *fb, size_t required)
|
|
83
83
|
{
|
|
84
84
|
if (required > fb->capa) {
|
|
85
85
|
if (fb->type == FBUFFER_STACK_ALLOCATED) {
|
|
@@ -94,7 +94,7 @@ static void fbuffer_realloc(FBuffer *fb, unsigned long required)
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
static void fbuffer_do_inc_capa(FBuffer *fb,
|
|
97
|
+
static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
|
|
98
98
|
{
|
|
99
99
|
if (RB_UNLIKELY(fb->io)) {
|
|
100
100
|
if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
|
|
@@ -108,7 +108,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
size_t required;
|
|
112
112
|
|
|
113
113
|
if (RB_UNLIKELY(!fb->ptr)) {
|
|
114
114
|
fb->ptr = ALLOC_N(char, fb->initial_length);
|
|
@@ -120,7 +120,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
|
|
120
120
|
fbuffer_realloc(fb, required);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
static inline void fbuffer_inc_capa(FBuffer *fb,
|
|
123
|
+
static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
|
|
124
124
|
{
|
|
125
125
|
#if JSON_DEBUG
|
|
126
126
|
fb->requested = requested;
|
|
@@ -131,13 +131,13 @@ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr,
|
|
134
|
+
static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len)
|
|
135
135
|
{
|
|
136
136
|
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
|
137
137
|
fbuffer_consumed(fb, len);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
static inline void fbuffer_append(FBuffer *fb, const char *newstr,
|
|
140
|
+
static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len)
|
|
141
141
|
{
|
|
142
142
|
if (len > 0) {
|
|
143
143
|
fbuffer_inc_capa(fb, len);
|
|
@@ -162,16 +162,17 @@ static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
|
|
|
162
162
|
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
163
163
|
{
|
|
164
164
|
const char *ptr;
|
|
165
|
-
|
|
165
|
+
size_t len;
|
|
166
166
|
RSTRING_GETMEM(str, ptr, len);
|
|
167
167
|
|
|
168
168
|
fbuffer_append(fb, ptr, len);
|
|
169
|
+
RB_GC_GUARD(str);
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
|
|
172
173
|
{
|
|
173
174
|
const char *ptr;
|
|
174
|
-
|
|
175
|
+
size_t len;
|
|
175
176
|
RSTRING_GETMEM(str, ptr, len);
|
|
176
177
|
|
|
177
178
|
fbuffer_inc_capa(fb, repeat * len);
|
|
@@ -182,6 +183,7 @@ static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
|
|
|
182
183
|
fbuffer_append_reserved(fb, ptr, len);
|
|
183
184
|
repeat--;
|
|
184
185
|
}
|
|
186
|
+
RB_GC_GUARD(str);
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
@@ -5,6 +5,8 @@ if RUBY_ENGINE == 'truffleruby'
|
|
|
5
5
|
File.write('Makefile', dummy_makefile("").join)
|
|
6
6
|
else
|
|
7
7
|
append_cflags("-std=c99")
|
|
8
|
+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
|
|
9
|
+
|
|
8
10
|
$defs << "-DJSON_GENERATOR"
|
|
9
11
|
$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
|
|
10
12
|
|
|
@@ -74,9 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
|
|
|
74
74
|
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
75
75
|
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
76
76
|
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
77
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
78
|
-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
79
|
-
#endif
|
|
80
77
|
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
81
78
|
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
82
79
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
@@ -703,233 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
|
|
|
703
700
|
}
|
|
704
701
|
}
|
|
705
702
|
|
|
706
|
-
/*
|
|
707
|
-
* Document-module: JSON::Ext::Generator
|
|
708
|
-
*
|
|
709
|
-
* This is the JSON generator implemented as a C extension. It can be
|
|
710
|
-
* configured to be used by setting
|
|
711
|
-
*
|
|
712
|
-
* JSON.generator = JSON::Ext::Generator
|
|
713
|
-
*
|
|
714
|
-
* with the method generator= in JSON.
|
|
715
|
-
*
|
|
716
|
-
*/
|
|
717
|
-
|
|
718
|
-
/* Explanation of the following: that's the only way to not pollute
|
|
719
|
-
* standard library's docs with GeneratorMethods::<ClassName> which
|
|
720
|
-
* are uninformative and take a large place in a list of classes
|
|
721
|
-
*/
|
|
722
|
-
|
|
723
|
-
/*
|
|
724
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods
|
|
725
|
-
* :nodoc:
|
|
726
|
-
*/
|
|
727
|
-
|
|
728
|
-
/*
|
|
729
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
|
|
730
|
-
* :nodoc:
|
|
731
|
-
*/
|
|
732
|
-
|
|
733
|
-
/*
|
|
734
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
|
|
735
|
-
* :nodoc:
|
|
736
|
-
*/
|
|
737
|
-
|
|
738
|
-
/*
|
|
739
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
|
|
740
|
-
* :nodoc:
|
|
741
|
-
*/
|
|
742
|
-
|
|
743
|
-
/*
|
|
744
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
|
|
745
|
-
* :nodoc:
|
|
746
|
-
*/
|
|
747
|
-
|
|
748
|
-
/*
|
|
749
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
|
|
750
|
-
* :nodoc:
|
|
751
|
-
*/
|
|
752
|
-
|
|
753
|
-
/*
|
|
754
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
|
|
755
|
-
* :nodoc:
|
|
756
|
-
*/
|
|
757
|
-
|
|
758
|
-
/*
|
|
759
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
|
|
760
|
-
* :nodoc:
|
|
761
|
-
*/
|
|
762
|
-
|
|
763
|
-
/*
|
|
764
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
|
|
765
|
-
* :nodoc:
|
|
766
|
-
*/
|
|
767
|
-
|
|
768
|
-
/*
|
|
769
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
|
|
770
|
-
* :nodoc:
|
|
771
|
-
*/
|
|
772
|
-
|
|
773
|
-
/*
|
|
774
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
|
|
775
|
-
* :nodoc:
|
|
776
|
-
*/
|
|
777
|
-
|
|
778
|
-
/*
|
|
779
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
|
|
780
|
-
* :nodoc:
|
|
781
|
-
*/
|
|
782
|
-
|
|
783
|
-
/*
|
|
784
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
|
|
785
|
-
* :nodoc:
|
|
786
|
-
*/
|
|
787
|
-
|
|
788
|
-
/*
|
|
789
|
-
* call-seq: to_json(state = nil)
|
|
790
|
-
*
|
|
791
|
-
* Returns a JSON string containing a JSON object, that is generated from
|
|
792
|
-
* this Hash instance.
|
|
793
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
|
794
|
-
* produced JSON string output further.
|
|
795
|
-
*/
|
|
796
|
-
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
797
|
-
{
|
|
798
|
-
rb_check_arity(argc, 0, 1);
|
|
799
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
800
|
-
return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
/*
|
|
804
|
-
* call-seq: to_json(state = nil)
|
|
805
|
-
*
|
|
806
|
-
* Returns a JSON string containing a JSON array, that is generated from
|
|
807
|
-
* this Array instance.
|
|
808
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
|
809
|
-
* produced JSON string output further.
|
|
810
|
-
*/
|
|
811
|
-
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
|
|
812
|
-
{
|
|
813
|
-
rb_check_arity(argc, 0, 1);
|
|
814
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
815
|
-
return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
819
|
-
/*
|
|
820
|
-
* call-seq: to_json(*)
|
|
821
|
-
*
|
|
822
|
-
* Returns a JSON string representation for this Integer number.
|
|
823
|
-
*/
|
|
824
|
-
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
825
|
-
{
|
|
826
|
-
rb_check_arity(argc, 0, 1);
|
|
827
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
828
|
-
return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
#else
|
|
832
|
-
/*
|
|
833
|
-
* call-seq: to_json(*)
|
|
834
|
-
*
|
|
835
|
-
* Returns a JSON string representation for this Integer number.
|
|
836
|
-
*/
|
|
837
|
-
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
838
|
-
{
|
|
839
|
-
rb_check_arity(argc, 0, 1);
|
|
840
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
841
|
-
return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
/*
|
|
845
|
-
* call-seq: to_json(*)
|
|
846
|
-
*
|
|
847
|
-
* Returns a JSON string representation for this Integer number.
|
|
848
|
-
*/
|
|
849
|
-
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
850
|
-
{
|
|
851
|
-
rb_check_arity(argc, 0, 1);
|
|
852
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
853
|
-
return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
|
|
854
|
-
}
|
|
855
|
-
#endif
|
|
856
|
-
|
|
857
|
-
/*
|
|
858
|
-
* call-seq: to_json(*)
|
|
859
|
-
*
|
|
860
|
-
* Returns a JSON string representation for this Float number.
|
|
861
|
-
*/
|
|
862
|
-
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
863
|
-
{
|
|
864
|
-
rb_check_arity(argc, 0, 1);
|
|
865
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
866
|
-
return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
/*
|
|
870
|
-
* call-seq: to_json(*)
|
|
871
|
-
*
|
|
872
|
-
* This string should be encoded with UTF-8 A call to this method
|
|
873
|
-
* returns a JSON string encoded with UTF16 big endian characters as
|
|
874
|
-
* \u????.
|
|
875
|
-
*/
|
|
876
|
-
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
|
877
|
-
{
|
|
878
|
-
rb_check_arity(argc, 0, 1);
|
|
879
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
880
|
-
return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
/*
|
|
884
|
-
* call-seq: to_json(*)
|
|
885
|
-
*
|
|
886
|
-
* Returns a JSON string for true: 'true'.
|
|
887
|
-
*/
|
|
888
|
-
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
889
|
-
{
|
|
890
|
-
rb_check_arity(argc, 0, 1);
|
|
891
|
-
return rb_utf8_str_new("true", 4);
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
/*
|
|
895
|
-
* call-seq: to_json(*)
|
|
896
|
-
*
|
|
897
|
-
* Returns a JSON string for false: 'false'.
|
|
898
|
-
*/
|
|
899
|
-
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
900
|
-
{
|
|
901
|
-
rb_check_arity(argc, 0, 1);
|
|
902
|
-
return rb_utf8_str_new("false", 5);
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
/*
|
|
906
|
-
* call-seq: to_json(*)
|
|
907
|
-
*
|
|
908
|
-
* Returns a JSON string for nil: 'null'.
|
|
909
|
-
*/
|
|
910
|
-
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
911
|
-
{
|
|
912
|
-
rb_check_arity(argc, 0, 1);
|
|
913
|
-
return rb_utf8_str_new("null", 4);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
/*
|
|
917
|
-
* call-seq: to_json(*)
|
|
918
|
-
*
|
|
919
|
-
* Converts this object to a string (calling #to_s), converts
|
|
920
|
-
* it to a JSON string, and returns the result. This is a fallback, if no
|
|
921
|
-
* special method #to_json was defined for some object.
|
|
922
|
-
*/
|
|
923
|
-
static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
924
|
-
{
|
|
925
|
-
VALUE state;
|
|
926
|
-
VALUE string = rb_funcall(self, i_to_s, 0);
|
|
927
|
-
rb_scan_args(argc, argv, "01", &state);
|
|
928
|
-
Check_Type(string, T_STRING);
|
|
929
|
-
state = cState_from_state_s(cState, state);
|
|
930
|
-
return cState_partial_generate(state, string, generate_json_string, Qfalse);
|
|
931
|
-
}
|
|
932
|
-
|
|
933
703
|
static void State_mark(void *ptr)
|
|
934
704
|
{
|
|
935
705
|
JSON_Generator_State *state = ptr;
|
|
@@ -952,27 +722,20 @@ static void State_compact(void *ptr)
|
|
|
952
722
|
state->as_json = rb_gc_location(state->as_json);
|
|
953
723
|
}
|
|
954
724
|
|
|
955
|
-
static void State_free(void *ptr)
|
|
956
|
-
{
|
|
957
|
-
JSON_Generator_State *state = ptr;
|
|
958
|
-
ruby_xfree(state);
|
|
959
|
-
}
|
|
960
|
-
|
|
961
725
|
static size_t State_memsize(const void *ptr)
|
|
962
726
|
{
|
|
963
727
|
return sizeof(JSON_Generator_State);
|
|
964
728
|
}
|
|
965
729
|
|
|
966
730
|
static const rb_data_type_t JSON_Generator_State_type = {
|
|
967
|
-
"JSON/Generator/State",
|
|
968
|
-
{
|
|
731
|
+
.wrap_struct_name = "JSON/Generator/State",
|
|
732
|
+
.function = {
|
|
969
733
|
.dmark = State_mark,
|
|
970
|
-
.dfree =
|
|
734
|
+
.dfree = RUBY_DEFAULT_FREE,
|
|
971
735
|
.dsize = State_memsize,
|
|
972
736
|
.dcompact = State_compact,
|
|
973
737
|
},
|
|
974
|
-
|
|
975
|
-
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
738
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
|
|
976
739
|
};
|
|
977
740
|
|
|
978
741
|
static void state_init(JSON_Generator_State *state)
|
|
@@ -1377,16 +1140,6 @@ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1377
1140
|
fbuffer_append_str(buffer, StringValue(tmp));
|
|
1378
1141
|
}
|
|
1379
1142
|
|
|
1380
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
1381
|
-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1382
|
-
{
|
|
1383
|
-
if (FIXNUM_P(obj))
|
|
1384
|
-
generate_json_fixnum(buffer, data, obj);
|
|
1385
|
-
else
|
|
1386
|
-
generate_json_bignum(buffer, data, obj);
|
|
1387
|
-
}
|
|
1388
|
-
#endif
|
|
1389
|
-
|
|
1390
1143
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1391
1144
|
{
|
|
1392
1145
|
double value = RFLOAT_VALUE(obj);
|
|
@@ -1430,7 +1183,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
|
|
|
1430
1183
|
fbuffer_append_str(buffer, fragment);
|
|
1431
1184
|
}
|
|
1432
1185
|
|
|
1433
|
-
static void
|
|
1186
|
+
static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
|
|
1434
1187
|
{
|
|
1435
1188
|
bool as_json_called = false;
|
|
1436
1189
|
start:
|
|
@@ -1457,15 +1210,15 @@ start:
|
|
|
1457
1210
|
generate_json_bignum(buffer, data, obj);
|
|
1458
1211
|
break;
|
|
1459
1212
|
case T_HASH:
|
|
1460
|
-
if (klass != rb_cHash) goto general;
|
|
1213
|
+
if (fallback && klass != rb_cHash) goto general;
|
|
1461
1214
|
generate_json_object(buffer, data, obj);
|
|
1462
1215
|
break;
|
|
1463
1216
|
case T_ARRAY:
|
|
1464
|
-
if (klass != rb_cArray) goto general;
|
|
1217
|
+
if (fallback && klass != rb_cArray) goto general;
|
|
1465
1218
|
generate_json_array(buffer, data, obj);
|
|
1466
1219
|
break;
|
|
1467
1220
|
case T_STRING:
|
|
1468
|
-
if (klass != rb_cString) goto general;
|
|
1221
|
+
if (fallback && klass != rb_cString) goto general;
|
|
1469
1222
|
|
|
1470
1223
|
if (RB_LIKELY(valid_json_string_p(obj))) {
|
|
1471
1224
|
raw_generate_json_string(buffer, data, obj);
|
|
@@ -1481,7 +1234,7 @@ start:
|
|
|
1481
1234
|
generate_json_symbol(buffer, data, obj);
|
|
1482
1235
|
break;
|
|
1483
1236
|
case T_FLOAT:
|
|
1484
|
-
if (klass != rb_cFloat) goto general;
|
|
1237
|
+
if (fallback && klass != rb_cFloat) goto general;
|
|
1485
1238
|
generate_json_float(buffer, data, obj);
|
|
1486
1239
|
break;
|
|
1487
1240
|
case T_STRUCT:
|
|
@@ -1505,6 +1258,16 @@ start:
|
|
|
1505
1258
|
}
|
|
1506
1259
|
}
|
|
1507
1260
|
|
|
1261
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1262
|
+
{
|
|
1263
|
+
generate_json_general(buffer, data, obj, true);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1267
|
+
{
|
|
1268
|
+
generate_json_general(buffer, data, obj, false);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1508
1271
|
static VALUE generate_json_try(VALUE d)
|
|
1509
1272
|
{
|
|
1510
1273
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
|
@@ -1522,7 +1285,7 @@ static VALUE generate_json_ensure(VALUE d)
|
|
|
1522
1285
|
return Qundef;
|
|
1523
1286
|
}
|
|
1524
1287
|
|
|
1525
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
|
1288
|
+
static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
|
1526
1289
|
{
|
|
1527
1290
|
GET_STATE(self);
|
|
1528
1291
|
|
|
@@ -1540,9 +1303,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
|
|
|
1540
1303
|
.obj = obj,
|
|
1541
1304
|
.func = func
|
|
1542
1305
|
};
|
|
1543
|
-
|
|
1544
|
-
RB_GC_GUARD(self);
|
|
1545
|
-
return result;
|
|
1306
|
+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
1546
1307
|
}
|
|
1547
1308
|
|
|
1548
1309
|
/* call-seq:
|
|
@@ -1561,6 +1322,15 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
|
|
|
1561
1322
|
return cState_partial_generate(self, obj, generate_json, io);
|
|
1562
1323
|
}
|
|
1563
1324
|
|
|
1325
|
+
/* :nodoc: */
|
|
1326
|
+
static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
|
|
1327
|
+
{
|
|
1328
|
+
rb_check_arity(argc, 1, 2);
|
|
1329
|
+
VALUE obj = argv[0];
|
|
1330
|
+
VALUE io = argc > 1 ? argv[1] : Qnil;
|
|
1331
|
+
return cState_partial_generate(self, obj, generate_json_no_fallback, io);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1564
1334
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
1565
1335
|
{
|
|
1566
1336
|
rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
|
|
@@ -1798,6 +1568,17 @@ static long long_config(VALUE num)
|
|
|
1798
1568
|
return RTEST(num) ? FIX2LONG(num) : 0;
|
|
1799
1569
|
}
|
|
1800
1570
|
|
|
1571
|
+
// depth must never be negative; reject early with a clear error.
|
|
1572
|
+
static long depth_config(VALUE num)
|
|
1573
|
+
{
|
|
1574
|
+
if (!RTEST(num)) return 0;
|
|
1575
|
+
long d = NUM2LONG(num);
|
|
1576
|
+
if (RB_UNLIKELY(d < 0)) {
|
|
1577
|
+
rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
|
|
1578
|
+
}
|
|
1579
|
+
return d;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1801
1582
|
/*
|
|
1802
1583
|
* call-seq: max_nesting=(depth)
|
|
1803
1584
|
*
|
|
@@ -1954,7 +1735,7 @@ static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
|
1954
1735
|
{
|
|
1955
1736
|
rb_check_frozen(self);
|
|
1956
1737
|
GET_STATE(self);
|
|
1957
|
-
state->depth =
|
|
1738
|
+
state->depth = depth_config(depth);
|
|
1958
1739
|
return Qnil;
|
|
1959
1740
|
}
|
|
1960
1741
|
|
|
@@ -2019,7 +1800,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
2019
1800
|
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
|
|
2020
1801
|
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
|
|
2021
1802
|
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
|
|
2022
|
-
else if (key == sym_depth) { state->depth =
|
|
1803
|
+
else if (key == sym_depth) { state->depth = depth_config(val); }
|
|
2023
1804
|
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
|
2024
1805
|
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
|
2025
1806
|
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
|
@@ -2059,7 +1840,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
|
2059
1840
|
return self;
|
|
2060
1841
|
}
|
|
2061
1842
|
|
|
2062
|
-
static VALUE
|
|
1843
|
+
static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
|
|
2063
1844
|
{
|
|
2064
1845
|
JSON_Generator_State state = {0};
|
|
2065
1846
|
state_init(&state);
|
|
@@ -2077,14 +1858,21 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
|
2077
1858
|
.state = &state,
|
|
2078
1859
|
.depth = state.depth,
|
|
2079
1860
|
.obj = obj,
|
|
2080
|
-
.func =
|
|
1861
|
+
.func = func,
|
|
2081
1862
|
};
|
|
2082
1863
|
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
2083
1864
|
}
|
|
2084
1865
|
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
1866
|
+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
1867
|
+
{
|
|
1868
|
+
return cState_m_do_generate(klass, obj, opts, io, generate_json);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
1872
|
+
{
|
|
1873
|
+
return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
2088
1876
|
void Init_generator(void)
|
|
2089
1877
|
{
|
|
2090
1878
|
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
@@ -2149,46 +1937,12 @@ void Init_generator(void)
|
|
|
2149
1937
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
2150
1938
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
|
2151
1939
|
rb_define_method(cState, "generate", cState_generate, -1);
|
|
1940
|
+
rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
|
|
2152
1941
|
|
|
2153
1942
|
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
|
|
2154
1943
|
|
|
2155
1944
|
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
|
|
2156
|
-
|
|
2157
|
-
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
|
2158
|
-
|
|
2159
|
-
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
|
2160
|
-
rb_define_method(mObject, "to_json", mObject_to_json, -1);
|
|
2161
|
-
|
|
2162
|
-
VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
|
|
2163
|
-
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
|
2164
|
-
|
|
2165
|
-
VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
|
2166
|
-
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
|
2167
|
-
|
|
2168
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
2169
|
-
VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
|
|
2170
|
-
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
|
|
2171
|
-
#else
|
|
2172
|
-
VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
|
2173
|
-
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
|
2174
|
-
|
|
2175
|
-
VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
|
2176
|
-
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
|
2177
|
-
#endif
|
|
2178
|
-
VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
|
2179
|
-
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
|
2180
|
-
|
|
2181
|
-
VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
|
|
2182
|
-
rb_define_method(mString, "to_json", mString_to_json, -1);
|
|
2183
|
-
|
|
2184
|
-
VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
|
|
2185
|
-
rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
|
|
2186
|
-
|
|
2187
|
-
VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
|
|
2188
|
-
rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
|
|
2189
|
-
|
|
2190
|
-
VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
2191
|
-
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
1945
|
+
rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
|
|
2192
1946
|
|
|
2193
1947
|
rb_global_variable(&Encoding_UTF_8);
|
|
2194
1948
|
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
|