json 2.15.2 → 2.17.0
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 +22 -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 +191 -187
- data/ext/json/ext/json.h +97 -0
- data/ext/json/ext/parser/extconf.rb +2 -1
- data/ext/json/ext/parser/parser.c +497 -388
- 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 +52 -19
- 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. Did you try to serialize objects with circular references?", --
|
|
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:
|
|
@@ -1494,38 +1522,6 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
|
|
|
1494
1522
|
return cState_partial_generate(self, obj, generate_json, io);
|
|
1495
1523
|
}
|
|
1496
1524
|
|
|
1497
|
-
static VALUE cState_generate_new(int argc, VALUE *argv, VALUE self)
|
|
1498
|
-
{
|
|
1499
|
-
rb_check_arity(argc, 1, 2);
|
|
1500
|
-
VALUE obj = argv[0];
|
|
1501
|
-
VALUE io = argc > 1 ? argv[1] : Qnil;
|
|
1502
|
-
|
|
1503
|
-
GET_STATE(self);
|
|
1504
|
-
|
|
1505
|
-
JSON_Generator_State new_state;
|
|
1506
|
-
MEMCPY(&new_state, state, JSON_Generator_State, 1);
|
|
1507
|
-
|
|
1508
|
-
// FIXME: depth shouldn't be part of JSON_Generator_State, as that prevents it from being used concurrently.
|
|
1509
|
-
new_state.depth = 0;
|
|
1510
|
-
|
|
1511
|
-
char stack_buffer[FBUFFER_STACK_SIZE];
|
|
1512
|
-
FBuffer buffer = {
|
|
1513
|
-
.io = RTEST(io) ? io : Qfalse,
|
|
1514
|
-
};
|
|
1515
|
-
fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
|
1516
|
-
|
|
1517
|
-
struct generate_json_data data = {
|
|
1518
|
-
.buffer = &buffer,
|
|
1519
|
-
.vstate = Qfalse,
|
|
1520
|
-
.state = &new_state,
|
|
1521
|
-
.obj = obj,
|
|
1522
|
-
.func = generate_json
|
|
1523
|
-
};
|
|
1524
|
-
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
|
1525
|
-
|
|
1526
|
-
return fbuffer_finalize(&buffer);
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
1525
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
1530
1526
|
{
|
|
1531
1527
|
rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
|
|
@@ -1604,6 +1600,7 @@ static VALUE string_config(VALUE config)
|
|
|
1604
1600
|
*/
|
|
1605
1601
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1606
1602
|
{
|
|
1603
|
+
rb_check_frozen(self);
|
|
1607
1604
|
GET_STATE(self);
|
|
1608
1605
|
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
|
1609
1606
|
return Qnil;
|
|
@@ -1629,6 +1626,7 @@ static VALUE cState_space(VALUE self)
|
|
|
1629
1626
|
*/
|
|
1630
1627
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1631
1628
|
{
|
|
1629
|
+
rb_check_frozen(self);
|
|
1632
1630
|
GET_STATE(self);
|
|
1633
1631
|
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
|
1634
1632
|
return Qnil;
|
|
@@ -1652,6 +1650,7 @@ static VALUE cState_space_before(VALUE self)
|
|
|
1652
1650
|
*/
|
|
1653
1651
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1654
1652
|
{
|
|
1653
|
+
rb_check_frozen(self);
|
|
1655
1654
|
GET_STATE(self);
|
|
1656
1655
|
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
|
1657
1656
|
return Qnil;
|
|
@@ -1677,6 +1676,7 @@ static VALUE cState_object_nl(VALUE self)
|
|
|
1677
1676
|
*/
|
|
1678
1677
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1679
1678
|
{
|
|
1679
|
+
rb_check_frozen(self);
|
|
1680
1680
|
GET_STATE(self);
|
|
1681
1681
|
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
|
1682
1682
|
return Qnil;
|
|
@@ -1700,6 +1700,7 @@ static VALUE cState_array_nl(VALUE self)
|
|
|
1700
1700
|
*/
|
|
1701
1701
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
1702
1702
|
{
|
|
1703
|
+
rb_check_frozen(self);
|
|
1703
1704
|
GET_STATE(self);
|
|
1704
1705
|
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
|
1705
1706
|
return Qnil;
|
|
@@ -1723,6 +1724,7 @@ static VALUE cState_as_json(VALUE self)
|
|
|
1723
1724
|
*/
|
|
1724
1725
|
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
|
|
1725
1726
|
{
|
|
1727
|
+
rb_check_frozen(self);
|
|
1726
1728
|
GET_STATE(self);
|
|
1727
1729
|
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
|
|
1728
1730
|
return Qnil;
|
|
@@ -1765,6 +1767,7 @@ static long long_config(VALUE num)
|
|
|
1765
1767
|
*/
|
|
1766
1768
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
1767
1769
|
{
|
|
1770
|
+
rb_check_frozen(self);
|
|
1768
1771
|
GET_STATE(self);
|
|
1769
1772
|
state->max_nesting = long_config(depth);
|
|
1770
1773
|
return Qnil;
|
|
@@ -1790,6 +1793,7 @@ static VALUE cState_script_safe(VALUE self)
|
|
|
1790
1793
|
*/
|
|
1791
1794
|
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
|
|
1792
1795
|
{
|
|
1796
|
+
rb_check_frozen(self);
|
|
1793
1797
|
GET_STATE(self);
|
|
1794
1798
|
state->script_safe = RTEST(enable);
|
|
1795
1799
|
return Qnil;
|
|
@@ -1821,6 +1825,7 @@ static VALUE cState_strict(VALUE self)
|
|
|
1821
1825
|
*/
|
|
1822
1826
|
static VALUE cState_strict_set(VALUE self, VALUE enable)
|
|
1823
1827
|
{
|
|
1828
|
+
rb_check_frozen(self);
|
|
1824
1829
|
GET_STATE(self);
|
|
1825
1830
|
state->strict = RTEST(enable);
|
|
1826
1831
|
return Qnil;
|
|
@@ -1845,6 +1850,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
|
1845
1850
|
*/
|
|
1846
1851
|
static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
|
|
1847
1852
|
{
|
|
1853
|
+
rb_check_frozen(self);
|
|
1848
1854
|
GET_STATE(self);
|
|
1849
1855
|
state->allow_nan = RTEST(enable);
|
|
1850
1856
|
return Qnil;
|
|
@@ -1869,6 +1875,7 @@ static VALUE cState_ascii_only_p(VALUE self)
|
|
|
1869
1875
|
*/
|
|
1870
1876
|
static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
|
|
1871
1877
|
{
|
|
1878
|
+
rb_check_frozen(self);
|
|
1872
1879
|
GET_STATE(self);
|
|
1873
1880
|
state->ascii_only = RTEST(enable);
|
|
1874
1881
|
return Qnil;
|
|
@@ -1906,6 +1913,7 @@ static VALUE cState_depth(VALUE self)
|
|
|
1906
1913
|
*/
|
|
1907
1914
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
1908
1915
|
{
|
|
1916
|
+
rb_check_frozen(self);
|
|
1909
1917
|
GET_STATE(self);
|
|
1910
1918
|
state->depth = long_config(depth);
|
|
1911
1919
|
return Qnil;
|
|
@@ -1939,6 +1947,7 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
|
|
|
1939
1947
|
*/
|
|
1940
1948
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
|
1941
1949
|
{
|
|
1950
|
+
rb_check_frozen(self);
|
|
1942
1951
|
GET_STATE(self);
|
|
1943
1952
|
buffer_initial_length_set(state, buffer_initial_length);
|
|
1944
1953
|
return Qnil;
|
|
@@ -2005,6 +2014,7 @@ static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE con
|
|
|
2005
2014
|
|
|
2006
2015
|
static VALUE cState_configure(VALUE self, VALUE opts)
|
|
2007
2016
|
{
|
|
2017
|
+
rb_check_frozen(self);
|
|
2008
2018
|
GET_STATE(self);
|
|
2009
2019
|
configure_state(state, self, opts);
|
|
2010
2020
|
return self;
|
|
@@ -2026,12 +2036,11 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
|
2026
2036
|
.buffer = &buffer,
|
|
2027
2037
|
.vstate = Qfalse,
|
|
2028
2038
|
.state = &state,
|
|
2039
|
+
.depth = state.depth,
|
|
2029
2040
|
.obj = obj,
|
|
2030
2041
|
.func = generate_json,
|
|
2031
2042
|
};
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
return fbuffer_finalize(&buffer);
|
|
2043
|
+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
2035
2044
|
}
|
|
2036
2045
|
|
|
2037
2046
|
/*
|
|
@@ -2101,7 +2110,6 @@ void Init_generator(void)
|
|
|
2101
2110
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
2102
2111
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
|
2103
2112
|
rb_define_method(cState, "generate", cState_generate, -1);
|
|
2104
|
-
rb_define_method(cState, "generate_new", cState_generate_new, -1); // :nodoc:
|
|
2105
2113
|
|
|
2106
2114
|
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
|
|
2107
2115
|
|
|
@@ -2149,10 +2157,6 @@ void Init_generator(void)
|
|
|
2149
2157
|
i_to_s = rb_intern("to_s");
|
|
2150
2158
|
i_to_json = rb_intern("to_json");
|
|
2151
2159
|
i_new = rb_intern("new");
|
|
2152
|
-
i_pack = rb_intern("pack");
|
|
2153
|
-
i_unpack = rb_intern("unpack");
|
|
2154
|
-
i_create_id = rb_intern("create_id");
|
|
2155
|
-
i_extend = rb_intern("extend");
|
|
2156
2160
|
i_encode = rb_intern("encode");
|
|
2157
2161
|
|
|
2158
2162
|
sym_indent = ID2SYM(rb_intern("indent"));
|