json 2.7.4 → 2.10.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 +54 -0
- data/LEGAL +0 -52
- data/README.md +61 -57
- data/ext/json/ext/fbuffer/fbuffer.h +123 -64
- data/ext/json/ext/generator/generator.c +784 -474
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1164 -1923
- data/json.gemspec +7 -5
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/add/symbol.rb +7 -2
- data/lib/json/common.rb +341 -77
- data/lib/json/ext/generator/state.rb +2 -31
- data/lib/json/ext.rb +28 -8
- data/lib/json/{pure → truffle_ruby}/generator.rb +264 -154
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +8 -17
- data/ext/json/ext/generator/generator.h +0 -129
- data/ext/json/ext/parser/parser.h +0 -60
- data/ext/json/ext/parser/parser.rl +0 -997
- data/lib/json/pure/parser.rb +0 -331
- data/lib/json/pure.rb +0 -16
@@ -1,13 +1,171 @@
|
|
1
|
+
#include "ruby.h"
|
1
2
|
#include "../fbuffer/fbuffer.h"
|
2
|
-
|
3
|
+
|
4
|
+
#include <math.h>
|
5
|
+
#include <ctype.h>
|
6
|
+
|
7
|
+
/* ruby api and some helpers */
|
8
|
+
|
9
|
+
typedef struct JSON_Generator_StateStruct {
|
10
|
+
VALUE indent;
|
11
|
+
VALUE space;
|
12
|
+
VALUE space_before;
|
13
|
+
VALUE object_nl;
|
14
|
+
VALUE array_nl;
|
15
|
+
VALUE as_json;
|
16
|
+
|
17
|
+
long max_nesting;
|
18
|
+
long depth;
|
19
|
+
long buffer_initial_length;
|
20
|
+
|
21
|
+
bool allow_nan;
|
22
|
+
bool ascii_only;
|
23
|
+
bool script_safe;
|
24
|
+
bool strict;
|
25
|
+
} JSON_Generator_State;
|
3
26
|
|
4
27
|
#ifndef RB_UNLIKELY
|
5
28
|
#define RB_UNLIKELY(cond) (cond)
|
6
29
|
#endif
|
7
30
|
|
8
|
-
static VALUE mJSON, cState, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
|
31
|
+
static VALUE mJSON, cState, cFragment, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
|
9
32
|
|
10
33
|
static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
|
34
|
+
static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
|
35
|
+
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
|
36
|
+
|
37
|
+
|
38
|
+
#define GET_STATE_TO(self, state) \
|
39
|
+
TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state)
|
40
|
+
|
41
|
+
#define GET_STATE(self) \
|
42
|
+
JSON_Generator_State *state; \
|
43
|
+
GET_STATE_TO(self, state)
|
44
|
+
|
45
|
+
struct generate_json_data;
|
46
|
+
|
47
|
+
typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
48
|
+
|
49
|
+
struct generate_json_data {
|
50
|
+
FBuffer *buffer;
|
51
|
+
VALUE vstate;
|
52
|
+
JSON_Generator_State *state;
|
53
|
+
VALUE obj;
|
54
|
+
generator_func func;
|
55
|
+
};
|
56
|
+
|
57
|
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
58
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
|
59
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
60
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
61
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
62
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
63
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
64
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
65
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
66
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
67
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
68
|
+
#endif
|
69
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
70
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
71
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
72
|
+
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
73
|
+
|
74
|
+
static int usascii_encindex, utf8_encindex, binary_encindex;
|
75
|
+
|
76
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
77
|
+
RBIMPL_ATTR_NORETURN()
|
78
|
+
#endif
|
79
|
+
static void raise_generator_error_str(VALUE invalid_object, VALUE str)
|
80
|
+
{
|
81
|
+
VALUE exc = rb_exc_new_str(eGeneratorError, str);
|
82
|
+
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
|
83
|
+
rb_exc_raise(exc);
|
84
|
+
}
|
85
|
+
|
86
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
87
|
+
RBIMPL_ATTR_NORETURN()
|
88
|
+
#endif
|
89
|
+
#ifdef RBIMPL_ATTR_FORMAT
|
90
|
+
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
|
91
|
+
#endif
|
92
|
+
static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
|
93
|
+
{
|
94
|
+
va_list args;
|
95
|
+
va_start(args, fmt);
|
96
|
+
VALUE str = rb_vsprintf(fmt, args);
|
97
|
+
va_end(args);
|
98
|
+
raise_generator_error_str(invalid_object, str);
|
99
|
+
}
|
100
|
+
|
101
|
+
// 0 - single byte char that don't need to be escaped.
|
102
|
+
// (x | 8) - char that needs to be escaped.
|
103
|
+
static const unsigned char CHAR_LENGTH_MASK = 7;
|
104
|
+
static const unsigned char ESCAPE_MASK = 8;
|
105
|
+
|
106
|
+
typedef struct _search_state {
|
107
|
+
const char *ptr;
|
108
|
+
const char *end;
|
109
|
+
const char *cursor;
|
110
|
+
FBuffer *buffer;
|
111
|
+
} search_state;
|
112
|
+
|
113
|
+
static inline void search_flush(search_state *search)
|
114
|
+
{
|
115
|
+
fbuffer_append(search->buffer, search->cursor, search->ptr - search->cursor);
|
116
|
+
search->cursor = search->ptr;
|
117
|
+
}
|
118
|
+
|
119
|
+
static const unsigned char escape_table_basic[256] = {
|
120
|
+
// ASCII Control Characters
|
121
|
+
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
122
|
+
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
123
|
+
// ASCII Characters
|
124
|
+
0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"'
|
125
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
126
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
127
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
|
128
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
129
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
130
|
+
};
|
131
|
+
|
132
|
+
static inline unsigned char search_escape_basic(search_state *search)
|
133
|
+
{
|
134
|
+
while (search->ptr < search->end) {
|
135
|
+
if (RB_UNLIKELY(escape_table_basic[(const unsigned char)*search->ptr])) {
|
136
|
+
search_flush(search);
|
137
|
+
return 1;
|
138
|
+
} else {
|
139
|
+
search->ptr++;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
search_flush(search);
|
143
|
+
return 0;
|
144
|
+
}
|
145
|
+
|
146
|
+
static inline void escape_UTF8_char_basic(search_state *search) {
|
147
|
+
const unsigned char ch = (unsigned char)*search->ptr;
|
148
|
+
switch (ch) {
|
149
|
+
case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
|
150
|
+
case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
|
151
|
+
case '/': fbuffer_append(search->buffer, "\\/", 2); break;
|
152
|
+
case '\b': fbuffer_append(search->buffer, "\\b", 2); break;
|
153
|
+
case '\f': fbuffer_append(search->buffer, "\\f", 2); break;
|
154
|
+
case '\n': fbuffer_append(search->buffer, "\\n", 2); break;
|
155
|
+
case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
|
156
|
+
case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
|
157
|
+
default: {
|
158
|
+
const char *hexdig = "0123456789abcdef";
|
159
|
+
char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
|
160
|
+
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
161
|
+
scratch[5] = hexdig[ch & 0xf];
|
162
|
+
fbuffer_append(search->buffer, scratch, 6);
|
163
|
+
break;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
search->ptr++;
|
167
|
+
search->cursor = search->ptr;
|
168
|
+
}
|
11
169
|
|
12
170
|
/* Converts in_string to a JSON string (without the wrapping '"'
|
13
171
|
* characters) in FBuffer out_buffer.
|
@@ -19,296 +177,241 @@ static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_e
|
|
19
177
|
*
|
20
178
|
* - If out_ascii_only: non-ASCII characters (>0x7F)
|
21
179
|
*
|
22
|
-
* - If
|
180
|
+
* - If script_safe: forwardslash (/), line separator (U+2028), and
|
23
181
|
* paragraph separator (U+2029)
|
24
182
|
*
|
25
183
|
* Everything else (should be UTF-8) is just passed through and
|
26
184
|
* appended to the result.
|
27
185
|
*/
|
28
|
-
static void convert_UTF8_to_JSON(
|
186
|
+
static inline void convert_UTF8_to_JSON(search_state *search)
|
29
187
|
{
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
unsigned long len = RSTRING_LEN(str);
|
188
|
+
while (search_escape_basic(search)) {
|
189
|
+
escape_UTF8_char_basic(search);
|
190
|
+
}
|
191
|
+
}
|
35
192
|
|
36
|
-
|
193
|
+
static inline void escape_UTF8_char(search_state *search, unsigned char ch_len) {
|
194
|
+
const unsigned char ch = (unsigned char)*search->ptr;
|
195
|
+
switch (ch_len) {
|
196
|
+
case 1: {
|
197
|
+
switch (ch) {
|
198
|
+
case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
|
199
|
+
case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
|
200
|
+
case '/': fbuffer_append(search->buffer, "\\/", 2); break;
|
201
|
+
case '\b': fbuffer_append(search->buffer, "\\b", 2); break;
|
202
|
+
case '\f': fbuffer_append(search->buffer, "\\f", 2); break;
|
203
|
+
case '\n': fbuffer_append(search->buffer, "\\n", 2); break;
|
204
|
+
case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
|
205
|
+
case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
|
206
|
+
default: {
|
207
|
+
const char *hexdig = "0123456789abcdef";
|
208
|
+
char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
|
209
|
+
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
210
|
+
scratch[5] = hexdig[ch & 0xf];
|
211
|
+
fbuffer_append(search->buffer, scratch, 6);
|
212
|
+
break;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
break;
|
216
|
+
}
|
217
|
+
case 3: {
|
218
|
+
if (search->ptr[2] & 1) {
|
219
|
+
fbuffer_append(search->buffer, "\\u2029", 6);
|
220
|
+
} else {
|
221
|
+
fbuffer_append(search->buffer, "\\u2028", 6);
|
222
|
+
}
|
223
|
+
break;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
search->cursor = (search->ptr += ch_len);
|
227
|
+
}
|
37
228
|
|
38
|
-
|
229
|
+
static const unsigned char script_safe_escape_table[256] = {
|
230
|
+
// ASCII Control Characters
|
231
|
+
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
232
|
+
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
233
|
+
// ASCII Characters
|
234
|
+
0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, // '"' and '/'
|
235
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
236
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
237
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
|
238
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
239
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
240
|
+
// Continuation byte
|
241
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
242
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
243
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
244
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
245
|
+
// First byte of a 2-byte code point
|
246
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
247
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
248
|
+
// First byte of a 3-byte code point
|
249
|
+
3, 3,11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xE2 is the start of \u2028 and \u2029
|
250
|
+
//First byte of a 4+ byte code point
|
251
|
+
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9,
|
252
|
+
};
|
39
253
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
254
|
+
static inline unsigned char search_script_safe_escape(search_state *search)
|
255
|
+
{
|
256
|
+
while (search->ptr < search->end) {
|
257
|
+
unsigned char ch = (unsigned char)*search->ptr;
|
258
|
+
unsigned char ch_len = script_safe_escape_table[ch];
|
44
259
|
|
45
260
|
if (RB_UNLIKELY(ch_len)) {
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
switch (ch) {
|
53
|
-
case '"': fbuffer_append(out_buffer, "\\\"", 2); break;
|
54
|
-
case '\\': fbuffer_append(out_buffer, "\\\\", 2); break;
|
55
|
-
case '/': fbuffer_append(out_buffer, "\\/", 2); break;
|
56
|
-
case '\b': fbuffer_append(out_buffer, "\\b", 2); break;
|
57
|
-
case '\f': fbuffer_append(out_buffer, "\\f", 2); break;
|
58
|
-
case '\n': fbuffer_append(out_buffer, "\\n", 2); break;
|
59
|
-
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
60
|
-
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
61
|
-
default: {
|
62
|
-
scratch[2] = hexdig[ch >> 12];
|
63
|
-
scratch[3] = hexdig[(ch >> 8) & 0xf];
|
64
|
-
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
65
|
-
scratch[5] = hexdig[ch & 0xf];
|
66
|
-
fbuffer_append(out_buffer, scratch, 6);
|
67
|
-
break;
|
68
|
-
}
|
261
|
+
if (ch_len & ESCAPE_MASK) {
|
262
|
+
if (RB_UNLIKELY(ch_len == 11)) {
|
263
|
+
const unsigned char *uptr = (const unsigned char *)search->ptr;
|
264
|
+
if (!(uptr[1] == 0x80 && (uptr[2] >> 1) == 0x54)) {
|
265
|
+
search->ptr += 3;
|
266
|
+
continue;
|
69
267
|
}
|
70
|
-
break;
|
71
|
-
}
|
72
|
-
case 3: {
|
73
|
-
unsigned char b2 = ptr[pos + 1];
|
74
|
-
if (RB_UNLIKELY(out_script_safe && b2 == 0x80)) {
|
75
|
-
unsigned char b3 = ptr[pos + 2];
|
76
|
-
if (b3 == 0xA8) {
|
77
|
-
FLUSH_POS(3);
|
78
|
-
fbuffer_append(out_buffer, "\\u2028", 6);
|
79
|
-
break;
|
80
|
-
} else if (b3 == 0xA9) {
|
81
|
-
FLUSH_POS(3);
|
82
|
-
fbuffer_append(out_buffer, "\\u2029", 6);
|
83
|
-
break;
|
84
|
-
}
|
85
|
-
}
|
86
|
-
// fallthrough
|
87
268
|
}
|
88
|
-
|
89
|
-
|
90
|
-
|
269
|
+
search_flush(search);
|
270
|
+
return ch_len & CHAR_LENGTH_MASK;
|
271
|
+
} else {
|
272
|
+
search->ptr += ch_len;
|
91
273
|
}
|
92
274
|
} else {
|
93
|
-
|
275
|
+
search->ptr++;
|
94
276
|
}
|
95
277
|
}
|
96
|
-
|
278
|
+
search_flush(search);
|
279
|
+
return 0;
|
280
|
+
}
|
97
281
|
|
98
|
-
|
99
|
-
|
282
|
+
static void convert_UTF8_to_script_safe_JSON(search_state *search)
|
283
|
+
{
|
284
|
+
unsigned char ch_len;
|
285
|
+
while ((ch_len = search_script_safe_escape(search))) {
|
286
|
+
escape_UTF8_char(search, ch_len);
|
100
287
|
}
|
101
|
-
|
102
|
-
RB_GC_GUARD(str);
|
103
288
|
}
|
104
289
|
|
105
|
-
static const char
|
106
|
-
// ASCII Control Characters
|
107
|
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
108
|
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
109
|
-
// ASCII Characters
|
110
|
-
0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, // '"'
|
111
|
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
112
|
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
113
|
-
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, // '\\'
|
114
|
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
115
|
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
116
|
-
// Continuation byte
|
117
|
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
118
|
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
119
|
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
120
|
-
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
121
|
-
// First byte of a 2-byte code point
|
122
|
-
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
123
|
-
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
124
|
-
// First byte of a 4-byte code point
|
125
|
-
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
126
|
-
//First byte of a 4+byte code point
|
127
|
-
4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
|
128
|
-
};
|
129
|
-
|
130
|
-
static const char script_safe_escape_table[256] = {
|
290
|
+
static const unsigned char ascii_only_escape_table[256] = {
|
131
291
|
// ASCII Control Characters
|
132
|
-
|
133
|
-
|
292
|
+
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
293
|
+
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
134
294
|
// ASCII Characters
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
295
|
+
0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // '"'
|
296
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
297
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
298
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, // '\\'
|
299
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
300
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
141
301
|
// Continuation byte
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
// First byte of a
|
147
|
-
|
148
|
-
|
149
|
-
// First byte of a
|
150
|
-
|
151
|
-
//First byte of a 4+byte code point
|
152
|
-
|
302
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
303
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
304
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
305
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
306
|
+
// First byte of a 2-byte code point
|
307
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
308
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
309
|
+
// First byte of a 3-byte code point
|
310
|
+
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
311
|
+
//First byte of a 4+ byte code point
|
312
|
+
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 9, 9,
|
153
313
|
};
|
154
314
|
|
155
|
-
static
|
315
|
+
static inline unsigned char search_ascii_only_escape(search_state *search, const unsigned char escape_table[256])
|
156
316
|
{
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
const char *ptr = RSTRING_PTR(str);
|
161
|
-
unsigned long len = RSTRING_LEN(str);
|
162
|
-
|
163
|
-
unsigned long beg = 0, pos;
|
317
|
+
while (search->ptr < search->end) {
|
318
|
+
unsigned char ch = (unsigned char)*search->ptr;
|
319
|
+
unsigned char ch_len = escape_table[ch];
|
164
320
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
321
|
+
if (RB_UNLIKELY(ch_len)) {
|
322
|
+
search_flush(search);
|
323
|
+
return ch_len & CHAR_LENGTH_MASK;
|
324
|
+
} else {
|
325
|
+
search->ptr++;
|
326
|
+
}
|
327
|
+
}
|
328
|
+
search_flush(search);
|
329
|
+
return 0;
|
330
|
+
}
|
172
331
|
|
173
|
-
|
332
|
+
static inline void full_escape_UTF8_char(search_state *search, unsigned char ch_len) {
|
333
|
+
const unsigned char ch = (unsigned char)*search->ptr;
|
334
|
+
switch (ch_len) {
|
335
|
+
case 1: {
|
174
336
|
switch (ch) {
|
175
|
-
case '"': fbuffer_append(
|
176
|
-
case '\\': fbuffer_append(
|
177
|
-
case '/': fbuffer_append(
|
178
|
-
case '\b': fbuffer_append(
|
179
|
-
case '\f': fbuffer_append(
|
180
|
-
case '\n': fbuffer_append(
|
181
|
-
case '\r': fbuffer_append(
|
182
|
-
case '\t': fbuffer_append(
|
183
|
-
default:
|
184
|
-
|
185
|
-
scratch[
|
337
|
+
case '"': fbuffer_append(search->buffer, "\\\"", 2); break;
|
338
|
+
case '\\': fbuffer_append(search->buffer, "\\\\", 2); break;
|
339
|
+
case '/': fbuffer_append(search->buffer, "\\/", 2); break;
|
340
|
+
case '\b': fbuffer_append(search->buffer, "\\b", 2); break;
|
341
|
+
case '\f': fbuffer_append(search->buffer, "\\f", 2); break;
|
342
|
+
case '\n': fbuffer_append(search->buffer, "\\n", 2); break;
|
343
|
+
case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
|
344
|
+
case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
|
345
|
+
default: {
|
346
|
+
const char *hexdig = "0123456789abcdef";
|
347
|
+
char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
|
186
348
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
187
349
|
scratch[5] = hexdig[ch & 0xf];
|
188
|
-
fbuffer_append(
|
350
|
+
fbuffer_append(search->buffer, scratch, 6);
|
351
|
+
break;
|
352
|
+
}
|
189
353
|
}
|
354
|
+
break;
|
190
355
|
}
|
356
|
+
default: {
|
357
|
+
const char *hexdig = "0123456789abcdef";
|
358
|
+
char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
|
191
359
|
|
192
|
-
|
193
|
-
}
|
194
|
-
|
195
|
-
if (beg < len) {
|
196
|
-
fbuffer_append(out_buffer, &ptr[beg], len - beg);
|
197
|
-
}
|
198
|
-
|
199
|
-
RB_GC_GUARD(str);
|
200
|
-
}
|
201
|
-
|
202
|
-
static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, const char escape_table[256], bool out_script_safe)
|
203
|
-
{
|
204
|
-
const char *hexdig = "0123456789abcdef";
|
205
|
-
char scratch[12] = { '\\', 'u', 0, 0, 0, 0, '\\', 'u' };
|
206
|
-
|
207
|
-
const char *ptr = RSTRING_PTR(str);
|
208
|
-
unsigned long len = RSTRING_LEN(str);
|
209
|
-
|
210
|
-
unsigned long beg = 0, pos = 0;
|
211
|
-
|
212
|
-
#define FLUSH_POS(bytes) if (pos > beg) { fbuffer_append(out_buffer, &ptr[beg], pos - beg); } pos += bytes; beg = pos;
|
360
|
+
uint32_t wchar = 0;
|
213
361
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
if (RB_UNLIKELY(ch_len)) {
|
219
|
-
switch (ch_len) {
|
220
|
-
case 0:
|
221
|
-
pos++;
|
362
|
+
switch(ch_len) {
|
363
|
+
case 2:
|
364
|
+
wchar = ch & 0x1F;
|
222
365
|
break;
|
223
|
-
case
|
224
|
-
|
225
|
-
switch (ch) {
|
226
|
-
case '"': fbuffer_append(out_buffer, "\\\"", 2); break;
|
227
|
-
case '\\': fbuffer_append(out_buffer, "\\\\", 2); break;
|
228
|
-
case '/': fbuffer_append(out_buffer, "\\/", 2); break;
|
229
|
-
case '\b': fbuffer_append(out_buffer, "\\b", 2); break;
|
230
|
-
case '\f': fbuffer_append(out_buffer, "\\f", 2); break;
|
231
|
-
case '\n': fbuffer_append(out_buffer, "\\n", 2); break;
|
232
|
-
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
233
|
-
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
234
|
-
default: {
|
235
|
-
scratch[2] = hexdig[ch >> 12];
|
236
|
-
scratch[3] = hexdig[(ch >> 8) & 0xf];
|
237
|
-
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
238
|
-
scratch[5] = hexdig[ch & 0xf];
|
239
|
-
fbuffer_append(out_buffer, scratch, 6);
|
240
|
-
break;
|
241
|
-
}
|
242
|
-
}
|
366
|
+
case 3:
|
367
|
+
wchar = ch & 0x0F;
|
243
368
|
break;
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
case 2:
|
249
|
-
wchar = ptr[pos] & 0x1F;
|
250
|
-
break;
|
251
|
-
case 3:
|
252
|
-
wchar = ptr[pos] & 0x0F;
|
253
|
-
break;
|
254
|
-
case 4:
|
255
|
-
wchar = ptr[pos] & 0x07;
|
256
|
-
break;
|
257
|
-
}
|
258
|
-
|
259
|
-
for (short i = 1; i < ch_len; i++) {
|
260
|
-
wchar = (wchar << 6) | (ptr[pos+i] & 0x3F);
|
261
|
-
}
|
262
|
-
|
263
|
-
FLUSH_POS(ch_len);
|
369
|
+
case 4:
|
370
|
+
wchar = ch & 0x07;
|
371
|
+
break;
|
372
|
+
}
|
264
373
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
scratch[4] = hexdig[(wchar >> 4) & 0xf];
|
269
|
-
scratch[5] = hexdig[wchar & 0xf];
|
270
|
-
fbuffer_append(out_buffer, scratch, 6);
|
271
|
-
} else {
|
272
|
-
uint16_t hi, lo;
|
273
|
-
wchar -= 0x10000;
|
274
|
-
hi = 0xD800 + (uint16_t)(wchar >> 10);
|
275
|
-
lo = 0xDC00 + (uint16_t)(wchar & 0x3FF);
|
276
|
-
|
277
|
-
scratch[2] = hexdig[hi >> 12];
|
278
|
-
scratch[3] = hexdig[(hi >> 8) & 0xf];
|
279
|
-
scratch[4] = hexdig[(hi >> 4) & 0xf];
|
280
|
-
scratch[5] = hexdig[hi & 0xf];
|
281
|
-
|
282
|
-
scratch[8] = hexdig[lo >> 12];
|
283
|
-
scratch[9] = hexdig[(lo >> 8) & 0xf];
|
284
|
-
scratch[10] = hexdig[(lo >> 4) & 0xf];
|
285
|
-
scratch[11] = hexdig[lo & 0xf];
|
286
|
-
|
287
|
-
fbuffer_append(out_buffer, scratch, 12);
|
288
|
-
}
|
374
|
+
for (short i = 1; i < ch_len; i++) {
|
375
|
+
wchar = (wchar << 6) | (search->ptr[i] & 0x3F);
|
376
|
+
}
|
289
377
|
|
290
|
-
|
291
|
-
|
378
|
+
if (wchar <= 0xFFFF) {
|
379
|
+
scratch[2] = hexdig[wchar >> 12];
|
380
|
+
scratch[3] = hexdig[(wchar >> 8) & 0xf];
|
381
|
+
scratch[4] = hexdig[(wchar >> 4) & 0xf];
|
382
|
+
scratch[5] = hexdig[wchar & 0xf];
|
383
|
+
fbuffer_append(search->buffer, scratch, 6);
|
384
|
+
} else {
|
385
|
+
uint16_t hi, lo;
|
386
|
+
wchar -= 0x10000;
|
387
|
+
hi = 0xD800 + (uint16_t)(wchar >> 10);
|
388
|
+
lo = 0xDC00 + (uint16_t)(wchar & 0x3FF);
|
389
|
+
|
390
|
+
scratch[2] = hexdig[hi >> 12];
|
391
|
+
scratch[3] = hexdig[(hi >> 8) & 0xf];
|
392
|
+
scratch[4] = hexdig[(hi >> 4) & 0xf];
|
393
|
+
scratch[5] = hexdig[hi & 0xf];
|
394
|
+
|
395
|
+
scratch[8] = hexdig[lo >> 12];
|
396
|
+
scratch[9] = hexdig[(lo >> 8) & 0xf];
|
397
|
+
scratch[10] = hexdig[(lo >> 4) & 0xf];
|
398
|
+
scratch[11] = hexdig[lo & 0xf];
|
399
|
+
|
400
|
+
fbuffer_append(search->buffer, scratch, 12);
|
292
401
|
}
|
293
|
-
} else {
|
294
|
-
pos++;
|
295
|
-
}
|
296
|
-
}
|
297
|
-
#undef FLUSH_POS
|
298
402
|
|
299
|
-
|
300
|
-
|
403
|
+
break;
|
404
|
+
}
|
301
405
|
}
|
302
|
-
|
303
|
-
RB_GC_GUARD(str);
|
406
|
+
search->cursor = (search->ptr += ch_len);
|
304
407
|
}
|
305
408
|
|
306
|
-
static
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
409
|
+
static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned char escape_table[256])
|
410
|
+
{
|
411
|
+
unsigned char ch_len;
|
412
|
+
while ((ch_len = search_ascii_only_escape(search, escape_table))) {
|
413
|
+
full_escape_UTF8_char(search, ch_len);
|
414
|
+
}
|
312
415
|
}
|
313
416
|
|
314
417
|
/*
|
@@ -403,7 +506,9 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
403
506
|
*/
|
404
507
|
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
405
508
|
{
|
406
|
-
|
509
|
+
rb_check_arity(argc, 0, 1);
|
510
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
511
|
+
return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
|
407
512
|
}
|
408
513
|
|
409
514
|
/*
|
@@ -415,7 +520,9 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
415
520
|
* produced JSON string output further.
|
416
521
|
*/
|
417
522
|
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
418
|
-
|
523
|
+
rb_check_arity(argc, 0, 1);
|
524
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
525
|
+
return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
|
419
526
|
}
|
420
527
|
|
421
528
|
#ifdef RUBY_INTEGER_UNIFICATION
|
@@ -426,7 +533,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
426
533
|
*/
|
427
534
|
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
428
535
|
{
|
429
|
-
|
536
|
+
rb_check_arity(argc, 0, 1);
|
537
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
538
|
+
return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
|
430
539
|
}
|
431
540
|
|
432
541
|
#else
|
@@ -437,7 +546,9 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
437
546
|
*/
|
438
547
|
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
439
548
|
{
|
440
|
-
|
549
|
+
rb_check_arity(argc, 0, 1);
|
550
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
551
|
+
return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
|
441
552
|
}
|
442
553
|
|
443
554
|
/*
|
@@ -447,7 +558,9 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
447
558
|
*/
|
448
559
|
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
449
560
|
{
|
450
|
-
|
561
|
+
rb_check_arity(argc, 0, 1);
|
562
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
563
|
+
return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
|
451
564
|
}
|
452
565
|
#endif
|
453
566
|
|
@@ -458,7 +571,9 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
458
571
|
*/
|
459
572
|
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
460
573
|
{
|
461
|
-
|
574
|
+
rb_check_arity(argc, 0, 1);
|
575
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
576
|
+
return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
|
462
577
|
}
|
463
578
|
|
464
579
|
/*
|
@@ -481,7 +596,9 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
|
|
481
596
|
*/
|
482
597
|
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
483
598
|
{
|
484
|
-
|
599
|
+
rb_check_arity(argc, 0, 1);
|
600
|
+
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
601
|
+
return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
|
485
602
|
}
|
486
603
|
|
487
604
|
/*
|
@@ -498,7 +615,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
|
|
498
615
|
VALUE result = rb_hash_new();
|
499
616
|
rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
|
500
617
|
ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
|
501
|
-
rb_hash_aset(result,
|
618
|
+
rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
|
502
619
|
return result;
|
503
620
|
}
|
504
621
|
|
@@ -536,7 +653,8 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
|
536
653
|
*/
|
537
654
|
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
538
655
|
{
|
539
|
-
|
656
|
+
rb_check_arity(argc, 0, 1);
|
657
|
+
return rb_utf8_str_new("true", 4);
|
540
658
|
}
|
541
659
|
|
542
660
|
/*
|
@@ -546,7 +664,8 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
546
664
|
*/
|
547
665
|
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
548
666
|
{
|
549
|
-
|
667
|
+
rb_check_arity(argc, 0, 1);
|
668
|
+
return rb_utf8_str_new("false", 5);
|
550
669
|
}
|
551
670
|
|
552
671
|
/*
|
@@ -556,7 +675,8 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
556
675
|
*/
|
557
676
|
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
558
677
|
{
|
559
|
-
|
678
|
+
rb_check_arity(argc, 0, 1);
|
679
|
+
return rb_utf8_str_new("null", 4);
|
560
680
|
}
|
561
681
|
|
562
682
|
/*
|
@@ -573,30 +693,40 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
573
693
|
rb_scan_args(argc, argv, "01", &state);
|
574
694
|
Check_Type(string, T_STRING);
|
575
695
|
state = cState_from_state_s(cState, state);
|
576
|
-
return cState_partial_generate(state, string);
|
696
|
+
return cState_partial_generate(state, string, generate_json_string, Qfalse);
|
697
|
+
}
|
698
|
+
|
699
|
+
static void State_mark(void *ptr)
|
700
|
+
{
|
701
|
+
JSON_Generator_State *state = ptr;
|
702
|
+
rb_gc_mark_movable(state->indent);
|
703
|
+
rb_gc_mark_movable(state->space);
|
704
|
+
rb_gc_mark_movable(state->space_before);
|
705
|
+
rb_gc_mark_movable(state->object_nl);
|
706
|
+
rb_gc_mark_movable(state->array_nl);
|
707
|
+
rb_gc_mark_movable(state->as_json);
|
708
|
+
}
|
709
|
+
|
710
|
+
static void State_compact(void *ptr)
|
711
|
+
{
|
712
|
+
JSON_Generator_State *state = ptr;
|
713
|
+
state->indent = rb_gc_location(state->indent);
|
714
|
+
state->space = rb_gc_location(state->space);
|
715
|
+
state->space_before = rb_gc_location(state->space_before);
|
716
|
+
state->object_nl = rb_gc_location(state->object_nl);
|
717
|
+
state->array_nl = rb_gc_location(state->array_nl);
|
718
|
+
state->as_json = rb_gc_location(state->as_json);
|
577
719
|
}
|
578
720
|
|
579
721
|
static void State_free(void *ptr)
|
580
722
|
{
|
581
723
|
JSON_Generator_State *state = ptr;
|
582
|
-
if (state->indent) ruby_xfree(state->indent);
|
583
|
-
if (state->space) ruby_xfree(state->space);
|
584
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
585
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
586
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
587
724
|
ruby_xfree(state);
|
588
725
|
}
|
589
726
|
|
590
727
|
static size_t State_memsize(const void *ptr)
|
591
728
|
{
|
592
|
-
|
593
|
-
size_t size = sizeof(*state);
|
594
|
-
if (state->indent) size += state->indent_len + 1;
|
595
|
-
if (state->space) size += state->space_len + 1;
|
596
|
-
if (state->space_before) size += state->space_before_len + 1;
|
597
|
-
if (state->object_nl) size += state->object_nl_len + 1;
|
598
|
-
if (state->array_nl) size += state->array_nl_len + 1;
|
599
|
-
return size;
|
729
|
+
return sizeof(JSON_Generator_State);
|
600
730
|
}
|
601
731
|
|
602
732
|
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
@@ -606,24 +736,55 @@ static size_t State_memsize(const void *ptr)
|
|
606
736
|
|
607
737
|
static const rb_data_type_t JSON_Generator_State_type = {
|
608
738
|
"JSON/Generator/State",
|
609
|
-
{
|
739
|
+
{
|
740
|
+
.dmark = State_mark,
|
741
|
+
.dfree = State_free,
|
742
|
+
.dsize = State_memsize,
|
743
|
+
.dcompact = State_compact,
|
744
|
+
},
|
610
745
|
0, 0,
|
611
746
|
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
612
747
|
};
|
613
748
|
|
749
|
+
static void state_init(JSON_Generator_State *state)
|
750
|
+
{
|
751
|
+
state->max_nesting = 100;
|
752
|
+
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
753
|
+
}
|
754
|
+
|
614
755
|
static VALUE cState_s_allocate(VALUE klass)
|
615
756
|
{
|
616
757
|
JSON_Generator_State *state;
|
617
758
|
VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
|
618
|
-
state
|
619
|
-
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
759
|
+
state_init(state);
|
620
760
|
return obj;
|
621
761
|
}
|
622
762
|
|
763
|
+
static void vstate_spill(struct generate_json_data *data)
|
764
|
+
{
|
765
|
+
VALUE vstate = cState_s_allocate(cState);
|
766
|
+
GET_STATE(vstate);
|
767
|
+
MEMCPY(state, data->state, JSON_Generator_State, 1);
|
768
|
+
data->state = state;
|
769
|
+
data->vstate = vstate;
|
770
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->indent);
|
771
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->space);
|
772
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->space_before);
|
773
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl);
|
774
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl);
|
775
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
|
776
|
+
}
|
777
|
+
|
778
|
+
static inline VALUE vstate_get(struct generate_json_data *data)
|
779
|
+
{
|
780
|
+
if (RB_UNLIKELY(!data->vstate)) {
|
781
|
+
vstate_spill(data);
|
782
|
+
}
|
783
|
+
return data->vstate;
|
784
|
+
}
|
785
|
+
|
623
786
|
struct hash_foreach_arg {
|
624
|
-
|
625
|
-
JSON_Generator_State *state;
|
626
|
-
VALUE Vstate;
|
787
|
+
struct generate_json_data *data;
|
627
788
|
int iter;
|
628
789
|
};
|
629
790
|
|
@@ -631,27 +792,32 @@ static int
|
|
631
792
|
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
632
793
|
{
|
633
794
|
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
634
|
-
|
635
|
-
|
636
|
-
|
795
|
+
struct generate_json_data *data = arg->data;
|
796
|
+
|
797
|
+
FBuffer *buffer = data->buffer;
|
798
|
+
JSON_Generator_State *state = data->state;
|
637
799
|
|
638
800
|
long depth = state->depth;
|
639
801
|
int j;
|
640
802
|
|
641
803
|
if (arg->iter > 0) fbuffer_append_char(buffer, ',');
|
642
804
|
if (RB_UNLIKELY(state->object_nl)) {
|
643
|
-
|
805
|
+
fbuffer_append_str(buffer, state->object_nl);
|
644
806
|
}
|
645
807
|
if (RB_UNLIKELY(state->indent)) {
|
646
808
|
for (j = 0; j < depth; j++) {
|
647
|
-
|
809
|
+
fbuffer_append_str(buffer, state->indent);
|
648
810
|
}
|
649
811
|
}
|
650
812
|
|
651
813
|
VALUE key_to_s;
|
652
814
|
switch(rb_type(key)) {
|
653
815
|
case T_STRING:
|
654
|
-
|
816
|
+
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
|
817
|
+
key_to_s = key;
|
818
|
+
} else {
|
819
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
820
|
+
}
|
655
821
|
break;
|
656
822
|
case T_SYMBOL:
|
657
823
|
key_to_s = rb_sym2str(key);
|
@@ -661,82 +827,97 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
661
827
|
break;
|
662
828
|
}
|
663
829
|
|
664
|
-
|
665
|
-
|
830
|
+
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
|
831
|
+
generate_json_string(buffer, data, state, key_to_s);
|
832
|
+
} else {
|
833
|
+
generate_json(buffer, data, state, key_to_s);
|
834
|
+
}
|
835
|
+
if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
|
666
836
|
fbuffer_append_char(buffer, ':');
|
667
|
-
if (RB_UNLIKELY(state->space))
|
668
|
-
generate_json(buffer,
|
837
|
+
if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
|
838
|
+
generate_json(buffer, data, state, val);
|
669
839
|
|
670
840
|
arg->iter++;
|
671
841
|
return ST_CONTINUE;
|
672
842
|
}
|
673
843
|
|
674
|
-
static
|
844
|
+
static inline long increase_depth(JSON_Generator_State *state)
|
675
845
|
{
|
676
|
-
long max_nesting = state->max_nesting;
|
677
846
|
long depth = ++state->depth;
|
847
|
+
if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
|
848
|
+
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
849
|
+
}
|
850
|
+
return depth;
|
851
|
+
}
|
852
|
+
|
853
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
854
|
+
{
|
678
855
|
int j;
|
679
|
-
|
856
|
+
long depth = increase_depth(state);
|
680
857
|
|
681
|
-
if (
|
682
|
-
|
858
|
+
if (RHASH_SIZE(obj) == 0) {
|
859
|
+
fbuffer_append(buffer, "{}", 2);
|
860
|
+
--state->depth;
|
861
|
+
return;
|
683
862
|
}
|
863
|
+
|
684
864
|
fbuffer_append_char(buffer, '{');
|
685
865
|
|
686
|
-
arg
|
687
|
-
|
688
|
-
|
689
|
-
|
866
|
+
struct hash_foreach_arg arg = {
|
867
|
+
.data = data,
|
868
|
+
.iter = 0,
|
869
|
+
};
|
690
870
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
691
871
|
|
692
872
|
depth = --state->depth;
|
693
873
|
if (RB_UNLIKELY(state->object_nl)) {
|
694
|
-
|
874
|
+
fbuffer_append_str(buffer, state->object_nl);
|
695
875
|
if (RB_UNLIKELY(state->indent)) {
|
696
876
|
for (j = 0; j < depth; j++) {
|
697
|
-
|
877
|
+
fbuffer_append_str(buffer, state->indent);
|
698
878
|
}
|
699
879
|
}
|
700
880
|
}
|
701
881
|
fbuffer_append_char(buffer, '}');
|
702
882
|
}
|
703
883
|
|
704
|
-
static void generate_json_array(FBuffer *buffer,
|
884
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
705
885
|
{
|
706
|
-
long max_nesting = state->max_nesting;
|
707
|
-
long depth = ++state->depth;
|
708
886
|
int i, j;
|
709
|
-
|
710
|
-
|
887
|
+
long depth = increase_depth(state);
|
888
|
+
|
889
|
+
if (RARRAY_LEN(obj) == 0) {
|
890
|
+
fbuffer_append(buffer, "[]", 2);
|
891
|
+
--state->depth;
|
892
|
+
return;
|
711
893
|
}
|
894
|
+
|
712
895
|
fbuffer_append_char(buffer, '[');
|
713
|
-
if (RB_UNLIKELY(state->array_nl))
|
896
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
714
897
|
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
715
898
|
if (i > 0) {
|
716
899
|
fbuffer_append_char(buffer, ',');
|
717
|
-
if (RB_UNLIKELY(state->array_nl))
|
900
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
718
901
|
}
|
719
902
|
if (RB_UNLIKELY(state->indent)) {
|
720
903
|
for (j = 0; j < depth; j++) {
|
721
|
-
|
904
|
+
fbuffer_append_str(buffer, state->indent);
|
722
905
|
}
|
723
906
|
}
|
724
|
-
generate_json(buffer,
|
907
|
+
generate_json(buffer, data, state, RARRAY_AREF(obj, i));
|
725
908
|
}
|
726
909
|
state->depth = --depth;
|
727
910
|
if (RB_UNLIKELY(state->array_nl)) {
|
728
|
-
|
911
|
+
fbuffer_append_str(buffer, state->array_nl);
|
729
912
|
if (RB_UNLIKELY(state->indent)) {
|
730
913
|
for (j = 0; j < depth; j++) {
|
731
|
-
|
914
|
+
fbuffer_append_str(buffer, state->indent);
|
732
915
|
}
|
733
916
|
}
|
734
917
|
}
|
735
918
|
fbuffer_append_char(buffer, ']');
|
736
919
|
}
|
737
920
|
|
738
|
-
static int usascii_encindex, utf8_encindex, binary_encindex;
|
739
|
-
|
740
921
|
static inline int enc_utf8_compatible_p(int enc_idx)
|
741
922
|
{
|
742
923
|
if (enc_idx == usascii_encindex) return 1;
|
@@ -744,117 +925,176 @@ static inline int enc_utf8_compatible_p(int enc_idx)
|
|
744
925
|
return 0;
|
745
926
|
}
|
746
927
|
|
928
|
+
static VALUE encode_json_string_try(VALUE str)
|
929
|
+
{
|
930
|
+
return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
|
931
|
+
}
|
932
|
+
|
933
|
+
static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
934
|
+
{
|
935
|
+
raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
|
936
|
+
return Qundef;
|
937
|
+
}
|
938
|
+
|
747
939
|
static inline VALUE ensure_valid_encoding(VALUE str)
|
748
940
|
{
|
749
941
|
int encindex = RB_ENCODING_GET(str);
|
750
942
|
VALUE utf8_string;
|
751
943
|
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
752
944
|
if (encindex == binary_encindex) {
|
753
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
754
|
-
// TODO: Deprecate in 2.8.0
|
755
|
-
// TODO: Remove in 3.0.0
|
756
945
|
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
757
946
|
switch (rb_enc_str_coderange(utf8_string)) {
|
758
947
|
case ENC_CODERANGE_7BIT:
|
948
|
+
return utf8_string;
|
759
949
|
case ENC_CODERANGE_VALID:
|
950
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
951
|
+
// TODO: Raise in 3.0.0
|
952
|
+
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
760
953
|
return utf8_string;
|
761
954
|
break;
|
762
955
|
}
|
763
956
|
}
|
764
957
|
|
765
|
-
str =
|
958
|
+
str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
766
959
|
}
|
767
960
|
return str;
|
768
961
|
}
|
769
962
|
|
770
|
-
static void generate_json_string(FBuffer *buffer,
|
963
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
771
964
|
{
|
772
965
|
obj = ensure_valid_encoding(obj);
|
773
966
|
|
774
967
|
fbuffer_append_char(buffer, '"');
|
775
968
|
|
969
|
+
long len;
|
970
|
+
search_state search;
|
971
|
+
search.buffer = buffer;
|
972
|
+
RSTRING_GETMEM(obj, search.ptr, len);
|
973
|
+
search.cursor = search.ptr;
|
974
|
+
search.end = search.ptr + len;
|
975
|
+
|
776
976
|
switch(rb_enc_str_coderange(obj)) {
|
777
977
|
case ENC_CODERANGE_7BIT:
|
778
|
-
convert_ASCII_to_JSON(buffer, obj, state->script_safe ? script_safe_escape_table : escape_table);
|
779
|
-
break;
|
780
978
|
case ENC_CODERANGE_VALID:
|
781
979
|
if (RB_UNLIKELY(state->ascii_only)) {
|
782
|
-
convert_UTF8_to_ASCII_only_JSON(
|
980
|
+
convert_UTF8_to_ASCII_only_JSON(&search, state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
|
981
|
+
} else if (RB_UNLIKELY(state->script_safe)) {
|
982
|
+
convert_UTF8_to_script_safe_JSON(&search);
|
783
983
|
} else {
|
784
|
-
convert_UTF8_to_JSON(
|
984
|
+
convert_UTF8_to_JSON(&search);
|
785
985
|
}
|
786
986
|
break;
|
787
987
|
default:
|
788
|
-
|
988
|
+
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
789
989
|
break;
|
790
990
|
}
|
791
991
|
fbuffer_append_char(buffer, '"');
|
792
992
|
}
|
793
993
|
|
794
|
-
static void
|
994
|
+
static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
995
|
+
{
|
996
|
+
VALUE tmp;
|
997
|
+
if (rb_respond_to(obj, i_to_json)) {
|
998
|
+
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
|
999
|
+
Check_Type(tmp, T_STRING);
|
1000
|
+
fbuffer_append_str(buffer, tmp);
|
1001
|
+
} else {
|
1002
|
+
tmp = rb_funcall(obj, i_to_s, 0);
|
1003
|
+
Check_Type(tmp, T_STRING);
|
1004
|
+
generate_json_string(buffer, data, state, tmp);
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
1009
|
+
{
|
1010
|
+
if (state->strict) {
|
1011
|
+
generate_json_string(buffer, data, state, rb_sym2str(obj));
|
1012
|
+
} else {
|
1013
|
+
generate_json_fallback(buffer, data, state, obj);
|
1014
|
+
}
|
1015
|
+
}
|
1016
|
+
|
1017
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
795
1018
|
{
|
796
1019
|
fbuffer_append(buffer, "null", 4);
|
797
1020
|
}
|
798
1021
|
|
799
|
-
static void generate_json_false(FBuffer *buffer,
|
1022
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
800
1023
|
{
|
801
1024
|
fbuffer_append(buffer, "false", 5);
|
802
1025
|
}
|
803
1026
|
|
804
|
-
static void generate_json_true(FBuffer *buffer,
|
1027
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
805
1028
|
{
|
806
1029
|
fbuffer_append(buffer, "true", 4);
|
807
1030
|
}
|
808
1031
|
|
809
|
-
static void generate_json_fixnum(FBuffer *buffer,
|
1032
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
810
1033
|
{
|
811
1034
|
fbuffer_append_long(buffer, FIX2LONG(obj));
|
812
1035
|
}
|
813
1036
|
|
814
|
-
static void generate_json_bignum(FBuffer *buffer,
|
1037
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
815
1038
|
{
|
816
1039
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
817
1040
|
fbuffer_append_str(buffer, tmp);
|
818
1041
|
}
|
819
1042
|
|
820
1043
|
#ifdef RUBY_INTEGER_UNIFICATION
|
821
|
-
static void generate_json_integer(FBuffer *buffer,
|
1044
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
822
1045
|
{
|
823
1046
|
if (FIXNUM_P(obj))
|
824
|
-
generate_json_fixnum(buffer,
|
1047
|
+
generate_json_fixnum(buffer, data, state, obj);
|
825
1048
|
else
|
826
|
-
generate_json_bignum(buffer,
|
1049
|
+
generate_json_bignum(buffer, data, state, obj);
|
827
1050
|
}
|
828
1051
|
#endif
|
829
|
-
|
1052
|
+
|
1053
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
830
1054
|
{
|
831
1055
|
double value = RFLOAT_VALUE(obj);
|
832
1056
|
char allow_nan = state->allow_nan;
|
833
|
-
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
834
1057
|
if (!allow_nan) {
|
835
|
-
if (isinf(value)) {
|
836
|
-
|
837
|
-
|
838
|
-
|
1058
|
+
if (isinf(value) || isnan(value)) {
|
1059
|
+
if (state->strict && state->as_json) {
|
1060
|
+
VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
|
1061
|
+
if (casted_obj != obj) {
|
1062
|
+
increase_depth(state);
|
1063
|
+
generate_json(buffer, data, state, casted_obj);
|
1064
|
+
state->depth--;
|
1065
|
+
return;
|
1066
|
+
}
|
1067
|
+
}
|
1068
|
+
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", rb_funcall(obj, i_to_s, 0));
|
839
1069
|
}
|
840
1070
|
}
|
841
|
-
fbuffer_append_str(buffer,
|
1071
|
+
fbuffer_append_str(buffer, rb_funcall(obj, i_to_s, 0));
|
842
1072
|
}
|
843
1073
|
|
844
|
-
static void
|
1074
|
+
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
845
1075
|
{
|
846
|
-
VALUE
|
1076
|
+
VALUE fragment = RSTRUCT_GET(obj, 0);
|
1077
|
+
Check_Type(fragment, T_STRING);
|
1078
|
+
fbuffer_append_str(buffer, fragment);
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
1082
|
+
{
|
1083
|
+
bool as_json_called = false;
|
1084
|
+
start:
|
847
1085
|
if (obj == Qnil) {
|
848
|
-
generate_json_null(buffer,
|
1086
|
+
generate_json_null(buffer, data, state, obj);
|
849
1087
|
} else if (obj == Qfalse) {
|
850
|
-
generate_json_false(buffer,
|
1088
|
+
generate_json_false(buffer, data, state, obj);
|
851
1089
|
} else if (obj == Qtrue) {
|
852
|
-
generate_json_true(buffer,
|
1090
|
+
generate_json_true(buffer, data, state, obj);
|
853
1091
|
} else if (RB_SPECIAL_CONST_P(obj)) {
|
854
1092
|
if (RB_FIXNUM_P(obj)) {
|
855
|
-
generate_json_fixnum(buffer,
|
1093
|
+
generate_json_fixnum(buffer, data, state, obj);
|
856
1094
|
} else if (RB_FLONUM_P(obj)) {
|
857
|
-
generate_json_float(buffer,
|
1095
|
+
generate_json_float(buffer, data, state, obj);
|
1096
|
+
} else if (RB_STATIC_SYM_P(obj)) {
|
1097
|
+
generate_json_symbol(buffer, data, state, obj);
|
858
1098
|
} else {
|
859
1099
|
goto general;
|
860
1100
|
}
|
@@ -862,62 +1102,53 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
862
1102
|
VALUE klass = RBASIC_CLASS(obj);
|
863
1103
|
switch (RB_BUILTIN_TYPE(obj)) {
|
864
1104
|
case T_BIGNUM:
|
865
|
-
generate_json_bignum(buffer,
|
1105
|
+
generate_json_bignum(buffer, data, state, obj);
|
866
1106
|
break;
|
867
1107
|
case T_HASH:
|
868
1108
|
if (klass != rb_cHash) goto general;
|
869
|
-
generate_json_object(buffer,
|
1109
|
+
generate_json_object(buffer, data, state, obj);
|
870
1110
|
break;
|
871
1111
|
case T_ARRAY:
|
872
1112
|
if (klass != rb_cArray) goto general;
|
873
|
-
generate_json_array(buffer,
|
1113
|
+
generate_json_array(buffer, data, state, obj);
|
874
1114
|
break;
|
875
1115
|
case T_STRING:
|
876
1116
|
if (klass != rb_cString) goto general;
|
877
|
-
generate_json_string(buffer,
|
1117
|
+
generate_json_string(buffer, data, state, obj);
|
1118
|
+
break;
|
1119
|
+
case T_SYMBOL:
|
1120
|
+
generate_json_symbol(buffer, data, state, obj);
|
878
1121
|
break;
|
879
1122
|
case T_FLOAT:
|
880
1123
|
if (klass != rb_cFloat) goto general;
|
881
|
-
generate_json_float(buffer,
|
1124
|
+
generate_json_float(buffer, data, state, obj);
|
1125
|
+
break;
|
1126
|
+
case T_STRUCT:
|
1127
|
+
if (klass != cFragment) goto general;
|
1128
|
+
generate_json_fragment(buffer, data, state, obj);
|
882
1129
|
break;
|
883
1130
|
default:
|
884
1131
|
general:
|
885
1132
|
if (state->strict) {
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
1133
|
+
if (RTEST(state->as_json) && !as_json_called) {
|
1134
|
+
obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
|
1135
|
+
as_json_called = true;
|
1136
|
+
goto start;
|
1137
|
+
} else {
|
1138
|
+
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
|
1139
|
+
}
|
891
1140
|
} else {
|
892
|
-
|
893
|
-
Check_Type(tmp, T_STRING);
|
894
|
-
generate_json_string(buffer, Vstate, state, tmp);
|
1141
|
+
generate_json_fallback(buffer, data, state, obj);
|
895
1142
|
}
|
896
1143
|
}
|
897
1144
|
}
|
898
1145
|
}
|
899
1146
|
|
900
|
-
static FBuffer *cState_prepare_buffer(VALUE self)
|
901
|
-
{
|
902
|
-
FBuffer *buffer;
|
903
|
-
GET_STATE(self);
|
904
|
-
buffer = fbuffer_alloc(state->buffer_initial_length);
|
905
|
-
|
906
|
-
return buffer;
|
907
|
-
}
|
908
|
-
|
909
|
-
struct generate_json_data {
|
910
|
-
FBuffer *buffer;
|
911
|
-
VALUE vstate;
|
912
|
-
JSON_Generator_State *state;
|
913
|
-
VALUE obj;
|
914
|
-
};
|
915
|
-
|
916
1147
|
static VALUE generate_json_try(VALUE d)
|
917
1148
|
{
|
918
1149
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
919
1150
|
|
920
|
-
|
1151
|
+
data->func(data->buffer, data, data->state, data->obj);
|
921
1152
|
|
922
1153
|
return Qnil;
|
923
1154
|
}
|
@@ -932,32 +1163,42 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
|
932
1163
|
return Qundef;
|
933
1164
|
}
|
934
1165
|
|
935
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
1166
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
936
1167
|
{
|
937
|
-
FBuffer *buffer = cState_prepare_buffer(self);
|
938
1168
|
GET_STATE(self);
|
939
1169
|
|
1170
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1171
|
+
FBuffer buffer = {
|
1172
|
+
.io = RTEST(io) ? io : Qfalse,
|
1173
|
+
};
|
1174
|
+
fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
1175
|
+
|
940
1176
|
struct generate_json_data data = {
|
941
|
-
.buffer = buffer,
|
1177
|
+
.buffer = &buffer,
|
942
1178
|
.vstate = self,
|
943
1179
|
.state = state,
|
944
|
-
.obj = obj
|
1180
|
+
.obj = obj,
|
1181
|
+
.func = func
|
945
1182
|
};
|
946
1183
|
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
947
1184
|
|
948
|
-
return
|
1185
|
+
return fbuffer_finalize(&buffer);
|
949
1186
|
}
|
950
1187
|
|
951
|
-
/*
|
952
|
-
*
|
1188
|
+
/* call-seq:
|
1189
|
+
* generate(obj) -> String
|
1190
|
+
* generate(obj, anIO) -> anIO
|
953
1191
|
*
|
954
1192
|
* Generates a valid JSON document from object +obj+ and returns the
|
955
1193
|
* result. If no valid JSON document can be created this method raises a
|
956
1194
|
* GeneratorError exception.
|
957
1195
|
*/
|
958
|
-
static VALUE cState_generate(VALUE
|
1196
|
+
static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
|
959
1197
|
{
|
960
|
-
|
1198
|
+
rb_check_arity(argc, 1, 2);
|
1199
|
+
VALUE obj = argv[0];
|
1200
|
+
VALUE io = argc > 1 ? argv[1] : Qnil;
|
1201
|
+
VALUE result = cState_partial_generate(self, obj, generate_json, io);
|
961
1202
|
GET_STATE(self);
|
962
1203
|
(void)state;
|
963
1204
|
return result;
|
@@ -985,11 +1226,12 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
985
1226
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
986
1227
|
|
987
1228
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
988
|
-
objState->indent =
|
989
|
-
objState->space =
|
990
|
-
objState->space_before =
|
991
|
-
objState->object_nl =
|
992
|
-
objState->array_nl =
|
1229
|
+
objState->indent = origState->indent;
|
1230
|
+
objState->space = origState->space;
|
1231
|
+
objState->space_before = origState->space_before;
|
1232
|
+
objState->object_nl = origState->object_nl;
|
1233
|
+
objState->array_nl = origState->array_nl;
|
1234
|
+
objState->as_json = origState->as_json;
|
993
1235
|
return obj;
|
994
1236
|
}
|
995
1237
|
|
@@ -1019,7 +1261,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1019
1261
|
static VALUE cState_indent(VALUE self)
|
1020
1262
|
{
|
1021
1263
|
GET_STATE(self);
|
1022
|
-
return state->indent ?
|
1264
|
+
return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
static VALUE string_config(VALUE config)
|
1268
|
+
{
|
1269
|
+
if (RTEST(config)) {
|
1270
|
+
Check_Type(config, T_STRING);
|
1271
|
+
if (RSTRING_LEN(config)) {
|
1272
|
+
return rb_str_new_frozen(config);
|
1273
|
+
}
|
1274
|
+
}
|
1275
|
+
return Qfalse;
|
1023
1276
|
}
|
1024
1277
|
|
1025
1278
|
/*
|
@@ -1029,21 +1282,8 @@ static VALUE cState_indent(VALUE self)
|
|
1029
1282
|
*/
|
1030
1283
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
1031
1284
|
{
|
1032
|
-
unsigned long len;
|
1033
1285
|
GET_STATE(self);
|
1034
|
-
|
1035
|
-
len = RSTRING_LEN(indent);
|
1036
|
-
if (len == 0) {
|
1037
|
-
if (state->indent) {
|
1038
|
-
ruby_xfree(state->indent);
|
1039
|
-
state->indent = NULL;
|
1040
|
-
state->indent_len = 0;
|
1041
|
-
}
|
1042
|
-
} else {
|
1043
|
-
if (state->indent) ruby_xfree(state->indent);
|
1044
|
-
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
1045
|
-
state->indent_len = len;
|
1046
|
-
}
|
1286
|
+
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
1047
1287
|
return Qnil;
|
1048
1288
|
}
|
1049
1289
|
|
@@ -1056,7 +1296,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1056
1296
|
static VALUE cState_space(VALUE self)
|
1057
1297
|
{
|
1058
1298
|
GET_STATE(self);
|
1059
|
-
return state->space ?
|
1299
|
+
return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
|
1060
1300
|
}
|
1061
1301
|
|
1062
1302
|
/*
|
@@ -1067,21 +1307,8 @@ static VALUE cState_space(VALUE self)
|
|
1067
1307
|
*/
|
1068
1308
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
1069
1309
|
{
|
1070
|
-
unsigned long len;
|
1071
1310
|
GET_STATE(self);
|
1072
|
-
|
1073
|
-
len = RSTRING_LEN(space);
|
1074
|
-
if (len == 0) {
|
1075
|
-
if (state->space) {
|
1076
|
-
ruby_xfree(state->space);
|
1077
|
-
state->space = NULL;
|
1078
|
-
state->space_len = 0;
|
1079
|
-
}
|
1080
|
-
} else {
|
1081
|
-
if (state->space) ruby_xfree(state->space);
|
1082
|
-
state->space = fstrndup(RSTRING_PTR(space), len);
|
1083
|
-
state->space_len = len;
|
1084
|
-
}
|
1311
|
+
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
1085
1312
|
return Qnil;
|
1086
1313
|
}
|
1087
1314
|
|
@@ -1093,7 +1320,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1093
1320
|
static VALUE cState_space_before(VALUE self)
|
1094
1321
|
{
|
1095
1322
|
GET_STATE(self);
|
1096
|
-
return state->space_before ?
|
1323
|
+
return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
|
1097
1324
|
}
|
1098
1325
|
|
1099
1326
|
/*
|
@@ -1103,21 +1330,8 @@ static VALUE cState_space_before(VALUE self)
|
|
1103
1330
|
*/
|
1104
1331
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1105
1332
|
{
|
1106
|
-
unsigned long len;
|
1107
1333
|
GET_STATE(self);
|
1108
|
-
|
1109
|
-
len = RSTRING_LEN(space_before);
|
1110
|
-
if (len == 0) {
|
1111
|
-
if (state->space_before) {
|
1112
|
-
ruby_xfree(state->space_before);
|
1113
|
-
state->space_before = NULL;
|
1114
|
-
state->space_before_len = 0;
|
1115
|
-
}
|
1116
|
-
} else {
|
1117
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
1118
|
-
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1119
|
-
state->space_before_len = len;
|
1120
|
-
}
|
1334
|
+
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
1121
1335
|
return Qnil;
|
1122
1336
|
}
|
1123
1337
|
|
@@ -1130,7 +1344,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1130
1344
|
static VALUE cState_object_nl(VALUE self)
|
1131
1345
|
{
|
1132
1346
|
GET_STATE(self);
|
1133
|
-
return state->object_nl ?
|
1347
|
+
return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1134
1348
|
}
|
1135
1349
|
|
1136
1350
|
/*
|
@@ -1141,20 +1355,8 @@ static VALUE cState_object_nl(VALUE self)
|
|
1141
1355
|
*/
|
1142
1356
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
1143
1357
|
{
|
1144
|
-
unsigned long len;
|
1145
1358
|
GET_STATE(self);
|
1146
|
-
|
1147
|
-
len = RSTRING_LEN(object_nl);
|
1148
|
-
if (len == 0) {
|
1149
|
-
if (state->object_nl) {
|
1150
|
-
ruby_xfree(state->object_nl);
|
1151
|
-
state->object_nl = NULL;
|
1152
|
-
}
|
1153
|
-
} else {
|
1154
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
1155
|
-
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1156
|
-
state->object_nl_len = len;
|
1157
|
-
}
|
1359
|
+
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
1158
1360
|
return Qnil;
|
1159
1361
|
}
|
1160
1362
|
|
@@ -1166,7 +1368,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1166
1368
|
static VALUE cState_array_nl(VALUE self)
|
1167
1369
|
{
|
1168
1370
|
GET_STATE(self);
|
1169
|
-
return state->array_nl ?
|
1371
|
+
return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1170
1372
|
}
|
1171
1373
|
|
1172
1374
|
/*
|
@@ -1176,23 +1378,33 @@ static VALUE cState_array_nl(VALUE self)
|
|
1176
1378
|
*/
|
1177
1379
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
1178
1380
|
{
|
1179
|
-
unsigned long len;
|
1180
1381
|
GET_STATE(self);
|
1181
|
-
|
1182
|
-
len = RSTRING_LEN(array_nl);
|
1183
|
-
if (len == 0) {
|
1184
|
-
if (state->array_nl) {
|
1185
|
-
ruby_xfree(state->array_nl);
|
1186
|
-
state->array_nl = NULL;
|
1187
|
-
}
|
1188
|
-
} else {
|
1189
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
1190
|
-
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1191
|
-
state->array_nl_len = len;
|
1192
|
-
}
|
1382
|
+
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
1193
1383
|
return Qnil;
|
1194
1384
|
}
|
1195
1385
|
|
1386
|
+
/*
|
1387
|
+
* call-seq: as_json()
|
1388
|
+
*
|
1389
|
+
* This string is put at the end of a line that holds a JSON array.
|
1390
|
+
*/
|
1391
|
+
static VALUE cState_as_json(VALUE self)
|
1392
|
+
{
|
1393
|
+
GET_STATE(self);
|
1394
|
+
return state->as_json;
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
/*
|
1398
|
+
* call-seq: as_json=(as_json)
|
1399
|
+
*
|
1400
|
+
* This string is put at the end of a line that holds a JSON array.
|
1401
|
+
*/
|
1402
|
+
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
|
1403
|
+
{
|
1404
|
+
GET_STATE(self);
|
1405
|
+
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
|
1406
|
+
return Qnil;
|
1407
|
+
}
|
1196
1408
|
|
1197
1409
|
/*
|
1198
1410
|
* call-seq: check_circular?
|
@@ -1218,6 +1430,11 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1218
1430
|
return LONG2FIX(state->max_nesting);
|
1219
1431
|
}
|
1220
1432
|
|
1433
|
+
static long long_config(VALUE num)
|
1434
|
+
{
|
1435
|
+
return RTEST(num) ? FIX2LONG(num) : 0;
|
1436
|
+
}
|
1437
|
+
|
1221
1438
|
/*
|
1222
1439
|
* call-seq: max_nesting=(depth)
|
1223
1440
|
*
|
@@ -1227,8 +1444,7 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1227
1444
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
1228
1445
|
{
|
1229
1446
|
GET_STATE(self);
|
1230
|
-
|
1231
|
-
state->max_nesting = FIX2LONG(depth);
|
1447
|
+
state->max_nesting = long_config(depth);
|
1232
1448
|
return Qnil;
|
1233
1449
|
}
|
1234
1450
|
|
@@ -1356,8 +1572,7 @@ static VALUE cState_depth(VALUE self)
|
|
1356
1572
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1357
1573
|
{
|
1358
1574
|
GET_STATE(self);
|
1359
|
-
|
1360
|
-
state->depth = FIX2LONG(depth);
|
1575
|
+
state->depth = long_config(depth);
|
1361
1576
|
return Qnil;
|
1362
1577
|
}
|
1363
1578
|
|
@@ -1372,6 +1587,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1372
1587
|
return LONG2FIX(state->buffer_initial_length);
|
1373
1588
|
}
|
1374
1589
|
|
1590
|
+
static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length)
|
1591
|
+
{
|
1592
|
+
Check_Type(buffer_initial_length, T_FIXNUM);
|
1593
|
+
long initial_length = FIX2LONG(buffer_initial_length);
|
1594
|
+
if (initial_length > 0) {
|
1595
|
+
state->buffer_initial_length = initial_length;
|
1596
|
+
}
|
1597
|
+
}
|
1598
|
+
|
1375
1599
|
/*
|
1376
1600
|
* call-seq: buffer_initial_length=(length)
|
1377
1601
|
*
|
@@ -1380,16 +1604,76 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1380
1604
|
*/
|
1381
1605
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1382
1606
|
{
|
1383
|
-
long initial_length;
|
1384
1607
|
GET_STATE(self);
|
1385
|
-
|
1386
|
-
initial_length = FIX2LONG(buffer_initial_length);
|
1387
|
-
if (initial_length > 0) {
|
1388
|
-
state->buffer_initial_length = initial_length;
|
1389
|
-
}
|
1608
|
+
buffer_initial_length_set(state, buffer_initial_length);
|
1390
1609
|
return Qnil;
|
1391
1610
|
}
|
1392
1611
|
|
1612
|
+
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
1613
|
+
{
|
1614
|
+
JSON_Generator_State *state = (JSON_Generator_State *)_arg;
|
1615
|
+
|
1616
|
+
if (key == sym_indent) { state->indent = string_config(val); }
|
1617
|
+
else if (key == sym_space) { state->space = string_config(val); }
|
1618
|
+
else if (key == sym_space_before) { state->space_before = string_config(val); }
|
1619
|
+
else if (key == sym_object_nl) { state->object_nl = string_config(val); }
|
1620
|
+
else if (key == sym_array_nl) { state->array_nl = string_config(val); }
|
1621
|
+
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
|
1622
|
+
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
|
1623
|
+
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
|
1624
|
+
else if (key == sym_depth) { state->depth = long_config(val); }
|
1625
|
+
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
1626
|
+
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
1627
|
+
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
1628
|
+
else if (key == sym_strict) { state->strict = RTEST(val); }
|
1629
|
+
else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
|
1630
|
+
return ST_CONTINUE;
|
1631
|
+
}
|
1632
|
+
|
1633
|
+
static void configure_state(JSON_Generator_State *state, VALUE config)
|
1634
|
+
{
|
1635
|
+
if (!RTEST(config)) return;
|
1636
|
+
|
1637
|
+
Check_Type(config, T_HASH);
|
1638
|
+
|
1639
|
+
if (!RHASH_SIZE(config)) return;
|
1640
|
+
|
1641
|
+
// We assume in most cases few keys are set so it's faster to go over
|
1642
|
+
// the provided keys than to check all possible keys.
|
1643
|
+
rb_hash_foreach(config, configure_state_i, (VALUE)state);
|
1644
|
+
}
|
1645
|
+
|
1646
|
+
static VALUE cState_configure(VALUE self, VALUE opts)
|
1647
|
+
{
|
1648
|
+
GET_STATE(self);
|
1649
|
+
configure_state(state, opts);
|
1650
|
+
return self;
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
1654
|
+
{
|
1655
|
+
JSON_Generator_State state = {0};
|
1656
|
+
state_init(&state);
|
1657
|
+
configure_state(&state, opts);
|
1658
|
+
|
1659
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1660
|
+
FBuffer buffer = {
|
1661
|
+
.io = RTEST(io) ? io : Qfalse,
|
1662
|
+
};
|
1663
|
+
fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
1664
|
+
|
1665
|
+
struct generate_json_data data = {
|
1666
|
+
.buffer = &buffer,
|
1667
|
+
.vstate = Qfalse,
|
1668
|
+
.state = &state,
|
1669
|
+
.obj = obj,
|
1670
|
+
.func = generate_json,
|
1671
|
+
};
|
1672
|
+
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
1673
|
+
|
1674
|
+
return fbuffer_finalize(&buffer);
|
1675
|
+
}
|
1676
|
+
|
1393
1677
|
/*
|
1394
1678
|
*
|
1395
1679
|
*/
|
@@ -1403,19 +1687,25 @@ void Init_generator(void)
|
|
1403
1687
|
rb_require("json/common");
|
1404
1688
|
|
1405
1689
|
mJSON = rb_define_module("JSON");
|
1690
|
+
|
1691
|
+
rb_global_variable(&cFragment);
|
1692
|
+
cFragment = rb_const_get(mJSON, rb_intern("Fragment"));
|
1693
|
+
|
1406
1694
|
VALUE mExt = rb_define_module_under(mJSON, "Ext");
|
1407
1695
|
VALUE mGenerator = rb_define_module_under(mExt, "Generator");
|
1408
1696
|
|
1697
|
+
rb_global_variable(&eGeneratorError);
|
1409
1698
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
1699
|
+
|
1700
|
+
rb_global_variable(&eNestingError);
|
1410
1701
|
eNestingError = rb_path2class("JSON::NestingError");
|
1411
|
-
rb_gc_register_mark_object(eGeneratorError);
|
1412
|
-
rb_gc_register_mark_object(eNestingError);
|
1413
1702
|
|
1414
1703
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
1415
1704
|
rb_define_alloc_func(cState, cState_s_allocate);
|
1416
1705
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
1417
1706
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
1418
1707
|
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
1708
|
+
rb_define_private_method(cState, "_configure", cState_configure, 1);
|
1419
1709
|
|
1420
1710
|
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
1421
1711
|
rb_define_method(cState, "indent", cState_indent, 0);
|
@@ -1428,6 +1718,8 @@ void Init_generator(void)
|
|
1428
1718
|
rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
|
1429
1719
|
rb_define_method(cState, "array_nl", cState_array_nl, 0);
|
1430
1720
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
1721
|
+
rb_define_method(cState, "as_json", cState_as_json, 0);
|
1722
|
+
rb_define_method(cState, "as_json=", cState_as_json_set, 1);
|
1431
1723
|
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
1432
1724
|
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
|
1433
1725
|
rb_define_method(cState, "script_safe", cState_script_safe, 0);
|
@@ -1448,7 +1740,10 @@ void Init_generator(void)
|
|
1448
1740
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
1449
1741
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
1450
1742
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1451
|
-
rb_define_method(cState, "generate", cState_generate, 1);
|
1743
|
+
rb_define_method(cState, "generate", cState_generate, -1);
|
1744
|
+
rb_define_alias(cState, "generate_new", "generate"); // :nodoc:
|
1745
|
+
|
1746
|
+
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
|
1452
1747
|
|
1453
1748
|
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
1454
1749
|
|
@@ -1504,6 +1799,21 @@ void Init_generator(void)
|
|
1504
1799
|
i_extend = rb_intern("extend");
|
1505
1800
|
i_encode = rb_intern("encode");
|
1506
1801
|
|
1802
|
+
sym_indent = ID2SYM(rb_intern("indent"));
|
1803
|
+
sym_space = ID2SYM(rb_intern("space"));
|
1804
|
+
sym_space_before = ID2SYM(rb_intern("space_before"));
|
1805
|
+
sym_object_nl = ID2SYM(rb_intern("object_nl"));
|
1806
|
+
sym_array_nl = ID2SYM(rb_intern("array_nl"));
|
1807
|
+
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
|
1808
|
+
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
1809
|
+
sym_ascii_only = ID2SYM(rb_intern("ascii_only"));
|
1810
|
+
sym_depth = ID2SYM(rb_intern("depth"));
|
1811
|
+
sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
|
1812
|
+
sym_script_safe = ID2SYM(rb_intern("script_safe"));
|
1813
|
+
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
|
1814
|
+
sym_strict = ID2SYM(rb_intern("strict"));
|
1815
|
+
sym_as_json = ID2SYM(rb_intern("as_json"));
|
1816
|
+
|
1507
1817
|
usascii_encindex = rb_usascii_encindex();
|
1508
1818
|
utf8_encindex = rb_utf8_encindex();
|
1509
1819
|
binary_encindex = rb_ascii8bit_encindex();
|