json 2.7.3 → 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 +61 -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 +795 -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 -11
- 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
268
|
}
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
}
|
88
|
-
default:
|
89
|
-
pos += ch_len;
|
90
|
-
break;
|
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;
|
213
|
-
|
214
|
-
while (pos < len) {
|
215
|
-
unsigned char ch = ptr[pos];
|
216
|
-
unsigned char ch_len = escape_table[ch];
|
360
|
+
uint32_t wchar = 0;
|
217
361
|
|
218
|
-
|
219
|
-
|
220
|
-
|
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,37 +1163,53 @@ 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;
|
964
1205
|
}
|
965
1206
|
|
1207
|
+
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
1208
|
+
{
|
1209
|
+
rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
|
1210
|
+
return self;
|
1211
|
+
}
|
1212
|
+
|
966
1213
|
/*
|
967
1214
|
* call-seq: initialize_copy(orig)
|
968
1215
|
*
|
@@ -979,11 +1226,12 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
979
1226
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
980
1227
|
|
981
1228
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
982
|
-
objState->indent =
|
983
|
-
objState->space =
|
984
|
-
objState->space_before =
|
985
|
-
objState->object_nl =
|
986
|
-
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;
|
987
1235
|
return obj;
|
988
1236
|
}
|
989
1237
|
|
@@ -1013,7 +1261,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1013
1261
|
static VALUE cState_indent(VALUE self)
|
1014
1262
|
{
|
1015
1263
|
GET_STATE(self);
|
1016
|
-
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;
|
1017
1276
|
}
|
1018
1277
|
|
1019
1278
|
/*
|
@@ -1023,21 +1282,8 @@ static VALUE cState_indent(VALUE self)
|
|
1023
1282
|
*/
|
1024
1283
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
1025
1284
|
{
|
1026
|
-
unsigned long len;
|
1027
1285
|
GET_STATE(self);
|
1028
|
-
|
1029
|
-
len = RSTRING_LEN(indent);
|
1030
|
-
if (len == 0) {
|
1031
|
-
if (state->indent) {
|
1032
|
-
ruby_xfree(state->indent);
|
1033
|
-
state->indent = NULL;
|
1034
|
-
state->indent_len = 0;
|
1035
|
-
}
|
1036
|
-
} else {
|
1037
|
-
if (state->indent) ruby_xfree(state->indent);
|
1038
|
-
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
1039
|
-
state->indent_len = len;
|
1040
|
-
}
|
1286
|
+
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
1041
1287
|
return Qnil;
|
1042
1288
|
}
|
1043
1289
|
|
@@ -1050,7 +1296,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1050
1296
|
static VALUE cState_space(VALUE self)
|
1051
1297
|
{
|
1052
1298
|
GET_STATE(self);
|
1053
|
-
return state->space ?
|
1299
|
+
return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
|
1054
1300
|
}
|
1055
1301
|
|
1056
1302
|
/*
|
@@ -1061,21 +1307,8 @@ static VALUE cState_space(VALUE self)
|
|
1061
1307
|
*/
|
1062
1308
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
1063
1309
|
{
|
1064
|
-
unsigned long len;
|
1065
1310
|
GET_STATE(self);
|
1066
|
-
|
1067
|
-
len = RSTRING_LEN(space);
|
1068
|
-
if (len == 0) {
|
1069
|
-
if (state->space) {
|
1070
|
-
ruby_xfree(state->space);
|
1071
|
-
state->space = NULL;
|
1072
|
-
state->space_len = 0;
|
1073
|
-
}
|
1074
|
-
} else {
|
1075
|
-
if (state->space) ruby_xfree(state->space);
|
1076
|
-
state->space = fstrndup(RSTRING_PTR(space), len);
|
1077
|
-
state->space_len = len;
|
1078
|
-
}
|
1311
|
+
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
1079
1312
|
return Qnil;
|
1080
1313
|
}
|
1081
1314
|
|
@@ -1087,7 +1320,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1087
1320
|
static VALUE cState_space_before(VALUE self)
|
1088
1321
|
{
|
1089
1322
|
GET_STATE(self);
|
1090
|
-
return state->space_before ?
|
1323
|
+
return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
|
1091
1324
|
}
|
1092
1325
|
|
1093
1326
|
/*
|
@@ -1097,21 +1330,8 @@ static VALUE cState_space_before(VALUE self)
|
|
1097
1330
|
*/
|
1098
1331
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1099
1332
|
{
|
1100
|
-
unsigned long len;
|
1101
1333
|
GET_STATE(self);
|
1102
|
-
|
1103
|
-
len = RSTRING_LEN(space_before);
|
1104
|
-
if (len == 0) {
|
1105
|
-
if (state->space_before) {
|
1106
|
-
ruby_xfree(state->space_before);
|
1107
|
-
state->space_before = NULL;
|
1108
|
-
state->space_before_len = 0;
|
1109
|
-
}
|
1110
|
-
} else {
|
1111
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
1112
|
-
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1113
|
-
state->space_before_len = len;
|
1114
|
-
}
|
1334
|
+
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
1115
1335
|
return Qnil;
|
1116
1336
|
}
|
1117
1337
|
|
@@ -1124,7 +1344,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1124
1344
|
static VALUE cState_object_nl(VALUE self)
|
1125
1345
|
{
|
1126
1346
|
GET_STATE(self);
|
1127
|
-
return state->object_nl ?
|
1347
|
+
return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1128
1348
|
}
|
1129
1349
|
|
1130
1350
|
/*
|
@@ -1135,20 +1355,8 @@ static VALUE cState_object_nl(VALUE self)
|
|
1135
1355
|
*/
|
1136
1356
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
1137
1357
|
{
|
1138
|
-
unsigned long len;
|
1139
1358
|
GET_STATE(self);
|
1140
|
-
|
1141
|
-
len = RSTRING_LEN(object_nl);
|
1142
|
-
if (len == 0) {
|
1143
|
-
if (state->object_nl) {
|
1144
|
-
ruby_xfree(state->object_nl);
|
1145
|
-
state->object_nl = NULL;
|
1146
|
-
}
|
1147
|
-
} else {
|
1148
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
1149
|
-
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1150
|
-
state->object_nl_len = len;
|
1151
|
-
}
|
1359
|
+
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
1152
1360
|
return Qnil;
|
1153
1361
|
}
|
1154
1362
|
|
@@ -1160,7 +1368,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1160
1368
|
static VALUE cState_array_nl(VALUE self)
|
1161
1369
|
{
|
1162
1370
|
GET_STATE(self);
|
1163
|
-
return state->array_nl ?
|
1371
|
+
return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1164
1372
|
}
|
1165
1373
|
|
1166
1374
|
/*
|
@@ -1170,23 +1378,33 @@ static VALUE cState_array_nl(VALUE self)
|
|
1170
1378
|
*/
|
1171
1379
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
1172
1380
|
{
|
1173
|
-
unsigned long len;
|
1174
1381
|
GET_STATE(self);
|
1175
|
-
|
1176
|
-
len = RSTRING_LEN(array_nl);
|
1177
|
-
if (len == 0) {
|
1178
|
-
if (state->array_nl) {
|
1179
|
-
ruby_xfree(state->array_nl);
|
1180
|
-
state->array_nl = NULL;
|
1181
|
-
}
|
1182
|
-
} else {
|
1183
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
1184
|
-
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1185
|
-
state->array_nl_len = len;
|
1186
|
-
}
|
1382
|
+
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
1187
1383
|
return Qnil;
|
1188
1384
|
}
|
1189
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
|
+
}
|
1190
1408
|
|
1191
1409
|
/*
|
1192
1410
|
* call-seq: check_circular?
|
@@ -1212,6 +1430,11 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1212
1430
|
return LONG2FIX(state->max_nesting);
|
1213
1431
|
}
|
1214
1432
|
|
1433
|
+
static long long_config(VALUE num)
|
1434
|
+
{
|
1435
|
+
return RTEST(num) ? FIX2LONG(num) : 0;
|
1436
|
+
}
|
1437
|
+
|
1215
1438
|
/*
|
1216
1439
|
* call-seq: max_nesting=(depth)
|
1217
1440
|
*
|
@@ -1221,8 +1444,7 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1221
1444
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
1222
1445
|
{
|
1223
1446
|
GET_STATE(self);
|
1224
|
-
|
1225
|
-
state->max_nesting = FIX2LONG(depth);
|
1447
|
+
state->max_nesting = long_config(depth);
|
1226
1448
|
return Qnil;
|
1227
1449
|
}
|
1228
1450
|
|
@@ -1350,8 +1572,7 @@ static VALUE cState_depth(VALUE self)
|
|
1350
1572
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1351
1573
|
{
|
1352
1574
|
GET_STATE(self);
|
1353
|
-
|
1354
|
-
state->depth = FIX2LONG(depth);
|
1575
|
+
state->depth = long_config(depth);
|
1355
1576
|
return Qnil;
|
1356
1577
|
}
|
1357
1578
|
|
@@ -1366,6 +1587,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1366
1587
|
return LONG2FIX(state->buffer_initial_length);
|
1367
1588
|
}
|
1368
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
|
+
|
1369
1599
|
/*
|
1370
1600
|
* call-seq: buffer_initial_length=(length)
|
1371
1601
|
*
|
@@ -1374,16 +1604,76 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1374
1604
|
*/
|
1375
1605
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1376
1606
|
{
|
1377
|
-
long initial_length;
|
1378
1607
|
GET_STATE(self);
|
1379
|
-
|
1380
|
-
initial_length = FIX2LONG(buffer_initial_length);
|
1381
|
-
if (initial_length > 0) {
|
1382
|
-
state->buffer_initial_length = initial_length;
|
1383
|
-
}
|
1608
|
+
buffer_initial_length_set(state, buffer_initial_length);
|
1384
1609
|
return Qnil;
|
1385
1610
|
}
|
1386
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
|
+
|
1387
1677
|
/*
|
1388
1678
|
*
|
1389
1679
|
*/
|
@@ -1397,17 +1687,26 @@ void Init_generator(void)
|
|
1397
1687
|
rb_require("json/common");
|
1398
1688
|
|
1399
1689
|
mJSON = rb_define_module("JSON");
|
1690
|
+
|
1691
|
+
rb_global_variable(&cFragment);
|
1692
|
+
cFragment = rb_const_get(mJSON, rb_intern("Fragment"));
|
1693
|
+
|
1400
1694
|
VALUE mExt = rb_define_module_under(mJSON, "Ext");
|
1401
1695
|
VALUE mGenerator = rb_define_module_under(mExt, "Generator");
|
1402
1696
|
|
1697
|
+
rb_global_variable(&eGeneratorError);
|
1403
1698
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
1699
|
+
|
1700
|
+
rb_global_variable(&eNestingError);
|
1404
1701
|
eNestingError = rb_path2class("JSON::NestingError");
|
1405
|
-
rb_gc_register_mark_object(eGeneratorError);
|
1406
|
-
rb_gc_register_mark_object(eNestingError);
|
1407
1702
|
|
1408
1703
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
1409
1704
|
rb_define_alloc_func(cState, cState_s_allocate);
|
1410
1705
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
1706
|
+
rb_define_method(cState, "initialize", cState_initialize, -1);
|
1707
|
+
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
1708
|
+
rb_define_private_method(cState, "_configure", cState_configure, 1);
|
1709
|
+
|
1411
1710
|
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
1412
1711
|
rb_define_method(cState, "indent", cState_indent, 0);
|
1413
1712
|
rb_define_method(cState, "indent=", cState_indent_set, 1);
|
@@ -1419,6 +1718,8 @@ void Init_generator(void)
|
|
1419
1718
|
rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
|
1420
1719
|
rb_define_method(cState, "array_nl", cState_array_nl, 0);
|
1421
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);
|
1422
1723
|
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
1423
1724
|
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
|
1424
1725
|
rb_define_method(cState, "script_safe", cState_script_safe, 0);
|
@@ -1439,7 +1740,10 @@ void Init_generator(void)
|
|
1439
1740
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
1440
1741
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
1441
1742
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1442
|
-
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);
|
1443
1747
|
|
1444
1748
|
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
1445
1749
|
|
@@ -1495,7 +1799,24 @@ void Init_generator(void)
|
|
1495
1799
|
i_extend = rb_intern("extend");
|
1496
1800
|
i_encode = rb_intern("encode");
|
1497
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
|
+
|
1498
1817
|
usascii_encindex = rb_usascii_encindex();
|
1499
1818
|
utf8_encindex = rb_utf8_encindex();
|
1500
1819
|
binary_encindex = rb_ascii8bit_encindex();
|
1820
|
+
|
1821
|
+
rb_require("json/ext/generator/state");
|
1501
1822
|
}
|