json 1.0.0 → 2.7.2
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 +7 -0
- data/CHANGES.md +503 -0
- data/LICENSE +56 -0
- data/README.md +416 -0
- data/ext/json/ext/fbuffer/fbuffer.h +187 -0
- data/ext/json/ext/generator/depend +1 -0
- data/ext/json/ext/generator/extconf.rb +2 -7
- data/ext/json/ext/generator/generator.c +1312 -338
- data/ext/json/ext/generator/generator.h +177 -0
- data/ext/json/ext/parser/depend +1 -0
- data/ext/json/ext/parser/extconf.rb +28 -5
- data/ext/json/ext/parser/parser.c +1349 -689
- data/ext/json/ext/parser/parser.h +96 -0
- data/ext/json/ext/parser/parser.rl +644 -188
- data/ext/json/extconf.rb +3 -0
- data/json.gemspec +68 -0
- data/lib/json/add/bigdecimal.rb +58 -0
- data/lib/json/add/complex.rb +51 -0
- data/lib/json/add/core.rb +12 -0
- data/lib/json/add/date.rb +54 -0
- data/lib/json/add/date_time.rb +67 -0
- data/lib/json/add/exception.rb +49 -0
- data/lib/json/add/ostruct.rb +54 -0
- data/lib/json/add/range.rb +54 -0
- data/lib/json/add/rational.rb +49 -0
- data/lib/json/add/regexp.rb +48 -0
- data/lib/json/add/set.rb +48 -0
- data/lib/json/add/struct.rb +52 -0
- data/lib/json/add/symbol.rb +48 -0
- data/lib/json/add/time.rb +59 -0
- data/lib/json/common.rb +588 -74
- data/lib/json/ext.rb +3 -1
- data/lib/json/generic_object.rb +75 -0
- data/lib/json/pure/generator.rb +311 -119
- data/lib/json/pure/parser.rb +182 -55
- data/lib/json/pure.rb +5 -65
- data/lib/json/version.rb +2 -1
- data/lib/json.rb +583 -196
- metadata +78 -137
- data/CHANGES +0 -25
- data/GPL +0 -340
- data/README +0 -77
- data/Rakefile +0 -250
- data/TODO +0 -1
- data/VERSION +0 -1
- data/benchmarks/benchmark.txt +0 -133
- data/benchmarks/benchmark_generator.rb +0 -44
- data/benchmarks/benchmark_parser.rb +0 -22
- data/benchmarks/benchmark_rails.rb +0 -26
- data/bin/edit_json.rb +0 -11
- data/data/example.json +0 -1
- data/data/index.html +0 -37
- data/data/prototype.js +0 -2515
- data/ext/json/ext/generator/Makefile +0 -149
- data/ext/json/ext/generator/unicode.c +0 -184
- data/ext/json/ext/generator/unicode.h +0 -40
- data/ext/json/ext/parser/Makefile +0 -149
- data/ext/json/ext/parser/unicode.c +0 -156
- data/ext/json/ext/parser/unicode.h +0 -44
- data/install.rb +0 -26
- data/lib/json/Array.xpm +0 -21
- data/lib/json/FalseClass.xpm +0 -21
- data/lib/json/Hash.xpm +0 -21
- data/lib/json/Key.xpm +0 -73
- data/lib/json/NilClass.xpm +0 -21
- data/lib/json/Numeric.xpm +0 -28
- data/lib/json/String.xpm +0 -96
- data/lib/json/TrueClass.xpm +0 -21
- data/lib/json/editor.rb +0 -1207
- data/lib/json/json.xpm +0 -1499
- data/tests/fixtures/fail1.json +0 -1
- data/tests/fixtures/fail10.json +0 -1
- data/tests/fixtures/fail11.json +0 -1
- data/tests/fixtures/fail12.json +0 -1
- data/tests/fixtures/fail13.json +0 -1
- data/tests/fixtures/fail14.json +0 -1
- data/tests/fixtures/fail15.json +0 -1
- data/tests/fixtures/fail16.json +0 -1
- data/tests/fixtures/fail17.json +0 -1
- data/tests/fixtures/fail19.json +0 -1
- data/tests/fixtures/fail2.json +0 -1
- data/tests/fixtures/fail20.json +0 -1
- data/tests/fixtures/fail21.json +0 -1
- data/tests/fixtures/fail22.json +0 -1
- data/tests/fixtures/fail23.json +0 -1
- data/tests/fixtures/fail24.json +0 -1
- data/tests/fixtures/fail25.json +0 -1
- data/tests/fixtures/fail26.json +0 -1
- data/tests/fixtures/fail27.json +0 -2
- data/tests/fixtures/fail28.json +0 -2
- data/tests/fixtures/fail3.json +0 -1
- data/tests/fixtures/fail4.json +0 -1
- data/tests/fixtures/fail5.json +0 -1
- data/tests/fixtures/fail6.json +0 -1
- data/tests/fixtures/fail7.json +0 -1
- data/tests/fixtures/fail8.json +0 -1
- data/tests/fixtures/fail9.json +0 -1
- data/tests/fixtures/pass1.json +0 -56
- data/tests/fixtures/pass18.json +0 -1
- data/tests/fixtures/pass2.json +0 -1
- data/tests/fixtures/pass3.json +0 -6
- data/tests/runner.rb +0 -24
- data/tests/test_json.rb +0 -235
- data/tests/test_json_addition.rb +0 -94
- data/tests/test_json_fixtures.rb +0 -30
- data/tests/test_json_generate.rb +0 -81
- data/tests/test_json_unicode.rb +0 -55
- data/tools/fuzz.rb +0 -133
- data/tools/server.rb +0 -62
@@ -1,248 +1,450 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
#include <string.h>
|
4
|
-
#include "ruby.h"
|
5
|
-
#include "st.h"
|
6
|
-
#include "unicode.h"
|
1
|
+
#include "../fbuffer/fbuffer.h"
|
2
|
+
#include "generator.h"
|
7
3
|
|
8
4
|
static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
|
9
|
-
mHash, mArray,
|
5
|
+
mHash, mArray,
|
6
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
7
|
+
mInteger,
|
8
|
+
#else
|
9
|
+
mFixnum, mBignum,
|
10
|
+
#endif
|
11
|
+
mFloat, mString, mString_Extend,
|
10
12
|
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
|
11
|
-
|
13
|
+
eNestingError;
|
12
14
|
|
13
15
|
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
|
14
|
-
i_object_nl, i_array_nl,
|
15
|
-
i_create_id, i_extend
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
VALUE object_nl;
|
22
|
-
VALUE array_nl;
|
23
|
-
int check_circular;
|
24
|
-
VALUE seen;
|
25
|
-
VALUE memo;
|
26
|
-
VALUE depth;
|
27
|
-
int flag;
|
28
|
-
} JSON_Generator_State;
|
29
|
-
|
30
|
-
#define GET_STATE(self) \
|
31
|
-
JSON_Generator_State *state; \
|
32
|
-
Data_Get_Struct(self, JSON_Generator_State, state);
|
33
|
-
#define FUL(string) RSTRING(string)->len
|
34
|
-
|
35
|
-
/*
|
36
|
-
* Document-module: JSON::Ext::Generator
|
16
|
+
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
|
17
|
+
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
|
18
|
+
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
|
19
|
+
i_buffer_initial_length, i_dup, i_script_safe, i_escape_slash, i_strict;
|
20
|
+
|
21
|
+
/*
|
22
|
+
* Copyright 2001-2004 Unicode, Inc.
|
37
23
|
*
|
38
|
-
*
|
39
|
-
* configured to be used by setting
|
24
|
+
* Disclaimer
|
40
25
|
*
|
41
|
-
*
|
26
|
+
* This source code is provided as is by Unicode, Inc. No claims are
|
27
|
+
* made as to fitness for any particular purpose. No warranties of any
|
28
|
+
* kind are expressed or implied. The recipient agrees to determine
|
29
|
+
* applicability of information provided. If this file has been
|
30
|
+
* purchased on magnetic or optical media from Unicode, Inc., the
|
31
|
+
* sole remedy for any claim will be exchange of defective media
|
32
|
+
* within 90 days of receipt.
|
42
33
|
*
|
43
|
-
*
|
34
|
+
* Limitations on Rights to Redistribute This Code
|
44
35
|
*
|
36
|
+
* Unicode, Inc. hereby grants the right to freely use the information
|
37
|
+
* supplied in this file in the creation of products supporting the
|
38
|
+
* Unicode Standard, and to make copies of this file in any form
|
39
|
+
* for internal or external distribution as long as this notice
|
40
|
+
* remains attached.
|
41
|
+
*/
|
42
|
+
|
43
|
+
/*
|
44
|
+
* Index into the table below with the first byte of a UTF-8 sequence to
|
45
|
+
* get the number of trailing bytes that are supposed to follow it.
|
46
|
+
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
47
|
+
* left as-is for anyone who may want to do such conversion, which was
|
48
|
+
* allowed in earlier algorithms.
|
49
|
+
*/
|
50
|
+
static const char trailingBytesForUTF8[256] = {
|
51
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
52
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
53
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
54
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
55
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
56
|
+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
57
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
58
|
+
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
59
|
+
};
|
60
|
+
|
61
|
+
/*
|
62
|
+
* Magic values subtracted from a buffer value during UTF8 conversion.
|
63
|
+
* This table contains as many values as there might be trailing bytes
|
64
|
+
* in a UTF-8 sequence.
|
45
65
|
*/
|
66
|
+
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
67
|
+
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
46
68
|
|
47
|
-
|
69
|
+
/*
|
70
|
+
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
71
|
+
* This must be called with the length pre-determined by the first byte.
|
72
|
+
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
73
|
+
* length = trailingBytesForUTF8[*source]+1;
|
74
|
+
* and the sequence is illegal right away if there aren't that many bytes
|
75
|
+
* available.
|
76
|
+
* If presented with a length > 4, this returns 0. The Unicode
|
77
|
+
* definition of UTF-8 goes up to 4-byte sequences.
|
78
|
+
*/
|
79
|
+
static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length)
|
48
80
|
{
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
81
|
+
UTF8 a;
|
82
|
+
const UTF8 *srcptr = source+length;
|
83
|
+
switch (length) {
|
84
|
+
default: return 0;
|
85
|
+
/* Everything else falls through when "1"... */
|
86
|
+
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
87
|
+
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
88
|
+
case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
|
53
89
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
}
|
63
|
-
json = rb_funcall(rb_funcall(key, i_to_s, 0), i_to_json, 2, Vstate, Vdepth);
|
64
|
-
rb_str_buf_append(buf, json);
|
65
|
-
OBJ_INFECT(buf, json);
|
66
|
-
if (FUL(state->space_before)) {
|
67
|
-
rb_str_buf_append(buf, state->space_before);
|
68
|
-
}
|
69
|
-
rb_str_buf_cat2(buf, ":");
|
70
|
-
if (FUL(state->space)) rb_str_buf_append(buf, state->space);
|
71
|
-
json = rb_funcall(value, i_to_json, 2, Vstate, Vdepth);
|
72
|
-
state->flag = 1;
|
73
|
-
rb_str_buf_append(buf, json);
|
74
|
-
OBJ_INFECT(buf, json);
|
75
|
-
state->depth = Vdepth;
|
76
|
-
state->memo = buf;
|
77
|
-
return ST_CONTINUE;
|
78
|
-
}
|
90
|
+
switch (*source) {
|
91
|
+
/* no fall-through in this inner switch */
|
92
|
+
case 0xE0: if (a < 0xA0) return 0; break;
|
93
|
+
case 0xED: if (a > 0x9F) return 0; break;
|
94
|
+
case 0xF0: if (a < 0x90) return 0; break;
|
95
|
+
case 0xF4: if (a > 0x8F) return 0; break;
|
96
|
+
default: if (a < 0x80) return 0;
|
97
|
+
}
|
79
98
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
depth = 1 + FIX2LONG(Vdepth);
|
86
|
-
result = rb_str_buf_new(len);
|
87
|
-
state->memo = result;
|
88
|
-
state->depth = LONG2FIX(depth);
|
89
|
-
state->flag = 0;
|
90
|
-
rb_str_buf_cat2(result, "{");
|
91
|
-
if (FUL(state->object_nl)) rb_str_buf_append(result, state->object_nl);
|
92
|
-
rb_hash_foreach(self, hash_to_json_state_i, Vstate);
|
93
|
-
if (FUL(state->object_nl)) rb_str_buf_append(result, state->object_nl);
|
94
|
-
if (FUL(state->object_nl)) {
|
95
|
-
rb_str_buf_append(result, rb_str_times(state->indent, Vdepth));
|
96
|
-
}
|
97
|
-
rb_str_buf_cat2(result, "}");
|
98
|
-
return result;
|
99
|
+
case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
|
100
|
+
}
|
101
|
+
if (*source > 0xF4) return 0;
|
102
|
+
return 1;
|
99
103
|
}
|
100
104
|
|
101
|
-
|
105
|
+
/* Escapes the UTF16 character and stores the result in the buffer buf. */
|
106
|
+
static void unicode_escape(char *buf, UTF16 character)
|
102
107
|
{
|
103
|
-
|
108
|
+
const char *digits = "0123456789abcdef";
|
104
109
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
rb_str_buf_cat2(buf, ":");
|
111
|
-
tmp = rb_funcall(value, i_to_json, 0);
|
112
|
-
rb_str_buf_append(buf, tmp);
|
113
|
-
OBJ_INFECT(buf, tmp);
|
110
|
+
buf[2] = digits[character >> 12];
|
111
|
+
buf[3] = digits[(character >> 8) & 0xf];
|
112
|
+
buf[4] = digits[(character >> 4) & 0xf];
|
113
|
+
buf[5] = digits[character & 0xf];
|
114
|
+
}
|
114
115
|
|
115
|
-
|
116
|
+
/* Escapes the UTF16 character and stores the result in the buffer buf, then
|
117
|
+
* the buffer buf is appended to the FBuffer buffer. */
|
118
|
+
static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
|
119
|
+
character)
|
120
|
+
{
|
121
|
+
unicode_escape(buf, character);
|
122
|
+
fbuffer_append(buffer, buf, 6);
|
116
123
|
}
|
117
124
|
|
118
|
-
/*
|
119
|
-
*
|
120
|
-
*
|
121
|
-
* Returns a JSON string containing a JSON object, that is unparsed from
|
122
|
-
* this Hash instance.
|
123
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
124
|
-
* produced JSON string output further.
|
125
|
-
* _depth_ is used to find out nesting depth, to indent accordingly.
|
126
|
-
*/
|
127
|
-
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
125
|
+
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
|
126
|
+
* and control characters are JSON escaped. */
|
127
|
+
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe)
|
128
128
|
{
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
129
|
+
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
|
130
|
+
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
|
131
|
+
char buf[6] = { '\\', 'u' };
|
132
|
+
|
133
|
+
while (source < sourceEnd) {
|
134
|
+
UTF32 ch = 0;
|
135
|
+
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
136
|
+
if (source + extraBytesToRead >= sourceEnd) {
|
137
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
138
|
+
"partial character in source, but hit end");
|
139
|
+
}
|
140
|
+
if (!isLegalUTF8(source, extraBytesToRead+1)) {
|
141
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
142
|
+
"source sequence is illegal/malformed utf-8");
|
143
|
+
}
|
144
|
+
/*
|
145
|
+
* The cases all fall through. See "Note A" below.
|
146
|
+
*/
|
147
|
+
switch (extraBytesToRead) {
|
148
|
+
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
149
|
+
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
150
|
+
case 3: ch += *source++; ch <<= 6;
|
151
|
+
case 2: ch += *source++; ch <<= 6;
|
152
|
+
case 1: ch += *source++; ch <<= 6;
|
153
|
+
case 0: ch += *source++;
|
154
|
+
}
|
155
|
+
ch -= offsetsFromUTF8[extraBytesToRead];
|
156
|
+
|
157
|
+
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
158
|
+
/* UTF-16 surrogate values are illegal in UTF-32 */
|
159
|
+
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
160
|
+
#if UNI_STRICT_CONVERSION
|
161
|
+
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
162
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
163
|
+
"source sequence is illegal/malformed utf-8");
|
164
|
+
#else
|
165
|
+
unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
|
166
|
+
#endif
|
167
|
+
} else {
|
168
|
+
/* normal case */
|
169
|
+
if (ch >= 0x20 && ch <= 0x7f) {
|
170
|
+
switch (ch) {
|
171
|
+
case '\\':
|
172
|
+
fbuffer_append(buffer, "\\\\", 2);
|
173
|
+
break;
|
174
|
+
case '"':
|
175
|
+
fbuffer_append(buffer, "\\\"", 2);
|
176
|
+
break;
|
177
|
+
case '/':
|
178
|
+
if(script_safe) {
|
179
|
+
fbuffer_append(buffer, "\\/", 2);
|
180
|
+
break;
|
181
|
+
}
|
182
|
+
default:
|
183
|
+
fbuffer_append_char(buffer, (char)ch);
|
184
|
+
break;
|
185
|
+
}
|
186
|
+
} else {
|
187
|
+
switch (ch) {
|
188
|
+
case '\n':
|
189
|
+
fbuffer_append(buffer, "\\n", 2);
|
190
|
+
break;
|
191
|
+
case '\r':
|
192
|
+
fbuffer_append(buffer, "\\r", 2);
|
193
|
+
break;
|
194
|
+
case '\t':
|
195
|
+
fbuffer_append(buffer, "\\t", 2);
|
196
|
+
break;
|
197
|
+
case '\f':
|
198
|
+
fbuffer_append(buffer, "\\f", 2);
|
199
|
+
break;
|
200
|
+
case '\b':
|
201
|
+
fbuffer_append(buffer, "\\b", 2);
|
202
|
+
break;
|
203
|
+
default:
|
204
|
+
unicode_escape_to_buffer(buffer, buf, (UTF16) ch);
|
205
|
+
break;
|
206
|
+
}
|
207
|
+
}
|
147
208
|
}
|
148
|
-
|
149
|
-
|
150
|
-
|
209
|
+
} else if (ch > UNI_MAX_UTF16) {
|
210
|
+
#if UNI_STRICT_CONVERSION
|
211
|
+
source -= (extraBytesToRead+1); /* return to the start */
|
212
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
213
|
+
"source sequence is illegal/malformed utf8");
|
214
|
+
#else
|
215
|
+
unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
|
216
|
+
#endif
|
151
217
|
} else {
|
152
|
-
|
218
|
+
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
219
|
+
ch -= halfBase;
|
220
|
+
unicode_escape_to_buffer(buffer, buf, (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START));
|
221
|
+
unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
|
153
222
|
}
|
154
223
|
}
|
155
|
-
|
156
|
-
return result;
|
224
|
+
RB_GC_GUARD(string);
|
157
225
|
}
|
158
226
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
227
|
+
/* Converts string to a JSON string in FBuffer buffer, where only the
|
228
|
+
* characters required by the JSON standard are JSON escaped. The remaining
|
229
|
+
* characters (should be UTF8) are just passed through and appended to the
|
230
|
+
* result. */
|
231
|
+
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe)
|
232
|
+
{
|
233
|
+
const char *ptr = RSTRING_PTR(string), *p;
|
234
|
+
unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
|
235
|
+
const char *escape = NULL;
|
236
|
+
int escape_len;
|
237
|
+
unsigned char c;
|
238
|
+
char buf[6] = { '\\', 'u' };
|
239
|
+
int ascii_only = rb_enc_str_asciionly_p(string);
|
240
|
+
|
241
|
+
for (start = 0, end = 0; end < len;) {
|
242
|
+
p = ptr + end;
|
243
|
+
c = (unsigned char) *p;
|
244
|
+
if (c < 0x20) {
|
245
|
+
switch (c) {
|
246
|
+
case '\n':
|
247
|
+
escape = "\\n";
|
248
|
+
escape_len = 2;
|
249
|
+
break;
|
250
|
+
case '\r':
|
251
|
+
escape = "\\r";
|
252
|
+
escape_len = 2;
|
253
|
+
break;
|
254
|
+
case '\t':
|
255
|
+
escape = "\\t";
|
256
|
+
escape_len = 2;
|
257
|
+
break;
|
258
|
+
case '\f':
|
259
|
+
escape = "\\f";
|
260
|
+
escape_len = 2;
|
261
|
+
break;
|
262
|
+
case '\b':
|
263
|
+
escape = "\\b";
|
264
|
+
escape_len = 2;
|
265
|
+
break;
|
266
|
+
default:
|
267
|
+
unicode_escape(buf, (UTF16) *p);
|
268
|
+
escape = buf;
|
269
|
+
escape_len = 6;
|
270
|
+
break;
|
271
|
+
}
|
272
|
+
} else {
|
273
|
+
switch (c) {
|
274
|
+
case '\\':
|
275
|
+
escape = "\\\\";
|
276
|
+
escape_len = 2;
|
277
|
+
break;
|
278
|
+
case '"':
|
279
|
+
escape = "\\\"";
|
280
|
+
escape_len = 2;
|
281
|
+
break;
|
282
|
+
case '/':
|
283
|
+
if(script_safe) {
|
284
|
+
escape = "\\/";
|
285
|
+
escape_len = 2;
|
286
|
+
break;
|
287
|
+
}
|
288
|
+
default:
|
289
|
+
{
|
290
|
+
unsigned short clen = 1;
|
291
|
+
if (!ascii_only) {
|
292
|
+
clen += trailingBytesForUTF8[c];
|
293
|
+
if (end + clen > len) {
|
294
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
295
|
+
"partial character in source, but hit end");
|
296
|
+
}
|
297
|
+
|
298
|
+
if (script_safe && c == 0xE2) {
|
299
|
+
unsigned char c2 = (unsigned char) *(p+1);
|
300
|
+
unsigned char c3 = (unsigned char) *(p+2);
|
301
|
+
if (c2 == 0x80 && (c3 == 0xA8 || c3 == 0xA9)) {
|
302
|
+
fbuffer_append(buffer, ptr + start, end - start);
|
303
|
+
start = end = (end + clen);
|
304
|
+
if (c3 == 0xA8) {
|
305
|
+
fbuffer_append(buffer, "\\u2028", 6);
|
306
|
+
} else {
|
307
|
+
fbuffer_append(buffer, "\\u2029", 6);
|
308
|
+
}
|
309
|
+
continue;
|
310
|
+
}
|
311
|
+
}
|
312
|
+
|
313
|
+
if (!isLegalUTF8((UTF8 *) p, clen)) {
|
314
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
315
|
+
"source sequence is illegal/malformed utf-8");
|
316
|
+
}
|
317
|
+
}
|
318
|
+
end += clen;
|
319
|
+
}
|
320
|
+
continue;
|
321
|
+
break;
|
180
322
|
}
|
181
|
-
OBJ_INFECT(result, element);
|
182
|
-
if (i > 0) rb_str_buf_append(result, delim);
|
183
|
-
rb_str_buf_append(result, shift);
|
184
|
-
rb_str_buf_append(result, rb_funcall(element, i_to_json, 2, Vstate, LONG2FIX(depth + 1)));
|
185
|
-
}
|
186
|
-
if (FUL(state->array_nl)) {
|
187
|
-
rb_str_buf_append(result, state->array_nl);
|
188
|
-
rb_str_buf_append(result, rb_str_times(state->indent, LONG2FIX(depth)));
|
189
|
-
}
|
190
|
-
rb_str_buf_cat2(result, "]");
|
191
|
-
rb_hash_delete(state->seen, self_id);
|
192
|
-
} else {
|
193
|
-
result = rb_str_buf_new(len);
|
194
|
-
if (FUL(state->array_nl)) rb_str_append(delim, state->array_nl);
|
195
|
-
shift = rb_str_times(state->indent, LONG2FIX(depth + 1));
|
196
|
-
|
197
|
-
rb_str_buf_cat2(result, "[");
|
198
|
-
rb_str_buf_append(result, state->array_nl);
|
199
|
-
for (i = 0; i < len; i++) {
|
200
|
-
VALUE element = RARRAY(self)->ptr[i];
|
201
|
-
OBJ_INFECT(result, element);
|
202
|
-
if (i > 0) rb_str_buf_append(result, delim);
|
203
|
-
rb_str_buf_append(result, shift);
|
204
|
-
rb_str_buf_append(result, rb_funcall(element, i_to_json, 2, Vstate, LONG2FIX(depth + 1)));
|
205
|
-
}
|
206
|
-
rb_str_buf_append(result, state->array_nl);
|
207
|
-
if (FUL(state->array_nl)) {
|
208
|
-
rb_str_buf_append(result, rb_str_times(state->indent, LONG2FIX(depth)));
|
209
323
|
}
|
210
|
-
|
324
|
+
fbuffer_append(buffer, ptr + start, end - start);
|
325
|
+
fbuffer_append(buffer, escape, escape_len);
|
326
|
+
start = ++end;
|
327
|
+
escape = NULL;
|
211
328
|
}
|
212
|
-
|
329
|
+
fbuffer_append(buffer, ptr + start, end - start);
|
330
|
+
}
|
331
|
+
|
332
|
+
static char *fstrndup(const char *ptr, unsigned long len) {
|
333
|
+
char *result;
|
334
|
+
if (len <= 0) return NULL;
|
335
|
+
result = ALLOC_N(char, len);
|
336
|
+
memcpy(result, ptr, len);
|
337
|
+
return result;
|
338
|
+
}
|
339
|
+
|
340
|
+
/*
|
341
|
+
* Document-module: JSON::Ext::Generator
|
342
|
+
*
|
343
|
+
* This is the JSON generator implemented as a C extension. It can be
|
344
|
+
* configured to be used by setting
|
345
|
+
*
|
346
|
+
* JSON.generator = JSON::Ext::Generator
|
347
|
+
*
|
348
|
+
* with the method generator= in JSON.
|
349
|
+
*
|
350
|
+
*/
|
351
|
+
|
352
|
+
/* Explanation of the following: that's the only way to not pollute
|
353
|
+
* standard library's docs with GeneratorMethods::<ClassName> which
|
354
|
+
* are uninformative and take a large place in a list of classes
|
355
|
+
*/
|
356
|
+
|
357
|
+
/*
|
358
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods
|
359
|
+
* :nodoc:
|
360
|
+
*/
|
361
|
+
|
362
|
+
/*
|
363
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
|
364
|
+
* :nodoc:
|
365
|
+
*/
|
366
|
+
|
367
|
+
/*
|
368
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
|
369
|
+
* :nodoc:
|
370
|
+
*/
|
371
|
+
|
372
|
+
/*
|
373
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
|
374
|
+
* :nodoc:
|
375
|
+
*/
|
376
|
+
|
377
|
+
/*
|
378
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
|
379
|
+
* :nodoc:
|
380
|
+
*/
|
381
|
+
|
382
|
+
/*
|
383
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
|
384
|
+
* :nodoc:
|
385
|
+
*/
|
386
|
+
|
387
|
+
/*
|
388
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
|
389
|
+
* :nodoc:
|
390
|
+
*/
|
391
|
+
|
392
|
+
/*
|
393
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
|
394
|
+
* :nodoc:
|
395
|
+
*/
|
396
|
+
|
397
|
+
/*
|
398
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
|
399
|
+
* :nodoc:
|
400
|
+
*/
|
401
|
+
|
402
|
+
/*
|
403
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
|
404
|
+
* :nodoc:
|
405
|
+
*/
|
406
|
+
|
407
|
+
/*
|
408
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
|
409
|
+
* :nodoc:
|
410
|
+
*/
|
411
|
+
|
412
|
+
/*
|
413
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
|
414
|
+
* :nodoc:
|
415
|
+
*/
|
416
|
+
|
417
|
+
/*
|
418
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
|
419
|
+
* :nodoc:
|
420
|
+
*/
|
421
|
+
|
422
|
+
/*
|
423
|
+
* call-seq: to_json(state = nil)
|
424
|
+
*
|
425
|
+
* Returns a JSON string containing a JSON object, that is generated from
|
426
|
+
* this Hash instance.
|
427
|
+
* _state_ is a JSON::State object, that can also be used to configure the
|
428
|
+
* produced JSON string output further.
|
429
|
+
*/
|
430
|
+
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
431
|
+
{
|
432
|
+
GENERATE_JSON(object);
|
213
433
|
}
|
214
434
|
|
215
435
|
/*
|
216
|
-
* call-seq: to_json(state = nil
|
436
|
+
* call-seq: to_json(state = nil)
|
217
437
|
*
|
218
|
-
* Returns a JSON string containing a JSON array, that is
|
438
|
+
* Returns a JSON string containing a JSON array, that is generated from
|
219
439
|
* this Array instance.
|
220
440
|
* _state_ is a JSON::State object, that can also be used to configure the
|
221
441
|
* produced JSON string output further.
|
222
|
-
* _depth_ is used to find out nesting depth, to indent accordingly.
|
223
442
|
*/
|
224
443
|
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
225
|
-
|
226
|
-
|
227
|
-
rb_scan_args(argc, argv, "02", &Vstate, &Vdepth);
|
228
|
-
if (NIL_P(Vstate)) {
|
229
|
-
long i, len = RARRAY(self)->len;
|
230
|
-
result = rb_str_buf_new(2 + 2 * len);
|
231
|
-
rb_str_buf_cat2(result, "[");
|
232
|
-
for (i = 0; i < len; i++) {
|
233
|
-
VALUE element = RARRAY(self)->ptr[i];
|
234
|
-
OBJ_INFECT(result, element);
|
235
|
-
if (i > 0) rb_str_buf_cat2(result, ",");
|
236
|
-
rb_str_buf_append(result, rb_funcall(element, i_to_json, 0));
|
237
|
-
}
|
238
|
-
rb_str_buf_cat2(result, "]");
|
239
|
-
} else {
|
240
|
-
result = mArray_json_transfrom(self, Vstate, Vdepth);
|
241
|
-
}
|
242
|
-
OBJ_INFECT(result, self);
|
243
|
-
return result;
|
444
|
+
GENERATE_JSON(array);
|
244
445
|
}
|
245
446
|
|
447
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
246
448
|
/*
|
247
449
|
* call-seq: to_json(*)
|
248
450
|
*
|
@@ -250,9 +452,31 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
250
452
|
*/
|
251
453
|
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
252
454
|
{
|
253
|
-
|
455
|
+
GENERATE_JSON(integer);
|
456
|
+
}
|
457
|
+
|
458
|
+
#else
|
459
|
+
/*
|
460
|
+
* call-seq: to_json(*)
|
461
|
+
*
|
462
|
+
* Returns a JSON string representation for this Integer number.
|
463
|
+
*/
|
464
|
+
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
465
|
+
{
|
466
|
+
GENERATE_JSON(fixnum);
|
254
467
|
}
|
255
468
|
|
469
|
+
/*
|
470
|
+
* call-seq: to_json(*)
|
471
|
+
*
|
472
|
+
* Returns a JSON string representation for this Integer number.
|
473
|
+
*/
|
474
|
+
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
475
|
+
{
|
476
|
+
GENERATE_JSON(bignum);
|
477
|
+
}
|
478
|
+
#endif
|
479
|
+
|
256
480
|
/*
|
257
481
|
* call-seq: to_json(*)
|
258
482
|
*
|
@@ -260,7 +484,7 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
260
484
|
*/
|
261
485
|
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
262
486
|
{
|
263
|
-
|
487
|
+
GENERATE_JSON(float);
|
264
488
|
}
|
265
489
|
|
266
490
|
/*
|
@@ -269,7 +493,9 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
269
493
|
* Extends _modul_ with the String::Extend module.
|
270
494
|
*/
|
271
495
|
static VALUE mString_included_s(VALUE self, VALUE modul) {
|
272
|
-
|
496
|
+
VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
|
497
|
+
rb_call_super(1, &modul);
|
498
|
+
return result;
|
273
499
|
}
|
274
500
|
|
275
501
|
/*
|
@@ -281,22 +507,19 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
|
|
281
507
|
*/
|
282
508
|
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
283
509
|
{
|
284
|
-
|
285
|
-
rb_str_buf_cat2(result, "\"");
|
286
|
-
JSON_convert_UTF8_to_JSON(result, self, strictConversion);
|
287
|
-
rb_str_buf_cat2(result, "\"");
|
288
|
-
return result;
|
510
|
+
GENERATE_JSON(string);
|
289
511
|
}
|
290
512
|
|
291
513
|
/*
|
292
514
|
* call-seq: to_json_raw_object()
|
293
515
|
*
|
294
516
|
* This method creates a raw object hash, that can be nested into
|
295
|
-
* other data structures and will be
|
517
|
+
* other data structures and will be generated as a raw string. This
|
296
518
|
* method should be used, if you want to convert raw strings to JSON
|
297
519
|
* instead of UTF-8 strings, e. g. binary data.
|
298
520
|
*/
|
299
|
-
static VALUE mString_to_json_raw_object(VALUE self)
|
521
|
+
static VALUE mString_to_json_raw_object(VALUE self)
|
522
|
+
{
|
300
523
|
VALUE ary;
|
301
524
|
VALUE result = rb_hash_new();
|
302
525
|
rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
|
@@ -311,7 +534,8 @@ static VALUE mString_to_json_raw_object(VALUE self) {
|
|
311
534
|
* This method creates a JSON text from the result of a call to
|
312
535
|
* to_json_raw_object of this String.
|
313
536
|
*/
|
314
|
-
static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
|
537
|
+
static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
|
538
|
+
{
|
315
539
|
VALUE obj = mString_to_json_raw_object(self);
|
316
540
|
Check_Type(obj, T_HASH);
|
317
541
|
return mHash_to_json(argc, argv, obj);
|
@@ -323,7 +547,8 @@ static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self) {
|
|
323
547
|
* Raw Strings are JSON Objects (the raw bytes are stored in an array for the
|
324
548
|
* key "raw"). The Ruby String can be created by this module method.
|
325
549
|
*/
|
326
|
-
static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
550
|
+
static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
551
|
+
{
|
327
552
|
VALUE ary;
|
328
553
|
Check_Type(o, T_HASH);
|
329
554
|
ary = rb_hash_aref(o, rb_str_new2("raw"));
|
@@ -331,32 +556,33 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o) {
|
|
331
556
|
}
|
332
557
|
|
333
558
|
/*
|
334
|
-
* call-seq: to_json(
|
559
|
+
* call-seq: to_json(*)
|
335
560
|
*
|
336
561
|
* Returns a JSON string for true: 'true'.
|
337
562
|
*/
|
338
563
|
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
339
564
|
{
|
340
|
-
|
565
|
+
GENERATE_JSON(true);
|
341
566
|
}
|
342
567
|
|
343
568
|
/*
|
344
|
-
* call-seq: to_json(
|
569
|
+
* call-seq: to_json(*)
|
345
570
|
*
|
346
571
|
* Returns a JSON string for false: 'false'.
|
347
572
|
*/
|
348
573
|
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
349
574
|
{
|
350
|
-
|
575
|
+
GENERATE_JSON(false);
|
351
576
|
}
|
352
577
|
|
353
578
|
/*
|
354
|
-
* call-seq: to_json(
|
579
|
+
* call-seq: to_json(*)
|
355
580
|
*
|
581
|
+
* Returns a JSON string for nil: 'null'.
|
356
582
|
*/
|
357
583
|
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
358
584
|
{
|
359
|
-
|
585
|
+
GENERATE_JSON(null);
|
360
586
|
}
|
361
587
|
|
362
588
|
/*
|
@@ -368,40 +594,559 @@ static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
368
594
|
*/
|
369
595
|
static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
370
596
|
{
|
597
|
+
VALUE state;
|
371
598
|
VALUE string = rb_funcall(self, i_to_s, 0);
|
599
|
+
rb_scan_args(argc, argv, "01", &state);
|
372
600
|
Check_Type(string, T_STRING);
|
373
|
-
|
601
|
+
state = cState_from_state_s(cState, state);
|
602
|
+
return cState_partial_generate(state, string);
|
374
603
|
}
|
375
604
|
|
376
|
-
|
377
|
-
|
605
|
+
static void State_free(void *ptr)
|
606
|
+
{
|
607
|
+
JSON_Generator_State *state = ptr;
|
608
|
+
if (state->indent) ruby_xfree(state->indent);
|
609
|
+
if (state->space) ruby_xfree(state->space);
|
610
|
+
if (state->space_before) ruby_xfree(state->space_before);
|
611
|
+
if (state->object_nl) ruby_xfree(state->object_nl);
|
612
|
+
if (state->array_nl) ruby_xfree(state->array_nl);
|
613
|
+
if (state->array_delim) fbuffer_free(state->array_delim);
|
614
|
+
if (state->object_delim) fbuffer_free(state->object_delim);
|
615
|
+
if (state->object_delim2) fbuffer_free(state->object_delim2);
|
616
|
+
ruby_xfree(state);
|
617
|
+
}
|
618
|
+
|
619
|
+
static size_t State_memsize(const void *ptr)
|
620
|
+
{
|
621
|
+
const JSON_Generator_State *state = ptr;
|
622
|
+
size_t size = sizeof(*state);
|
623
|
+
if (state->indent) size += state->indent_len + 1;
|
624
|
+
if (state->space) size += state->space_len + 1;
|
625
|
+
if (state->space_before) size += state->space_before_len + 1;
|
626
|
+
if (state->object_nl) size += state->object_nl_len + 1;
|
627
|
+
if (state->array_nl) size += state->array_nl_len + 1;
|
628
|
+
if (state->array_delim) size += FBUFFER_CAPA(state->array_delim);
|
629
|
+
if (state->object_delim) size += FBUFFER_CAPA(state->object_delim);
|
630
|
+
if (state->object_delim2) size += FBUFFER_CAPA(state->object_delim2);
|
631
|
+
return size;
|
632
|
+
}
|
633
|
+
|
634
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
635
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
636
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
637
|
+
#endif
|
638
|
+
|
639
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
640
|
+
static const rb_data_type_t JSON_Generator_State_type = {
|
641
|
+
"JSON/Generator/State",
|
642
|
+
{NULL, State_free, State_memsize,},
|
643
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
644
|
+
0, 0,
|
645
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
646
|
+
#endif
|
647
|
+
};
|
648
|
+
#endif
|
649
|
+
|
650
|
+
static VALUE cState_s_allocate(VALUE klass)
|
651
|
+
{
|
652
|
+
JSON_Generator_State *state;
|
653
|
+
return TypedData_Make_Struct(klass, JSON_Generator_State,
|
654
|
+
&JSON_Generator_State_type, state);
|
655
|
+
}
|
656
|
+
|
657
|
+
/*
|
658
|
+
* call-seq: configure(opts)
|
378
659
|
*
|
379
|
-
*
|
380
|
-
*
|
660
|
+
* Configure this State instance with the Hash _opts_, and return
|
661
|
+
* itself.
|
381
662
|
*/
|
663
|
+
static VALUE cState_configure(VALUE self, VALUE opts)
|
664
|
+
{
|
665
|
+
VALUE tmp;
|
666
|
+
GET_STATE(self);
|
667
|
+
tmp = rb_check_convert_type(opts, T_HASH, "Hash", "to_hash");
|
668
|
+
if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
|
669
|
+
opts = tmp;
|
670
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_indent));
|
671
|
+
if (RTEST(tmp)) {
|
672
|
+
unsigned long len;
|
673
|
+
Check_Type(tmp, T_STRING);
|
674
|
+
len = RSTRING_LEN(tmp);
|
675
|
+
state->indent = fstrndup(RSTRING_PTR(tmp), len + 1);
|
676
|
+
state->indent_len = len;
|
677
|
+
}
|
678
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_space));
|
679
|
+
if (RTEST(tmp)) {
|
680
|
+
unsigned long len;
|
681
|
+
Check_Type(tmp, T_STRING);
|
682
|
+
len = RSTRING_LEN(tmp);
|
683
|
+
state->space = fstrndup(RSTRING_PTR(tmp), len + 1);
|
684
|
+
state->space_len = len;
|
685
|
+
}
|
686
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
|
687
|
+
if (RTEST(tmp)) {
|
688
|
+
unsigned long len;
|
689
|
+
Check_Type(tmp, T_STRING);
|
690
|
+
len = RSTRING_LEN(tmp);
|
691
|
+
state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1);
|
692
|
+
state->space_before_len = len;
|
693
|
+
}
|
694
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
|
695
|
+
if (RTEST(tmp)) {
|
696
|
+
unsigned long len;
|
697
|
+
Check_Type(tmp, T_STRING);
|
698
|
+
len = RSTRING_LEN(tmp);
|
699
|
+
state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
|
700
|
+
state->array_nl_len = len;
|
701
|
+
}
|
702
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
|
703
|
+
if (RTEST(tmp)) {
|
704
|
+
unsigned long len;
|
705
|
+
Check_Type(tmp, T_STRING);
|
706
|
+
len = RSTRING_LEN(tmp);
|
707
|
+
state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
|
708
|
+
state->object_nl_len = len;
|
709
|
+
}
|
710
|
+
tmp = ID2SYM(i_max_nesting);
|
711
|
+
state->max_nesting = 100;
|
712
|
+
if (option_given_p(opts, tmp)) {
|
713
|
+
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
714
|
+
if (RTEST(max_nesting)) {
|
715
|
+
Check_Type(max_nesting, T_FIXNUM);
|
716
|
+
state->max_nesting = FIX2LONG(max_nesting);
|
717
|
+
} else {
|
718
|
+
state->max_nesting = 0;
|
719
|
+
}
|
720
|
+
}
|
721
|
+
tmp = ID2SYM(i_depth);
|
722
|
+
state->depth = 0;
|
723
|
+
if (option_given_p(opts, tmp)) {
|
724
|
+
VALUE depth = rb_hash_aref(opts, tmp);
|
725
|
+
if (RTEST(depth)) {
|
726
|
+
Check_Type(depth, T_FIXNUM);
|
727
|
+
state->depth = FIX2LONG(depth);
|
728
|
+
} else {
|
729
|
+
state->depth = 0;
|
730
|
+
}
|
731
|
+
}
|
732
|
+
tmp = ID2SYM(i_buffer_initial_length);
|
733
|
+
if (option_given_p(opts, tmp)) {
|
734
|
+
VALUE buffer_initial_length = rb_hash_aref(opts, tmp);
|
735
|
+
if (RTEST(buffer_initial_length)) {
|
736
|
+
long initial_length;
|
737
|
+
Check_Type(buffer_initial_length, T_FIXNUM);
|
738
|
+
initial_length = FIX2LONG(buffer_initial_length);
|
739
|
+
if (initial_length > 0) state->buffer_initial_length = initial_length;
|
740
|
+
}
|
741
|
+
}
|
742
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_allow_nan));
|
743
|
+
state->allow_nan = RTEST(tmp);
|
744
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
745
|
+
state->ascii_only = RTEST(tmp);
|
746
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_script_safe));
|
747
|
+
state->script_safe = RTEST(tmp);
|
748
|
+
if (!state->script_safe) {
|
749
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
|
750
|
+
state->script_safe = RTEST(tmp);
|
751
|
+
}
|
752
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_strict));
|
753
|
+
state->strict = RTEST(tmp);
|
754
|
+
return self;
|
755
|
+
}
|
382
756
|
|
383
|
-
static void
|
757
|
+
static void set_state_ivars(VALUE hash, VALUE state)
|
384
758
|
{
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
759
|
+
VALUE ivars = rb_obj_instance_variables(state);
|
760
|
+
int i = 0;
|
761
|
+
for (i = 0; i < RARRAY_LEN(ivars); i++) {
|
762
|
+
VALUE key = rb_funcall(rb_ary_entry(ivars, i), i_to_s, 0);
|
763
|
+
long key_len = RSTRING_LEN(key);
|
764
|
+
VALUE value = rb_iv_get(state, StringValueCStr(key));
|
765
|
+
rb_hash_aset(hash, rb_str_intern(rb_str_substr(key, 1, key_len - 1)), value);
|
766
|
+
}
|
393
767
|
}
|
394
768
|
|
395
|
-
|
769
|
+
/*
|
770
|
+
* call-seq: to_h
|
771
|
+
*
|
772
|
+
* Returns the configuration instance variables as a hash, that can be
|
773
|
+
* passed to the configure method.
|
774
|
+
*/
|
775
|
+
static VALUE cState_to_h(VALUE self)
|
396
776
|
{
|
397
|
-
|
398
|
-
|
777
|
+
VALUE result = rb_hash_new();
|
778
|
+
GET_STATE(self);
|
779
|
+
set_state_ivars(result, self);
|
780
|
+
rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len));
|
781
|
+
rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len));
|
782
|
+
rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len));
|
783
|
+
rb_hash_aset(result, ID2SYM(i_object_nl), rb_str_new(state->object_nl, state->object_nl_len));
|
784
|
+
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
|
785
|
+
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
786
|
+
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
|
787
|
+
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
|
788
|
+
rb_hash_aset(result, ID2SYM(i_script_safe), state->script_safe ? Qtrue : Qfalse);
|
789
|
+
rb_hash_aset(result, ID2SYM(i_strict), state->strict ? Qtrue : Qfalse);
|
790
|
+
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
791
|
+
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
792
|
+
return result;
|
399
793
|
}
|
400
794
|
|
401
|
-
|
795
|
+
/*
|
796
|
+
* call-seq: [](name)
|
797
|
+
*
|
798
|
+
* Returns the value returned by method +name+.
|
799
|
+
*/
|
800
|
+
static VALUE cState_aref(VALUE self, VALUE name)
|
801
|
+
{
|
802
|
+
name = rb_funcall(name, i_to_s, 0);
|
803
|
+
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
804
|
+
return rb_funcall(self, i_send, 1, name);
|
805
|
+
} else {
|
806
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
807
|
+
}
|
808
|
+
}
|
809
|
+
|
810
|
+
/*
|
811
|
+
* call-seq: []=(name, value)
|
812
|
+
*
|
813
|
+
* Sets the attribute name to value.
|
814
|
+
*/
|
815
|
+
static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
816
|
+
{
|
817
|
+
VALUE name_writer;
|
818
|
+
|
819
|
+
name = rb_funcall(name, i_to_s, 0);
|
820
|
+
name_writer = rb_str_cat2(rb_str_dup(name), "=");
|
821
|
+
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name_writer))) {
|
822
|
+
return rb_funcall(self, i_send, 2, name_writer, value);
|
823
|
+
} else {
|
824
|
+
rb_ivar_set(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)), value);
|
825
|
+
}
|
826
|
+
return Qnil;
|
827
|
+
}
|
828
|
+
|
829
|
+
struct hash_foreach_arg {
|
830
|
+
FBuffer *buffer;
|
831
|
+
JSON_Generator_State *state;
|
832
|
+
VALUE Vstate;
|
833
|
+
int iter;
|
834
|
+
};
|
835
|
+
|
836
|
+
static int
|
837
|
+
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
838
|
+
{
|
839
|
+
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
840
|
+
FBuffer *buffer = arg->buffer;
|
841
|
+
JSON_Generator_State *state = arg->state;
|
842
|
+
VALUE Vstate = arg->Vstate;
|
843
|
+
|
844
|
+
char *object_nl = state->object_nl;
|
845
|
+
long object_nl_len = state->object_nl_len;
|
846
|
+
char *indent = state->indent;
|
847
|
+
long indent_len = state->indent_len;
|
848
|
+
char *delim = FBUFFER_PTR(state->object_delim);
|
849
|
+
long delim_len = FBUFFER_LEN(state->object_delim);
|
850
|
+
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
851
|
+
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
852
|
+
long depth = state->depth;
|
853
|
+
int j;
|
854
|
+
VALUE klass, key_to_s;
|
855
|
+
|
856
|
+
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
|
857
|
+
if (object_nl) {
|
858
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
859
|
+
}
|
860
|
+
if (indent) {
|
861
|
+
for (j = 0; j < depth; j++) {
|
862
|
+
fbuffer_append(buffer, indent, indent_len);
|
863
|
+
}
|
864
|
+
}
|
865
|
+
|
866
|
+
klass = CLASS_OF(key);
|
867
|
+
if (klass == rb_cString) {
|
868
|
+
key_to_s = key;
|
869
|
+
} else if (klass == rb_cSymbol) {
|
870
|
+
key_to_s = rb_sym2str(key);
|
871
|
+
} else {
|
872
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
873
|
+
}
|
874
|
+
Check_Type(key_to_s, T_STRING);
|
875
|
+
generate_json(buffer, Vstate, state, key_to_s);
|
876
|
+
fbuffer_append(buffer, delim2, delim2_len);
|
877
|
+
generate_json(buffer, Vstate, state, val);
|
878
|
+
|
879
|
+
arg->iter++;
|
880
|
+
return ST_CONTINUE;
|
881
|
+
}
|
882
|
+
|
883
|
+
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
884
|
+
{
|
885
|
+
char *object_nl = state->object_nl;
|
886
|
+
long object_nl_len = state->object_nl_len;
|
887
|
+
char *indent = state->indent;
|
888
|
+
long indent_len = state->indent_len;
|
889
|
+
long max_nesting = state->max_nesting;
|
890
|
+
long depth = ++state->depth;
|
891
|
+
int j;
|
892
|
+
struct hash_foreach_arg arg;
|
893
|
+
|
894
|
+
if (max_nesting != 0 && depth > max_nesting) {
|
895
|
+
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
896
|
+
}
|
897
|
+
fbuffer_append_char(buffer, '{');
|
898
|
+
|
899
|
+
arg.buffer = buffer;
|
900
|
+
arg.state = state;
|
901
|
+
arg.Vstate = Vstate;
|
902
|
+
arg.iter = 0;
|
903
|
+
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
904
|
+
|
905
|
+
depth = --state->depth;
|
906
|
+
if (object_nl) {
|
907
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
908
|
+
if (indent) {
|
909
|
+
for (j = 0; j < depth; j++) {
|
910
|
+
fbuffer_append(buffer, indent, indent_len);
|
911
|
+
}
|
912
|
+
}
|
913
|
+
}
|
914
|
+
fbuffer_append_char(buffer, '}');
|
915
|
+
}
|
916
|
+
|
917
|
+
static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
918
|
+
{
|
919
|
+
char *array_nl = state->array_nl;
|
920
|
+
long array_nl_len = state->array_nl_len;
|
921
|
+
char *indent = state->indent;
|
922
|
+
long indent_len = state->indent_len;
|
923
|
+
long max_nesting = state->max_nesting;
|
924
|
+
char *delim = FBUFFER_PTR(state->array_delim);
|
925
|
+
long delim_len = FBUFFER_LEN(state->array_delim);
|
926
|
+
long depth = ++state->depth;
|
927
|
+
int i, j;
|
928
|
+
if (max_nesting != 0 && depth > max_nesting) {
|
929
|
+
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
930
|
+
}
|
931
|
+
fbuffer_append_char(buffer, '[');
|
932
|
+
if (array_nl) fbuffer_append(buffer, array_nl, array_nl_len);
|
933
|
+
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
934
|
+
if (i > 0) fbuffer_append(buffer, delim, delim_len);
|
935
|
+
if (indent) {
|
936
|
+
for (j = 0; j < depth; j++) {
|
937
|
+
fbuffer_append(buffer, indent, indent_len);
|
938
|
+
}
|
939
|
+
}
|
940
|
+
generate_json(buffer, Vstate, state, rb_ary_entry(obj, i));
|
941
|
+
}
|
942
|
+
state->depth = --depth;
|
943
|
+
if (array_nl) {
|
944
|
+
fbuffer_append(buffer, array_nl, array_nl_len);
|
945
|
+
if (indent) {
|
946
|
+
for (j = 0; j < depth; j++) {
|
947
|
+
fbuffer_append(buffer, indent, indent_len);
|
948
|
+
}
|
949
|
+
}
|
950
|
+
}
|
951
|
+
fbuffer_append_char(buffer, ']');
|
952
|
+
}
|
953
|
+
|
954
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
955
|
+
static int enc_utf8_compatible_p(rb_encoding *enc)
|
402
956
|
{
|
403
|
-
|
404
|
-
|
957
|
+
if (enc == rb_usascii_encoding()) return 1;
|
958
|
+
if (enc == rb_utf8_encoding()) return 1;
|
959
|
+
return 0;
|
960
|
+
}
|
961
|
+
#endif
|
962
|
+
|
963
|
+
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
964
|
+
{
|
965
|
+
fbuffer_append_char(buffer, '"');
|
966
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
967
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
968
|
+
obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
|
969
|
+
}
|
970
|
+
#endif
|
971
|
+
if (state->ascii_only) {
|
972
|
+
convert_UTF8_to_JSON_ASCII(buffer, obj, state->script_safe);
|
973
|
+
} else {
|
974
|
+
convert_UTF8_to_JSON(buffer, obj, state->script_safe);
|
975
|
+
}
|
976
|
+
fbuffer_append_char(buffer, '"');
|
977
|
+
}
|
978
|
+
|
979
|
+
static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
980
|
+
{
|
981
|
+
fbuffer_append(buffer, "null", 4);
|
982
|
+
}
|
983
|
+
|
984
|
+
static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
985
|
+
{
|
986
|
+
fbuffer_append(buffer, "false", 5);
|
987
|
+
}
|
988
|
+
|
989
|
+
static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
990
|
+
{
|
991
|
+
fbuffer_append(buffer, "true", 4);
|
992
|
+
}
|
993
|
+
|
994
|
+
static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
995
|
+
{
|
996
|
+
fbuffer_append_long(buffer, FIX2LONG(obj));
|
997
|
+
}
|
998
|
+
|
999
|
+
static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
1000
|
+
{
|
1001
|
+
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
1002
|
+
fbuffer_append_str(buffer, tmp);
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
1006
|
+
static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
1007
|
+
{
|
1008
|
+
if (FIXNUM_P(obj))
|
1009
|
+
generate_json_fixnum(buffer, Vstate, state, obj);
|
1010
|
+
else
|
1011
|
+
generate_json_bignum(buffer, Vstate, state, obj);
|
1012
|
+
}
|
1013
|
+
#endif
|
1014
|
+
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
1015
|
+
{
|
1016
|
+
double value = RFLOAT_VALUE(obj);
|
1017
|
+
char allow_nan = state->allow_nan;
|
1018
|
+
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
1019
|
+
if (!allow_nan) {
|
1020
|
+
if (isinf(value)) {
|
1021
|
+
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
|
1022
|
+
} else if (isnan(value)) {
|
1023
|
+
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
|
1024
|
+
}
|
1025
|
+
}
|
1026
|
+
fbuffer_append_str(buffer, tmp);
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
1030
|
+
{
|
1031
|
+
VALUE tmp;
|
1032
|
+
VALUE klass = CLASS_OF(obj);
|
1033
|
+
if (klass == rb_cHash) {
|
1034
|
+
generate_json_object(buffer, Vstate, state, obj);
|
1035
|
+
} else if (klass == rb_cArray) {
|
1036
|
+
generate_json_array(buffer, Vstate, state, obj);
|
1037
|
+
} else if (klass == rb_cString) {
|
1038
|
+
generate_json_string(buffer, Vstate, state, obj);
|
1039
|
+
} else if (obj == Qnil) {
|
1040
|
+
generate_json_null(buffer, Vstate, state, obj);
|
1041
|
+
} else if (obj == Qfalse) {
|
1042
|
+
generate_json_false(buffer, Vstate, state, obj);
|
1043
|
+
} else if (obj == Qtrue) {
|
1044
|
+
generate_json_true(buffer, Vstate, state, obj);
|
1045
|
+
} else if (FIXNUM_P(obj)) {
|
1046
|
+
generate_json_fixnum(buffer, Vstate, state, obj);
|
1047
|
+
} else if (RB_TYPE_P(obj, T_BIGNUM)) {
|
1048
|
+
generate_json_bignum(buffer, Vstate, state, obj);
|
1049
|
+
} else if (klass == rb_cFloat) {
|
1050
|
+
generate_json_float(buffer, Vstate, state, obj);
|
1051
|
+
} else if (state->strict) {
|
1052
|
+
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj)));
|
1053
|
+
} else if (rb_respond_to(obj, i_to_json)) {
|
1054
|
+
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
|
1055
|
+
Check_Type(tmp, T_STRING);
|
1056
|
+
fbuffer_append_str(buffer, tmp);
|
1057
|
+
} else {
|
1058
|
+
tmp = rb_funcall(obj, i_to_s, 0);
|
1059
|
+
Check_Type(tmp, T_STRING);
|
1060
|
+
generate_json_string(buffer, Vstate, state, tmp);
|
1061
|
+
}
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
static FBuffer *cState_prepare_buffer(VALUE self)
|
1065
|
+
{
|
1066
|
+
FBuffer *buffer;
|
1067
|
+
GET_STATE(self);
|
1068
|
+
buffer = fbuffer_alloc(state->buffer_initial_length);
|
1069
|
+
|
1070
|
+
if (state->object_delim) {
|
1071
|
+
fbuffer_clear(state->object_delim);
|
1072
|
+
} else {
|
1073
|
+
state->object_delim = fbuffer_alloc(16);
|
1074
|
+
}
|
1075
|
+
fbuffer_append_char(state->object_delim, ',');
|
1076
|
+
if (state->object_delim2) {
|
1077
|
+
fbuffer_clear(state->object_delim2);
|
1078
|
+
} else {
|
1079
|
+
state->object_delim2 = fbuffer_alloc(16);
|
1080
|
+
}
|
1081
|
+
if (state->space_before) fbuffer_append(state->object_delim2, state->space_before, state->space_before_len);
|
1082
|
+
fbuffer_append_char(state->object_delim2, ':');
|
1083
|
+
if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
|
1084
|
+
|
1085
|
+
if (state->array_delim) {
|
1086
|
+
fbuffer_clear(state->array_delim);
|
1087
|
+
} else {
|
1088
|
+
state->array_delim = fbuffer_alloc(16);
|
1089
|
+
}
|
1090
|
+
fbuffer_append_char(state->array_delim, ',');
|
1091
|
+
if (state->array_nl) fbuffer_append(state->array_delim, state->array_nl, state->array_nl_len);
|
1092
|
+
return buffer;
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
struct generate_json_data {
|
1096
|
+
FBuffer *buffer;
|
1097
|
+
VALUE vstate;
|
1098
|
+
JSON_Generator_State *state;
|
1099
|
+
VALUE obj;
|
1100
|
+
};
|
1101
|
+
|
1102
|
+
static VALUE generate_json_try(VALUE d)
|
1103
|
+
{
|
1104
|
+
struct generate_json_data *data = (struct generate_json_data *)d;
|
1105
|
+
|
1106
|
+
generate_json(data->buffer, data->vstate, data->state, data->obj);
|
1107
|
+
|
1108
|
+
return Qnil;
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
1112
|
+
{
|
1113
|
+
struct generate_json_data *data = (struct generate_json_data *)d;
|
1114
|
+
fbuffer_free(data->buffer);
|
1115
|
+
|
1116
|
+
rb_exc_raise(exc);
|
1117
|
+
|
1118
|
+
return Qundef;
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
1122
|
+
{
|
1123
|
+
FBuffer *buffer = cState_prepare_buffer(self);
|
1124
|
+
GET_STATE(self);
|
1125
|
+
|
1126
|
+
struct generate_json_data data = {
|
1127
|
+
.buffer = buffer,
|
1128
|
+
.vstate = self,
|
1129
|
+
.state = state,
|
1130
|
+
.obj = obj
|
1131
|
+
};
|
1132
|
+
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
1133
|
+
|
1134
|
+
return fbuffer_to_s(buffer);
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
/*
|
1138
|
+
* call-seq: generate(obj)
|
1139
|
+
*
|
1140
|
+
* Generates a valid JSON document from object +obj+ and returns the
|
1141
|
+
* result. If no valid JSON document can be created this method raises a
|
1142
|
+
* GeneratorError exception.
|
1143
|
+
*/
|
1144
|
+
static VALUE cState_generate(VALUE self, VALUE obj)
|
1145
|
+
{
|
1146
|
+
VALUE result = cState_partial_generate(self, obj);
|
1147
|
+
GET_STATE(self);
|
1148
|
+
(void)state;
|
1149
|
+
return result;
|
405
1150
|
}
|
406
1151
|
|
407
1152
|
/*
|
@@ -414,71 +1159,54 @@ static VALUE cState_s_allocate(VALUE klass)
|
|
414
1159
|
* * *indent*: a string used to indent levels (default: ''),
|
415
1160
|
* * *space*: a string that is put after, a : or , delimiter (default: ''),
|
416
1161
|
* * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
417
|
-
* * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
1162
|
+
* * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
418
1163
|
* * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
419
|
-
* * *
|
420
|
-
*
|
1164
|
+
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
1165
|
+
* generated, otherwise an exception is thrown, if these values are
|
1166
|
+
* encountered. This options defaults to false.
|
1167
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
1168
|
+
* option defaults to false.
|
1169
|
+
* * *buffer_initial_length*: sets the initial length of the generator's
|
1170
|
+
* internal buffer.
|
421
1171
|
*/
|
422
1172
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
423
1173
|
{
|
424
1174
|
VALUE opts;
|
425
1175
|
GET_STATE(self);
|
426
|
-
|
1176
|
+
state->max_nesting = 100;
|
1177
|
+
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
427
1178
|
rb_scan_args(argc, argv, "01", &opts);
|
428
|
-
if (NIL_P(opts))
|
429
|
-
state->indent = rb_str_new2("");
|
430
|
-
state->space = rb_str_new2("");
|
431
|
-
state->space_before = rb_str_new2("");
|
432
|
-
state->array_nl = rb_str_new2("");
|
433
|
-
state->object_nl = rb_str_new2("");
|
434
|
-
state->check_circular = 0;
|
435
|
-
} else {
|
436
|
-
VALUE tmp;
|
437
|
-
opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
|
438
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_indent));
|
439
|
-
if (RTEST(tmp)) {
|
440
|
-
Check_Type(tmp, T_STRING);
|
441
|
-
state->indent = tmp;
|
442
|
-
} else {
|
443
|
-
state->indent = rb_str_new2("");
|
444
|
-
}
|
445
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_space));
|
446
|
-
if (RTEST(tmp)) {
|
447
|
-
Check_Type(tmp, T_STRING);
|
448
|
-
state->space = tmp;
|
449
|
-
} else {
|
450
|
-
state->space = rb_str_new2("");
|
451
|
-
}
|
452
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
|
453
|
-
if (RTEST(tmp)) {
|
454
|
-
Check_Type(tmp, T_STRING);
|
455
|
-
state->space_before = tmp;
|
456
|
-
} else {
|
457
|
-
state->space_before = rb_str_new2("");
|
458
|
-
}
|
459
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
|
460
|
-
if (RTEST(tmp)) {
|
461
|
-
Check_Type(tmp, T_STRING);
|
462
|
-
state->array_nl = tmp;
|
463
|
-
} else {
|
464
|
-
state->array_nl = rb_str_new2("");
|
465
|
-
}
|
466
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
|
467
|
-
if (RTEST(tmp)) {
|
468
|
-
Check_Type(tmp, T_STRING);
|
469
|
-
state->object_nl = tmp;
|
470
|
-
} else {
|
471
|
-
state->object_nl = rb_str_new2("");
|
472
|
-
}
|
473
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_check_circular));
|
474
|
-
state->check_circular = RTEST(tmp);
|
475
|
-
}
|
476
|
-
state->seen = rb_hash_new();
|
477
|
-
state->memo = Qnil;
|
478
|
-
state->depth = INT2FIX(0);
|
1179
|
+
if (!NIL_P(opts)) cState_configure(self, opts);
|
479
1180
|
return self;
|
480
1181
|
}
|
481
1182
|
|
1183
|
+
/*
|
1184
|
+
* call-seq: initialize_copy(orig)
|
1185
|
+
*
|
1186
|
+
* Initializes this object from orig if it can be duplicated/cloned and returns
|
1187
|
+
* it.
|
1188
|
+
*/
|
1189
|
+
static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
1190
|
+
{
|
1191
|
+
JSON_Generator_State *objState, *origState;
|
1192
|
+
|
1193
|
+
if (obj == orig) return obj;
|
1194
|
+
GET_STATE_TO(obj, objState);
|
1195
|
+
GET_STATE_TO(orig, origState);
|
1196
|
+
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
1197
|
+
|
1198
|
+
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
1199
|
+
objState->indent = fstrndup(origState->indent, origState->indent_len);
|
1200
|
+
objState->space = fstrndup(origState->space, origState->space_len);
|
1201
|
+
objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
|
1202
|
+
objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
|
1203
|
+
objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
|
1204
|
+
if (origState->array_delim) objState->array_delim = fbuffer_dup(origState->array_delim);
|
1205
|
+
if (origState->object_delim) objState->object_delim = fbuffer_dup(origState->object_delim);
|
1206
|
+
if (origState->object_delim2) objState->object_delim2 = fbuffer_dup(origState->object_delim2);
|
1207
|
+
return obj;
|
1208
|
+
}
|
1209
|
+
|
482
1210
|
/*
|
483
1211
|
* call-seq: from_state(opts)
|
484
1212
|
*
|
@@ -493,79 +1221,118 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
493
1221
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
494
1222
|
return rb_funcall(self, i_new, 1, opts);
|
495
1223
|
} else {
|
496
|
-
return
|
1224
|
+
return rb_class_new_instance(0, NULL, cState);
|
497
1225
|
}
|
498
1226
|
}
|
499
1227
|
|
500
1228
|
/*
|
501
1229
|
* call-seq: indent()
|
502
1230
|
*
|
503
|
-
*
|
1231
|
+
* Returns the string that is used to indent levels in the JSON text.
|
504
1232
|
*/
|
505
1233
|
static VALUE cState_indent(VALUE self)
|
506
1234
|
{
|
507
1235
|
GET_STATE(self);
|
508
|
-
return state->indent;
|
1236
|
+
return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
|
509
1237
|
}
|
510
1238
|
|
511
1239
|
/*
|
512
1240
|
* call-seq: indent=(indent)
|
513
1241
|
*
|
514
|
-
*
|
1242
|
+
* Sets the string that is used to indent levels in the JSON text.
|
515
1243
|
*/
|
516
1244
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
517
1245
|
{
|
1246
|
+
unsigned long len;
|
518
1247
|
GET_STATE(self);
|
519
1248
|
Check_Type(indent, T_STRING);
|
520
|
-
|
1249
|
+
len = RSTRING_LEN(indent);
|
1250
|
+
if (len == 0) {
|
1251
|
+
if (state->indent) {
|
1252
|
+
ruby_xfree(state->indent);
|
1253
|
+
state->indent = NULL;
|
1254
|
+
state->indent_len = 0;
|
1255
|
+
}
|
1256
|
+
} else {
|
1257
|
+
if (state->indent) ruby_xfree(state->indent);
|
1258
|
+
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
1259
|
+
state->indent_len = len;
|
1260
|
+
}
|
1261
|
+
return Qnil;
|
521
1262
|
}
|
522
1263
|
|
523
1264
|
/*
|
524
1265
|
* call-seq: space()
|
525
1266
|
*
|
526
|
-
*
|
1267
|
+
* Returns the string that is used to insert a space between the tokens in a JSON
|
527
1268
|
* string.
|
528
1269
|
*/
|
529
1270
|
static VALUE cState_space(VALUE self)
|
530
1271
|
{
|
531
1272
|
GET_STATE(self);
|
532
|
-
return state->space;
|
1273
|
+
return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
|
533
1274
|
}
|
534
1275
|
|
535
1276
|
/*
|
536
1277
|
* call-seq: space=(space)
|
537
1278
|
*
|
538
|
-
*
|
1279
|
+
* Sets _space_ to the string that is used to insert a space between the tokens in a JSON
|
539
1280
|
* string.
|
540
1281
|
*/
|
541
1282
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
542
1283
|
{
|
1284
|
+
unsigned long len;
|
543
1285
|
GET_STATE(self);
|
544
1286
|
Check_Type(space, T_STRING);
|
545
|
-
|
1287
|
+
len = RSTRING_LEN(space);
|
1288
|
+
if (len == 0) {
|
1289
|
+
if (state->space) {
|
1290
|
+
ruby_xfree(state->space);
|
1291
|
+
state->space = NULL;
|
1292
|
+
state->space_len = 0;
|
1293
|
+
}
|
1294
|
+
} else {
|
1295
|
+
if (state->space) ruby_xfree(state->space);
|
1296
|
+
state->space = fstrndup(RSTRING_PTR(space), len);
|
1297
|
+
state->space_len = len;
|
1298
|
+
}
|
1299
|
+
return Qnil;
|
546
1300
|
}
|
547
1301
|
|
548
1302
|
/*
|
549
1303
|
* call-seq: space_before()
|
550
1304
|
*
|
551
|
-
*
|
1305
|
+
* Returns the string that is used to insert a space before the ':' in JSON objects.
|
552
1306
|
*/
|
553
1307
|
static VALUE cState_space_before(VALUE self)
|
554
1308
|
{
|
555
1309
|
GET_STATE(self);
|
556
|
-
return state->space_before;
|
1310
|
+
return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
|
557
1311
|
}
|
558
1312
|
|
559
1313
|
/*
|
560
1314
|
* call-seq: space_before=(space_before)
|
561
1315
|
*
|
562
|
-
*
|
1316
|
+
* Sets the string that is used to insert a space before the ':' in JSON objects.
|
563
1317
|
*/
|
564
1318
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
565
1319
|
{
|
1320
|
+
unsigned long len;
|
566
1321
|
GET_STATE(self);
|
567
1322
|
Check_Type(space_before, T_STRING);
|
568
|
-
|
1323
|
+
len = RSTRING_LEN(space_before);
|
1324
|
+
if (len == 0) {
|
1325
|
+
if (state->space_before) {
|
1326
|
+
ruby_xfree(state->space_before);
|
1327
|
+
state->space_before = NULL;
|
1328
|
+
state->space_before_len = 0;
|
1329
|
+
}
|
1330
|
+
} else {
|
1331
|
+
if (state->space_before) ruby_xfree(state->space_before);
|
1332
|
+
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1333
|
+
state->space_before_len = len;
|
1334
|
+
}
|
1335
|
+
return Qnil;
|
569
1336
|
}
|
570
1337
|
|
571
1338
|
/*
|
@@ -577,7 +1344,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
577
1344
|
static VALUE cState_object_nl(VALUE self)
|
578
1345
|
{
|
579
1346
|
GET_STATE(self);
|
580
|
-
return state->object_nl;
|
1347
|
+
return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
|
581
1348
|
}
|
582
1349
|
|
583
1350
|
/*
|
@@ -588,9 +1355,21 @@ static VALUE cState_object_nl(VALUE self)
|
|
588
1355
|
*/
|
589
1356
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
590
1357
|
{
|
1358
|
+
unsigned long len;
|
591
1359
|
GET_STATE(self);
|
592
1360
|
Check_Type(object_nl, T_STRING);
|
593
|
-
|
1361
|
+
len = RSTRING_LEN(object_nl);
|
1362
|
+
if (len == 0) {
|
1363
|
+
if (state->object_nl) {
|
1364
|
+
ruby_xfree(state->object_nl);
|
1365
|
+
state->object_nl = NULL;
|
1366
|
+
}
|
1367
|
+
} else {
|
1368
|
+
if (state->object_nl) ruby_xfree(state->object_nl);
|
1369
|
+
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1370
|
+
state->object_nl_len = len;
|
1371
|
+
}
|
1372
|
+
return Qnil;
|
594
1373
|
}
|
595
1374
|
|
596
1375
|
/*
|
@@ -601,7 +1380,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
601
1380
|
static VALUE cState_array_nl(VALUE self)
|
602
1381
|
{
|
603
1382
|
GET_STATE(self);
|
604
|
-
return state->array_nl;
|
1383
|
+
return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
|
605
1384
|
}
|
606
1385
|
|
607
1386
|
/*
|
@@ -611,69 +1390,221 @@ static VALUE cState_array_nl(VALUE self)
|
|
611
1390
|
*/
|
612
1391
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
613
1392
|
{
|
1393
|
+
unsigned long len;
|
614
1394
|
GET_STATE(self);
|
615
1395
|
Check_Type(array_nl, T_STRING);
|
616
|
-
|
1396
|
+
len = RSTRING_LEN(array_nl);
|
1397
|
+
if (len == 0) {
|
1398
|
+
if (state->array_nl) {
|
1399
|
+
ruby_xfree(state->array_nl);
|
1400
|
+
state->array_nl = NULL;
|
1401
|
+
}
|
1402
|
+
} else {
|
1403
|
+
if (state->array_nl) ruby_xfree(state->array_nl);
|
1404
|
+
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1405
|
+
state->array_nl_len = len;
|
1406
|
+
}
|
1407
|
+
return Qnil;
|
617
1408
|
}
|
618
1409
|
|
1410
|
+
|
619
1411
|
/*
|
620
|
-
|
1412
|
+
* call-seq: check_circular?
|
1413
|
+
*
|
1414
|
+
* Returns true, if circular data structures should be checked,
|
1415
|
+
* otherwise returns false.
|
1416
|
+
*/
|
1417
|
+
static VALUE cState_check_circular_p(VALUE self)
|
1418
|
+
{
|
1419
|
+
GET_STATE(self);
|
1420
|
+
return state->max_nesting ? Qtrue : Qfalse;
|
1421
|
+
}
|
1422
|
+
|
1423
|
+
/*
|
1424
|
+
* call-seq: max_nesting
|
621
1425
|
*
|
622
|
-
*
|
623
|
-
*
|
1426
|
+
* This integer returns the maximum level of data structure nesting in
|
1427
|
+
* the generated JSON, max_nesting = 0 if no maximum is checked.
|
624
1428
|
*/
|
625
|
-
static VALUE
|
1429
|
+
static VALUE cState_max_nesting(VALUE self)
|
1430
|
+
{
|
1431
|
+
GET_STATE(self);
|
1432
|
+
return LONG2FIX(state->max_nesting);
|
1433
|
+
}
|
1434
|
+
|
1435
|
+
/*
|
1436
|
+
* call-seq: max_nesting=(depth)
|
1437
|
+
*
|
1438
|
+
* This sets the maximum level of data structure nesting in the generated JSON
|
1439
|
+
* to the integer depth, max_nesting = 0 if no maximum should be checked.
|
1440
|
+
*/
|
1441
|
+
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
626
1442
|
{
|
627
1443
|
GET_STATE(self);
|
628
|
-
|
1444
|
+
Check_Type(depth, T_FIXNUM);
|
1445
|
+
return state->max_nesting = FIX2LONG(depth);
|
629
1446
|
}
|
630
1447
|
|
631
1448
|
/*
|
632
|
-
* call-seq:
|
1449
|
+
* call-seq: script_safe
|
633
1450
|
*
|
634
|
-
*
|
1451
|
+
* If this boolean is true, the forward slashes will be escaped in
|
1452
|
+
* the json output.
|
635
1453
|
*/
|
636
|
-
static VALUE
|
1454
|
+
static VALUE cState_script_safe(VALUE self)
|
637
1455
|
{
|
638
1456
|
GET_STATE(self);
|
639
|
-
return
|
1457
|
+
return state->script_safe ? Qtrue : Qfalse;
|
640
1458
|
}
|
641
1459
|
|
642
1460
|
/*
|
643
|
-
* call-seq:
|
1461
|
+
* call-seq: script_safe=(enable)
|
644
1462
|
*
|
645
|
-
*
|
646
|
-
*
|
1463
|
+
* This sets whether or not the forward slashes will be escaped in
|
1464
|
+
* the json output.
|
647
1465
|
*/
|
648
|
-
static VALUE
|
1466
|
+
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
|
649
1467
|
{
|
650
1468
|
GET_STATE(self);
|
651
|
-
|
1469
|
+
state->script_safe = RTEST(enable);
|
1470
|
+
return Qnil;
|
652
1471
|
}
|
653
1472
|
|
654
1473
|
/*
|
655
|
-
* call-seq:
|
1474
|
+
* call-seq: strict
|
656
1475
|
*
|
657
|
-
*
|
1476
|
+
* If this boolean is false, types unsupported by the JSON format will
|
1477
|
+
* be serialized as strings.
|
1478
|
+
* If this boolean is true, types unsupported by the JSON format will
|
1479
|
+
* raise a JSON::GeneratorError.
|
658
1480
|
*/
|
659
|
-
static VALUE
|
1481
|
+
static VALUE cState_strict(VALUE self)
|
660
1482
|
{
|
661
1483
|
GET_STATE(self);
|
662
|
-
return
|
1484
|
+
return state->strict ? Qtrue : Qfalse;
|
663
1485
|
}
|
664
1486
|
|
665
|
-
|
1487
|
+
/*
|
1488
|
+
* call-seq: strict=(enable)
|
1489
|
+
*
|
1490
|
+
* This sets whether or not to serialize types unsupported by the
|
1491
|
+
* JSON format as strings.
|
1492
|
+
* If this boolean is false, types unsupported by the JSON format will
|
1493
|
+
* be serialized as strings.
|
1494
|
+
* If this boolean is true, types unsupported by the JSON format will
|
1495
|
+
* raise a JSON::GeneratorError.
|
1496
|
+
*/
|
1497
|
+
static VALUE cState_strict_set(VALUE self, VALUE enable)
|
666
1498
|
{
|
1499
|
+
GET_STATE(self);
|
1500
|
+
state->strict = RTEST(enable);
|
1501
|
+
return Qnil;
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
/*
|
1505
|
+
* call-seq: allow_nan?
|
1506
|
+
*
|
1507
|
+
* Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
|
1508
|
+
* returns false.
|
1509
|
+
*/
|
1510
|
+
static VALUE cState_allow_nan_p(VALUE self)
|
1511
|
+
{
|
1512
|
+
GET_STATE(self);
|
1513
|
+
return state->allow_nan ? Qtrue : Qfalse;
|
1514
|
+
}
|
1515
|
+
|
1516
|
+
/*
|
1517
|
+
* call-seq: ascii_only?
|
1518
|
+
*
|
1519
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
1520
|
+
* returns false.
|
1521
|
+
*/
|
1522
|
+
static VALUE cState_ascii_only_p(VALUE self)
|
1523
|
+
{
|
1524
|
+
GET_STATE(self);
|
1525
|
+
return state->ascii_only ? Qtrue : Qfalse;
|
1526
|
+
}
|
1527
|
+
|
1528
|
+
/*
|
1529
|
+
* call-seq: depth
|
1530
|
+
*
|
1531
|
+
* This integer returns the current depth of data structure nesting.
|
1532
|
+
*/
|
1533
|
+
static VALUE cState_depth(VALUE self)
|
1534
|
+
{
|
1535
|
+
GET_STATE(self);
|
1536
|
+
return LONG2FIX(state->depth);
|
1537
|
+
}
|
1538
|
+
|
1539
|
+
/*
|
1540
|
+
* call-seq: depth=(depth)
|
1541
|
+
*
|
1542
|
+
* This sets the maximum level of data structure nesting in the generated JSON
|
1543
|
+
* to the integer depth, max_nesting = 0 if no maximum should be checked.
|
1544
|
+
*/
|
1545
|
+
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1546
|
+
{
|
1547
|
+
GET_STATE(self);
|
1548
|
+
Check_Type(depth, T_FIXNUM);
|
1549
|
+
state->depth = FIX2LONG(depth);
|
1550
|
+
return Qnil;
|
1551
|
+
}
|
1552
|
+
|
1553
|
+
/*
|
1554
|
+
* call-seq: buffer_initial_length
|
1555
|
+
*
|
1556
|
+
* This integer returns the current initial length of the buffer.
|
1557
|
+
*/
|
1558
|
+
static VALUE cState_buffer_initial_length(VALUE self)
|
1559
|
+
{
|
1560
|
+
GET_STATE(self);
|
1561
|
+
return LONG2FIX(state->buffer_initial_length);
|
1562
|
+
}
|
1563
|
+
|
1564
|
+
/*
|
1565
|
+
* call-seq: buffer_initial_length=(length)
|
1566
|
+
*
|
1567
|
+
* This sets the initial length of the buffer to +length+, if +length+ > 0,
|
1568
|
+
* otherwise its value isn't changed.
|
1569
|
+
*/
|
1570
|
+
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1571
|
+
{
|
1572
|
+
long initial_length;
|
1573
|
+
GET_STATE(self);
|
1574
|
+
Check_Type(buffer_initial_length, T_FIXNUM);
|
1575
|
+
initial_length = FIX2LONG(buffer_initial_length);
|
1576
|
+
if (initial_length > 0) {
|
1577
|
+
state->buffer_initial_length = initial_length;
|
1578
|
+
}
|
1579
|
+
return Qnil;
|
1580
|
+
}
|
1581
|
+
|
1582
|
+
/*
|
1583
|
+
*
|
1584
|
+
*/
|
1585
|
+
void Init_generator(void)
|
1586
|
+
{
|
1587
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
1588
|
+
rb_ext_ractor_safe(true);
|
1589
|
+
#endif
|
1590
|
+
|
1591
|
+
#undef rb_intern
|
1592
|
+
rb_require("json/common");
|
1593
|
+
|
667
1594
|
mJSON = rb_define_module("JSON");
|
668
1595
|
mExt = rb_define_module_under(mJSON, "Ext");
|
669
1596
|
mGenerator = rb_define_module_under(mExt, "Generator");
|
1597
|
+
|
670
1598
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
671
|
-
|
1599
|
+
eNestingError = rb_path2class("JSON::NestingError");
|
1600
|
+
rb_gc_register_mark_object(eGeneratorError);
|
1601
|
+
rb_gc_register_mark_object(eNestingError);
|
1602
|
+
|
672
1603
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
673
1604
|
rb_define_alloc_func(cState, cState_s_allocate);
|
674
1605
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
675
1606
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
676
|
-
|
1607
|
+
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
677
1608
|
rb_define_method(cState, "indent", cState_indent, 0);
|
678
1609
|
rb_define_method(cState, "indent=", cState_indent_set, 1);
|
679
1610
|
rb_define_method(cState, "space", cState_space, 0);
|
@@ -684,10 +1615,32 @@ void Init_generator()
|
|
684
1615
|
rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
|
685
1616
|
rb_define_method(cState, "array_nl", cState_array_nl, 0);
|
686
1617
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
1618
|
+
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
1619
|
+
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
|
1620
|
+
rb_define_method(cState, "script_safe", cState_script_safe, 0);
|
1621
|
+
rb_define_method(cState, "script_safe?", cState_script_safe, 0);
|
1622
|
+
rb_define_method(cState, "script_safe=", cState_script_safe_set, 1);
|
1623
|
+
rb_define_alias(cState, "escape_slash", "script_safe");
|
1624
|
+
rb_define_alias(cState, "escape_slash?", "script_safe?");
|
1625
|
+
rb_define_alias(cState, "escape_slash=", "script_safe=");
|
1626
|
+
rb_define_method(cState, "strict", cState_strict, 0);
|
1627
|
+
rb_define_method(cState, "strict?", cState_strict, 0);
|
1628
|
+
rb_define_method(cState, "strict=", cState_strict_set, 1);
|
687
1629
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
688
|
-
rb_define_method(cState, "
|
689
|
-
rb_define_method(cState, "
|
690
|
-
rb_define_method(cState, "
|
1630
|
+
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
1631
|
+
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
|
1632
|
+
rb_define_method(cState, "depth", cState_depth, 0);
|
1633
|
+
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
1634
|
+
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
1635
|
+
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1636
|
+
rb_define_method(cState, "configure", cState_configure, 1);
|
1637
|
+
rb_define_alias(cState, "merge", "configure");
|
1638
|
+
rb_define_method(cState, "to_h", cState_to_h, 0);
|
1639
|
+
rb_define_alias(cState, "to_hash", "to_h");
|
1640
|
+
rb_define_method(cState, "[]", cState_aref, 1);
|
1641
|
+
rb_define_method(cState, "[]=", cState_aset, 2);
|
1642
|
+
rb_define_method(cState, "generate", cState_generate, 1);
|
1643
|
+
|
691
1644
|
mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
692
1645
|
mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
693
1646
|
rb_define_method(mObject, "to_json", mObject_to_json, -1);
|
@@ -695,8 +1648,15 @@ void Init_generator()
|
|
695
1648
|
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
696
1649
|
mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
697
1650
|
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
1651
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
698
1652
|
mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
|
699
1653
|
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
|
1654
|
+
#else
|
1655
|
+
mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
1656
|
+
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
1657
|
+
mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
1658
|
+
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
1659
|
+
#endif
|
700
1660
|
mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
701
1661
|
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
702
1662
|
mString = rb_define_module_under(mGeneratorMethods, "String");
|
@@ -721,9 +1681,23 @@ void Init_generator()
|
|
721
1681
|
i_space_before = rb_intern("space_before");
|
722
1682
|
i_object_nl = rb_intern("object_nl");
|
723
1683
|
i_array_nl = rb_intern("array_nl");
|
724
|
-
|
1684
|
+
i_max_nesting = rb_intern("max_nesting");
|
1685
|
+
i_script_safe = rb_intern("script_safe");
|
1686
|
+
i_escape_slash = rb_intern("escape_slash");
|
1687
|
+
i_strict = rb_intern("strict");
|
1688
|
+
i_allow_nan = rb_intern("allow_nan");
|
1689
|
+
i_ascii_only = rb_intern("ascii_only");
|
1690
|
+
i_depth = rb_intern("depth");
|
1691
|
+
i_buffer_initial_length = rb_intern("buffer_initial_length");
|
725
1692
|
i_pack = rb_intern("pack");
|
726
1693
|
i_unpack = rb_intern("unpack");
|
727
1694
|
i_create_id = rb_intern("create_id");
|
728
1695
|
i_extend = rb_intern("extend");
|
1696
|
+
i_key_p = rb_intern("key?");
|
1697
|
+
i_aref = rb_intern("[]");
|
1698
|
+
i_send = rb_intern("__send__");
|
1699
|
+
i_respond_to_p = rb_intern("respond_to?");
|
1700
|
+
i_match = rb_intern("match");
|
1701
|
+
i_keys = rb_intern("keys");
|
1702
|
+
i_dup = rb_intern("dup");
|
729
1703
|
}
|