json 1.0.0 → 2.7.2

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