json_pure 1.0.0 → 1.4.6
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.
- data/CHANGES +155 -1
- data/COPYING +58 -0
- data/GPL +7 -7
- data/README +324 -45
- data/Rakefile +166 -124
- data/TODO +1 -1
- data/VERSION +1 -1
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
- data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
- data/benchmarks/generator2_benchmark.rb +222 -0
- data/benchmarks/generator_benchmark.rb +224 -0
- data/benchmarks/ohai.json +1216 -0
- data/benchmarks/ohai.ruby +1 -0
- data/benchmarks/parser2_benchmark.rb +251 -0
- data/benchmarks/parser_benchmark.rb +259 -0
- data/bin/edit_json.rb +1 -3
- data/bin/prettify_json.rb +75 -0
- data/data/index.html +5 -4
- data/data/prototype.js +2764 -1095
- data/ext/json/ext/generator/extconf.rb +14 -3
- data/ext/json/ext/generator/generator.c +1022 -334
- data/ext/json/ext/generator/generator.h +197 -0
- data/ext/json/ext/parser/extconf.rb +9 -3
- data/ext/json/ext/parser/parser.c +961 -577
- data/ext/json/ext/parser/parser.h +71 -0
- data/ext/json/ext/parser/parser.rl +400 -123
- data/install.rb +0 -0
- data/lib/json/add/core.rb +148 -0
- data/lib/json/add/rails.rb +58 -0
- data/lib/json/common.rb +254 -47
- data/lib/json/editor.rb +236 -72
- data/lib/json/ext.rb +2 -0
- data/lib/json/pure/generator.rb +235 -117
- data/lib/json/pure/parser.rb +124 -25
- data/lib/json/pure.rb +5 -3
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +2 -197
- data/tests/fixtures/fail18.json +1 -0
- data/tests/test_json.rb +181 -22
- data/tests/test_json_addition.rb +84 -16
- data/tests/test_json_encoding.rb +68 -0
- data/tests/test_json_fixtures.rb +9 -5
- data/tests/test_json_generate.rb +114 -14
- data/tests/test_json_rails.rb +144 -0
- data/tests/test_json_unicode.rb +35 -14
- data/tools/fuzz.rb +13 -7
- data/tools/server.rb +0 -1
- metadata +156 -122
- 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/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/tests/fixtures/pass18.json +0 -1
- data/tests/runner.rb +0 -24
- /data/tests/fixtures/{fail15.json → pass15.json} +0 -0
- /data/tests/fixtures/{fail16.json → pass16.json} +0 -0
- /data/tests/fixtures/{fail17.json → pass17.json} +0 -0
- /data/tests/fixtures/{fail26.json → pass26.json} +0 -0
|
@@ -1,246 +1,444 @@
|
|
|
1
|
-
|
|
1
|
+
#include "generator.h"
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
#
|
|
3
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
4
|
+
static VALUE CEncoding_UTF_8;
|
|
5
|
+
static ID i_encoding, i_encode;
|
|
6
|
+
#endif
|
|
7
7
|
|
|
8
8
|
static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
|
|
9
|
-
mHash, mArray,
|
|
9
|
+
mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,
|
|
10
10
|
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
|
|
11
|
-
|
|
11
|
+
eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
|
|
12
|
+
i_SAFE_STATE_PROTOTYPE;
|
|
12
13
|
|
|
13
14
|
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
|
-
typedef struct JSON_Generator_StateStruct {
|
|
18
|
-
VALUE indent;
|
|
19
|
-
VALUE space;
|
|
20
|
-
VALUE space_before;
|
|
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
|
|
15
|
+
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
|
|
16
|
+
i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,
|
|
17
|
+
i_respond_to_p, i_match, i_keys, i_depth, i_dup;
|
|
34
18
|
|
|
35
|
-
/*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
19
|
+
/*
|
|
20
|
+
* Copyright 2001-2004 Unicode, Inc.
|
|
21
|
+
*
|
|
22
|
+
* Disclaimer
|
|
23
|
+
*
|
|
24
|
+
* This source code is provided as is by Unicode, Inc. No claims are
|
|
25
|
+
* made as to fitness for any particular purpose. No warranties of any
|
|
26
|
+
* kind are expressed or implied. The recipient agrees to determine
|
|
27
|
+
* applicability of information provided. If this file has been
|
|
28
|
+
* purchased on magnetic or optical media from Unicode, Inc., the
|
|
29
|
+
* sole remedy for any claim will be exchange of defective media
|
|
30
|
+
* within 90 days of receipt.
|
|
31
|
+
*
|
|
32
|
+
* Limitations on Rights to Redistribute This Code
|
|
33
|
+
*
|
|
34
|
+
* Unicode, Inc. hereby grants the right to freely use the information
|
|
35
|
+
* supplied in this file in the creation of products supporting the
|
|
36
|
+
* Unicode Standard, and to make copies of this file in any form
|
|
37
|
+
* for internal or external distribution as long as this notice
|
|
38
|
+
* remains attached.
|
|
45
39
|
*/
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
41
|
+
/*
|
|
42
|
+
* Index into the table below with the first byte of a UTF-8 sequence to
|
|
43
|
+
* get the number of trailing bytes that are supposed to follow it.
|
|
44
|
+
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
|
45
|
+
* left as-is for anyone who may want to do such conversion, which was
|
|
46
|
+
* allowed in earlier algorithms.
|
|
47
|
+
*/
|
|
48
|
+
static const char trailingBytesForUTF8[256] = {
|
|
49
|
+
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,
|
|
50
|
+
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,
|
|
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
|
+
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,
|
|
56
|
+
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
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* Magic values subtracted from a buffer value during UTF8 conversion.
|
|
61
|
+
* This table contains as many values as there might be trailing bytes
|
|
62
|
+
* in a UTF-8 sequence.
|
|
63
|
+
*/
|
|
64
|
+
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
|
65
|
+
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
|
69
|
+
* This must be called with the length pre-determined by the first byte.
|
|
70
|
+
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
|
71
|
+
* length = trailingBytesForUTF8[*source]+1;
|
|
72
|
+
* and the sequence is illegal right away if there aren't that many bytes
|
|
73
|
+
* available.
|
|
74
|
+
* If presented with a length > 4, this returns 0. The Unicode
|
|
75
|
+
* definition of UTF-8 goes up to 4-byte sequences.
|
|
76
|
+
*/
|
|
77
|
+
static unsigned char isLegalUTF8(const UTF8 *source, int length)
|
|
78
|
+
{
|
|
79
|
+
UTF8 a;
|
|
80
|
+
const UTF8 *srcptr = source+length;
|
|
81
|
+
switch (length) {
|
|
82
|
+
default: return 0;
|
|
83
|
+
/* Everything else falls through when "1"... */
|
|
84
|
+
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
|
85
|
+
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
|
86
|
+
case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
|
|
87
|
+
|
|
88
|
+
switch (*source) {
|
|
89
|
+
/* no fall-through in this inner switch */
|
|
90
|
+
case 0xE0: if (a < 0xA0) return 0; break;
|
|
91
|
+
case 0xED: if (a > 0x9F) return 0; break;
|
|
92
|
+
case 0xF0: if (a < 0x90) return 0; break;
|
|
93
|
+
case 0xF4: if (a > 0x8F) return 0; break;
|
|
94
|
+
default: if (a < 0x80) return 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
|
|
98
|
+
}
|
|
99
|
+
if (*source > 0xF4) return 0;
|
|
100
|
+
return 1;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
/* Escapes the UTF16 character and stores the result in the buffer buf. */
|
|
104
|
+
static void unicode_escape(char *buf, UTF16 character)
|
|
102
105
|
{
|
|
103
|
-
|
|
106
|
+
const char *digits = "0123456789abcdef";
|
|
104
107
|
|
|
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);
|
|
108
|
+
buf[2] = digits[character >> 12];
|
|
109
|
+
buf[3] = digits[(character >> 8) & 0xf];
|
|
110
|
+
buf[4] = digits[(character >> 4) & 0xf];
|
|
111
|
+
buf[5] = digits[character & 0xf];
|
|
112
|
+
}
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
/* Escapes the UTF16 character and stores the result in the buffer buf, then
|
|
115
|
+
* the buffer buf іs appended to the FBuffer buffer. */
|
|
116
|
+
static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
|
|
117
|
+
character)
|
|
118
|
+
{
|
|
119
|
+
unicode_escape(buf, character);
|
|
120
|
+
fbuffer_append(buffer, buf, 6);
|
|
116
121
|
}
|
|
117
122
|
|
|
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)
|
|
123
|
+
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
|
|
124
|
+
* and control characters are JSON escaped. */
|
|
125
|
+
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
128
126
|
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
127
|
+
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
|
|
128
|
+
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
|
|
129
|
+
char buf[6] = { '\\', 'u' };
|
|
130
|
+
|
|
131
|
+
while (source < sourceEnd) {
|
|
132
|
+
UTF32 ch = 0;
|
|
133
|
+
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
|
134
|
+
if (source + extraBytesToRead >= sourceEnd) {
|
|
135
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
|
136
|
+
"partial character in source, but hit end");
|
|
137
|
+
}
|
|
138
|
+
if (!isLegalUTF8(source, extraBytesToRead+1)) {
|
|
139
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
|
140
|
+
"source sequence is illegal/malformed utf-8");
|
|
141
|
+
}
|
|
142
|
+
/*
|
|
143
|
+
* The cases all fall through. See "Note A" below.
|
|
144
|
+
*/
|
|
145
|
+
switch (extraBytesToRead) {
|
|
146
|
+
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
|
147
|
+
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
|
148
|
+
case 3: ch += *source++; ch <<= 6;
|
|
149
|
+
case 2: ch += *source++; ch <<= 6;
|
|
150
|
+
case 1: ch += *source++; ch <<= 6;
|
|
151
|
+
case 0: ch += *source++;
|
|
152
|
+
}
|
|
153
|
+
ch -= offsetsFromUTF8[extraBytesToRead];
|
|
154
|
+
|
|
155
|
+
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
|
156
|
+
/* UTF-16 surrogate values are illegal in UTF-32 */
|
|
157
|
+
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
|
158
|
+
#if UNI_STRICT_CONVERSION
|
|
159
|
+
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
|
160
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
|
161
|
+
"source sequence is illegal/malformed utf-8");
|
|
162
|
+
#else
|
|
163
|
+
unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
|
|
164
|
+
#endif
|
|
165
|
+
} else {
|
|
166
|
+
/* normal case */
|
|
167
|
+
if (ch >= 0x20 && ch <= 0x7f) {
|
|
168
|
+
switch (ch) {
|
|
169
|
+
case '\\':
|
|
170
|
+
fbuffer_append(buffer, "\\\\", 2);
|
|
171
|
+
break;
|
|
172
|
+
case '"':
|
|
173
|
+
fbuffer_append(buffer, "\\\"", 2);
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
fbuffer_append_char(buffer, (char)ch);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
switch (ch) {
|
|
181
|
+
case '\n':
|
|
182
|
+
fbuffer_append(buffer, "\\n", 2);
|
|
183
|
+
break;
|
|
184
|
+
case '\r':
|
|
185
|
+
fbuffer_append(buffer, "\\r", 2);
|
|
186
|
+
break;
|
|
187
|
+
case '\t':
|
|
188
|
+
fbuffer_append(buffer, "\\t", 2);
|
|
189
|
+
break;
|
|
190
|
+
case '\f':
|
|
191
|
+
fbuffer_append(buffer, "\\f", 2);
|
|
192
|
+
break;
|
|
193
|
+
case '\b':
|
|
194
|
+
fbuffer_append(buffer, "\\b", 2);
|
|
195
|
+
break;
|
|
196
|
+
default:
|
|
197
|
+
unicode_escape_to_buffer(buffer, buf, (UTF16) ch);
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
147
201
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
202
|
+
} else if (ch > UNI_MAX_UTF16) {
|
|
203
|
+
#if UNI_STRICT_CONVERSION
|
|
204
|
+
source -= (extraBytesToRead+1); /* return to the start */
|
|
205
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
|
206
|
+
"source sequence is illegal/malformed utf8");
|
|
207
|
+
#else
|
|
208
|
+
unicode_escape_to_buffer(buffer, buf, UNI_REPLACEMENT_CHAR);
|
|
209
|
+
#endif
|
|
151
210
|
} else {
|
|
152
|
-
|
|
211
|
+
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
|
212
|
+
ch -= halfBase;
|
|
213
|
+
unicode_escape_to_buffer(buffer, buf, (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START));
|
|
214
|
+
unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
|
|
153
215
|
}
|
|
154
216
|
}
|
|
155
|
-
OBJ_INFECT(result, self);
|
|
156
|
-
return result;
|
|
157
217
|
}
|
|
158
218
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
219
|
+
/* Converts string to a JSON string in FBuffer buffer, where only the
|
|
220
|
+
* characters required by the JSON standard are JSON escaped. The remaining
|
|
221
|
+
* characters (should be UTF8) are just passed through and appended to the
|
|
222
|
+
* result. */
|
|
223
|
+
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
224
|
+
{
|
|
225
|
+
const char *ptr = RSTRING_PTR(string), *p;
|
|
226
|
+
int len = RSTRING_LEN(string), start = 0, end = 0;
|
|
227
|
+
const char *escape = NULL;
|
|
228
|
+
int escape_len;
|
|
229
|
+
unsigned char c;
|
|
230
|
+
char buf[6] = { '\\', 'u' };
|
|
231
|
+
|
|
232
|
+
for (start = 0, end = 0; end < len;) {
|
|
233
|
+
p = ptr + end;
|
|
234
|
+
c = (unsigned char) *p;
|
|
235
|
+
if (c < 0x20) {
|
|
236
|
+
switch (c) {
|
|
237
|
+
case '\n':
|
|
238
|
+
escape = "\\n";
|
|
239
|
+
escape_len = 2;
|
|
240
|
+
break;
|
|
241
|
+
case '\r':
|
|
242
|
+
escape = "\\r";
|
|
243
|
+
escape_len = 2;
|
|
244
|
+
break;
|
|
245
|
+
case '\t':
|
|
246
|
+
escape = "\\t";
|
|
247
|
+
escape_len = 2;
|
|
248
|
+
break;
|
|
249
|
+
case '\f':
|
|
250
|
+
escape = "\\f";
|
|
251
|
+
escape_len = 2;
|
|
252
|
+
break;
|
|
253
|
+
case '\b':
|
|
254
|
+
escape = "\\b";
|
|
255
|
+
escape_len = 2;
|
|
256
|
+
break;
|
|
257
|
+
default:
|
|
258
|
+
unicode_escape(buf, (UTF16) *p);
|
|
259
|
+
escape = buf;
|
|
260
|
+
escape_len = 6;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
switch (c) {
|
|
265
|
+
case '\\':
|
|
266
|
+
escape = "\\\\";
|
|
267
|
+
escape_len = 2;
|
|
268
|
+
break;
|
|
269
|
+
case '"':
|
|
270
|
+
escape = "\\\"";
|
|
271
|
+
escape_len = 2;
|
|
272
|
+
break;
|
|
273
|
+
default:
|
|
274
|
+
end++;
|
|
275
|
+
continue;
|
|
276
|
+
break;
|
|
180
277
|
}
|
|
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
278
|
}
|
|
190
|
-
|
|
191
|
-
|
|
279
|
+
fbuffer_append(buffer, ptr + start, end - start);
|
|
280
|
+
fbuffer_append(buffer, escape, escape_len);
|
|
281
|
+
start = ++end;
|
|
282
|
+
escape = NULL;
|
|
283
|
+
}
|
|
284
|
+
fbuffer_append(buffer, ptr + start, end - start);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static char *fstrndup(const char *ptr, int len) {
|
|
288
|
+
char *result;
|
|
289
|
+
if (len <= 0) return NULL;
|
|
290
|
+
result = ALLOC_N(char, len);
|
|
291
|
+
memccpy(result, ptr, 0, len);
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* fbuffer implementation */
|
|
296
|
+
|
|
297
|
+
static FBuffer *fbuffer_alloc()
|
|
298
|
+
{
|
|
299
|
+
FBuffer *fb = ALLOC(FBuffer);
|
|
300
|
+
memset((void *) fb, 0, sizeof(FBuffer));
|
|
301
|
+
fb->initial_length = FBUFFER_INITIAL_LENGTH;
|
|
302
|
+
return fb;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
static FBuffer *fbuffer_alloc_with_length(unsigned int initial_length)
|
|
306
|
+
{
|
|
307
|
+
FBuffer *fb;
|
|
308
|
+
assert(initial_length > 0);
|
|
309
|
+
fb = ALLOC(FBuffer);
|
|
310
|
+
memset((void *) fb, 0, sizeof(FBuffer));
|
|
311
|
+
fb->initial_length = initial_length;
|
|
312
|
+
return fb;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
static void fbuffer_free(FBuffer *fb)
|
|
316
|
+
{
|
|
317
|
+
if (fb->ptr) ruby_xfree(fb->ptr);
|
|
318
|
+
ruby_xfree(fb);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
static void fbuffer_free_only_buffer(FBuffer *fb)
|
|
322
|
+
{
|
|
323
|
+
ruby_xfree(fb);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static void fbuffer_clear(FBuffer *fb)
|
|
327
|
+
{
|
|
328
|
+
fb->len = 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
static void fbuffer_inc_capa(FBuffer *fb, unsigned int requested)
|
|
332
|
+
{
|
|
333
|
+
unsigned int required;
|
|
334
|
+
|
|
335
|
+
if (!fb->ptr) {
|
|
336
|
+
fb->ptr = ALLOC_N(char, fb->initial_length);
|
|
337
|
+
fb->capa = fb->initial_length;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
for (required = fb->capa; requested > required - fb->len; required <<= 1);
|
|
341
|
+
|
|
342
|
+
if (required > fb->capa) {
|
|
343
|
+
REALLOC_N(fb->ptr, char, required);
|
|
344
|
+
fb->capa = required;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned int len)
|
|
349
|
+
{
|
|
350
|
+
if (len > 0) {
|
|
351
|
+
fbuffer_inc_capa(fb, len);
|
|
352
|
+
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
|
353
|
+
fb->len += len;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
static void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
358
|
+
{
|
|
359
|
+
fbuffer_inc_capa(fb, 1);
|
|
360
|
+
*(fb->ptr + fb->len) = newchr;
|
|
361
|
+
fb->len++;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
static void freverse(char *start, char *end)
|
|
365
|
+
{
|
|
366
|
+
char c;
|
|
367
|
+
|
|
368
|
+
while (end > start) {
|
|
369
|
+
c = *end, *end-- = *start, *start++ = c;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
static int fltoa(long number, char *buf)
|
|
374
|
+
{
|
|
375
|
+
static char digits[] = "0123456789";
|
|
376
|
+
long sign = number;
|
|
377
|
+
char* tmp = buf;
|
|
378
|
+
|
|
379
|
+
if (sign < 0) number = -number;
|
|
380
|
+
do *tmp++ = digits[number % 10]; while (number /= 10);
|
|
381
|
+
if (sign < 0) *tmp++ = '-';
|
|
382
|
+
freverse(buf, tmp - 1);
|
|
383
|
+
return tmp - buf;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
static void fbuffer_append_long(FBuffer *fb, long number)
|
|
387
|
+
{
|
|
388
|
+
char buf[20];
|
|
389
|
+
int len = fltoa(number, buf);
|
|
390
|
+
fbuffer_append(fb, buf, len);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
static FBuffer *fbuffer_dup(FBuffer *fb)
|
|
394
|
+
{
|
|
395
|
+
int len = fb->len;
|
|
396
|
+
FBuffer *result;
|
|
397
|
+
|
|
398
|
+
if (len > 0) {
|
|
399
|
+
result = fbuffer_alloc_with_length(len);
|
|
400
|
+
fbuffer_append(result, FBUFFER_PAIR(fb));
|
|
192
401
|
} else {
|
|
193
|
-
result =
|
|
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
|
-
}
|
|
210
|
-
rb_str_buf_cat2(result, "]");
|
|
402
|
+
result = fbuffer_alloc();
|
|
211
403
|
}
|
|
212
404
|
return result;
|
|
213
405
|
}
|
|
214
406
|
|
|
407
|
+
/*
|
|
408
|
+
* Document-module: JSON::Ext::Generator
|
|
409
|
+
*
|
|
410
|
+
* This is the JSON generator implemented as a C extension. It can be
|
|
411
|
+
* configured to be used by setting
|
|
412
|
+
*
|
|
413
|
+
* JSON.generator = JSON::Ext::Generator
|
|
414
|
+
*
|
|
415
|
+
* with the method generator= in JSON.
|
|
416
|
+
*
|
|
417
|
+
*/
|
|
418
|
+
|
|
419
|
+
/*
|
|
420
|
+
* call-seq: to_json(state = nil)
|
|
421
|
+
*
|
|
422
|
+
* Returns a JSON string containing a JSON object, that is generated from
|
|
423
|
+
* this Hash instance.
|
|
424
|
+
* _state_ is a JSON::State object, that can also be used to configure the
|
|
425
|
+
* produced JSON string output further.
|
|
426
|
+
*/
|
|
427
|
+
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
428
|
+
{
|
|
429
|
+
GENERATE_JSON(object);
|
|
430
|
+
}
|
|
431
|
+
|
|
215
432
|
/*
|
|
216
|
-
* call-seq: to_json(state = nil
|
|
433
|
+
* call-seq: to_json(state = nil)
|
|
217
434
|
*
|
|
218
|
-
* Returns a JSON string containing a JSON array, that is
|
|
435
|
+
* Returns a JSON string containing a JSON array, that is generated from
|
|
219
436
|
* this Array instance.
|
|
220
437
|
* _state_ is a JSON::State object, that can also be used to configure the
|
|
221
438
|
* produced JSON string output further.
|
|
222
|
-
* _depth_ is used to find out nesting depth, to indent accordingly.
|
|
223
439
|
*/
|
|
224
440
|
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;
|
|
441
|
+
GENERATE_JSON(array);
|
|
244
442
|
}
|
|
245
443
|
|
|
246
444
|
/*
|
|
@@ -248,9 +446,19 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
|
248
446
|
*
|
|
249
447
|
* Returns a JSON string representation for this Integer number.
|
|
250
448
|
*/
|
|
251
|
-
static VALUE
|
|
449
|
+
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
252
450
|
{
|
|
253
|
-
|
|
451
|
+
GENERATE_JSON(fixnum);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/*
|
|
455
|
+
* call-seq: to_json(*)
|
|
456
|
+
*
|
|
457
|
+
* Returns a JSON string representation for this Integer number.
|
|
458
|
+
*/
|
|
459
|
+
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
460
|
+
{
|
|
461
|
+
GENERATE_JSON(bignum);
|
|
254
462
|
}
|
|
255
463
|
|
|
256
464
|
/*
|
|
@@ -260,7 +468,7 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
|
260
468
|
*/
|
|
261
469
|
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
262
470
|
{
|
|
263
|
-
|
|
471
|
+
GENERATE_JSON(float);
|
|
264
472
|
}
|
|
265
473
|
|
|
266
474
|
/*
|
|
@@ -269,7 +477,8 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
|
269
477
|
* Extends _modul_ with the String::Extend module.
|
|
270
478
|
*/
|
|
271
479
|
static VALUE mString_included_s(VALUE self, VALUE modul) {
|
|
272
|
-
|
|
480
|
+
VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
|
|
481
|
+
return result;
|
|
273
482
|
}
|
|
274
483
|
|
|
275
484
|
/*
|
|
@@ -281,22 +490,19 @@ static VALUE mString_included_s(VALUE self, VALUE modul) {
|
|
|
281
490
|
*/
|
|
282
491
|
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
|
283
492
|
{
|
|
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;
|
|
493
|
+
GENERATE_JSON(string);
|
|
289
494
|
}
|
|
290
495
|
|
|
291
496
|
/*
|
|
292
497
|
* call-seq: to_json_raw_object()
|
|
293
498
|
*
|
|
294
499
|
* This method creates a raw object hash, that can be nested into
|
|
295
|
-
* other data structures and will be
|
|
500
|
+
* other data structures and will be generated as a raw string. This
|
|
296
501
|
* method should be used, if you want to convert raw strings to JSON
|
|
297
502
|
* instead of UTF-8 strings, e. g. binary data.
|
|
298
503
|
*/
|
|
299
|
-
static VALUE mString_to_json_raw_object(VALUE self)
|
|
504
|
+
static VALUE mString_to_json_raw_object(VALUE self)
|
|
505
|
+
{
|
|
300
506
|
VALUE ary;
|
|
301
507
|
VALUE result = rb_hash_new();
|
|
302
508
|
rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
|
|
@@ -311,7 +517,8 @@ static VALUE mString_to_json_raw_object(VALUE self) {
|
|
|
311
517
|
* This method creates a JSON text from the result of a call to
|
|
312
518
|
* to_json_raw_object of this String.
|
|
313
519
|
*/
|
|
314
|
-
static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
|
|
520
|
+
static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)
|
|
521
|
+
{
|
|
315
522
|
VALUE obj = mString_to_json_raw_object(self);
|
|
316
523
|
Check_Type(obj, T_HASH);
|
|
317
524
|
return mHash_to_json(argc, argv, obj);
|
|
@@ -323,7 +530,8 @@ static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self) {
|
|
|
323
530
|
* Raw Strings are JSON Objects (the raw bytes are stored in an array for the
|
|
324
531
|
* key "raw"). The Ruby String can be created by this module method.
|
|
325
532
|
*/
|
|
326
|
-
static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
|
533
|
+
static VALUE mString_Extend_json_create(VALUE self, VALUE o)
|
|
534
|
+
{
|
|
327
535
|
VALUE ary;
|
|
328
536
|
Check_Type(o, T_HASH);
|
|
329
537
|
ary = rb_hash_aref(o, rb_str_new2("raw"));
|
|
@@ -331,32 +539,32 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o) {
|
|
|
331
539
|
}
|
|
332
540
|
|
|
333
541
|
/*
|
|
334
|
-
* call-seq: to_json(
|
|
542
|
+
* call-seq: to_json(*)
|
|
335
543
|
*
|
|
336
544
|
* Returns a JSON string for true: 'true'.
|
|
337
545
|
*/
|
|
338
546
|
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
339
547
|
{
|
|
340
|
-
|
|
548
|
+
GENERATE_JSON(true);
|
|
341
549
|
}
|
|
342
550
|
|
|
343
551
|
/*
|
|
344
|
-
* call-seq: to_json(
|
|
552
|
+
* call-seq: to_json(*)
|
|
345
553
|
*
|
|
346
554
|
* Returns a JSON string for false: 'false'.
|
|
347
555
|
*/
|
|
348
556
|
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
349
557
|
{
|
|
350
|
-
|
|
558
|
+
GENERATE_JSON(false);
|
|
351
559
|
}
|
|
352
560
|
|
|
353
561
|
/*
|
|
354
|
-
* call-seq: to_json(
|
|
562
|
+
* call-seq: to_json(*)
|
|
355
563
|
*
|
|
356
564
|
*/
|
|
357
565
|
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
358
566
|
{
|
|
359
|
-
|
|
567
|
+
GENERATE_JSON(null);
|
|
360
568
|
}
|
|
361
569
|
|
|
362
570
|
/*
|
|
@@ -368,40 +576,402 @@ static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
|
368
576
|
*/
|
|
369
577
|
static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
370
578
|
{
|
|
579
|
+
VALUE state;
|
|
371
580
|
VALUE string = rb_funcall(self, i_to_s, 0);
|
|
581
|
+
rb_scan_args(argc, argv, "01", &state);
|
|
372
582
|
Check_Type(string, T_STRING);
|
|
373
|
-
|
|
583
|
+
state = cState_from_state_s(cState, state);
|
|
584
|
+
return cState_partial_generate(state, string);
|
|
374
585
|
}
|
|
375
586
|
|
|
376
|
-
|
|
377
|
-
* Document-class: JSON::Ext::Generator::State
|
|
378
|
-
*
|
|
379
|
-
* This class is used to create State instances, that are use to hold data
|
|
380
|
-
* while generating a JSON text from a a Ruby data structure.
|
|
381
|
-
*/
|
|
382
|
-
|
|
383
|
-
static void State_mark(JSON_Generator_State *state)
|
|
587
|
+
static void State_free(JSON_Generator_State *state)
|
|
384
588
|
{
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
589
|
+
if (state->indent) ruby_xfree(state->indent);
|
|
590
|
+
if (state->space) ruby_xfree(state->space);
|
|
591
|
+
if (state->space_before) ruby_xfree(state->space_before);
|
|
592
|
+
if (state->object_nl) ruby_xfree(state->object_nl);
|
|
593
|
+
if (state->array_nl) ruby_xfree(state->array_nl);
|
|
594
|
+
if (state->array_delim) fbuffer_free(state->array_delim);
|
|
595
|
+
if (state->object_delim) fbuffer_free(state->object_delim);
|
|
596
|
+
if (state->object_delim2) fbuffer_free(state->object_delim2);
|
|
597
|
+
ruby_xfree(state);
|
|
393
598
|
}
|
|
394
599
|
|
|
395
600
|
static JSON_Generator_State *State_allocate()
|
|
396
601
|
{
|
|
397
602
|
JSON_Generator_State *state = ALLOC(JSON_Generator_State);
|
|
603
|
+
MEMZERO(state, JSON_Generator_State, 1);
|
|
398
604
|
return state;
|
|
399
605
|
}
|
|
400
606
|
|
|
401
607
|
static VALUE cState_s_allocate(VALUE klass)
|
|
402
608
|
{
|
|
403
609
|
JSON_Generator_State *state = State_allocate();
|
|
404
|
-
return Data_Wrap_Struct(klass,
|
|
610
|
+
return Data_Wrap_Struct(klass, NULL, State_free, state);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/*
|
|
614
|
+
* call-seq: configure(opts)
|
|
615
|
+
*
|
|
616
|
+
* Configure this State instance with the Hash _opts_, and return
|
|
617
|
+
* itself.
|
|
618
|
+
*/
|
|
619
|
+
static VALUE cState_configure(VALUE self, VALUE opts)
|
|
620
|
+
{
|
|
621
|
+
VALUE tmp;
|
|
622
|
+
GET_STATE(self);
|
|
623
|
+
tmp = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
|
|
624
|
+
if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
|
|
625
|
+
if (NIL_P(tmp)) {
|
|
626
|
+
rb_raise(rb_eArgError, "opts has to be hash like or convertable into a hash");
|
|
627
|
+
}
|
|
628
|
+
opts = tmp;
|
|
629
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_indent));
|
|
630
|
+
if (RTEST(tmp)) {
|
|
631
|
+
int len;
|
|
632
|
+
Check_Type(tmp, T_STRING);
|
|
633
|
+
len = RSTRING_LEN(tmp);
|
|
634
|
+
state->indent = fstrndup(RSTRING_PTR(tmp), len);
|
|
635
|
+
state->indent_len = len;
|
|
636
|
+
}
|
|
637
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_space));
|
|
638
|
+
if (RTEST(tmp)) {
|
|
639
|
+
int len;
|
|
640
|
+
Check_Type(tmp, T_STRING);
|
|
641
|
+
len = RSTRING_LEN(tmp);
|
|
642
|
+
state->space = fstrndup(RSTRING_PTR(tmp), len);
|
|
643
|
+
state->space_len = len;
|
|
644
|
+
}
|
|
645
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
|
|
646
|
+
if (RTEST(tmp)) {
|
|
647
|
+
int len;
|
|
648
|
+
Check_Type(tmp, T_STRING);
|
|
649
|
+
len = RSTRING_LEN(tmp);
|
|
650
|
+
state->space_before = fstrndup(RSTRING_PTR(tmp), len);
|
|
651
|
+
state->space_before_len = len;
|
|
652
|
+
}
|
|
653
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
|
|
654
|
+
if (RTEST(tmp)) {
|
|
655
|
+
int len;
|
|
656
|
+
Check_Type(tmp, T_STRING);
|
|
657
|
+
len = RSTRING_LEN(tmp);
|
|
658
|
+
state->array_nl = fstrndup(RSTRING_PTR(tmp), len);
|
|
659
|
+
state->array_nl_len = len;
|
|
660
|
+
}
|
|
661
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
|
|
662
|
+
if (RTEST(tmp)) {
|
|
663
|
+
int len;
|
|
664
|
+
Check_Type(tmp, T_STRING);
|
|
665
|
+
len = RSTRING_LEN(tmp);
|
|
666
|
+
state->object_nl = fstrndup(RSTRING_PTR(tmp), len);
|
|
667
|
+
state->object_nl_len = len;
|
|
668
|
+
}
|
|
669
|
+
tmp = ID2SYM(i_max_nesting);
|
|
670
|
+
state->max_nesting = 19;
|
|
671
|
+
if (option_given_p(opts, tmp)) {
|
|
672
|
+
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
|
673
|
+
if (RTEST(max_nesting)) {
|
|
674
|
+
Check_Type(max_nesting, T_FIXNUM);
|
|
675
|
+
state->max_nesting = FIX2LONG(max_nesting);
|
|
676
|
+
} else {
|
|
677
|
+
state->max_nesting = 0;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
tmp = ID2SYM(i_depth);
|
|
681
|
+
state->depth = 0;
|
|
682
|
+
if (option_given_p(opts, tmp)) {
|
|
683
|
+
VALUE depth = rb_hash_aref(opts, tmp);
|
|
684
|
+
if (RTEST(depth)) {
|
|
685
|
+
Check_Type(depth, T_FIXNUM);
|
|
686
|
+
state->depth = FIX2LONG(depth);
|
|
687
|
+
} else {
|
|
688
|
+
state->depth = 0;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_allow_nan));
|
|
692
|
+
state->allow_nan = RTEST(tmp);
|
|
693
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
|
694
|
+
state->ascii_only = RTEST(tmp);
|
|
695
|
+
return self;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/*
|
|
699
|
+
* call-seq: to_h
|
|
700
|
+
*
|
|
701
|
+
* Returns the configuration instance variables as a hash, that can be
|
|
702
|
+
* passed to the configure method.
|
|
703
|
+
*/
|
|
704
|
+
static VALUE cState_to_h(VALUE self)
|
|
705
|
+
{
|
|
706
|
+
VALUE result = rb_hash_new();
|
|
707
|
+
GET_STATE(self);
|
|
708
|
+
rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len));
|
|
709
|
+
rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len));
|
|
710
|
+
rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len));
|
|
711
|
+
rb_hash_aset(result, ID2SYM(i_object_nl), rb_str_new(state->object_nl, state->object_nl_len));
|
|
712
|
+
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
|
|
713
|
+
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
|
714
|
+
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
|
|
715
|
+
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
|
|
716
|
+
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
|
717
|
+
return result;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/*
|
|
721
|
+
* call-seq: [](name)
|
|
722
|
+
*
|
|
723
|
+
* Return the value returned by method +name+.
|
|
724
|
+
*/
|
|
725
|
+
static VALUE cState_aref(VALUE self, VALUE name)
|
|
726
|
+
{
|
|
727
|
+
GET_STATE(self);
|
|
728
|
+
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
|
729
|
+
return rb_funcall(self, i_send, 1, name);
|
|
730
|
+
} else {
|
|
731
|
+
return Qnil;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
736
|
+
{
|
|
737
|
+
char *object_nl = state->object_nl;
|
|
738
|
+
long object_nl_len = state->object_nl_len;
|
|
739
|
+
char *indent = state->indent;
|
|
740
|
+
long indent_len = state->indent_len;
|
|
741
|
+
long max_nesting = state->max_nesting;
|
|
742
|
+
char *delim = FBUFFER_PTR(state->object_delim);
|
|
743
|
+
long delim_len = FBUFFER_LEN(state->object_delim);
|
|
744
|
+
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
|
745
|
+
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
|
746
|
+
long depth = ++state->depth;
|
|
747
|
+
int i, j;
|
|
748
|
+
VALUE key, key_to_s, keys;
|
|
749
|
+
if (max_nesting != 0 && depth > max_nesting) {
|
|
750
|
+
fbuffer_free(buffer);
|
|
751
|
+
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
|
752
|
+
}
|
|
753
|
+
fbuffer_append_char(buffer, '{');
|
|
754
|
+
keys = rb_funcall(obj, i_keys, 0);
|
|
755
|
+
for(i = 0; i < RARRAY_LEN(keys); i++) {
|
|
756
|
+
if (i > 0) fbuffer_append(buffer, delim, delim_len);
|
|
757
|
+
if (object_nl) {
|
|
758
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
|
759
|
+
}
|
|
760
|
+
if (indent) {
|
|
761
|
+
for (j = 0; j < depth; j++) {
|
|
762
|
+
fbuffer_append(buffer, indent, indent_len);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
key = rb_ary_entry(keys, i);
|
|
766
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
|
767
|
+
Check_Type(key_to_s, T_STRING);
|
|
768
|
+
generate_json(buffer, Vstate, state, key_to_s);
|
|
769
|
+
fbuffer_append(buffer, delim2, delim2_len);
|
|
770
|
+
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
|
|
771
|
+
}
|
|
772
|
+
depth = --state->depth;
|
|
773
|
+
if (object_nl) {
|
|
774
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
|
775
|
+
if (indent) {
|
|
776
|
+
for (j = 0; j < depth; j++) {
|
|
777
|
+
fbuffer_append(buffer, indent, indent_len);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
fbuffer_append_char(buffer, '}');
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
785
|
+
{
|
|
786
|
+
char *array_nl = state->array_nl;
|
|
787
|
+
long array_nl_len = state->array_nl_len;
|
|
788
|
+
char *indent = state->indent;
|
|
789
|
+
long indent_len = state->indent_len;
|
|
790
|
+
long max_nesting = state->max_nesting;
|
|
791
|
+
char *delim = FBUFFER_PTR(state->array_delim);
|
|
792
|
+
long delim_len = FBUFFER_LEN(state->array_delim);
|
|
793
|
+
long depth = ++state->depth;
|
|
794
|
+
int i, j;
|
|
795
|
+
if (max_nesting != 0 && depth > max_nesting) {
|
|
796
|
+
fbuffer_free(buffer);
|
|
797
|
+
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
|
798
|
+
}
|
|
799
|
+
fbuffer_append_char(buffer, '[');
|
|
800
|
+
if (array_nl) fbuffer_append(buffer, array_nl, array_nl_len);
|
|
801
|
+
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
|
802
|
+
if (i > 0) fbuffer_append(buffer, delim, delim_len);
|
|
803
|
+
if (indent) {
|
|
804
|
+
for (j = 0; j < depth; j++) {
|
|
805
|
+
fbuffer_append(buffer, indent, indent_len);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
generate_json(buffer, Vstate, state, rb_ary_entry(obj, i));
|
|
809
|
+
}
|
|
810
|
+
state->depth = --depth;
|
|
811
|
+
if (array_nl) {
|
|
812
|
+
fbuffer_append(buffer, array_nl, array_nl_len);
|
|
813
|
+
if (indent) {
|
|
814
|
+
for (j = 0; j < depth; j++) {
|
|
815
|
+
fbuffer_append(buffer, indent, indent_len);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
fbuffer_append_char(buffer, ']');
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
823
|
+
{
|
|
824
|
+
fbuffer_append_char(buffer, '"');
|
|
825
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
826
|
+
obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
|
|
827
|
+
#endif
|
|
828
|
+
if (state->ascii_only) {
|
|
829
|
+
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
|
830
|
+
} else {
|
|
831
|
+
convert_UTF8_to_JSON(buffer, obj);
|
|
832
|
+
}
|
|
833
|
+
fbuffer_append_char(buffer, '"');
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
837
|
+
{
|
|
838
|
+
fbuffer_append(buffer, "null", 4);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
842
|
+
{
|
|
843
|
+
fbuffer_append(buffer, "false", 5);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
847
|
+
{
|
|
848
|
+
fbuffer_append(buffer, "true", 4);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
852
|
+
{
|
|
853
|
+
fbuffer_append_long(buffer, FIX2LONG(obj));
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
857
|
+
{
|
|
858
|
+
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
|
859
|
+
fbuffer_append(buffer, RSTRING_PAIR(tmp));
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
863
|
+
{
|
|
864
|
+
double value = RFLOAT_VALUE(obj);
|
|
865
|
+
char allow_nan = state->allow_nan;
|
|
866
|
+
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
|
867
|
+
if (!allow_nan) {
|
|
868
|
+
if (isinf(value)) {
|
|
869
|
+
fbuffer_free(buffer);
|
|
870
|
+
rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
|
|
871
|
+
} else if (isnan(value)) {
|
|
872
|
+
fbuffer_free(buffer);
|
|
873
|
+
rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
fbuffer_append(buffer, RSTRING_PAIR(tmp));
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
880
|
+
{
|
|
881
|
+
VALUE tmp;
|
|
882
|
+
VALUE klass = CLASS_OF(obj);
|
|
883
|
+
if (klass == rb_cHash) {
|
|
884
|
+
generate_json_object(buffer, Vstate, state, obj);
|
|
885
|
+
} else if (klass == rb_cArray) {
|
|
886
|
+
generate_json_array(buffer, Vstate, state, obj);
|
|
887
|
+
} else if (klass == rb_cString) {
|
|
888
|
+
generate_json_string(buffer, Vstate, state, obj);
|
|
889
|
+
} else if (obj == Qnil) {
|
|
890
|
+
generate_json_null(buffer, Vstate, state, obj);
|
|
891
|
+
} else if (obj == Qfalse) {
|
|
892
|
+
generate_json_false(buffer, Vstate, state, obj);
|
|
893
|
+
} else if (obj == Qtrue) {
|
|
894
|
+
generate_json_true(buffer, Vstate, state, obj);
|
|
895
|
+
} else if (klass == rb_cFixnum) {
|
|
896
|
+
generate_json_fixnum(buffer, Vstate, state, obj);
|
|
897
|
+
} else if (klass == rb_cBignum) {
|
|
898
|
+
generate_json_bignum(buffer, Vstate, state, obj);
|
|
899
|
+
} else if (klass == rb_cFloat) {
|
|
900
|
+
generate_json_float(buffer, Vstate, state, obj);
|
|
901
|
+
} else if (rb_respond_to(obj, i_to_json)) {
|
|
902
|
+
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
|
|
903
|
+
Check_Type(tmp, T_STRING);
|
|
904
|
+
fbuffer_append(buffer, RSTRING_PAIR(tmp));
|
|
905
|
+
} else {
|
|
906
|
+
tmp = rb_funcall(obj, i_to_s, 0);
|
|
907
|
+
Check_Type(tmp, T_STRING);
|
|
908
|
+
generate_json(buffer, Vstate, state, tmp);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
static FBuffer *cState_prepare_buffer(VALUE self)
|
|
913
|
+
{
|
|
914
|
+
FBuffer *buffer = fbuffer_alloc();
|
|
915
|
+
GET_STATE(self);
|
|
916
|
+
|
|
917
|
+
if (state->object_delim) {
|
|
918
|
+
fbuffer_clear(state->object_delim);
|
|
919
|
+
} else {
|
|
920
|
+
state->object_delim = fbuffer_alloc_with_length(16);
|
|
921
|
+
}
|
|
922
|
+
fbuffer_append_char(state->object_delim, ',');
|
|
923
|
+
if (state->object_delim2) {
|
|
924
|
+
fbuffer_clear(state->object_delim2);
|
|
925
|
+
} else {
|
|
926
|
+
state->object_delim2 = fbuffer_alloc_with_length(16);
|
|
927
|
+
}
|
|
928
|
+
fbuffer_append_char(state->object_delim2, ':');
|
|
929
|
+
if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
|
|
930
|
+
|
|
931
|
+
if (state->array_delim) {
|
|
932
|
+
fbuffer_clear(state->array_delim);
|
|
933
|
+
} else {
|
|
934
|
+
state->array_delim = fbuffer_alloc_with_length(16);
|
|
935
|
+
}
|
|
936
|
+
fbuffer_append_char(state->array_delim, ',');
|
|
937
|
+
if (state->array_nl) fbuffer_append(state->array_delim, state->array_nl, state->array_nl_len);
|
|
938
|
+
return buffer;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
static VALUE fbuffer_to_s(FBuffer *fb)
|
|
942
|
+
{
|
|
943
|
+
VALUE result = rb_str_new(FBUFFER_PAIR(fb));
|
|
944
|
+
fbuffer_free(fb);
|
|
945
|
+
FORCE_UTF8(result);
|
|
946
|
+
return result;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|
950
|
+
{
|
|
951
|
+
FBuffer *buffer = cState_prepare_buffer(self);
|
|
952
|
+
GET_STATE(self);
|
|
953
|
+
generate_json(buffer, self, state, obj);
|
|
954
|
+
return fbuffer_to_s(buffer);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/*
|
|
958
|
+
* call-seq: generate(obj)
|
|
959
|
+
*
|
|
960
|
+
* Generates a valid JSON document from object +obj+ and returns the
|
|
961
|
+
* result. If no valid JSON document can be created this method raises a
|
|
962
|
+
* GeneratorError exception.
|
|
963
|
+
*/
|
|
964
|
+
static VALUE cState_generate(VALUE self, VALUE obj)
|
|
965
|
+
{
|
|
966
|
+
VALUE result = cState_partial_generate(self, obj);
|
|
967
|
+
VALUE re, args[2];
|
|
968
|
+
args[0] = rb_str_new2("\\A\\s*(?:\\[.*\\]|\\{.*\\})\\s*\\Z");
|
|
969
|
+
args[1] = CRegexp_MULTILINE;
|
|
970
|
+
re = rb_class_new_instance(2, args, rb_cRegexp);
|
|
971
|
+
if (NIL_P(rb_funcall(re, i_match, 1, result))) {
|
|
972
|
+
rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
|
|
973
|
+
}
|
|
974
|
+
return result;
|
|
405
975
|
}
|
|
406
976
|
|
|
407
977
|
/*
|
|
@@ -416,69 +986,46 @@ static VALUE cState_s_allocate(VALUE klass)
|
|
|
416
986
|
* * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
|
417
987
|
* * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
|
418
988
|
* * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
|
419
|
-
* * *
|
|
420
|
-
*
|
|
989
|
+
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
990
|
+
* generated, otherwise an exception is thrown, if these values are
|
|
991
|
+
* encountered. This options defaults to false.
|
|
421
992
|
*/
|
|
422
993
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
423
994
|
{
|
|
424
995
|
VALUE opts;
|
|
425
996
|
GET_STATE(self);
|
|
426
|
-
|
|
997
|
+
state->max_nesting = 19;
|
|
427
998
|
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);
|
|
999
|
+
if (!NIL_P(opts)) cState_configure(self, opts);
|
|
479
1000
|
return self;
|
|
480
1001
|
}
|
|
481
1002
|
|
|
1003
|
+
/*
|
|
1004
|
+
* call-seq: initialize_copy(orig)
|
|
1005
|
+
*
|
|
1006
|
+
* Initializes this object from orig if it to be duplicated/cloned and returns
|
|
1007
|
+
* it.
|
|
1008
|
+
*/
|
|
1009
|
+
static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
1010
|
+
{
|
|
1011
|
+
JSON_Generator_State *objState, *origState;
|
|
1012
|
+
|
|
1013
|
+
Data_Get_Struct(obj, JSON_Generator_State, objState);
|
|
1014
|
+
Data_Get_Struct(orig, JSON_Generator_State, origState);
|
|
1015
|
+
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
|
1016
|
+
|
|
1017
|
+
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
|
1018
|
+
objState->indent = fstrndup(origState->indent, origState->indent_len);
|
|
1019
|
+
objState->space = fstrndup(origState->space, origState->space_len);
|
|
1020
|
+
objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
|
|
1021
|
+
objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
|
|
1022
|
+
objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
|
|
1023
|
+
if (origState->array_delim) objState->array_delim = fbuffer_dup(origState->array_delim);
|
|
1024
|
+
if (origState->object_delim) objState->object_delim = fbuffer_dup(origState->object_delim);
|
|
1025
|
+
if (origState->object_delim2) objState->object_delim2 = fbuffer_dup(origState->object_delim2);
|
|
1026
|
+
return obj;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
482
1029
|
/*
|
|
483
1030
|
* call-seq: from_state(opts)
|
|
484
1031
|
*
|
|
@@ -493,7 +1040,10 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
|
493
1040
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
|
494
1041
|
return rb_funcall(self, i_new, 1, opts);
|
|
495
1042
|
} else {
|
|
496
|
-
|
|
1043
|
+
if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
|
|
1044
|
+
CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
|
|
1045
|
+
}
|
|
1046
|
+
return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
|
|
497
1047
|
}
|
|
498
1048
|
}
|
|
499
1049
|
|
|
@@ -505,7 +1055,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
|
505
1055
|
static VALUE cState_indent(VALUE self)
|
|
506
1056
|
{
|
|
507
1057
|
GET_STATE(self);
|
|
508
|
-
return state->indent;
|
|
1058
|
+
return state->indent ? rb_str_new2(state->indent) : rb_str_new2("");
|
|
509
1059
|
}
|
|
510
1060
|
|
|
511
1061
|
/*
|
|
@@ -515,9 +1065,22 @@ static VALUE cState_indent(VALUE self)
|
|
|
515
1065
|
*/
|
|
516
1066
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
517
1067
|
{
|
|
1068
|
+
int len;
|
|
518
1069
|
GET_STATE(self);
|
|
519
1070
|
Check_Type(indent, T_STRING);
|
|
520
|
-
|
|
1071
|
+
len = RSTRING_LEN(indent);
|
|
1072
|
+
if (len == 0) {
|
|
1073
|
+
if (state->indent) {
|
|
1074
|
+
ruby_xfree(state->indent);
|
|
1075
|
+
state->indent = NULL;
|
|
1076
|
+
state->indent_len = 0;
|
|
1077
|
+
}
|
|
1078
|
+
} else {
|
|
1079
|
+
if (state->indent) ruby_xfree(state->indent);
|
|
1080
|
+
state->indent = strdup(RSTRING_PTR(indent));
|
|
1081
|
+
state->indent_len = len;
|
|
1082
|
+
}
|
|
1083
|
+
return Qnil;
|
|
521
1084
|
}
|
|
522
1085
|
|
|
523
1086
|
/*
|
|
@@ -529,7 +1092,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
|
529
1092
|
static VALUE cState_space(VALUE self)
|
|
530
1093
|
{
|
|
531
1094
|
GET_STATE(self);
|
|
532
|
-
return state->space;
|
|
1095
|
+
return state->space ? rb_str_new2(state->space) : rb_str_new2("");
|
|
533
1096
|
}
|
|
534
1097
|
|
|
535
1098
|
/*
|
|
@@ -540,9 +1103,22 @@ static VALUE cState_space(VALUE self)
|
|
|
540
1103
|
*/
|
|
541
1104
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
|
542
1105
|
{
|
|
1106
|
+
int len;
|
|
543
1107
|
GET_STATE(self);
|
|
544
1108
|
Check_Type(space, T_STRING);
|
|
545
|
-
|
|
1109
|
+
len = RSTRING_LEN(space);
|
|
1110
|
+
if (len == 0) {
|
|
1111
|
+
if (state->space) {
|
|
1112
|
+
ruby_xfree(state->space);
|
|
1113
|
+
state->space = NULL;
|
|
1114
|
+
state->space_len = 0;
|
|
1115
|
+
}
|
|
1116
|
+
} else {
|
|
1117
|
+
if (state->space) ruby_xfree(state->space);
|
|
1118
|
+
state->space = strdup(RSTRING_PTR(space));
|
|
1119
|
+
state->space_len = len;
|
|
1120
|
+
}
|
|
1121
|
+
return Qnil;
|
|
546
1122
|
}
|
|
547
1123
|
|
|
548
1124
|
/*
|
|
@@ -553,7 +1129,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
|
553
1129
|
static VALUE cState_space_before(VALUE self)
|
|
554
1130
|
{
|
|
555
1131
|
GET_STATE(self);
|
|
556
|
-
return state->space_before;
|
|
1132
|
+
return state->space_before ? rb_str_new2(state->space_before) : rb_str_new2("");
|
|
557
1133
|
}
|
|
558
1134
|
|
|
559
1135
|
/*
|
|
@@ -563,9 +1139,22 @@ static VALUE cState_space_before(VALUE self)
|
|
|
563
1139
|
*/
|
|
564
1140
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
565
1141
|
{
|
|
1142
|
+
int len;
|
|
566
1143
|
GET_STATE(self);
|
|
567
1144
|
Check_Type(space_before, T_STRING);
|
|
568
|
-
|
|
1145
|
+
len = RSTRING_LEN(space_before);
|
|
1146
|
+
if (len == 0) {
|
|
1147
|
+
if (state->space_before) {
|
|
1148
|
+
ruby_xfree(state->space_before);
|
|
1149
|
+
state->space_before = NULL;
|
|
1150
|
+
state->space_before_len = 0;
|
|
1151
|
+
}
|
|
1152
|
+
} else {
|
|
1153
|
+
if (state->space_before) ruby_xfree(state->space_before);
|
|
1154
|
+
state->space_before = strdup(RSTRING_PTR(space_before));
|
|
1155
|
+
state->space_before_len = len;
|
|
1156
|
+
}
|
|
1157
|
+
return Qnil;
|
|
569
1158
|
}
|
|
570
1159
|
|
|
571
1160
|
/*
|
|
@@ -577,7 +1166,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
|
577
1166
|
static VALUE cState_object_nl(VALUE self)
|
|
578
1167
|
{
|
|
579
1168
|
GET_STATE(self);
|
|
580
|
-
return state->object_nl;
|
|
1169
|
+
return state->object_nl ? rb_str_new2(state->object_nl) : rb_str_new2("");
|
|
581
1170
|
}
|
|
582
1171
|
|
|
583
1172
|
/*
|
|
@@ -588,9 +1177,21 @@ static VALUE cState_object_nl(VALUE self)
|
|
|
588
1177
|
*/
|
|
589
1178
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
590
1179
|
{
|
|
1180
|
+
int len;
|
|
591
1181
|
GET_STATE(self);
|
|
592
1182
|
Check_Type(object_nl, T_STRING);
|
|
593
|
-
|
|
1183
|
+
len = RSTRING_LEN(object_nl);
|
|
1184
|
+
if (len == 0) {
|
|
1185
|
+
if (state->object_nl) {
|
|
1186
|
+
ruby_xfree(state->object_nl);
|
|
1187
|
+
state->object_nl = NULL;
|
|
1188
|
+
}
|
|
1189
|
+
} else {
|
|
1190
|
+
if (state->object_nl) ruby_xfree(state->object_nl);
|
|
1191
|
+
state->object_nl = strdup(RSTRING_PTR(object_nl));
|
|
1192
|
+
state->object_nl_len = len;
|
|
1193
|
+
}
|
|
1194
|
+
return Qnil;
|
|
594
1195
|
}
|
|
595
1196
|
|
|
596
1197
|
/*
|
|
@@ -601,7 +1202,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
|
601
1202
|
static VALUE cState_array_nl(VALUE self)
|
|
602
1203
|
{
|
|
603
1204
|
GET_STATE(self);
|
|
604
|
-
return state->array_nl;
|
|
1205
|
+
return state->array_nl ? rb_str_new2(state->array_nl) : rb_str_new2("");
|
|
605
1206
|
}
|
|
606
1207
|
|
|
607
1208
|
/*
|
|
@@ -611,69 +1212,128 @@ static VALUE cState_array_nl(VALUE self)
|
|
|
611
1212
|
*/
|
|
612
1213
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
613
1214
|
{
|
|
1215
|
+
int len;
|
|
614
1216
|
GET_STATE(self);
|
|
615
1217
|
Check_Type(array_nl, T_STRING);
|
|
616
|
-
|
|
1218
|
+
len = RSTRING_LEN(array_nl);
|
|
1219
|
+
if (len == 0) {
|
|
1220
|
+
if (state->array_nl) {
|
|
1221
|
+
ruby_xfree(state->array_nl);
|
|
1222
|
+
state->array_nl = NULL;
|
|
1223
|
+
}
|
|
1224
|
+
} else {
|
|
1225
|
+
if (state->array_nl) ruby_xfree(state->array_nl);
|
|
1226
|
+
state->array_nl = strdup(RSTRING_PTR(array_nl));
|
|
1227
|
+
state->array_nl_len = len;
|
|
1228
|
+
}
|
|
1229
|
+
return Qnil;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
/*
|
|
1234
|
+
* call-seq: check_circular?
|
|
1235
|
+
*
|
|
1236
|
+
* Returns true, if circular data structures should be checked,
|
|
1237
|
+
* otherwise returns false.
|
|
1238
|
+
*/
|
|
1239
|
+
static VALUE cState_check_circular_p(VALUE self)
|
|
1240
|
+
{
|
|
1241
|
+
GET_STATE(self);
|
|
1242
|
+
return state->max_nesting ? Qtrue : Qfalse;
|
|
617
1243
|
}
|
|
618
1244
|
|
|
619
1245
|
/*
|
|
620
|
-
* call-seq:
|
|
1246
|
+
* call-seq: max_nesting
|
|
621
1247
|
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
1248
|
+
* This integer returns the maximum level of data structure nesting in
|
|
1249
|
+
* the generated JSON, max_nesting = 0 if no maximum is checked.
|
|
624
1250
|
*/
|
|
625
|
-
static VALUE
|
|
1251
|
+
static VALUE cState_max_nesting(VALUE self)
|
|
1252
|
+
{
|
|
1253
|
+
GET_STATE(self);
|
|
1254
|
+
return LONG2FIX(state->max_nesting);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
/*
|
|
1258
|
+
* call-seq: max_nesting=(depth)
|
|
1259
|
+
*
|
|
1260
|
+
* This sets the maximum level of data structure nesting in the generated JSON
|
|
1261
|
+
* to the integer depth, max_nesting = 0 if no maximum should be checked.
|
|
1262
|
+
*/
|
|
1263
|
+
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
1264
|
+
{
|
|
1265
|
+
GET_STATE(self);
|
|
1266
|
+
Check_Type(depth, T_FIXNUM);
|
|
1267
|
+
return state->max_nesting = FIX2LONG(depth);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/*
|
|
1271
|
+
* call-seq: allow_nan?
|
|
1272
|
+
*
|
|
1273
|
+
* Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
|
|
1274
|
+
* returns false.
|
|
1275
|
+
*/
|
|
1276
|
+
static VALUE cState_allow_nan_p(VALUE self)
|
|
626
1277
|
{
|
|
627
1278
|
GET_STATE(self);
|
|
628
|
-
return state->
|
|
1279
|
+
return state->allow_nan ? Qtrue : Qfalse;
|
|
629
1280
|
}
|
|
630
1281
|
|
|
631
1282
|
/*
|
|
632
|
-
* call-seq:
|
|
1283
|
+
* call-seq: ascii_only?
|
|
633
1284
|
*
|
|
634
|
-
* Returns
|
|
1285
|
+
* Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
|
|
1286
|
+
* returns false.
|
|
635
1287
|
*/
|
|
636
|
-
static VALUE
|
|
1288
|
+
static VALUE cState_ascii_only_p(VALUE self)
|
|
637
1289
|
{
|
|
638
1290
|
GET_STATE(self);
|
|
639
|
-
return
|
|
1291
|
+
return state->ascii_only ? Qtrue : Qfalse;
|
|
640
1292
|
}
|
|
641
1293
|
|
|
642
1294
|
/*
|
|
643
|
-
* call-seq:
|
|
1295
|
+
* call-seq: depth
|
|
644
1296
|
*
|
|
645
|
-
*
|
|
646
|
-
* data structure is rendered).
|
|
1297
|
+
* This integer returns the current depth of data structure nesting.
|
|
647
1298
|
*/
|
|
648
|
-
static VALUE
|
|
1299
|
+
static VALUE cState_depth(VALUE self)
|
|
649
1300
|
{
|
|
650
1301
|
GET_STATE(self);
|
|
651
|
-
return
|
|
1302
|
+
return LONG2FIX(state->depth);
|
|
652
1303
|
}
|
|
653
1304
|
|
|
654
1305
|
/*
|
|
655
|
-
* call-seq:
|
|
1306
|
+
* call-seq: depth=(depth)
|
|
656
1307
|
*
|
|
657
|
-
*
|
|
1308
|
+
* This sets the maximum level of data structure nesting in the generated JSON
|
|
1309
|
+
* to the integer depth, max_nesting = 0 if no maximum should be checked.
|
|
658
1310
|
*/
|
|
659
|
-
static VALUE
|
|
1311
|
+
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
660
1312
|
{
|
|
661
1313
|
GET_STATE(self);
|
|
662
|
-
|
|
1314
|
+
Check_Type(depth, T_FIXNUM);
|
|
1315
|
+
return state->depth = FIX2LONG(depth);
|
|
663
1316
|
}
|
|
664
1317
|
|
|
1318
|
+
/*
|
|
1319
|
+
*
|
|
1320
|
+
*/
|
|
665
1321
|
void Init_generator()
|
|
666
1322
|
{
|
|
1323
|
+
rb_require("json/common");
|
|
1324
|
+
|
|
667
1325
|
mJSON = rb_define_module("JSON");
|
|
668
1326
|
mExt = rb_define_module_under(mJSON, "Ext");
|
|
669
1327
|
mGenerator = rb_define_module_under(mExt, "Generator");
|
|
1328
|
+
|
|
670
1329
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
|
671
|
-
|
|
1330
|
+
eNestingError = rb_path2class("JSON::NestingError");
|
|
1331
|
+
|
|
672
1332
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
|
673
1333
|
rb_define_alloc_func(cState, cState_s_allocate);
|
|
674
1334
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
|
675
1335
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
|
676
|
-
|
|
1336
|
+
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
|
677
1337
|
rb_define_method(cState, "indent", cState_indent, 0);
|
|
678
1338
|
rb_define_method(cState, "indent=", cState_indent_set, 1);
|
|
679
1339
|
rb_define_method(cState, "space", cState_space, 0);
|
|
@@ -684,10 +1344,18 @@ void Init_generator()
|
|
|
684
1344
|
rb_define_method(cState, "object_nl=", cState_object_nl_set, 1);
|
|
685
1345
|
rb_define_method(cState, "array_nl", cState_array_nl, 0);
|
|
686
1346
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
|
1347
|
+
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
|
1348
|
+
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
|
|
687
1349
|
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, "
|
|
1350
|
+
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
|
1351
|
+
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
|
|
1352
|
+
rb_define_method(cState, "depth", cState_depth, 0);
|
|
1353
|
+
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
|
1354
|
+
rb_define_method(cState, "configure", cState_configure, 1);
|
|
1355
|
+
rb_define_method(cState, "to_h", cState_to_h, 0);
|
|
1356
|
+
rb_define_method(cState, "[]", cState_aref, 1);
|
|
1357
|
+
rb_define_method(cState, "generate", cState_generate, 1);
|
|
1358
|
+
|
|
691
1359
|
mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
|
692
1360
|
mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
|
693
1361
|
rb_define_method(mObject, "to_json", mObject_to_json, -1);
|
|
@@ -695,8 +1363,10 @@ void Init_generator()
|
|
|
695
1363
|
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
|
696
1364
|
mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
|
697
1365
|
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
|
698
|
-
|
|
699
|
-
rb_define_method(
|
|
1366
|
+
mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
|
1367
|
+
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
|
1368
|
+
mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
|
1369
|
+
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
|
700
1370
|
mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
|
701
1371
|
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
|
702
1372
|
mString = rb_define_module_under(mGeneratorMethods, "String");
|
|
@@ -713,6 +1383,7 @@ void Init_generator()
|
|
|
713
1383
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
714
1384
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
715
1385
|
|
|
1386
|
+
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
|
716
1387
|
i_to_s = rb_intern("to_s");
|
|
717
1388
|
i_to_json = rb_intern("to_json");
|
|
718
1389
|
i_new = rb_intern("new");
|
|
@@ -721,9 +1392,26 @@ void Init_generator()
|
|
|
721
1392
|
i_space_before = rb_intern("space_before");
|
|
722
1393
|
i_object_nl = rb_intern("object_nl");
|
|
723
1394
|
i_array_nl = rb_intern("array_nl");
|
|
724
|
-
|
|
1395
|
+
i_max_nesting = rb_intern("max_nesting");
|
|
1396
|
+
i_allow_nan = rb_intern("allow_nan");
|
|
1397
|
+
i_ascii_only = rb_intern("ascii_only");
|
|
1398
|
+
i_depth = rb_intern("depth");
|
|
725
1399
|
i_pack = rb_intern("pack");
|
|
726
1400
|
i_unpack = rb_intern("unpack");
|
|
727
1401
|
i_create_id = rb_intern("create_id");
|
|
728
1402
|
i_extend = rb_intern("extend");
|
|
1403
|
+
i_key_p = rb_intern("key?");
|
|
1404
|
+
i_aref = rb_intern("[]");
|
|
1405
|
+
i_send = rb_intern("__send__");
|
|
1406
|
+
i_respond_to_p = rb_intern("respond_to?");
|
|
1407
|
+
i_match = rb_intern("match");
|
|
1408
|
+
i_keys = rb_intern("keys");
|
|
1409
|
+
i_dup = rb_intern("dup");
|
|
1410
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
|
1411
|
+
CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
|
|
1412
|
+
i_encoding = rb_intern("encoding");
|
|
1413
|
+
i_encode = rb_intern("encode");
|
|
1414
|
+
#endif
|
|
1415
|
+
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
|
|
1416
|
+
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
|
|
729
1417
|
}
|