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.
Files changed (93) hide show
  1. data/CHANGES +155 -1
  2. data/COPYING +58 -0
  3. data/GPL +7 -7
  4. data/README +324 -45
  5. data/Rakefile +166 -124
  6. data/TODO +1 -1
  7. data/VERSION +1 -1
  8. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  9. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  10. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  11. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  12. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  13. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  14. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  15. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  16. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  17. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  18. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  19. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  20. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  21. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  22. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  23. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  24. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  25. data/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  26. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  27. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  28. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  29. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  30. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  31. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  32. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  33. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  34. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  35. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  36. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  37. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  38. data/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  39. data/benchmarks/generator2_benchmark.rb +222 -0
  40. data/benchmarks/generator_benchmark.rb +224 -0
  41. data/benchmarks/ohai.json +1216 -0
  42. data/benchmarks/ohai.ruby +1 -0
  43. data/benchmarks/parser2_benchmark.rb +251 -0
  44. data/benchmarks/parser_benchmark.rb +259 -0
  45. data/bin/edit_json.rb +1 -3
  46. data/bin/prettify_json.rb +75 -0
  47. data/data/index.html +5 -4
  48. data/data/prototype.js +2764 -1095
  49. data/ext/json/ext/generator/extconf.rb +14 -3
  50. data/ext/json/ext/generator/generator.c +1022 -334
  51. data/ext/json/ext/generator/generator.h +197 -0
  52. data/ext/json/ext/parser/extconf.rb +9 -3
  53. data/ext/json/ext/parser/parser.c +961 -577
  54. data/ext/json/ext/parser/parser.h +71 -0
  55. data/ext/json/ext/parser/parser.rl +400 -123
  56. data/install.rb +0 -0
  57. data/lib/json/add/core.rb +148 -0
  58. data/lib/json/add/rails.rb +58 -0
  59. data/lib/json/common.rb +254 -47
  60. data/lib/json/editor.rb +236 -72
  61. data/lib/json/ext.rb +2 -0
  62. data/lib/json/pure/generator.rb +235 -117
  63. data/lib/json/pure/parser.rb +124 -25
  64. data/lib/json/pure.rb +5 -3
  65. data/lib/json/version.rb +1 -1
  66. data/lib/json.rb +2 -197
  67. data/tests/fixtures/fail18.json +1 -0
  68. data/tests/test_json.rb +181 -22
  69. data/tests/test_json_addition.rb +84 -16
  70. data/tests/test_json_encoding.rb +68 -0
  71. data/tests/test_json_fixtures.rb +9 -5
  72. data/tests/test_json_generate.rb +114 -14
  73. data/tests/test_json_rails.rb +144 -0
  74. data/tests/test_json_unicode.rb +35 -14
  75. data/tools/fuzz.rb +13 -7
  76. data/tools/server.rb +0 -1
  77. metadata +156 -122
  78. data/benchmarks/benchmark.txt +0 -133
  79. data/benchmarks/benchmark_generator.rb +0 -44
  80. data/benchmarks/benchmark_parser.rb +0 -22
  81. data/benchmarks/benchmark_rails.rb +0 -26
  82. data/ext/json/ext/generator/Makefile +0 -149
  83. data/ext/json/ext/generator/unicode.c +0 -184
  84. data/ext/json/ext/generator/unicode.h +0 -40
  85. data/ext/json/ext/parser/Makefile +0 -149
  86. data/ext/json/ext/parser/unicode.c +0 -156
  87. data/ext/json/ext/parser/unicode.h +0 -44
  88. data/tests/fixtures/pass18.json +0 -1
  89. data/tests/runner.rb +0 -24
  90. /data/tests/fixtures/{fail15.json → pass15.json} +0 -0
  91. /data/tests/fixtures/{fail16.json → pass16.json} +0 -0
  92. /data/tests/fixtures/{fail17.json → pass17.json} +0 -0
  93. /data/tests/fixtures/{fail26.json → pass26.json} +0 -0
@@ -1,246 +1,444 @@
1
- /* vim: set cin et sw=4 ts=4: */
1
+ #include "generator.h"
2
2
 
3
- #include <string.h>
4
- #include "ruby.h"
5
- #include "st.h"
6
- #include "unicode.h"
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, mInteger, mFloat, mString, mString_Extend,
9
+ mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,
10
10
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
11
- eCircularDatastructure;
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, i_check_circular, i_pack, i_unpack,
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
- * Document-module: JSON::Ext::Generator
37
- *
38
- * This is the JSON generator implemented as a C extension. It can be
39
- * configured to be used by setting
40
- *
41
- * JSON.generator = JSON::Ext::Generator
42
- *
43
- * with the method generator= in JSON.
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
- static int hash_to_json_state_i(VALUE key, VALUE value, VALUE Vstate)
48
- {
49
- VALUE json, buf, Vdepth;
50
- GET_STATE(Vstate);
51
- buf = state->memo;
52
- Vdepth = state->depth;
53
-
54
- if (key == Qundef) return ST_CONTINUE;
55
- if (state->flag) {
56
- state->flag = 0;
57
- rb_str_buf_cat2(buf, ",");
58
- if (FUL(state->object_nl)) rb_str_buf_append(buf, state->object_nl);
59
- }
60
- if (FUL(state->object_nl)) {
61
- rb_str_buf_append(buf, rb_str_times(state->indent, Vdepth));
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
- }
79
-
80
- inline static VALUE mHash_json_transfrom(VALUE self, VALUE Vstate, VALUE Vdepth) {
81
- long depth, len = RHASH(self)->tbl->num_entries;
82
- VALUE result;
83
- GET_STATE(Vstate);
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;
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
- static int hash_to_json_i(VALUE key, VALUE value, VALUE buf)
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
- VALUE tmp;
106
+ const char *digits = "0123456789abcdef";
104
107
 
105
- if (key == Qundef) return ST_CONTINUE;
106
- if (RSTRING(buf)->len > 1) rb_str_buf_cat2(buf, ",");
107
- tmp = rb_funcall(rb_funcall(key, i_to_s, 0), i_to_json, 0);
108
- rb_str_buf_append(buf, tmp);
109
- OBJ_INFECT(buf, tmp);
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
- return ST_CONTINUE;
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
- * call-seq: to_json(state = nil, depth = 0)
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
- VALUE Vstate, Vdepth, result;
130
- long depth;
131
-
132
- rb_scan_args(argc, argv, "02", &Vstate, &Vdepth);
133
- depth = NIL_P(Vdepth) ? 0 : FIX2LONG(Vdepth);
134
- if (NIL_P(Vstate)) {
135
- long len = RHASH(self)->tbl->num_entries;
136
- result = rb_str_buf_new(len);
137
- rb_str_buf_cat2(result, "{");
138
- rb_hash_foreach(self, hash_to_json_i, result);
139
- rb_str_buf_cat2(result, "}");
140
- } else {
141
- GET_STATE(Vstate);
142
- if (state->check_circular) {
143
- VALUE self_id = rb_obj_id(self);
144
- if (RTEST(rb_hash_aref(state->seen, self_id))) {
145
- rb_raise(eCircularDatastructure,
146
- "circular data structures not supported!");
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
- rb_hash_aset(state->seen, self_id, Qtrue);
149
- result = mHash_json_transfrom(self, Vstate, LONG2FIX(depth));
150
- rb_hash_delete(state->seen, self_id);
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
- result = mHash_json_transfrom(self, Vstate, LONG2FIX(depth));
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
- inline static VALUE mArray_json_transfrom(VALUE self, VALUE Vstate, VALUE Vdepth) {
160
- long i, len = RARRAY(self)->len;
161
- VALUE shift, result;
162
- long depth = NIL_P(Vdepth) ? 0 : FIX2LONG(Vdepth);
163
- VALUE delim = rb_str_new2(",");
164
- GET_STATE(Vstate);
165
-
166
- if (state->check_circular) {
167
- VALUE self_id = rb_obj_id(self);
168
- rb_hash_aset(state->seen, self_id, Qtrue);
169
- result = rb_str_buf_new(len);
170
- if (FUL(state->array_nl)) rb_str_append(delim, state->array_nl);
171
- shift = rb_str_times(state->indent, LONG2FIX(depth + 1));
172
-
173
- rb_str_buf_cat2(result, "[");
174
- rb_str_buf_append(result, state->array_nl);
175
- for (i = 0; i < len; i++) {
176
- VALUE element = RARRAY(self)->ptr[i];
177
- if (RTEST(rb_hash_aref(state->seen, rb_obj_id(element)))) {
178
- rb_raise(eCircularDatastructure,
179
- "circular data structures not supported!");
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
- rb_str_buf_cat2(result, "]");
191
- rb_hash_delete(state->seen, self_id);
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 = 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
- }
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, depth = 0)
433
+ * call-seq: to_json(state = nil)
217
434
  *
218
- * Returns a JSON string containing a JSON array, that is unparsed from
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
- VALUE Vstate, Vdepth, result;
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 mInteger_to_json(int argc, VALUE *argv, VALUE self)
449
+ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
252
450
  {
253
- return rb_funcall(self, i_to_s, 0);
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
- return rb_funcall(self, i_to_s, 0);
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
- return rb_funcall(modul, i_extend, 1, mString_Extend);
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
- VALUE result = rb_str_buf_new(RSTRING(self)->len);
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 unparsed as a raw string. This
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(state = nil, depth = 0)
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
- return rb_str_new2("true");
548
+ GENERATE_JSON(true);
341
549
  }
342
550
 
343
551
  /*
344
- * call-seq: to_json(state = nil, depth = 0)
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
- return rb_str_new2("false");
558
+ GENERATE_JSON(false);
351
559
  }
352
560
 
353
561
  /*
354
- * call-seq: to_json(state = nil, depth = 0)
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
- return rb_str_new2("null");
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
- return mString_to_json(argc, argv, string);
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
- rb_gc_mark_maybe(state->indent);
386
- rb_gc_mark_maybe(state->space);
387
- rb_gc_mark_maybe(state->space_before);
388
- rb_gc_mark_maybe(state->object_nl);
389
- rb_gc_mark_maybe(state->array_nl);
390
- rb_gc_mark_maybe(state->seen);
391
- rb_gc_mark_maybe(state->memo);
392
- rb_gc_mark_maybe(state->depth);
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, State_mark, -1, state);
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
- * * *check_circular*: true if checking for circular data structures
420
- * should be done, false (the default) otherwise.
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
- return rb_funcall(self, i_new, 0);
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
- return state->indent = indent;
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
- return state->space = space;
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
- return state->space_before = space_before;
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
- return state->object_nl = object_nl;
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
- return state->array_nl = array_nl;
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: check_circular?(object)
1246
+ * call-seq: max_nesting
621
1247
  *
622
- * Returns true, if circular data structures should be checked,
623
- * otherwise returns false.
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 cState_check_circular_p(VALUE self)
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->check_circular ? Qtrue : Qfalse;
1279
+ return state->allow_nan ? Qtrue : Qfalse;
629
1280
  }
630
1281
 
631
1282
  /*
632
- * call-seq: seen?(object)
1283
+ * call-seq: ascii_only?
633
1284
  *
634
- * Returns _true_, if _object_ was already seen during this generating run.
1285
+ * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1286
+ * returns false.
635
1287
  */
636
- static VALUE cState_seen_p(VALUE self, VALUE object)
1288
+ static VALUE cState_ascii_only_p(VALUE self)
637
1289
  {
638
1290
  GET_STATE(self);
639
- return rb_hash_aref(state->seen, rb_obj_id(object));
1291
+ return state->ascii_only ? Qtrue : Qfalse;
640
1292
  }
641
1293
 
642
1294
  /*
643
- * call-seq: remember(object)
1295
+ * call-seq: depth
644
1296
  *
645
- * Remember _object_, to find out if it was already encountered (if a cyclic
646
- * data structure is rendered).
1297
+ * This integer returns the current depth of data structure nesting.
647
1298
  */
648
- static VALUE cState_remember(VALUE self, VALUE object)
1299
+ static VALUE cState_depth(VALUE self)
649
1300
  {
650
1301
  GET_STATE(self);
651
- return rb_hash_aset(state->seen, rb_obj_id(object), Qtrue);
1302
+ return LONG2FIX(state->depth);
652
1303
  }
653
1304
 
654
1305
  /*
655
- * call-seq: forget(object)
1306
+ * call-seq: depth=(depth)
656
1307
  *
657
- * Forget _object_ for this generating run.
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 cState_forget(VALUE self, VALUE object)
1311
+ static VALUE cState_depth_set(VALUE self, VALUE depth)
660
1312
  {
661
1313
  GET_STATE(self);
662
- return rb_hash_delete(state->seen, rb_obj_id(object));
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
- eCircularDatastructure = rb_path2class("JSON::CircularDatastructure");
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, "seen?", cState_seen_p, 1);
689
- rb_define_method(cState, "remember", cState_remember, 1);
690
- rb_define_method(cState, "forget", cState_forget, 1);
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
- mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
699
- rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
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
- i_check_circular = rb_intern("check_circular");
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
  }