json 1.0.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }