json 2.15.1 → 2.17.1
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 +31 -0
- data/LEGAL +12 -0
- data/README.md +17 -1
- data/ext/json/ext/fbuffer/fbuffer.h +9 -58
- data/ext/json/ext/generator/extconf.rb +1 -1
- data/ext/json/ext/generator/generator.c +192 -159
- data/ext/json/ext/json.h +97 -0
- data/ext/json/ext/parser/extconf.rb +2 -1
- data/ext/json/ext/parser/parser.c +498 -387
- data/ext/json/ext/simd/simd.h +15 -12
- data/ext/json/ext/vendor/fpconv.c +2 -2
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/lib/json/common.rb +28 -16
- data/lib/json/ext/generator/state.rb +4 -0
- data/lib/json/truffle_ruby/generator.rb +53 -16
- data/lib/json/version.rb +1 -1
- metadata +3 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#include "
|
|
1
|
+
#include "../json.h"
|
|
2
2
|
#include "../fbuffer/fbuffer.h"
|
|
3
3
|
#include "../vendor/fpconv.c"
|
|
4
4
|
|
|
@@ -36,13 +36,9 @@ typedef struct JSON_Generator_StateStruct {
|
|
|
36
36
|
bool strict;
|
|
37
37
|
} JSON_Generator_State;
|
|
38
38
|
|
|
39
|
-
#ifndef RB_UNLIKELY
|
|
40
|
-
#define RB_UNLIKELY(cond) (cond)
|
|
41
|
-
#endif
|
|
42
|
-
|
|
43
39
|
static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8;
|
|
44
40
|
|
|
45
|
-
static ID i_to_s, i_to_json, i_new,
|
|
41
|
+
static ID i_to_s, i_to_json, i_new, i_encode;
|
|
46
42
|
static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
|
|
47
43
|
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
|
|
48
44
|
|
|
@@ -64,6 +60,7 @@ struct generate_json_data {
|
|
|
64
60
|
JSON_Generator_State *state;
|
|
65
61
|
VALUE obj;
|
|
66
62
|
generator_func func;
|
|
63
|
+
long depth;
|
|
67
64
|
};
|
|
68
65
|
|
|
69
66
|
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
|
@@ -85,23 +82,18 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
|
|
|
85
82
|
|
|
86
83
|
static int usascii_encindex, utf8_encindex, binary_encindex;
|
|
87
84
|
|
|
88
|
-
|
|
89
|
-
RBIMPL_ATTR_NORETURN()
|
|
90
|
-
#endif
|
|
91
|
-
static void raise_generator_error_str(VALUE invalid_object, VALUE str)
|
|
85
|
+
NORETURN(static void) raise_generator_error_str(VALUE invalid_object, VALUE str)
|
|
92
86
|
{
|
|
87
|
+
rb_enc_associate_index(str, utf8_encindex);
|
|
93
88
|
VALUE exc = rb_exc_new_str(eGeneratorError, str);
|
|
94
89
|
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
|
|
95
90
|
rb_exc_raise(exc);
|
|
96
91
|
}
|
|
97
92
|
|
|
98
|
-
#ifdef RBIMPL_ATTR_NORETURN
|
|
99
|
-
RBIMPL_ATTR_NORETURN()
|
|
100
|
-
#endif
|
|
101
93
|
#ifdef RBIMPL_ATTR_FORMAT
|
|
102
94
|
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
|
|
103
95
|
#endif
|
|
104
|
-
static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
|
|
96
|
+
NORETURN(static void) raise_generator_error(VALUE invalid_object, const char *fmt, ...)
|
|
105
97
|
{
|
|
106
98
|
va_list args;
|
|
107
99
|
va_start(args, fmt);
|
|
@@ -136,13 +128,7 @@ typedef struct _search_state {
|
|
|
136
128
|
#endif /* HAVE_SIMD */
|
|
137
129
|
} search_state;
|
|
138
130
|
|
|
139
|
-
|
|
140
|
-
#define FORCE_INLINE __attribute__((always_inline))
|
|
141
|
-
#else
|
|
142
|
-
#define FORCE_INLINE
|
|
143
|
-
#endif
|
|
144
|
-
|
|
145
|
-
static inline FORCE_INLINE void search_flush(search_state *search)
|
|
131
|
+
ALWAYS_INLINE(static) void search_flush(search_state *search)
|
|
146
132
|
{
|
|
147
133
|
// Do not remove this conditional without profiling, specifically escape-heavy text.
|
|
148
134
|
// escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush).
|
|
@@ -185,7 +171,7 @@ static inline unsigned char search_escape_basic(search_state *search)
|
|
|
185
171
|
return 0;
|
|
186
172
|
}
|
|
187
173
|
|
|
188
|
-
static
|
|
174
|
+
ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
|
|
189
175
|
{
|
|
190
176
|
const unsigned char ch = (unsigned char)*search->ptr;
|
|
191
177
|
switch (ch) {
|
|
@@ -272,7 +258,7 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
|
|
|
272
258
|
|
|
273
259
|
#ifdef HAVE_SIMD
|
|
274
260
|
|
|
275
|
-
static
|
|
261
|
+
ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
|
|
276
262
|
{
|
|
277
263
|
// Flush the buffer so everything up until the last 'len' characters are unflushed.
|
|
278
264
|
search_flush(search);
|
|
@@ -295,7 +281,7 @@ static inline FORCE_INLINE char *copy_remaining_bytes(search_state *search, unsi
|
|
|
295
281
|
|
|
296
282
|
#ifdef HAVE_SIMD_NEON
|
|
297
283
|
|
|
298
|
-
static
|
|
284
|
+
ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
|
|
299
285
|
{
|
|
300
286
|
uint64_t mask = search->matches_mask;
|
|
301
287
|
uint32_t index = trailing_zeros64(mask) >> 2;
|
|
@@ -409,7 +395,7 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
|
|
|
409
395
|
|
|
410
396
|
#ifdef HAVE_SIMD_SSE2
|
|
411
397
|
|
|
412
|
-
static
|
|
398
|
+
ALWAYS_INLINE(static) unsigned char sse2_next_match(search_state *search)
|
|
413
399
|
{
|
|
414
400
|
int mask = search->matches_mask;
|
|
415
401
|
int index = trailing_zeros(mask);
|
|
@@ -433,7 +419,7 @@ static inline FORCE_INLINE unsigned char sse2_next_match(search_state *search)
|
|
|
433
419
|
#define TARGET_SSE2
|
|
434
420
|
#endif
|
|
435
421
|
|
|
436
|
-
static
|
|
422
|
+
ALWAYS_INLINE(static) TARGET_SSE2 unsigned char search_escape_basic_sse2(search_state *search)
|
|
437
423
|
{
|
|
438
424
|
if (RB_UNLIKELY(search->has_matches)) {
|
|
439
425
|
// There are more matches if search->matches_mask > 0.
|
|
@@ -941,11 +927,6 @@ static size_t State_memsize(const void *ptr)
|
|
|
941
927
|
return sizeof(JSON_Generator_State);
|
|
942
928
|
}
|
|
943
929
|
|
|
944
|
-
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
945
|
-
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
946
|
-
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
947
|
-
#endif
|
|
948
|
-
|
|
949
930
|
static const rb_data_type_t JSON_Generator_State_type = {
|
|
950
931
|
"JSON/Generator/State",
|
|
951
932
|
{
|
|
@@ -987,21 +968,24 @@ static void vstate_spill(struct generate_json_data *data)
|
|
|
987
968
|
RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
|
|
988
969
|
}
|
|
989
970
|
|
|
990
|
-
static inline VALUE
|
|
971
|
+
static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
|
|
991
972
|
{
|
|
992
973
|
if (RB_UNLIKELY(!data->vstate)) {
|
|
993
974
|
vstate_spill(data);
|
|
994
975
|
}
|
|
995
|
-
|
|
976
|
+
GET_STATE(data->vstate);
|
|
977
|
+
state->depth = data->depth;
|
|
978
|
+
VALUE tmp = rb_funcall(obj, i_to_json, 1, data->vstate);
|
|
979
|
+
// no need to restore state->depth, vstate is just a temporary State
|
|
980
|
+
return tmp;
|
|
996
981
|
}
|
|
997
982
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
};
|
|
983
|
+
static VALUE
|
|
984
|
+
json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
|
|
985
|
+
{
|
|
986
|
+
VALUE proc_args[2] = {object, is_key};
|
|
987
|
+
return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
|
|
988
|
+
}
|
|
1005
989
|
|
|
1006
990
|
static VALUE
|
|
1007
991
|
convert_string_subclass(VALUE key)
|
|
@@ -1018,8 +1002,130 @@ convert_string_subclass(VALUE key)
|
|
|
1018
1002
|
return key_to_s;
|
|
1019
1003
|
}
|
|
1020
1004
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1005
|
+
static bool enc_utf8_compatible_p(int enc_idx)
|
|
1006
|
+
{
|
|
1007
|
+
if (enc_idx == usascii_encindex) return true;
|
|
1008
|
+
if (enc_idx == utf8_encindex) return true;
|
|
1009
|
+
return false;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
static VALUE encode_json_string_try(VALUE str)
|
|
1013
|
+
{
|
|
1014
|
+
return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
|
1018
|
+
{
|
|
1019
|
+
raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
|
|
1020
|
+
return Qundef;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
static inline bool valid_json_string_p(VALUE str)
|
|
1024
|
+
{
|
|
1025
|
+
int coderange = rb_enc_str_coderange(str);
|
|
1026
|
+
|
|
1027
|
+
if (RB_LIKELY(coderange == ENC_CODERANGE_7BIT)) {
|
|
1028
|
+
return true;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
if (RB_LIKELY(coderange == ENC_CODERANGE_VALID)) {
|
|
1032
|
+
return enc_utf8_compatible_p(RB_ENCODING_GET_INLINED(str));
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
static inline VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
|
|
1039
|
+
{
|
|
1040
|
+
if (RB_LIKELY(valid_json_string_p(str))) {
|
|
1041
|
+
return str;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if (!as_json_called && data->state->strict && RTEST(data->state->as_json)) {
|
|
1045
|
+
VALUE coerced_str = json_call_as_json(data->state, str, Qfalse);
|
|
1046
|
+
if (coerced_str != str) {
|
|
1047
|
+
if (RB_TYPE_P(coerced_str, T_STRING)) {
|
|
1048
|
+
if (!valid_json_string_p(coerced_str)) {
|
|
1049
|
+
raise_generator_error(str, "source sequence is illegal/malformed utf-8");
|
|
1050
|
+
}
|
|
1051
|
+
} else {
|
|
1052
|
+
// as_json could return another type than T_STRING
|
|
1053
|
+
if (is_key) {
|
|
1054
|
+
raise_generator_error(coerced_str, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(coerced_str));
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
return coerced_str;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
if (RB_ENCODING_GET_INLINED(str) == binary_encindex) {
|
|
1063
|
+
VALUE utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
|
1064
|
+
switch (rb_enc_str_coderange(utf8_string)) {
|
|
1065
|
+
case ENC_CODERANGE_7BIT:
|
|
1066
|
+
return utf8_string;
|
|
1067
|
+
case ENC_CODERANGE_VALID:
|
|
1068
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
|
1069
|
+
// TODO: Raise in 3.0.0
|
|
1070
|
+
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
|
1071
|
+
return utf8_string;
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1080
|
+
{
|
|
1081
|
+
fbuffer_append_char(buffer, '"');
|
|
1082
|
+
|
|
1083
|
+
long len;
|
|
1084
|
+
search_state search;
|
|
1085
|
+
search.buffer = buffer;
|
|
1086
|
+
RSTRING_GETMEM(obj, search.ptr, len);
|
|
1087
|
+
search.cursor = search.ptr;
|
|
1088
|
+
search.end = search.ptr + len;
|
|
1089
|
+
|
|
1090
|
+
#ifdef HAVE_SIMD
|
|
1091
|
+
search.matches_mask = 0;
|
|
1092
|
+
search.has_matches = false;
|
|
1093
|
+
search.chunk_base = NULL;
|
|
1094
|
+
#endif /* HAVE_SIMD */
|
|
1095
|
+
|
|
1096
|
+
switch (rb_enc_str_coderange(obj)) {
|
|
1097
|
+
case ENC_CODERANGE_7BIT:
|
|
1098
|
+
case ENC_CODERANGE_VALID:
|
|
1099
|
+
if (RB_UNLIKELY(data->state->ascii_only)) {
|
|
1100
|
+
convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
|
|
1101
|
+
} else if (RB_UNLIKELY(data->state->script_safe)) {
|
|
1102
|
+
convert_UTF8_to_script_safe_JSON(&search);
|
|
1103
|
+
} else {
|
|
1104
|
+
convert_UTF8_to_JSON(&search);
|
|
1105
|
+
}
|
|
1106
|
+
break;
|
|
1107
|
+
default:
|
|
1108
|
+
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
fbuffer_append_char(buffer, '"');
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1115
|
+
{
|
|
1116
|
+
obj = ensure_valid_encoding(data, obj, false, false);
|
|
1117
|
+
raw_generate_json_string(buffer, data, obj);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
struct hash_foreach_arg {
|
|
1121
|
+
VALUE hash;
|
|
1122
|
+
struct generate_json_data *data;
|
|
1123
|
+
int first_key_type;
|
|
1124
|
+
bool first;
|
|
1125
|
+
bool mixed_keys_encountered;
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1128
|
+
NOINLINE(static) void
|
|
1023
1129
|
json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
|
|
1024
1130
|
{
|
|
1025
1131
|
if (arg->mixed_keys_encountered) {
|
|
@@ -1034,13 +1140,6 @@ json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
|
|
|
1034
1140
|
}
|
|
1035
1141
|
}
|
|
1036
1142
|
|
|
1037
|
-
static VALUE
|
|
1038
|
-
json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
|
|
1039
|
-
{
|
|
1040
|
-
VALUE proc_args[2] = {object, is_key};
|
|
1041
|
-
return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
1143
|
static int
|
|
1045
1144
|
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
1046
1145
|
{
|
|
@@ -1050,7 +1149,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1050
1149
|
FBuffer *buffer = data->buffer;
|
|
1051
1150
|
JSON_Generator_State *state = data->state;
|
|
1052
1151
|
|
|
1053
|
-
long depth =
|
|
1152
|
+
long depth = data->depth;
|
|
1054
1153
|
int key_type = rb_type(key);
|
|
1055
1154
|
|
|
1056
1155
|
if (arg->first) {
|
|
@@ -1106,8 +1205,10 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1106
1205
|
break;
|
|
1107
1206
|
}
|
|
1108
1207
|
|
|
1208
|
+
key_to_s = ensure_valid_encoding(data, key_to_s, as_json_called, true);
|
|
1209
|
+
|
|
1109
1210
|
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
|
|
1110
|
-
|
|
1211
|
+
raw_generate_json_string(buffer, data, key_to_s);
|
|
1111
1212
|
} else {
|
|
1112
1213
|
generate_json(buffer, data, key_to_s);
|
|
1113
1214
|
}
|
|
@@ -1122,9 +1223,9 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1122
1223
|
static inline long increase_depth(struct generate_json_data *data)
|
|
1123
1224
|
{
|
|
1124
1225
|
JSON_Generator_State *state = data->state;
|
|
1125
|
-
long depth = ++
|
|
1226
|
+
long depth = ++data->depth;
|
|
1126
1227
|
if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
|
|
1127
|
-
rb_raise(eNestingError, "nesting of %ld is too deep", --
|
|
1228
|
+
rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
|
|
1128
1229
|
}
|
|
1129
1230
|
return depth;
|
|
1130
1231
|
}
|
|
@@ -1135,7 +1236,7 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1135
1236
|
|
|
1136
1237
|
if (RHASH_SIZE(obj) == 0) {
|
|
1137
1238
|
fbuffer_append(buffer, "{}", 2);
|
|
1138
|
-
--data->
|
|
1239
|
+
--data->depth;
|
|
1139
1240
|
return;
|
|
1140
1241
|
}
|
|
1141
1242
|
|
|
@@ -1148,7 +1249,7 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1148
1249
|
};
|
|
1149
1250
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
|
1150
1251
|
|
|
1151
|
-
depth = --data->
|
|
1252
|
+
depth = --data->depth;
|
|
1152
1253
|
if (RB_UNLIKELY(data->state->object_nl)) {
|
|
1153
1254
|
fbuffer_append_str(buffer, data->state->object_nl);
|
|
1154
1255
|
if (RB_UNLIKELY(data->state->indent)) {
|
|
@@ -1164,7 +1265,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1164
1265
|
|
|
1165
1266
|
if (RARRAY_LEN(obj) == 0) {
|
|
1166
1267
|
fbuffer_append(buffer, "[]", 2);
|
|
1167
|
-
--data->
|
|
1268
|
+
--data->depth;
|
|
1168
1269
|
return;
|
|
1169
1270
|
}
|
|
1170
1271
|
|
|
@@ -1180,7 +1281,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1180
1281
|
}
|
|
1181
1282
|
generate_json(buffer, data, RARRAY_AREF(obj, i));
|
|
1182
1283
|
}
|
|
1183
|
-
data->
|
|
1284
|
+
data->depth = --depth;
|
|
1184
1285
|
if (RB_UNLIKELY(data->state->array_nl)) {
|
|
1185
1286
|
fbuffer_append_str(buffer, data->state->array_nl);
|
|
1186
1287
|
if (RB_UNLIKELY(data->state->indent)) {
|
|
@@ -1190,90 +1291,11 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1190
1291
|
fbuffer_append_char(buffer, ']');
|
|
1191
1292
|
}
|
|
1192
1293
|
|
|
1193
|
-
static inline int enc_utf8_compatible_p(int enc_idx)
|
|
1194
|
-
{
|
|
1195
|
-
if (enc_idx == usascii_encindex) return 1;
|
|
1196
|
-
if (enc_idx == utf8_encindex) return 1;
|
|
1197
|
-
return 0;
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
static VALUE encode_json_string_try(VALUE str)
|
|
1201
|
-
{
|
|
1202
|
-
return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
|
1206
|
-
{
|
|
1207
|
-
raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
|
|
1208
|
-
return Qundef;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
static inline VALUE ensure_valid_encoding(VALUE str)
|
|
1212
|
-
{
|
|
1213
|
-
int encindex = RB_ENCODING_GET(str);
|
|
1214
|
-
VALUE utf8_string;
|
|
1215
|
-
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
|
1216
|
-
if (encindex == binary_encindex) {
|
|
1217
|
-
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
|
1218
|
-
switch (rb_enc_str_coderange(utf8_string)) {
|
|
1219
|
-
case ENC_CODERANGE_7BIT:
|
|
1220
|
-
return utf8_string;
|
|
1221
|
-
case ENC_CODERANGE_VALID:
|
|
1222
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
|
1223
|
-
// TODO: Raise in 3.0.0
|
|
1224
|
-
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
|
1225
|
-
return utf8_string;
|
|
1226
|
-
break;
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
1231
|
-
}
|
|
1232
|
-
return str;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1236
|
-
{
|
|
1237
|
-
obj = ensure_valid_encoding(obj);
|
|
1238
|
-
|
|
1239
|
-
fbuffer_append_char(buffer, '"');
|
|
1240
|
-
|
|
1241
|
-
long len;
|
|
1242
|
-
search_state search;
|
|
1243
|
-
search.buffer = buffer;
|
|
1244
|
-
RSTRING_GETMEM(obj, search.ptr, len);
|
|
1245
|
-
search.cursor = search.ptr;
|
|
1246
|
-
search.end = search.ptr + len;
|
|
1247
|
-
|
|
1248
|
-
#ifdef HAVE_SIMD
|
|
1249
|
-
search.matches_mask = 0;
|
|
1250
|
-
search.has_matches = false;
|
|
1251
|
-
search.chunk_base = NULL;
|
|
1252
|
-
#endif /* HAVE_SIMD */
|
|
1253
|
-
|
|
1254
|
-
switch (rb_enc_str_coderange(obj)) {
|
|
1255
|
-
case ENC_CODERANGE_7BIT:
|
|
1256
|
-
case ENC_CODERANGE_VALID:
|
|
1257
|
-
if (RB_UNLIKELY(data->state->ascii_only)) {
|
|
1258
|
-
convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
|
|
1259
|
-
} else if (RB_UNLIKELY(data->state->script_safe)) {
|
|
1260
|
-
convert_UTF8_to_script_safe_JSON(&search);
|
|
1261
|
-
} else {
|
|
1262
|
-
convert_UTF8_to_JSON(&search);
|
|
1263
|
-
}
|
|
1264
|
-
break;
|
|
1265
|
-
default:
|
|
1266
|
-
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
|
1267
|
-
break;
|
|
1268
|
-
}
|
|
1269
|
-
fbuffer_append_char(buffer, '"');
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
1294
|
static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1273
1295
|
{
|
|
1274
1296
|
VALUE tmp;
|
|
1275
1297
|
if (rb_respond_to(obj, i_to_json)) {
|
|
1276
|
-
tmp =
|
|
1298
|
+
tmp = json_call_to_json(data, obj);
|
|
1277
1299
|
Check_Type(tmp, T_STRING);
|
|
1278
1300
|
fbuffer_append_str(buffer, tmp);
|
|
1279
1301
|
} else {
|
|
@@ -1340,7 +1362,7 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
|
|
1340
1362
|
if (casted_obj != obj) {
|
|
1341
1363
|
increase_depth(data);
|
|
1342
1364
|
generate_json(buffer, data, casted_obj);
|
|
1343
|
-
data->
|
|
1365
|
+
data->depth--;
|
|
1344
1366
|
return;
|
|
1345
1367
|
}
|
|
1346
1368
|
}
|
|
@@ -1407,7 +1429,16 @@ start:
|
|
|
1407
1429
|
break;
|
|
1408
1430
|
case T_STRING:
|
|
1409
1431
|
if (klass != rb_cString) goto general;
|
|
1410
|
-
|
|
1432
|
+
|
|
1433
|
+
if (RB_LIKELY(valid_json_string_p(obj))) {
|
|
1434
|
+
raw_generate_json_string(buffer, data, obj);
|
|
1435
|
+
} else if (as_json_called) {
|
|
1436
|
+
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
|
1437
|
+
} else {
|
|
1438
|
+
obj = ensure_valid_encoding(data, obj, false, false);
|
|
1439
|
+
as_json_called = true;
|
|
1440
|
+
goto start;
|
|
1441
|
+
}
|
|
1411
1442
|
break;
|
|
1412
1443
|
case T_SYMBOL:
|
|
1413
1444
|
generate_json_symbol(buffer, data, obj);
|
|
@@ -1443,16 +1474,14 @@ static VALUE generate_json_try(VALUE d)
|
|
|
1443
1474
|
|
|
1444
1475
|
data->func(data->buffer, data, data->obj);
|
|
1445
1476
|
|
|
1446
|
-
return
|
|
1477
|
+
return fbuffer_finalize(data->buffer);
|
|
1447
1478
|
}
|
|
1448
1479
|
|
|
1449
|
-
static VALUE
|
|
1480
|
+
static VALUE generate_json_ensure(VALUE d)
|
|
1450
1481
|
{
|
|
1451
1482
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
|
1452
1483
|
fbuffer_free(data->buffer);
|
|
1453
1484
|
|
|
1454
|
-
rb_exc_raise(exc);
|
|
1455
|
-
|
|
1456
1485
|
return Qundef;
|
|
1457
1486
|
}
|
|
1458
1487
|
|
|
@@ -1468,14 +1497,13 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
|
|
|
1468
1497
|
|
|
1469
1498
|
struct generate_json_data data = {
|
|
1470
1499
|
.buffer = &buffer,
|
|
1471
|
-
.vstate = self
|
|
1500
|
+
.vstate = Qfalse, // don't use self as it may be frozen and its depth is mutated when calling to_json
|
|
1472
1501
|
.state = state,
|
|
1502
|
+
.depth = state->depth,
|
|
1473
1503
|
.obj = obj,
|
|
1474
1504
|
.func = func
|
|
1475
1505
|
};
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
return fbuffer_finalize(&buffer);
|
|
1506
|
+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
1479
1507
|
}
|
|
1480
1508
|
|
|
1481
1509
|
/* call-seq:
|
|
@@ -1491,10 +1519,7 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
|
|
|
1491
1519
|
rb_check_arity(argc, 1, 2);
|
|
1492
1520
|
VALUE obj = argv[0];
|
|
1493
1521
|
VALUE io = argc > 1 ? argv[1] : Qnil;
|
|
1494
|
-
|
|
1495
|
-
GET_STATE(self);
|
|
1496
|
-
(void)state;
|
|
1497
|
-
return result;
|
|
1522
|
+
return cState_partial_generate(self, obj, generate_json, io);
|
|
1498
1523
|
}
|
|
1499
1524
|
|
|
1500
1525
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
@@ -1575,6 +1600,7 @@ static VALUE string_config(VALUE config)
|
|
|
1575
1600
|
*/
|
|
1576
1601
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1577
1602
|
{
|
|
1603
|
+
rb_check_frozen(self);
|
|
1578
1604
|
GET_STATE(self);
|
|
1579
1605
|
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
|
1580
1606
|
return Qnil;
|
|
@@ -1600,6 +1626,7 @@ static VALUE cState_space(VALUE self)
|
|
|
1600
1626
|
*/
|
|
1601
1627
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1602
1628
|
{
|
|
1629
|
+
rb_check_frozen(self);
|
|
1603
1630
|
GET_STATE(self);
|
|
1604
1631
|
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
|
1605
1632
|
return Qnil;
|
|
@@ -1623,6 +1650,7 @@ static VALUE cState_space_before(VALUE self)
|
|
|
1623
1650
|
*/
|
|
1624
1651
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1625
1652
|
{
|
|
1653
|
+
rb_check_frozen(self);
|
|
1626
1654
|
GET_STATE(self);
|
|
1627
1655
|
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
|
1628
1656
|
return Qnil;
|
|
@@ -1648,6 +1676,7 @@ static VALUE cState_object_nl(VALUE self)
|
|
|
1648
1676
|
*/
|
|
1649
1677
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1650
1678
|
{
|
|
1679
|
+
rb_check_frozen(self);
|
|
1651
1680
|
GET_STATE(self);
|
|
1652
1681
|
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
|
1653
1682
|
return Qnil;
|
|
@@ -1671,6 +1700,7 @@ static VALUE cState_array_nl(VALUE self)
|
|
|
1671
1700
|
*/
|
|
1672
1701
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
1673
1702
|
{
|
|
1703
|
+
rb_check_frozen(self);
|
|
1674
1704
|
GET_STATE(self);
|
|
1675
1705
|
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
|
1676
1706
|
return Qnil;
|
|
@@ -1694,6 +1724,7 @@ static VALUE cState_as_json(VALUE self)
|
|
|
1694
1724
|
*/
|
|
1695
1725
|
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
|
|
1696
1726
|
{
|
|
1727
|
+
rb_check_frozen(self);
|
|
1697
1728
|
GET_STATE(self);
|
|
1698
1729
|
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
|
|
1699
1730
|
return Qnil;
|
|
@@ -1736,6 +1767,7 @@ static long long_config(VALUE num)
|
|
|
1736
1767
|
*/
|
|
1737
1768
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
1738
1769
|
{
|
|
1770
|
+
rb_check_frozen(self);
|
|
1739
1771
|
GET_STATE(self);
|
|
1740
1772
|
state->max_nesting = long_config(depth);
|
|
1741
1773
|
return Qnil;
|
|
@@ -1761,6 +1793,7 @@ static VALUE cState_script_safe(VALUE self)
|
|
|
1761
1793
|
*/
|
|
1762
1794
|
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
|
|
1763
1795
|
{
|
|
1796
|
+
rb_check_frozen(self);
|
|
1764
1797
|
GET_STATE(self);
|
|
1765
1798
|
state->script_safe = RTEST(enable);
|
|
1766
1799
|
return Qnil;
|
|
@@ -1792,6 +1825,7 @@ static VALUE cState_strict(VALUE self)
|
|
|
1792
1825
|
*/
|
|
1793
1826
|
static VALUE cState_strict_set(VALUE self, VALUE enable)
|
|
1794
1827
|
{
|
|
1828
|
+
rb_check_frozen(self);
|
|
1795
1829
|
GET_STATE(self);
|
|
1796
1830
|
state->strict = RTEST(enable);
|
|
1797
1831
|
return Qnil;
|
|
@@ -1816,6 +1850,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
|
1816
1850
|
*/
|
|
1817
1851
|
static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
|
|
1818
1852
|
{
|
|
1853
|
+
rb_check_frozen(self);
|
|
1819
1854
|
GET_STATE(self);
|
|
1820
1855
|
state->allow_nan = RTEST(enable);
|
|
1821
1856
|
return Qnil;
|
|
@@ -1840,6 +1875,7 @@ static VALUE cState_ascii_only_p(VALUE self)
|
|
|
1840
1875
|
*/
|
|
1841
1876
|
static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
|
|
1842
1877
|
{
|
|
1878
|
+
rb_check_frozen(self);
|
|
1843
1879
|
GET_STATE(self);
|
|
1844
1880
|
state->ascii_only = RTEST(enable);
|
|
1845
1881
|
return Qnil;
|
|
@@ -1877,6 +1913,7 @@ static VALUE cState_depth(VALUE self)
|
|
|
1877
1913
|
*/
|
|
1878
1914
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
1879
1915
|
{
|
|
1916
|
+
rb_check_frozen(self);
|
|
1880
1917
|
GET_STATE(self);
|
|
1881
1918
|
state->depth = long_config(depth);
|
|
1882
1919
|
return Qnil;
|
|
@@ -1910,6 +1947,7 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
|
|
|
1910
1947
|
*/
|
|
1911
1948
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
|
1912
1949
|
{
|
|
1950
|
+
rb_check_frozen(self);
|
|
1913
1951
|
GET_STATE(self);
|
|
1914
1952
|
buffer_initial_length_set(state, buffer_initial_length);
|
|
1915
1953
|
return Qnil;
|
|
@@ -1976,6 +2014,7 @@ static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE con
|
|
|
1976
2014
|
|
|
1977
2015
|
static VALUE cState_configure(VALUE self, VALUE opts)
|
|
1978
2016
|
{
|
|
2017
|
+
rb_check_frozen(self);
|
|
1979
2018
|
GET_STATE(self);
|
|
1980
2019
|
configure_state(state, self, opts);
|
|
1981
2020
|
return self;
|
|
@@ -1997,12 +2036,11 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
|
1997
2036
|
.buffer = &buffer,
|
|
1998
2037
|
.vstate = Qfalse,
|
|
1999
2038
|
.state = &state,
|
|
2039
|
+
.depth = state.depth,
|
|
2000
2040
|
.obj = obj,
|
|
2001
2041
|
.func = generate_json,
|
|
2002
2042
|
};
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
return fbuffer_finalize(&buffer);
|
|
2043
|
+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
2006
2044
|
}
|
|
2007
2045
|
|
|
2008
2046
|
/*
|
|
@@ -2072,7 +2110,6 @@ void Init_generator(void)
|
|
|
2072
2110
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
2073
2111
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
|
2074
2112
|
rb_define_method(cState, "generate", cState_generate, -1);
|
|
2075
|
-
rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
|
|
2076
2113
|
|
|
2077
2114
|
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
|
|
2078
2115
|
|
|
@@ -2120,10 +2157,6 @@ void Init_generator(void)
|
|
|
2120
2157
|
i_to_s = rb_intern("to_s");
|
|
2121
2158
|
i_to_json = rb_intern("to_json");
|
|
2122
2159
|
i_new = rb_intern("new");
|
|
2123
|
-
i_pack = rb_intern("pack");
|
|
2124
|
-
i_unpack = rb_intern("unpack");
|
|
2125
|
-
i_create_id = rb_intern("create_id");
|
|
2126
|
-
i_extend = rb_intern("extend");
|
|
2127
2160
|
i_encode = rb_intern("encode");
|
|
2128
2161
|
|
|
2129
2162
|
sym_indent = ID2SYM(rb_intern("indent"));
|