json 1.7.0 → 2.3.0

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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis.yml +18 -10
  4. data/{CHANGES → CHANGES.md} +217 -69
  5. data/Gemfile +11 -12
  6. data/{COPYING-json-jruby → LICENSE} +5 -6
  7. data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
  8. data/{README.rdoc → README.md} +188 -137
  9. data/Rakefile +52 -37
  10. data/VERSION +1 -1
  11. data/ext/json/ext/fbuffer/fbuffer.h +38 -7
  12. data/ext/json/ext/generator/depend +1 -0
  13. data/ext/json/ext/generator/extconf.rb +1 -10
  14. data/ext/json/ext/generator/generator.c +239 -133
  15. data/ext/json/ext/generator/generator.h +35 -26
  16. data/ext/json/ext/parser/depend +1 -0
  17. data/ext/json/ext/parser/extconf.rb +2 -9
  18. data/ext/json/ext/parser/parser.c +446 -514
  19. data/ext/json/ext/parser/parser.h +23 -9
  20. data/ext/json/ext/parser/parser.rl +177 -208
  21. data/ext/json/extconf.rb +2 -0
  22. data/java/src/json/ext/ByteListTranscoder.java +1 -2
  23. data/java/src/json/ext/Generator.java +49 -20
  24. data/java/src/json/ext/GeneratorMethods.java +1 -2
  25. data/java/src/json/ext/GeneratorService.java +1 -2
  26. data/java/src/json/ext/GeneratorState.java +25 -57
  27. data/java/src/json/ext/OptionsReader.java +5 -5
  28. data/java/src/json/ext/Parser.java +141 -419
  29. data/java/src/json/ext/Parser.rl +57 -128
  30. data/java/src/json/ext/ParserService.java +1 -2
  31. data/java/src/json/ext/RuntimeInfo.java +1 -6
  32. data/java/src/json/ext/StringDecoder.java +1 -2
  33. data/java/src/json/ext/StringEncoder.java +5 -0
  34. data/java/src/json/ext/Utils.java +1 -2
  35. data/json-java.gemspec +17 -2
  36. data/json.gemspec +0 -0
  37. data/json_pure.gemspec +25 -26
  38. data/lib/json.rb +3 -2
  39. data/lib/json/add/bigdecimal.rb +10 -2
  40. data/lib/json/add/complex.rb +9 -2
  41. data/lib/json/add/core.rb +1 -0
  42. data/lib/json/add/date.rb +1 -1
  43. data/lib/json/add/date_time.rb +1 -1
  44. data/lib/json/add/exception.rb +1 -1
  45. data/lib/json/add/ostruct.rb +3 -3
  46. data/lib/json/add/range.rb +1 -1
  47. data/lib/json/add/rational.rb +8 -2
  48. data/lib/json/add/regexp.rb +3 -3
  49. data/lib/json/add/set.rb +29 -0
  50. data/lib/json/add/struct.rb +1 -1
  51. data/lib/json/add/symbol.rb +1 -1
  52. data/lib/json/add/time.rb +6 -3
  53. data/lib/json/common.rb +51 -66
  54. data/lib/json/ext.rb +0 -6
  55. data/lib/json/generic_object.rb +36 -4
  56. data/lib/json/pure.rb +2 -8
  57. data/lib/json/pure/generator.rb +106 -119
  58. data/lib/json/pure/parser.rb +48 -88
  59. data/lib/json/version.rb +2 -1
  60. data/references/rfc7159.txt +899 -0
  61. data/tests/fixtures/fail18.json +1 -1
  62. data/tests/fixtures/obsolete_fail1.json +1 -0
  63. data/tests/{test_json_addition.rb → json_addition_test.rb} +53 -38
  64. data/tests/json_common_interface_test.rb +126 -0
  65. data/tests/json_encoding_test.rb +107 -0
  66. data/tests/json_ext_parser_test.rb +15 -0
  67. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
  68. data/tests/json_generator_test.rb +421 -0
  69. data/tests/json_generic_object_test.rb +82 -0
  70. data/tests/json_parser_test.rb +472 -0
  71. data/tests/json_string_matching_test.rb +38 -0
  72. data/tests/{setup_variant.rb → test_helper.rb} +6 -0
  73. data/tools/diff.sh +18 -0
  74. data/tools/fuzz.rb +1 -9
  75. metadata +49 -72
  76. data/COPYING +0 -58
  77. data/GPL +0 -340
  78. data/TODO +0 -1
  79. data/data/example.json +0 -1
  80. data/data/index.html +0 -38
  81. data/data/prototype.js +0 -4184
  82. data/tests/fixtures/fail1.json +0 -1
  83. data/tests/test_json.rb +0 -539
  84. data/tests/test_json_encoding.rb +0 -65
  85. data/tests/test_json_generate.rb +0 -251
  86. data/tests/test_json_generic_object.rb +0 -35
  87. data/tests/test_json_string_matching.rb +0 -40
  88. data/tests/test_json_unicode.rb +0 -72
data/Rakefile CHANGED
@@ -23,8 +23,13 @@ class UndocumentedTestTask < Rake::TestTask
23
23
  def desc(*) end
24
24
  end
25
25
 
26
- MAKE = ENV['MAKE'] || %w[gmake make].find { |c| system(c, '-v') }
27
- BUNDLE = ENV['BUNDLE'] || %w[bundle].find { |c| system(c, '-v') }
26
+ which = lambda { |c|
27
+ w = `which #{c}`
28
+ break w.chomp unless w.empty?
29
+ }
30
+
31
+ MAKE = ENV['MAKE'] || %w[gmake make].find(&which)
32
+ BUNDLE = ENV['BUNDLE'] || %w[bundle].find(&which)
28
33
  PKG_NAME = 'json'
29
34
  PKG_TITLE = 'JSON Implementation for Ruby'
30
35
  PKG_VERSION = File.read('VERSION').chomp
@@ -47,8 +52,8 @@ JAVA_CLASSES = []
47
52
  JRUBY_PARSER_JAR = File.expand_path("lib/json/ext/parser.jar")
48
53
  JRUBY_GENERATOR_JAR = File.expand_path("lib/json/ext/generator.jar")
49
54
 
50
- RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find { |c| system(c, '-v') }
51
- RAGEL_DOTGEN = %w[rlgen-dot rlgen-cd ragel].find { |c| system(c, '-v') }
55
+ RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find(&which)
56
+ RAGEL_DOTGEN = %w[rlgen-dot rlgen-cd ragel].find(&which)
52
57
 
53
58
  desc "Installing library (pure)"
54
59
  task :install_pure => :version do
@@ -83,19 +88,19 @@ if defined?(Gem) and defined?(Gem::PackageTask)
83
88
  s.files = PKG_FILES
84
89
 
85
90
  s.require_path = 'lib'
86
- s.add_development_dependency 'permutation'
87
- s.add_development_dependency 'sdoc'
88
- s.add_development_dependency 'rake', '~>0.9.2'
91
+ s.add_development_dependency 'rake'
92
+ s.add_development_dependency 'test-unit', '~> 2.0'
89
93
 
90
- s.extra_rdoc_files << 'README.rdoc'
94
+ s.extra_rdoc_files << 'README.md'
91
95
  s.rdoc_options <<
92
- '--title' << 'JSON implemention for ruby' << '--main' << 'README.rdoc'
96
+ '--title' << 'JSON implemention for ruby' << '--main' << 'README.md'
93
97
  s.test_files.concat Dir['./tests/test_*.rb']
94
98
 
95
99
  s.author = "Florian Frank"
96
100
  s.email = "flori@ping.de"
97
101
  s.homepage = "http://flori.github.com/#{PKG_NAME}"
98
- s.rubyforge_project = "json"
102
+ s.license = 'Ruby'
103
+ s.required_ruby_version = '>= 1.9'
99
104
  end
100
105
 
101
106
  desc 'Creates a json_pure.gemspec file'
@@ -120,21 +125,20 @@ if defined?(Gem) and defined?(Gem::PackageTask)
120
125
 
121
126
  s.extensions = FileList['ext/**/extconf.rb']
122
127
 
123
- s.require_path = EXT_ROOT_DIR
124
- s.require_paths << 'ext'
125
- s.require_paths << 'lib'
126
- s.add_development_dependency 'permutation'
127
- s.add_development_dependency 'sdoc'
128
+ s.require_path = 'lib'
129
+ s.add_development_dependency 'rake'
130
+ s.add_development_dependency 'test-unit', '~> 2.0'
128
131
 
129
- s.extra_rdoc_files << 'README.rdoc'
132
+ s.extra_rdoc_files << 'README.md'
130
133
  s.rdoc_options <<
131
- '--title' << 'JSON implemention for Ruby' << '--main' << 'README.rdoc'
134
+ '--title' << 'JSON implemention for Ruby' << '--main' << 'README.md'
132
135
  s.test_files.concat Dir['./tests/test_*.rb']
133
136
 
134
137
  s.author = "Florian Frank"
135
138
  s.email = "flori@ping.de"
136
139
  s.homepage = "http://flori.github.com/#{PKG_NAME}"
137
- s.rubyforge_project = "json"
140
+ s.license = 'Ruby'
141
+ s.required_ruby_version = '>= 1.9'
138
142
  end
139
143
 
140
144
  desc 'Creates a json.gemspec file'
@@ -159,6 +163,7 @@ task :version do
159
163
  puts m
160
164
  File.open(File.join('lib', 'json', 'version.rb'), 'w') do |v|
161
165
  v.puts <<EOT
166
+ # frozen_string_literal: false
162
167
  module JSON
163
168
  # JSON version
164
169
  VERSION = '#{PKG_VERSION}'
@@ -171,13 +176,17 @@ EOT
171
176
  end
172
177
  end
173
178
 
179
+ task :check_env do
180
+ ENV.key?('JSON') or fail "JSON env var is required"
181
+ end
182
+
174
183
  desc "Testing library (pure ruby)"
175
- task :test_pure => [ :clean, :do_test_pure ]
184
+ task :test_pure => [ :clean, :check_env, :do_test_pure ]
176
185
 
177
186
  UndocumentedTestTask.new do |t|
178
187
  t.name = 'do_test_pure'
179
- t.libs << 'lib'
180
- t.test_files = FileList['tests/test_*.rb']
188
+ t.libs << 'lib' << 'tests'
189
+ t.test_files = FileList['tests/*_test.rb']
181
190
  t.verbose = true
182
191
  t.options = '-v'
183
192
  end
@@ -196,13 +205,18 @@ namespace :gems do
196
205
  end
197
206
 
198
207
  if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
199
- if ENV.key?('JAVA_HOME')
200
- warn " *** JAVA_HOME was set to #{ENV['JAVA_HOME'].inspect}"
201
- else File.directory?(local_java = '/usr/local/java/jdk')
202
- ENV['JAVA_HOME'] = local_java
208
+ ENV['JAVA_HOME'] ||= [
209
+ '/usr/local/java/jdk',
210
+ '/usr/lib/jvm/java-6-openjdk',
211
+ '/Library/Java/Home',
212
+ ].find { |c| File.directory?(c) }
213
+ if ENV['JAVA_HOME']
203
214
  warn " *** JAVA_HOME is set to #{ENV['JAVA_HOME'].inspect}"
204
215
  ENV['PATH'] = ENV['PATH'].split(/:/).unshift(java_path = "#{ENV['JAVA_HOME']}/bin") * ':'
205
216
  warn " *** java binaries are assumed to be in #{java_path.inspect}"
217
+ else
218
+ warn " *** JAVA_HOME was not set or could not be guessed!"
219
+ exit 1
206
220
  end
207
221
 
208
222
  file JAVA_PARSER_SRC => JAVA_RAGEL_PATH do
@@ -229,7 +243,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
229
243
  classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
230
244
  obj = src.sub(/\.java\Z/, '.class')
231
245
  file obj => src do
232
- sh 'javac', '-classpath', classpath, '-source', '1.5', '-target', '1.5', src
246
+ sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
233
247
  end
234
248
  JAVA_CLASSES << obj
235
249
  end
@@ -248,12 +262,12 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
248
262
  end
249
263
 
250
264
  desc "Testing library (jruby)"
251
- task :test_ext => [ :create_jar, :do_test_ext ]
265
+ task :test_ext => [ :check_env, :create_jar, :do_test_ext ]
252
266
 
253
267
  UndocumentedTestTask.new do |t|
254
268
  t.name = 'do_test_ext'
255
- t.libs << 'lib'
256
- t.test_files = FileList['tests/test_*.rb']
269
+ t.libs << 'lib' << 'tests'
270
+ t.test_files = FileList['tests/*_test.rb']
257
271
  t.verbose = true
258
272
  t.options = '-v'
259
273
  end
@@ -322,21 +336,16 @@ else
322
336
  end
323
337
 
324
338
  desc "Testing library (extension)"
325
- task :test_ext => [ :compile, :do_test_ext ]
339
+ task :test_ext => [ :check_env, :compile, :do_test_ext ]
326
340
 
327
341
  UndocumentedTestTask.new do |t|
328
342
  t.name = 'do_test_ext'
329
- t.libs << 'ext' << 'lib'
330
- t.test_files = FileList['tests/test_*.rb']
343
+ t.libs << 'ext' << 'lib' << 'tests'
344
+ t.test_files = FileList['tests/*_test.rb']
331
345
  t.verbose = true
332
346
  t.options = '-v'
333
347
  end
334
348
 
335
- desc "Create RDOC documentation"
336
- task :doc => [ :version, EXT_PARSER_SRC ] do
337
- sh "sdoc -o doc -t '#{PKG_TITLE}' -m README.rdoc README.rdoc lib/json.rb #{FileList['lib/json/**/*.rb']} #{EXT_PARSER_SRC} #{EXT_GENERATOR_SRC}"
338
- end
339
-
340
349
  desc "Generate parser with ragel"
341
350
  task :ragel => EXT_PARSER_SRC
342
351
 
@@ -345,6 +354,11 @@ else
345
354
  rm_rf EXT_PARSER_SRC
346
355
  end
347
356
 
357
+ desc "Update the tags file"
358
+ task :tags do
359
+ system 'ctags', *Dir['**/*.{rb,c,h,java}']
360
+ end
361
+
348
362
  file EXT_PARSER_SRC => RAGEL_PATH do
349
363
  cd EXT_PARSER_DIR do
350
364
  if RAGEL_CODEGEN == 'ragel'
@@ -353,6 +367,7 @@ else
353
367
  sh "ragel -x parser.rl | #{RAGEL_CODEGEN} -G2"
354
368
  end
355
369
  src = File.read("parser.c").gsub(/[ \t]+$/, '')
370
+ src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
356
371
  File.open("parser.c", "w") {|f| f.print src}
357
372
  end
358
373
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.7.0
1
+ 2.3.0
@@ -2,9 +2,35 @@
2
2
  #ifndef _FBUFFER_H_
3
3
  #define _FBUFFER_H_
4
4
 
5
- #include <assert.h>
6
5
  #include "ruby.h"
7
6
 
7
+ #ifndef RHASH_SIZE
8
+ #define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries)
9
+ #endif
10
+
11
+ #ifndef RFLOAT_VALUE
12
+ #define RFLOAT_VALUE(val) (RFLOAT(val)->value)
13
+ #endif
14
+
15
+ #ifndef RARRAY_LEN
16
+ #define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
17
+ #endif
18
+ #ifndef RSTRING_PTR
19
+ #define RSTRING_PTR(string) RSTRING(string)->ptr
20
+ #endif
21
+ #ifndef RSTRING_LEN
22
+ #define RSTRING_LEN(string) RSTRING(string)->len
23
+ #endif
24
+
25
+ #ifdef PRIsVALUE
26
+ # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
27
+ # define RB_OBJ_STRING(obj) (obj)
28
+ #else
29
+ # define PRIsVALUE "s"
30
+ # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
31
+ # define RB_OBJ_STRING(obj) StringValueCStr(obj)
32
+ #endif
33
+
8
34
  #ifdef HAVE_RUBY_ENCODING_H
9
35
  #include "ruby/encoding.h"
10
36
  #define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
@@ -35,10 +61,14 @@ static FBuffer *fbuffer_alloc(unsigned long initial_length);
35
61
  static void fbuffer_free(FBuffer *fb);
36
62
  static void fbuffer_clear(FBuffer *fb);
37
63
  static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
64
+ #ifdef JSON_GENERATOR
38
65
  static void fbuffer_append_long(FBuffer *fb, long number);
66
+ #endif
39
67
  static void fbuffer_append_char(FBuffer *fb, char newchr);
68
+ #ifdef JSON_GENERATOR
40
69
  static FBuffer *fbuffer_dup(FBuffer *fb);
41
70
  static VALUE fbuffer_to_s(FBuffer *fb);
71
+ #endif
42
72
 
43
73
  static FBuffer *fbuffer_alloc(unsigned long initial_length)
44
74
  {
@@ -87,6 +117,7 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
87
117
  }
88
118
  }
89
119
 
120
+ #ifdef JSON_GENERATOR
90
121
  static void fbuffer_append_str(FBuffer *fb, VALUE str)
91
122
  {
92
123
  const char *newstr = StringValuePtr(str);
@@ -96,6 +127,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
96
127
 
97
128
  fbuffer_append(fb, newstr, len);
98
129
  }
130
+ #endif
99
131
 
100
132
  static void fbuffer_append_char(FBuffer *fb, char newchr)
101
133
  {
@@ -104,6 +136,7 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
104
136
  fb->len++;
105
137
  }
106
138
 
139
+ #ifdef JSON_GENERATOR
107
140
  static void freverse(char *start, char *end)
108
141
  {
109
142
  char c;
@@ -138,19 +171,17 @@ static FBuffer *fbuffer_dup(FBuffer *fb)
138
171
  unsigned long len = fb->len;
139
172
  FBuffer *result;
140
173
 
141
- assert(len > 0);
142
- if (len > 0) {
143
- result = fbuffer_alloc(len);
144
- fbuffer_append(result, FBUFFER_PAIR(fb));
145
- }
174
+ result = fbuffer_alloc(len);
175
+ fbuffer_append(result, FBUFFER_PAIR(fb));
146
176
  return result;
147
177
  }
148
178
 
149
179
  static VALUE fbuffer_to_s(FBuffer *fb)
150
180
  {
151
- VALUE result = rb_str_new(FBUFFER_PAIR(fb));
181
+ VALUE result = rb_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
152
182
  fbuffer_free(fb);
153
183
  FORCE_UTF8(result);
154
184
  return result;
155
185
  }
156
186
  #endif
187
+ #endif
@@ -0,0 +1 @@
1
+ generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h
@@ -1,13 +1,4 @@
1
1
  require 'mkmf'
2
2
 
3
- unless $CFLAGS.gsub!(/ -O[\dsz]?/, ' -O3')
4
- $CFLAGS << ' -O3'
5
- end
6
- if CONFIG['CC'] =~ /gcc/
7
- $CFLAGS << ' -Wall'
8
- unless $DEBUG && !$CFLAGS.gsub!(/ -O[\dsz]?/, ' -O0 -ggdb')
9
- $CFLAGS << ' -O0 -ggdb'
10
- end
11
- end
12
-
3
+ $defs << "-DJSON_GENERATOR"
13
4
  create_makefile 'json/ext/generator'
@@ -7,14 +7,20 @@ static ID i_encoding, i_encode;
7
7
  #endif
8
8
 
9
9
  static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
10
- mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,
10
+ mHash, mArray,
11
+ #ifdef RUBY_INTEGER_UNIFICATION
12
+ mInteger,
13
+ #else
14
+ mFixnum, mBignum,
15
+ #endif
16
+ mFloat, mString, mString_Extend,
11
17
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
12
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
18
+ eNestingError,
13
19
  i_SAFE_STATE_PROTOTYPE;
14
20
 
15
21
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
16
22
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
17
- i_quirks_mode, i_pack, i_unpack, i_create_id, i_extend, i_key_p,
23
+ i_pack, i_unpack, i_create_id, i_extend, i_key_p,
18
24
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
19
25
  i_buffer_initial_length, i_dup;
20
26
 
@@ -216,6 +222,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
216
222
  unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
217
223
  }
218
224
  }
225
+ RB_GC_GUARD(string);
219
226
  }
220
227
 
221
228
  /* Converts string to a JSON string in FBuffer buffer, where only the
@@ -230,6 +237,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
230
237
  int escape_len;
231
238
  unsigned char c;
232
239
  char buf[6] = { '\\', 'u' };
240
+ int ascii_only = rb_enc_str_asciionly_p(string);
233
241
 
234
242
  for (start = 0, end = 0; end < len;) {
235
243
  p = ptr + end;
@@ -273,7 +281,21 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
273
281
  escape_len = 2;
274
282
  break;
275
283
  default:
276
- end++;
284
+ {
285
+ unsigned short clen = 1;
286
+ if (!ascii_only) {
287
+ clen += trailingBytesForUTF8[c];
288
+ if (end + clen > len) {
289
+ rb_raise(rb_path2class("JSON::GeneratorError"),
290
+ "partial character in source, but hit end");
291
+ }
292
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
293
+ rb_raise(rb_path2class("JSON::GeneratorError"),
294
+ "source sequence is illegal/malformed utf-8");
295
+ }
296
+ }
297
+ end += clen;
298
+ }
277
299
  continue;
278
300
  break;
279
301
  }
@@ -290,7 +312,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
290
312
  char *result;
291
313
  if (len <= 0) return NULL;
292
314
  result = ALLOC_N(char, len);
293
- memccpy(result, ptr, 0, len);
315
+ memcpy(result, ptr, len);
294
316
  return result;
295
317
  }
296
318
 
@@ -331,6 +353,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
331
353
  GENERATE_JSON(array);
332
354
  }
333
355
 
356
+ #ifdef RUBY_INTEGER_UNIFICATION
357
+ /*
358
+ * call-seq: to_json(*)
359
+ *
360
+ * Returns a JSON string representation for this Integer number.
361
+ */
362
+ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
363
+ {
364
+ GENERATE_JSON(integer);
365
+ }
366
+
367
+ #else
334
368
  /*
335
369
  * call-seq: to_json(*)
336
370
  *
@@ -350,6 +384,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
350
384
  {
351
385
  GENERATE_JSON(bignum);
352
386
  }
387
+ #endif
353
388
 
354
389
  /*
355
390
  * call-seq: to_json(*)
@@ -475,8 +510,9 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
475
510
  return cState_partial_generate(state, string);
476
511
  }
477
512
 
478
- static void State_free(JSON_Generator_State *state)
513
+ static void State_free(void *ptr)
479
514
  {
515
+ JSON_Generator_State *state = ptr;
480
516
  if (state->indent) ruby_xfree(state->indent);
481
517
  if (state->space) ruby_xfree(state->space);
482
518
  if (state->space_before) ruby_xfree(state->space_before);
@@ -488,17 +524,37 @@ static void State_free(JSON_Generator_State *state)
488
524
  ruby_xfree(state);
489
525
  }
490
526
 
491
- static JSON_Generator_State *State_allocate()
527
+ static size_t State_memsize(const void *ptr)
492
528
  {
493
- JSON_Generator_State *state = ALLOC(JSON_Generator_State);
494
- MEMZERO(state, JSON_Generator_State, 1);
495
- return state;
496
- }
529
+ const JSON_Generator_State *state = ptr;
530
+ size_t size = sizeof(*state);
531
+ if (state->indent) size += state->indent_len + 1;
532
+ if (state->space) size += state->space_len + 1;
533
+ if (state->space_before) size += state->space_before_len + 1;
534
+ if (state->object_nl) size += state->object_nl_len + 1;
535
+ if (state->array_nl) size += state->array_nl_len + 1;
536
+ if (state->array_delim) size += FBUFFER_CAPA(state->array_delim);
537
+ if (state->object_delim) size += FBUFFER_CAPA(state->object_delim);
538
+ if (state->object_delim2) size += FBUFFER_CAPA(state->object_delim2);
539
+ return size;
540
+ }
541
+
542
+ #ifdef NEW_TYPEDDATA_WRAPPER
543
+ static const rb_data_type_t JSON_Generator_State_type = {
544
+ "JSON/Generator/State",
545
+ {NULL, State_free, State_memsize,},
546
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
547
+ 0, 0,
548
+ RUBY_TYPED_FREE_IMMEDIATELY,
549
+ #endif
550
+ };
551
+ #endif
497
552
 
498
553
  static VALUE cState_s_allocate(VALUE klass)
499
554
  {
500
- JSON_Generator_State *state = State_allocate();
501
- return Data_Wrap_Struct(klass, NULL, State_free, state);
555
+ JSON_Generator_State *state;
556
+ return TypedData_Make_Struct(klass, JSON_Generator_State,
557
+ &JSON_Generator_State_type, state);
502
558
  }
503
559
 
504
560
  /*
@@ -511,18 +567,15 @@ static VALUE cState_configure(VALUE self, VALUE opts)
511
567
  {
512
568
  VALUE tmp;
513
569
  GET_STATE(self);
514
- tmp = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
570
+ tmp = rb_check_convert_type(opts, T_HASH, "Hash", "to_hash");
515
571
  if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
516
- if (NIL_P(tmp)) {
517
- rb_raise(rb_eArgError, "opts has to be hash like or convertable into a hash");
518
- }
519
572
  opts = tmp;
520
573
  tmp = rb_hash_aref(opts, ID2SYM(i_indent));
521
574
  if (RTEST(tmp)) {
522
575
  unsigned long len;
523
576
  Check_Type(tmp, T_STRING);
524
577
  len = RSTRING_LEN(tmp);
525
- state->indent = fstrndup(RSTRING_PTR(tmp), len);
578
+ state->indent = fstrndup(RSTRING_PTR(tmp), len + 1);
526
579
  state->indent_len = len;
527
580
  }
528
581
  tmp = rb_hash_aref(opts, ID2SYM(i_space));
@@ -530,7 +583,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
530
583
  unsigned long len;
531
584
  Check_Type(tmp, T_STRING);
532
585
  len = RSTRING_LEN(tmp);
533
- state->space = fstrndup(RSTRING_PTR(tmp), len);
586
+ state->space = fstrndup(RSTRING_PTR(tmp), len + 1);
534
587
  state->space_len = len;
535
588
  }
536
589
  tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
@@ -538,7 +591,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
538
591
  unsigned long len;
539
592
  Check_Type(tmp, T_STRING);
540
593
  len = RSTRING_LEN(tmp);
541
- state->space_before = fstrndup(RSTRING_PTR(tmp), len);
594
+ state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1);
542
595
  state->space_before_len = len;
543
596
  }
544
597
  tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
@@ -546,7 +599,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
546
599
  unsigned long len;
547
600
  Check_Type(tmp, T_STRING);
548
601
  len = RSTRING_LEN(tmp);
549
- state->array_nl = fstrndup(RSTRING_PTR(tmp), len);
602
+ state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
550
603
  state->array_nl_len = len;
551
604
  }
552
605
  tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
@@ -554,11 +607,11 @@ static VALUE cState_configure(VALUE self, VALUE opts)
554
607
  unsigned long len;
555
608
  Check_Type(tmp, T_STRING);
556
609
  len = RSTRING_LEN(tmp);
557
- state->object_nl = fstrndup(RSTRING_PTR(tmp), len);
610
+ state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
558
611
  state->object_nl_len = len;
559
612
  }
560
613
  tmp = ID2SYM(i_max_nesting);
561
- state->max_nesting = 19;
614
+ state->max_nesting = 100;
562
615
  if (option_given_p(opts, tmp)) {
563
616
  VALUE max_nesting = rb_hash_aref(opts, tmp);
564
617
  if (RTEST(max_nesting)) {
@@ -593,11 +646,21 @@ static VALUE cState_configure(VALUE self, VALUE opts)
593
646
  state->allow_nan = RTEST(tmp);
594
647
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
595
648
  state->ascii_only = RTEST(tmp);
596
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
597
- state->quirks_mode = RTEST(tmp);
598
649
  return self;
599
650
  }
600
651
 
652
+ static void set_state_ivars(VALUE hash, VALUE state)
653
+ {
654
+ VALUE ivars = rb_obj_instance_variables(state);
655
+ int i = 0;
656
+ for (i = 0; i < RARRAY_LEN(ivars); i++) {
657
+ VALUE key = rb_funcall(rb_ary_entry(ivars, i), i_to_s, 0);
658
+ long key_len = RSTRING_LEN(key);
659
+ VALUE value = rb_iv_get(state, StringValueCStr(key));
660
+ rb_hash_aset(hash, rb_str_intern(rb_str_substr(key, 1, key_len - 1)), value);
661
+ }
662
+ }
663
+
601
664
  /*
602
665
  * call-seq: to_h
603
666
  *
@@ -608,6 +671,7 @@ static VALUE cState_to_h(VALUE self)
608
671
  {
609
672
  VALUE result = rb_hash_new();
610
673
  GET_STATE(self);
674
+ set_state_ivars(result, self);
611
675
  rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len));
612
676
  rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len));
613
677
  rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len));
@@ -615,7 +679,6 @@ static VALUE cState_to_h(VALUE self)
615
679
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
616
680
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
617
681
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
618
- rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
619
682
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
620
683
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
621
684
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
@@ -625,55 +688,114 @@ static VALUE cState_to_h(VALUE self)
625
688
  /*
626
689
  * call-seq: [](name)
627
690
  *
628
- * Return the value returned by method +name+.
691
+ * Returns the value returned by method +name+.
629
692
  */
630
693
  static VALUE cState_aref(VALUE self, VALUE name)
631
694
  {
632
- GET_STATE(self);
695
+ name = rb_funcall(name, i_to_s, 0);
633
696
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
634
697
  return rb_funcall(self, i_send, 1, name);
635
698
  } else {
636
- return Qnil;
699
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
637
700
  }
638
701
  }
639
702
 
640
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
703
+ /*
704
+ * call-seq: []=(name, value)
705
+ *
706
+ * Sets the attribute name to value.
707
+ */
708
+ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
641
709
  {
710
+ VALUE name_writer;
711
+
712
+ name = rb_funcall(name, i_to_s, 0);
713
+ name_writer = rb_str_cat2(rb_str_dup(name), "=");
714
+ if (RTEST(rb_funcall(self, i_respond_to_p, 1, name_writer))) {
715
+ return rb_funcall(self, i_send, 2, name_writer, value);
716
+ } else {
717
+ rb_ivar_set(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)), value);
718
+ }
719
+ return Qnil;
720
+ }
721
+
722
+ struct hash_foreach_arg {
723
+ FBuffer *buffer;
724
+ JSON_Generator_State *state;
725
+ VALUE Vstate;
726
+ int iter;
727
+ };
728
+
729
+ static int
730
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
731
+ {
732
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
733
+ FBuffer *buffer = arg->buffer;
734
+ JSON_Generator_State *state = arg->state;
735
+ VALUE Vstate = arg->Vstate;
736
+
642
737
  char *object_nl = state->object_nl;
643
738
  long object_nl_len = state->object_nl_len;
644
739
  char *indent = state->indent;
645
740
  long indent_len = state->indent_len;
646
- long max_nesting = state->max_nesting;
647
741
  char *delim = FBUFFER_PTR(state->object_delim);
648
742
  long delim_len = FBUFFER_LEN(state->object_delim);
649
743
  char *delim2 = FBUFFER_PTR(state->object_delim2);
650
744
  long delim2_len = FBUFFER_LEN(state->object_delim2);
745
+ long depth = state->depth;
746
+ int j;
747
+ VALUE klass, key_to_s;
748
+
749
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
750
+ if (object_nl) {
751
+ fbuffer_append(buffer, object_nl, object_nl_len);
752
+ }
753
+ if (indent) {
754
+ for (j = 0; j < depth; j++) {
755
+ fbuffer_append(buffer, indent, indent_len);
756
+ }
757
+ }
758
+
759
+ klass = CLASS_OF(key);
760
+ if (klass == rb_cString) {
761
+ key_to_s = key;
762
+ } else if (klass == rb_cSymbol) {
763
+ key_to_s = rb_id2str(SYM2ID(key));
764
+ } else {
765
+ key_to_s = rb_funcall(key, i_to_s, 0);
766
+ }
767
+ Check_Type(key_to_s, T_STRING);
768
+ generate_json(buffer, Vstate, state, key_to_s);
769
+ fbuffer_append(buffer, delim2, delim2_len);
770
+ generate_json(buffer, Vstate, state, val);
771
+
772
+ arg->iter++;
773
+ return ST_CONTINUE;
774
+ }
775
+
776
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
777
+ {
778
+ char *object_nl = state->object_nl;
779
+ long object_nl_len = state->object_nl_len;
780
+ char *indent = state->indent;
781
+ long indent_len = state->indent_len;
782
+ long max_nesting = state->max_nesting;
651
783
  long depth = ++state->depth;
652
- int i, j;
653
- VALUE key, key_to_s, keys;
784
+ int j;
785
+ struct hash_foreach_arg arg;
786
+
654
787
  if (max_nesting != 0 && depth > max_nesting) {
655
788
  fbuffer_free(buffer);
656
789
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
657
790
  }
658
791
  fbuffer_append_char(buffer, '{');
659
- keys = rb_funcall(obj, i_keys, 0);
660
- for(i = 0; i < RARRAY_LEN(keys); i++) {
661
- if (i > 0) fbuffer_append(buffer, delim, delim_len);
662
- if (object_nl) {
663
- fbuffer_append(buffer, object_nl, object_nl_len);
664
- }
665
- if (indent) {
666
- for (j = 0; j < depth; j++) {
667
- fbuffer_append(buffer, indent, indent_len);
668
- }
669
- }
670
- key = rb_ary_entry(keys, i);
671
- key_to_s = rb_funcall(key, i_to_s, 0);
672
- Check_Type(key_to_s, T_STRING);
673
- generate_json(buffer, Vstate, state, key_to_s);
674
- fbuffer_append(buffer, delim2, delim2_len);
675
- generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
676
- }
792
+
793
+ arg.buffer = buffer;
794
+ arg.state = state;
795
+ arg.Vstate = Vstate;
796
+ arg.iter = 0;
797
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
798
+
677
799
  depth = --state->depth;
678
800
  if (object_nl) {
679
801
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -724,11 +846,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
724
846
  fbuffer_append_char(buffer, ']');
725
847
  }
726
848
 
849
+ #ifdef HAVE_RUBY_ENCODING_H
850
+ static int enc_utf8_compatible_p(rb_encoding *enc)
851
+ {
852
+ if (enc == rb_usascii_encoding()) return 1;
853
+ if (enc == rb_utf8_encoding()) return 1;
854
+ return 0;
855
+ }
856
+ #endif
857
+
727
858
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
728
859
  {
729
860
  fbuffer_append_char(buffer, '"');
730
861
  #ifdef HAVE_RUBY_ENCODING_H
731
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
862
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
863
+ obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
864
+ }
732
865
  #endif
733
866
  if (state->ascii_only) {
734
867
  convert_UTF8_to_JSON_ASCII(buffer, obj);
@@ -764,6 +897,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
764
897
  fbuffer_append_str(buffer, tmp);
765
898
  }
766
899
 
900
+ #ifdef RUBY_INTEGER_UNIFICATION
901
+ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
902
+ {
903
+ if (FIXNUM_P(obj))
904
+ generate_json_fixnum(buffer, Vstate, state, obj);
905
+ else
906
+ generate_json_bignum(buffer, Vstate, state, obj);
907
+ }
908
+ #endif
767
909
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
768
910
  {
769
911
  double value = RFLOAT_VALUE(obj);
@@ -772,10 +914,10 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
772
914
  if (!allow_nan) {
773
915
  if (isinf(value)) {
774
916
  fbuffer_free(buffer);
775
- rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
917
+ rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp));
776
918
  } else if (isnan(value)) {
777
919
  fbuffer_free(buffer);
778
- rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
920
+ rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp));
779
921
  }
780
922
  }
781
923
  fbuffer_append_str(buffer, tmp);
@@ -797,9 +939,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
797
939
  generate_json_false(buffer, Vstate, state, obj);
798
940
  } else if (obj == Qtrue) {
799
941
  generate_json_true(buffer, Vstate, state, obj);
800
- } else if (klass == rb_cFixnum) {
942
+ } else if (FIXNUM_P(obj)) {
801
943
  generate_json_fixnum(buffer, Vstate, state, obj);
802
- } else if (klass == rb_cBignum) {
944
+ } else if (RB_TYPE_P(obj, T_BIGNUM)) {
803
945
  generate_json_bignum(buffer, Vstate, state, obj);
804
946
  } else if (klass == rb_cFloat) {
805
947
  generate_json_float(buffer, Vstate, state, obj);
@@ -810,7 +952,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
810
952
  } else {
811
953
  tmp = rb_funcall(obj, i_to_s, 0);
812
954
  Check_Type(tmp, T_STRING);
813
- generate_json(buffer, Vstate, state, tmp);
955
+ generate_json_string(buffer, Vstate, state, tmp);
814
956
  }
815
957
  }
816
958
 
@@ -831,6 +973,7 @@ static FBuffer *cState_prepare_buffer(VALUE self)
831
973
  } else {
832
974
  state->object_delim2 = fbuffer_alloc(16);
833
975
  }
976
+ if (state->space_before) fbuffer_append(state->object_delim2, state->space_before, state->space_before_len);
834
977
  fbuffer_append_char(state->object_delim2, ':');
835
978
  if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
836
979
 
@@ -852,21 +995,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
852
995
  return fbuffer_to_s(buffer);
853
996
  }
854
997
 
855
- /*
856
- * This function returns true if string is either a JSON array or JSON object.
857
- * It might suffer from false positives, e. g. syntactically incorrect JSON in
858
- * the string or certain UTF-8 characters on the right hand side.
859
- */
860
- static int isArrayOrObject(VALUE string)
861
- {
862
- long string_len = RSTRING_LEN(string);
863
- char *p = RSTRING_PTR(string), *q = p + string_len - 1;
864
- if (string_len < 2) return 0;
865
- for (; p < q && isspace(*p); p++);
866
- for (; q > p && isspace(*q); q--);
867
- return *p == '[' && *q == ']' || *p == '{' && *q == '}';
868
- }
869
-
870
998
  /*
871
999
  * call-seq: generate(obj)
872
1000
  *
@@ -878,9 +1006,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
878
1006
  {
879
1007
  VALUE result = cState_partial_generate(self, obj);
880
1008
  GET_STATE(self);
881
- if (!state->quirks_mode && !isArrayOrObject(result)) {
882
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
883
- }
1009
+ (void)state;
884
1010
  return result;
885
1011
  }
886
1012
 
@@ -899,8 +1025,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
899
1025
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
900
1026
  * generated, otherwise an exception is thrown, if these values are
901
1027
  * encountered. This options defaults to false.
902
- * * *quirks_mode*: Enables quirks_mode for parser, that is for example
903
- * generating single JSON values instead of documents is possible.
1028
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1029
+ * ontions defaults to false.
904
1030
  * * *buffer_initial_length*: sets the initial length of the generator's
905
1031
  * internal buffer.
906
1032
  */
@@ -908,7 +1034,7 @@ static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
908
1034
  {
909
1035
  VALUE opts;
910
1036
  GET_STATE(self);
911
- state->max_nesting = 19;
1037
+ state->max_nesting = 100;
912
1038
  state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
913
1039
  rb_scan_args(argc, argv, "01", &opts);
914
1040
  if (!NIL_P(opts)) cState_configure(self, opts);
@@ -918,15 +1044,16 @@ static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
918
1044
  /*
919
1045
  * call-seq: initialize_copy(orig)
920
1046
  *
921
- * Initializes this object from orig if it to be duplicated/cloned and returns
1047
+ * Initializes this object from orig if it can be duplicated/cloned and returns
922
1048
  * it.
923
1049
  */
924
1050
  static VALUE cState_init_copy(VALUE obj, VALUE orig)
925
1051
  {
926
1052
  JSON_Generator_State *objState, *origState;
927
1053
 
928
- Data_Get_Struct(obj, JSON_Generator_State, objState);
929
- Data_Get_Struct(orig, JSON_Generator_State, origState);
1054
+ if (obj == orig) return obj;
1055
+ GET_STATE_TO(obj, objState);
1056
+ GET_STATE_TO(orig, origState);
930
1057
  if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
931
1058
 
932
1059
  MEMCPY(objState, origState, JSON_Generator_State, 1);
@@ -955,28 +1082,26 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
955
1082
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
956
1083
  return rb_funcall(self, i_new, 1, opts);
957
1084
  } else {
958
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
959
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
960
- }
961
- return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
1085
+ VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1086
+ return rb_funcall(prototype, i_dup, 0);
962
1087
  }
963
1088
  }
964
1089
 
965
1090
  /*
966
1091
  * call-seq: indent()
967
1092
  *
968
- * This string is used to indent levels in the JSON text.
1093
+ * Returns the string that is used to indent levels in the JSON text.
969
1094
  */
970
1095
  static VALUE cState_indent(VALUE self)
971
1096
  {
972
1097
  GET_STATE(self);
973
- return state->indent ? rb_str_new2(state->indent) : rb_str_new2("");
1098
+ return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
974
1099
  }
975
1100
 
976
1101
  /*
977
1102
  * call-seq: indent=(indent)
978
1103
  *
979
- * This string is used to indent levels in the JSON text.
1104
+ * Sets the string that is used to indent levels in the JSON text.
980
1105
  */
981
1106
  static VALUE cState_indent_set(VALUE self, VALUE indent)
982
1107
  {
@@ -992,7 +1117,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
992
1117
  }
993
1118
  } else {
994
1119
  if (state->indent) ruby_xfree(state->indent);
995
- state->indent = strdup(RSTRING_PTR(indent));
1120
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
996
1121
  state->indent_len = len;
997
1122
  }
998
1123
  return Qnil;
@@ -1001,19 +1126,19 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1001
1126
  /*
1002
1127
  * call-seq: space()
1003
1128
  *
1004
- * This string is used to insert a space between the tokens in a JSON
1129
+ * Returns the string that is used to insert a space between the tokens in a JSON
1005
1130
  * string.
1006
1131
  */
1007
1132
  static VALUE cState_space(VALUE self)
1008
1133
  {
1009
1134
  GET_STATE(self);
1010
- return state->space ? rb_str_new2(state->space) : rb_str_new2("");
1135
+ return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
1011
1136
  }
1012
1137
 
1013
1138
  /*
1014
1139
  * call-seq: space=(space)
1015
1140
  *
1016
- * This string is used to insert a space between the tokens in a JSON
1141
+ * Sets _space_ to the string that is used to insert a space between the tokens in a JSON
1017
1142
  * string.
1018
1143
  */
1019
1144
  static VALUE cState_space_set(VALUE self, VALUE space)
@@ -1030,7 +1155,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1030
1155
  }
1031
1156
  } else {
1032
1157
  if (state->space) ruby_xfree(state->space);
1033
- state->space = strdup(RSTRING_PTR(space));
1158
+ state->space = fstrndup(RSTRING_PTR(space), len);
1034
1159
  state->space_len = len;
1035
1160
  }
1036
1161
  return Qnil;
@@ -1039,18 +1164,18 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1039
1164
  /*
1040
1165
  * call-seq: space_before()
1041
1166
  *
1042
- * This string is used to insert a space before the ':' in JSON objects.
1167
+ * Returns the string that is used to insert a space before the ':' in JSON objects.
1043
1168
  */
1044
1169
  static VALUE cState_space_before(VALUE self)
1045
1170
  {
1046
1171
  GET_STATE(self);
1047
- return state->space_before ? rb_str_new2(state->space_before) : rb_str_new2("");
1172
+ return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
1048
1173
  }
1049
1174
 
1050
1175
  /*
1051
1176
  * call-seq: space_before=(space_before)
1052
1177
  *
1053
- * This string is used to insert a space before the ':' in JSON objects.
1178
+ * Sets the string that is used to insert a space before the ':' in JSON objects.
1054
1179
  */
1055
1180
  static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1056
1181
  {
@@ -1066,7 +1191,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1066
1191
  }
1067
1192
  } else {
1068
1193
  if (state->space_before) ruby_xfree(state->space_before);
1069
- state->space_before = strdup(RSTRING_PTR(space_before));
1194
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1070
1195
  state->space_before_len = len;
1071
1196
  }
1072
1197
  return Qnil;
@@ -1081,7 +1206,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1081
1206
  static VALUE cState_object_nl(VALUE self)
1082
1207
  {
1083
1208
  GET_STATE(self);
1084
- return state->object_nl ? rb_str_new2(state->object_nl) : rb_str_new2("");
1209
+ return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
1085
1210
  }
1086
1211
 
1087
1212
  /*
@@ -1103,7 +1228,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1103
1228
  }
1104
1229
  } else {
1105
1230
  if (state->object_nl) ruby_xfree(state->object_nl);
1106
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1231
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1107
1232
  state->object_nl_len = len;
1108
1233
  }
1109
1234
  return Qnil;
@@ -1117,7 +1242,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1117
1242
  static VALUE cState_array_nl(VALUE self)
1118
1243
  {
1119
1244
  GET_STATE(self);
1120
- return state->array_nl ? rb_str_new2(state->array_nl) : rb_str_new2("");
1245
+ return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
1121
1246
  }
1122
1247
 
1123
1248
  /*
@@ -1138,7 +1263,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1138
1263
  }
1139
1264
  } else {
1140
1265
  if (state->array_nl) ruby_xfree(state->array_nl);
1141
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1266
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1142
1267
  state->array_nl_len = len;
1143
1268
  }
1144
1269
  return Qnil;
@@ -1197,7 +1322,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1197
1322
  /*
1198
1323
  * call-seq: ascii_only?
1199
1324
  *
1200
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1325
+ * Returns true, if only ASCII characters should be generated. Otherwise
1201
1326
  * returns false.
1202
1327
  */
1203
1328
  static VALUE cState_ascii_only_p(VALUE self)
@@ -1206,29 +1331,6 @@ static VALUE cState_ascii_only_p(VALUE self)
1206
1331
  return state->ascii_only ? Qtrue : Qfalse;
1207
1332
  }
1208
1333
 
1209
- /*
1210
- * call-seq: quirks_mode?
1211
- *
1212
- * Returns true, if quirks mode is enabled. Otherwise returns false.
1213
- */
1214
- static VALUE cState_quirks_mode_p(VALUE self)
1215
- {
1216
- GET_STATE(self);
1217
- return state->quirks_mode ? Qtrue : Qfalse;
1218
- }
1219
-
1220
- /*
1221
- * call-seq: quirks_mode=(enable)
1222
- *
1223
- * If set to true, enables the quirks_mode mode.
1224
- */
1225
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1226
- {
1227
- GET_STATE(self);
1228
- state->quirks_mode = RTEST(enable);
1229
- return Qnil;
1230
- }
1231
-
1232
1334
  /*
1233
1335
  * call-seq: depth
1234
1336
  *
@@ -1257,7 +1359,7 @@ static VALUE cState_depth_set(VALUE self, VALUE depth)
1257
1359
  /*
1258
1360
  * call-seq: buffer_initial_length
1259
1361
  *
1260
- * This integer returns the current inital length of the buffer.
1362
+ * This integer returns the current initial length of the buffer.
1261
1363
  */
1262
1364
  static VALUE cState_buffer_initial_length(VALUE self)
1263
1365
  {
@@ -1286,8 +1388,9 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1286
1388
  /*
1287
1389
  *
1288
1390
  */
1289
- void Init_generator()
1391
+ void Init_generator(void)
1290
1392
  {
1393
+ #undef rb_intern
1291
1394
  rb_require("json/common");
1292
1395
 
1293
1396
  mJSON = rb_define_module("JSON");
@@ -1296,6 +1399,8 @@ void Init_generator()
1296
1399
 
1297
1400
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1298
1401
  eNestingError = rb_path2class("JSON::NestingError");
1402
+ rb_gc_register_mark_object(eGeneratorError);
1403
+ rb_gc_register_mark_object(eNestingError);
1299
1404
 
1300
1405
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1301
1406
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1317,9 +1422,6 @@ void Init_generator()
1317
1422
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1318
1423
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1319
1424
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
1320
- rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
1321
- rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
1322
- rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
1323
1425
  rb_define_method(cState, "depth", cState_depth, 0);
1324
1426
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1325
1427
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1327,7 +1429,9 @@ void Init_generator()
1327
1429
  rb_define_method(cState, "configure", cState_configure, 1);
1328
1430
  rb_define_alias(cState, "merge", "configure");
1329
1431
  rb_define_method(cState, "to_h", cState_to_h, 0);
1432
+ rb_define_alias(cState, "to_hash", "to_h");
1330
1433
  rb_define_method(cState, "[]", cState_aref, 1);
1434
+ rb_define_method(cState, "[]=", cState_aset, 2);
1331
1435
  rb_define_method(cState, "generate", cState_generate, 1);
1332
1436
 
1333
1437
  mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
@@ -1337,10 +1441,15 @@ void Init_generator()
1337
1441
  rb_define_method(mHash, "to_json", mHash_to_json, -1);
1338
1442
  mArray = rb_define_module_under(mGeneratorMethods, "Array");
1339
1443
  rb_define_method(mArray, "to_json", mArray_to_json, -1);
1444
+ #ifdef RUBY_INTEGER_UNIFICATION
1445
+ mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
1446
+ rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
1447
+ #else
1340
1448
  mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
1341
1449
  rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
1342
1450
  mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
1343
1451
  rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
1452
+ #endif
1344
1453
  mFloat = rb_define_module_under(mGeneratorMethods, "Float");
1345
1454
  rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
1346
1455
  mString = rb_define_module_under(mGeneratorMethods, "String");
@@ -1357,7 +1466,6 @@ void Init_generator()
1357
1466
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1358
1467
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1359
1468
 
1360
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1361
1469
  i_to_s = rb_intern("to_s");
1362
1470
  i_to_json = rb_intern("to_json");
1363
1471
  i_new = rb_intern("new");
@@ -1369,7 +1477,6 @@ void Init_generator()
1369
1477
  i_max_nesting = rb_intern("max_nesting");
1370
1478
  i_allow_nan = rb_intern("allow_nan");
1371
1479
  i_ascii_only = rb_intern("ascii_only");
1372
- i_quirks_mode = rb_intern("quirks_mode");
1373
1480
  i_depth = rb_intern("depth");
1374
1481
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1375
1482
  i_pack = rb_intern("pack");
@@ -1389,5 +1496,4 @@ void Init_generator()
1389
1496
  i_encode = rb_intern("encode");
1390
1497
  #endif
1391
1498
  i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1392
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1393
1499
  }