json 1.8.2 → 2.3.1

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 (82) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.travis.yml +11 -9
  4. data/{CHANGES → CHANGES.md} +220 -89
  5. data/Gemfile +10 -6
  6. data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
  7. data/{README.rdoc → README.md} +204 -137
  8. data/Rakefile +35 -113
  9. data/VERSION +1 -1
  10. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  11. data/ext/json/ext/generator/generator.c +215 -110
  12. data/ext/json/ext/generator/generator.h +18 -5
  13. data/ext/json/ext/parser/extconf.rb +3 -0
  14. data/ext/json/ext/parser/parser.c +422 -508
  15. data/ext/json/ext/parser/parser.h +15 -8
  16. data/ext/json/ext/parser/parser.rl +151 -200
  17. data/ext/json/extconf.rb +0 -1
  18. data/java/src/json/ext/ByteListTranscoder.java +1 -2
  19. data/java/src/json/ext/Generator.java +44 -22
  20. data/java/src/json/ext/GeneratorMethods.java +1 -2
  21. data/java/src/json/ext/GeneratorService.java +1 -2
  22. data/java/src/json/ext/GeneratorState.java +3 -56
  23. data/java/src/json/ext/OptionsReader.java +2 -3
  24. data/java/src/json/ext/Parser.java +132 -415
  25. data/java/src/json/ext/Parser.rl +48 -124
  26. data/java/src/json/ext/ParserService.java +1 -2
  27. data/java/src/json/ext/RuntimeInfo.java +1 -6
  28. data/java/src/json/ext/StringDecoder.java +1 -2
  29. data/java/src/json/ext/StringEncoder.java +5 -0
  30. data/java/src/json/ext/Utils.java +1 -2
  31. data/json-java.gemspec +16 -2
  32. data/json.gemspec +0 -0
  33. data/json_pure.gemspec +22 -29
  34. data/lib/json.rb +379 -29
  35. data/lib/json/add/bigdecimal.rb +3 -2
  36. data/lib/json/add/complex.rb +4 -3
  37. data/lib/json/add/core.rb +1 -0
  38. data/lib/json/add/date.rb +1 -1
  39. data/lib/json/add/date_time.rb +1 -1
  40. data/lib/json/add/exception.rb +1 -1
  41. data/lib/json/add/ostruct.rb +3 -3
  42. data/lib/json/add/range.rb +1 -1
  43. data/lib/json/add/rational.rb +3 -2
  44. data/lib/json/add/regexp.rb +3 -3
  45. data/lib/json/add/set.rb +29 -0
  46. data/lib/json/add/struct.rb +1 -1
  47. data/lib/json/add/symbol.rb +1 -1
  48. data/lib/json/add/time.rb +1 -1
  49. data/lib/json/common.rb +335 -128
  50. data/lib/json/ext.rb +0 -6
  51. data/lib/json/generic_object.rb +5 -4
  52. data/lib/json/pure.rb +2 -8
  53. data/lib/json/pure/generator.rb +64 -127
  54. data/lib/json/pure/parser.rb +42 -82
  55. data/lib/json/version.rb +2 -1
  56. data/references/rfc7159.txt +899 -0
  57. data/tests/fixtures/obsolete_fail1.json +1 -0
  58. data/tests/{test_json_addition.rb → json_addition_test.rb} +32 -25
  59. data/tests/json_common_interface_test.rb +126 -0
  60. data/tests/json_encoding_test.rb +107 -0
  61. data/tests/json_ext_parser_test.rb +15 -0
  62. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +10 -8
  63. data/tests/{test_json_generate.rb → json_generator_test.rb} +123 -39
  64. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  65. data/tests/json_parser_test.rb +472 -0
  66. data/tests/json_string_matching_test.rb +38 -0
  67. data/tests/{setup_variant.rb → test_helper.rb} +6 -0
  68. data/tools/diff.sh +18 -0
  69. data/tools/fuzz.rb +1 -9
  70. metadata +46 -53
  71. data/COPYING +0 -58
  72. data/COPYING-json-jruby +0 -57
  73. data/GPL +0 -340
  74. data/TODO +0 -1
  75. data/data/example.json +0 -1
  76. data/data/index.html +0 -38
  77. data/data/prototype.js +0 -4184
  78. data/tests/fixtures/fail1.json +0 -1
  79. data/tests/test_json.rb +0 -553
  80. data/tests/test_json_encoding.rb +0 -65
  81. data/tests/test_json_string_matching.rb +0 -39
  82. data/tests/test_json_unicode.rb +0 -72
data/Rakefile CHANGED
@@ -23,12 +23,13 @@ class UndocumentedTestTask < Rake::TestTask
23
23
  def desc(*) end
24
24
  end
25
25
 
26
- def skip_sdoc(src)
27
- src.gsub(/^.*sdoc.*/) { |s| s + ' if RUBY_VERSION > "1.8.6"' }
28
- end
26
+ which = lambda { |c|
27
+ w = `which #{c}`
28
+ break w.chomp unless w.empty?
29
+ }
29
30
 
30
- MAKE = ENV['MAKE'] || %w[gmake make].find { |c| system(c, '-v') }
31
- BUNDLE = ENV['BUNDLE'] || %w[bundle].find { |c| system(c, '-v') }
31
+ MAKE = ENV['MAKE'] || %w[gmake make].find(&which)
32
+ BUNDLE = ENV['BUNDLE'] || %w[bundle].find(&which)
32
33
  PKG_NAME = 'json'
33
34
  PKG_TITLE = 'JSON Implementation for Ruby'
34
35
  PKG_VERSION = File.read('VERSION').chomp
@@ -51,8 +52,8 @@ JAVA_CLASSES = []
51
52
  JRUBY_PARSER_JAR = File.expand_path("lib/json/ext/parser.jar")
52
53
  JRUBY_GENERATOR_JAR = File.expand_path("lib/json/ext/generator.jar")
53
54
 
54
- RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find { |c| system(c, '-v') }
55
- 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)
56
57
 
57
58
  desc "Installing library (pure)"
58
59
  task :install_pure => :version do
@@ -77,90 +78,12 @@ task :install_ext => [ :compile, :install_pure, :install_ext_really ]
77
78
  desc "Installing library (extension)"
78
79
  task :install => :install_ext
79
80
 
80
- if defined?(Gem) and defined?(Gem::PackageTask)
81
- spec_pure = Gem::Specification.new do |s|
82
- s.name = 'json_pure'
83
- s.version = PKG_VERSION
84
- s.summary = PKG_TITLE
85
- s.description = "This is a JSON implementation in pure Ruby."
86
-
87
- s.files = PKG_FILES
88
-
89
- s.require_path = 'lib'
90
- s.add_development_dependency 'permutation'
91
- s.add_development_dependency 'sdoc', '~>0.3.16'
92
- s.add_development_dependency 'rake', '~>0.9.2'
93
-
94
- s.extra_rdoc_files << 'README.rdoc'
95
- s.rdoc_options <<
96
- '--title' << 'JSON implemention for ruby' << '--main' << 'README.rdoc'
97
- s.test_files.concat Dir['./tests/test_*.rb']
98
-
99
- s.author = "Florian Frank"
100
- s.email = "flori@ping.de"
101
- s.homepage = "http://flori.github.com/#{PKG_NAME}"
102
- s.license = 'Ruby'
103
- end
104
-
105
- desc 'Creates a json_pure.gemspec file'
106
- task :gemspec_pure => :version do
107
- File.open('json_pure.gemspec', 'w') do |gemspec|
108
- gemspec.write skip_sdoc(spec_pure.to_ruby)
109
- end
110
- end
111
-
112
- Gem::PackageTask.new(spec_pure) do |pkg|
113
- pkg.need_tar = true
114
- pkg.package_files = PKG_FILES
115
- end
116
-
117
- spec_ext = Gem::Specification.new do |s|
118
- s.name = 'json'
119
- s.version = PKG_VERSION
120
- s.summary = PKG_TITLE
121
- s.description = "This is a JSON implementation as a Ruby extension in C."
122
-
123
- s.files = PKG_FILES
124
-
125
- s.extensions = FileList['ext/**/extconf.rb']
126
-
127
- s.require_path = 'lib'
128
- s.add_development_dependency 'permutation'
129
- s.add_development_dependency 'sdoc', '~>0.3.16'
130
-
131
- s.extra_rdoc_files << 'README.rdoc'
132
- s.rdoc_options <<
133
- '--title' << 'JSON implemention for Ruby' << '--main' << 'README.rdoc'
134
- s.test_files.concat Dir['./tests/test_*.rb']
135
-
136
- s.author = "Florian Frank"
137
- s.email = "flori@ping.de"
138
- s.homepage = "http://flori.github.com/#{PKG_NAME}"
139
- s.license = 'Ruby'
140
- end
141
-
142
- desc 'Creates a json.gemspec file'
143
- task :gemspec_ext => :version do
144
- File.open('json.gemspec', 'w') do |gemspec|
145
- gemspec.write skip_sdoc(spec_ext.to_ruby)
146
- end
147
- end
148
-
149
- Gem::PackageTask.new(spec_ext) do |pkg|
150
- pkg.need_tar = true
151
- pkg.package_files = PKG_FILES
152
- end
153
-
154
-
155
- desc 'Create all gemspec files'
156
- task :gemspec => [ :gemspec_pure, :gemspec_ext ]
157
- end
158
-
159
81
  desc m = "Writing version information for #{PKG_VERSION}"
160
82
  task :version do
161
83
  puts m
162
84
  File.open(File.join('lib', 'json', 'version.rb'), 'w') do |v|
163
85
  v.puts <<EOT
86
+ # frozen_string_literal: false
164
87
  module JSON
165
88
  # JSON version
166
89
  VERSION = '#{PKG_VERSION}'
@@ -173,22 +96,24 @@ EOT
173
96
  end
174
97
  end
175
98
 
99
+ task :check_env do
100
+ ENV.key?('JSON') or fail "JSON env var is required"
101
+ end
102
+
176
103
  desc "Testing library (pure ruby)"
177
- task :test_pure => [ :clean, :do_test_pure ]
104
+ task :test_pure => [ :set_env_pure, :check_env, :do_test_pure ]
105
+ task(:set_env_pure) { ENV['JSON'] = 'pure' }
178
106
 
179
107
  UndocumentedTestTask.new do |t|
180
108
  t.name = 'do_test_pure'
181
- t.libs << 'lib'
182
- t.test_files = FileList['tests/test_*.rb']
109
+ t.libs << 'lib' << 'tests'
110
+ t.test_files = FileList['tests/*_test.rb']
183
111
  t.verbose = true
184
112
  t.options = '-v'
185
113
  end
186
114
 
187
115
  desc "Testing library (pure ruby and extension)"
188
- task :test do
189
- sh "env JSON=pure #{BUNDLE} exec rake test_pure" or exit 1
190
- sh "env JSON=ext #{BUNDLE} exec rake test_ext" or exit 1
191
- end
116
+ task :test => [ :test_pure, :test_ext ]
192
117
 
193
118
  namespace :gems do
194
119
  desc 'Install all development gems'
@@ -198,13 +123,11 @@ namespace :gems do
198
123
  end
199
124
 
200
125
  if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
201
- if ENV.key?('JAVA_HOME')
202
- warn " *** JAVA_HOME was set to #{ENV['JAVA_HOME'].inspect}"
203
- elsif File.directory?(local_java = '/usr/local/java/jdk') ||
204
- File.directory?(local_java = '/usr/lib/jvm/java-6-openjdk')
205
- then
206
- ENV['JAVA_HOME'] = local_java
207
- end
126
+ ENV['JAVA_HOME'] ||= [
127
+ '/usr/local/java/jdk',
128
+ '/usr/lib/jvm/java-6-openjdk',
129
+ '/Library/Java/Home',
130
+ ].find { |c| File.directory?(c) }
208
131
  if ENV['JAVA_HOME']
209
132
  warn " *** JAVA_HOME is set to #{ENV['JAVA_HOME'].inspect}"
210
133
  ENV['PATH'] = ENV['PATH'].split(/:/).unshift(java_path = "#{ENV['JAVA_HOME']}/bin") * ':'
@@ -238,7 +161,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
238
161
  classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
239
162
  obj = src.sub(/\.java\Z/, '.class')
240
163
  file obj => src do
241
- sh 'javac', '-classpath', classpath, '-source', '1.5', '-target', '1.5', src
164
+ sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
242
165
  end
243
166
  JAVA_CLASSES << obj
244
167
  end
@@ -257,12 +180,13 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
257
180
  end
258
181
 
259
182
  desc "Testing library (jruby)"
260
- task :test_ext => [ :create_jar, :do_test_ext ]
183
+ task :test_ext => [ :set_env_ext, :create_jar, :check_env, :do_test_ext ]
184
+ task(:set_env_ext) { ENV['JSON'] = 'ext' }
261
185
 
262
186
  UndocumentedTestTask.new do |t|
263
187
  t.name = 'do_test_ext'
264
- t.libs << 'lib'
265
- t.test_files = FileList['tests/test_*.rb']
188
+ t.libs << 'lib' << 'tests'
189
+ t.test_files = FileList['tests/*_test.rb']
266
190
  t.verbose = true
267
191
  t.options = '-v'
268
192
  end
@@ -331,21 +255,16 @@ else
331
255
  end
332
256
 
333
257
  desc "Testing library (extension)"
334
- task :test_ext => [ :compile, :do_test_ext ]
258
+ task :test_ext => [ :check_env, :compile, :do_test_ext ]
335
259
 
336
260
  UndocumentedTestTask.new do |t|
337
261
  t.name = 'do_test_ext'
338
- t.libs << 'ext' << 'lib'
339
- t.test_files = FileList['tests/test_*.rb']
262
+ t.libs << 'ext' << 'lib' << 'tests'
263
+ t.test_files = FileList['tests/*_test.rb']
340
264
  t.verbose = true
341
265
  t.options = '-v'
342
266
  end
343
267
 
344
- desc "Create RDOC documentation"
345
- task :doc => [ :version, EXT_PARSER_SRC ] do
346
- 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}"
347
- end
348
-
349
268
  desc "Generate parser with ragel"
350
269
  task :ragel => EXT_PARSER_SRC
351
270
 
@@ -367,6 +286,9 @@ else
367
286
  sh "ragel -x parser.rl | #{RAGEL_CODEGEN} -G2"
368
287
  end
369
288
  src = File.read("parser.c").gsub(/[ \t]+$/, '')
289
+ src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
290
+ src.gsub!(/0 <= \(\*p\) && \(\*p\) <= 31/, "0 <= (signed char)(*p) && (*p) <= 31")
291
+ src[0, 0] = "/* This file is automatically generated from parser.rl by using ragel */"
370
292
  File.open("parser.c", "w") {|f| f.print src}
371
293
  end
372
294
  end
@@ -409,4 +331,4 @@ else
409
331
  end
410
332
 
411
333
  desc "Compile in the the source directory"
412
- task :default => [ :clean, :gemspec, :test ]
334
+ task :default => [ :clean, :test ]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.2
1
+ 2.3.1
@@ -12,9 +12,6 @@
12
12
  #define RFLOAT_VALUE(val) (RFLOAT(val)->value)
13
13
  #endif
14
14
 
15
- #ifndef RARRAY_PTR
16
- #define RARRAY_PTR(ARRAY) RARRAY(ARRAY)->ptr
17
- #endif
18
15
  #ifndef RARRAY_LEN
19
16
  #define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
20
17
  #endif
@@ -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;
@@ -274,14 +282,17 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
274
282
  break;
275
283
  default:
276
284
  {
277
- unsigned short clen = trailingBytesForUTF8[c] + 1;
278
- if (end + clen > len) {
279
- rb_raise(rb_path2class("JSON::GeneratorError"),
280
- "partial character in source, but hit end");
281
- }
282
- if (!isLegalUTF8((UTF8 *) p, clen)) {
283
- rb_raise(rb_path2class("JSON::GeneratorError"),
284
- "source sequence is illegal/malformed utf-8");
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
+ }
285
296
  }
286
297
  end += clen;
287
298
  }
@@ -301,7 +312,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
301
312
  char *result;
302
313
  if (len <= 0) return NULL;
303
314
  result = ALLOC_N(char, len);
304
- memccpy(result, ptr, 0, len);
315
+ memcpy(result, ptr, len);
305
316
  return result;
306
317
  }
307
318
 
@@ -317,6 +328,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
317
328
  *
318
329
  */
319
330
 
331
+ /* Explanation of the following: that's the only way to not pollute
332
+ * standard library's docs with GeneratorMethods::<ClassName> which
333
+ * are uninformative and take a large place in a list of classes
334
+ */
335
+
336
+ /*
337
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
338
+ * :nodoc:
339
+ */
340
+
341
+ /*
342
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
343
+ * :nodoc:
344
+ */
345
+
346
+ /*
347
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
348
+ * :nodoc:
349
+ */
350
+
351
+ /*
352
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
353
+ * :nodoc:
354
+ */
355
+
356
+ /*
357
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
358
+ * :nodoc:
359
+ */
360
+
361
+ /*
362
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
363
+ * :nodoc:
364
+ */
365
+
366
+ /*
367
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
368
+ * :nodoc:
369
+ */
370
+
371
+ /*
372
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
373
+ * :nodoc:
374
+ */
375
+
376
+ /*
377
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
378
+ * :nodoc:
379
+ */
380
+
381
+ /*
382
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
383
+ * :nodoc:
384
+ */
385
+
386
+ /*
387
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
388
+ * :nodoc:
389
+ */
390
+
391
+ /*
392
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
393
+ * :nodoc:
394
+ */
395
+
396
+ /*
397
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
398
+ * :nodoc:
399
+ */
400
+
320
401
  /*
321
402
  * call-seq: to_json(state = nil)
322
403
  *
@@ -342,6 +423,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
342
423
  GENERATE_JSON(array);
343
424
  }
344
425
 
426
+ #ifdef RUBY_INTEGER_UNIFICATION
427
+ /*
428
+ * call-seq: to_json(*)
429
+ *
430
+ * Returns a JSON string representation for this Integer number.
431
+ */
432
+ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
433
+ {
434
+ GENERATE_JSON(integer);
435
+ }
436
+
437
+ #else
345
438
  /*
346
439
  * call-seq: to_json(*)
347
440
  *
@@ -361,6 +454,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
361
454
  {
362
455
  GENERATE_JSON(bignum);
363
456
  }
457
+ #endif
364
458
 
365
459
  /*
366
460
  * call-seq: to_json(*)
@@ -526,17 +620,11 @@ static const rb_data_type_t JSON_Generator_State_type = {
526
620
  };
527
621
  #endif
528
622
 
529
- static JSON_Generator_State *State_allocate(void)
530
- {
531
- JSON_Generator_State *state = ALLOC(JSON_Generator_State);
532
- MEMZERO(state, JSON_Generator_State, 1);
533
- return state;
534
- }
535
-
536
623
  static VALUE cState_s_allocate(VALUE klass)
537
624
  {
538
- JSON_Generator_State *state = State_allocate();
539
- return TypedData_Wrap_Struct(klass, &JSON_Generator_State_type, state);
625
+ JSON_Generator_State *state;
626
+ return TypedData_Make_Struct(klass, JSON_Generator_State,
627
+ &JSON_Generator_State_type, state);
540
628
  }
541
629
 
542
630
  /*
@@ -628,8 +716,6 @@ static VALUE cState_configure(VALUE self, VALUE opts)
628
716
  state->allow_nan = RTEST(tmp);
629
717
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
630
718
  state->ascii_only = RTEST(tmp);
631
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
632
- state->quirks_mode = RTEST(tmp);
633
719
  return self;
634
720
  }
635
721
 
@@ -663,7 +749,6 @@ static VALUE cState_to_h(VALUE self)
663
749
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
664
750
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
665
751
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
666
- rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
667
752
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
668
753
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
669
754
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
@@ -681,7 +766,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
681
766
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
682
767
  return rb_funcall(self, i_send, 1, name);
683
768
  } else {
684
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
769
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
685
770
  }
686
771
  }
687
772
 
@@ -704,43 +789,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
704
789
  return Qnil;
705
790
  }
706
791
 
707
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
792
+ struct hash_foreach_arg {
793
+ FBuffer *buffer;
794
+ JSON_Generator_State *state;
795
+ VALUE Vstate;
796
+ int iter;
797
+ };
798
+
799
+ static int
800
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
708
801
  {
802
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
803
+ FBuffer *buffer = arg->buffer;
804
+ JSON_Generator_State *state = arg->state;
805
+ VALUE Vstate = arg->Vstate;
806
+
709
807
  char *object_nl = state->object_nl;
710
808
  long object_nl_len = state->object_nl_len;
711
809
  char *indent = state->indent;
712
810
  long indent_len = state->indent_len;
713
- long max_nesting = state->max_nesting;
714
811
  char *delim = FBUFFER_PTR(state->object_delim);
715
812
  long delim_len = FBUFFER_LEN(state->object_delim);
716
813
  char *delim2 = FBUFFER_PTR(state->object_delim2);
717
814
  long delim2_len = FBUFFER_LEN(state->object_delim2);
815
+ long depth = state->depth;
816
+ int j;
817
+ VALUE klass, key_to_s;
818
+
819
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
820
+ if (object_nl) {
821
+ fbuffer_append(buffer, object_nl, object_nl_len);
822
+ }
823
+ if (indent) {
824
+ for (j = 0; j < depth; j++) {
825
+ fbuffer_append(buffer, indent, indent_len);
826
+ }
827
+ }
828
+
829
+ klass = CLASS_OF(key);
830
+ if (klass == rb_cString) {
831
+ key_to_s = key;
832
+ } else if (klass == rb_cSymbol) {
833
+ key_to_s = rb_id2str(SYM2ID(key));
834
+ } else {
835
+ key_to_s = rb_funcall(key, i_to_s, 0);
836
+ }
837
+ Check_Type(key_to_s, T_STRING);
838
+ generate_json(buffer, Vstate, state, key_to_s);
839
+ fbuffer_append(buffer, delim2, delim2_len);
840
+ generate_json(buffer, Vstate, state, val);
841
+
842
+ arg->iter++;
843
+ return ST_CONTINUE;
844
+ }
845
+
846
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
847
+ {
848
+ char *object_nl = state->object_nl;
849
+ long object_nl_len = state->object_nl_len;
850
+ char *indent = state->indent;
851
+ long indent_len = state->indent_len;
852
+ long max_nesting = state->max_nesting;
718
853
  long depth = ++state->depth;
719
- int i, j;
720
- VALUE key, key_to_s, keys;
854
+ int j;
855
+ struct hash_foreach_arg arg;
856
+
721
857
  if (max_nesting != 0 && depth > max_nesting) {
722
858
  fbuffer_free(buffer);
723
859
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
724
860
  }
725
861
  fbuffer_append_char(buffer, '{');
726
- keys = rb_funcall(obj, i_keys, 0);
727
- for(i = 0; i < RARRAY_LEN(keys); i++) {
728
- if (i > 0) fbuffer_append(buffer, delim, delim_len);
729
- if (object_nl) {
730
- fbuffer_append(buffer, object_nl, object_nl_len);
731
- }
732
- if (indent) {
733
- for (j = 0; j < depth; j++) {
734
- fbuffer_append(buffer, indent, indent_len);
735
- }
736
- }
737
- key = rb_ary_entry(keys, i);
738
- key_to_s = rb_funcall(key, i_to_s, 0);
739
- Check_Type(key_to_s, T_STRING);
740
- generate_json(buffer, Vstate, state, key_to_s);
741
- fbuffer_append(buffer, delim2, delim2_len);
742
- generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
743
- }
862
+
863
+ arg.buffer = buffer;
864
+ arg.state = state;
865
+ arg.Vstate = Vstate;
866
+ arg.iter = 0;
867
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
868
+
744
869
  depth = --state->depth;
745
870
  if (object_nl) {
746
871
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -791,11 +916,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
791
916
  fbuffer_append_char(buffer, ']');
792
917
  }
793
918
 
919
+ #ifdef HAVE_RUBY_ENCODING_H
920
+ static int enc_utf8_compatible_p(rb_encoding *enc)
921
+ {
922
+ if (enc == rb_usascii_encoding()) return 1;
923
+ if (enc == rb_utf8_encoding()) return 1;
924
+ return 0;
925
+ }
926
+ #endif
927
+
794
928
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
795
929
  {
796
930
  fbuffer_append_char(buffer, '"');
797
931
  #ifdef HAVE_RUBY_ENCODING_H
798
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
932
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
933
+ obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
934
+ }
799
935
  #endif
800
936
  if (state->ascii_only) {
801
937
  convert_UTF8_to_JSON_ASCII(buffer, obj);
@@ -831,6 +967,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
831
967
  fbuffer_append_str(buffer, tmp);
832
968
  }
833
969
 
970
+ #ifdef RUBY_INTEGER_UNIFICATION
971
+ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
972
+ {
973
+ if (FIXNUM_P(obj))
974
+ generate_json_fixnum(buffer, Vstate, state, obj);
975
+ else
976
+ generate_json_bignum(buffer, Vstate, state, obj);
977
+ }
978
+ #endif
834
979
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
835
980
  {
836
981
  double value = RFLOAT_VALUE(obj);
@@ -864,9 +1009,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
864
1009
  generate_json_false(buffer, Vstate, state, obj);
865
1010
  } else if (obj == Qtrue) {
866
1011
  generate_json_true(buffer, Vstate, state, obj);
867
- } else if (klass == rb_cFixnum) {
1012
+ } else if (FIXNUM_P(obj)) {
868
1013
  generate_json_fixnum(buffer, Vstate, state, obj);
869
- } else if (klass == rb_cBignum) {
1014
+ } else if (RB_TYPE_P(obj, T_BIGNUM)) {
870
1015
  generate_json_bignum(buffer, Vstate, state, obj);
871
1016
  } else if (klass == rb_cFloat) {
872
1017
  generate_json_float(buffer, Vstate, state, obj);
@@ -877,7 +1022,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
877
1022
  } else {
878
1023
  tmp = rb_funcall(obj, i_to_s, 0);
879
1024
  Check_Type(tmp, T_STRING);
880
- generate_json(buffer, Vstate, state, tmp);
1025
+ generate_json_string(buffer, Vstate, state, tmp);
881
1026
  }
882
1027
  }
883
1028
 
@@ -920,21 +1065,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
920
1065
  return fbuffer_to_s(buffer);
921
1066
  }
922
1067
 
923
- /*
924
- * This function returns true if string is either a JSON array or JSON object.
925
- * It might suffer from false positives, e. g. syntactically incorrect JSON in
926
- * the string or certain UTF-8 characters on the right hand side.
927
- */
928
- static int isArrayOrObject(VALUE string)
929
- {
930
- long string_len = RSTRING_LEN(string);
931
- char *p = RSTRING_PTR(string), *q = p + string_len - 1;
932
- if (string_len < 2) return 0;
933
- for (; p < q && isspace((unsigned char)*p); p++);
934
- for (; q > p && isspace((unsigned char)*q); q--);
935
- return (*p == '[' && *q == ']') || (*p == '{' && *q == '}');
936
- }
937
-
938
1068
  /*
939
1069
  * call-seq: generate(obj)
940
1070
  *
@@ -946,9 +1076,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
946
1076
  {
947
1077
  VALUE result = cState_partial_generate(self, obj);
948
1078
  GET_STATE(self);
949
- if (!state->quirks_mode && !isArrayOrObject(result)) {
950
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
951
- }
1079
+ (void)state;
952
1080
  return result;
953
1081
  }
954
1082
 
@@ -967,8 +1095,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
967
1095
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
968
1096
  * generated, otherwise an exception is thrown, if these values are
969
1097
  * encountered. This options defaults to false.
970
- * * *quirks_mode*: Enables quirks_mode for parser, that is for example
971
- * generating single JSON values instead of documents is possible.
1098
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1099
+ * option defaults to false.
972
1100
  * * *buffer_initial_length*: sets the initial length of the generator's
973
1101
  * internal buffer.
974
1102
  */
@@ -1024,10 +1152,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1024
1152
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1025
1153
  return rb_funcall(self, i_new, 1, opts);
1026
1154
  } else {
1027
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
1028
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1029
- }
1030
- return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
1155
+ VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1156
+ return rb_funcall(prototype, i_dup, 0);
1031
1157
  }
1032
1158
  }
1033
1159
 
@@ -1061,7 +1187,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1061
1187
  }
1062
1188
  } else {
1063
1189
  if (state->indent) ruby_xfree(state->indent);
1064
- state->indent = strdup(RSTRING_PTR(indent));
1190
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1065
1191
  state->indent_len = len;
1066
1192
  }
1067
1193
  return Qnil;
@@ -1099,7 +1225,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1099
1225
  }
1100
1226
  } else {
1101
1227
  if (state->space) ruby_xfree(state->space);
1102
- state->space = strdup(RSTRING_PTR(space));
1228
+ state->space = fstrndup(RSTRING_PTR(space), len);
1103
1229
  state->space_len = len;
1104
1230
  }
1105
1231
  return Qnil;
@@ -1135,7 +1261,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1135
1261
  }
1136
1262
  } else {
1137
1263
  if (state->space_before) ruby_xfree(state->space_before);
1138
- state->space_before = strdup(RSTRING_PTR(space_before));
1264
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1139
1265
  state->space_before_len = len;
1140
1266
  }
1141
1267
  return Qnil;
@@ -1172,7 +1298,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1172
1298
  }
1173
1299
  } else {
1174
1300
  if (state->object_nl) ruby_xfree(state->object_nl);
1175
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1301
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1176
1302
  state->object_nl_len = len;
1177
1303
  }
1178
1304
  return Qnil;
@@ -1207,7 +1333,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1207
1333
  }
1208
1334
  } else {
1209
1335
  if (state->array_nl) ruby_xfree(state->array_nl);
1210
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1336
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1211
1337
  state->array_nl_len = len;
1212
1338
  }
1213
1339
  return Qnil;
@@ -1266,7 +1392,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1266
1392
  /*
1267
1393
  * call-seq: ascii_only?
1268
1394
  *
1269
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1395
+ * Returns true, if only ASCII characters should be generated. Otherwise
1270
1396
  * returns false.
1271
1397
  */
1272
1398
  static VALUE cState_ascii_only_p(VALUE self)
@@ -1275,29 +1401,6 @@ static VALUE cState_ascii_only_p(VALUE self)
1275
1401
  return state->ascii_only ? Qtrue : Qfalse;
1276
1402
  }
1277
1403
 
1278
- /*
1279
- * call-seq: quirks_mode?
1280
- *
1281
- * Returns true, if quirks mode is enabled. Otherwise returns false.
1282
- */
1283
- static VALUE cState_quirks_mode_p(VALUE self)
1284
- {
1285
- GET_STATE(self);
1286
- return state->quirks_mode ? Qtrue : Qfalse;
1287
- }
1288
-
1289
- /*
1290
- * call-seq: quirks_mode=(enable)
1291
- *
1292
- * If set to true, enables the quirks_mode mode.
1293
- */
1294
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1295
- {
1296
- GET_STATE(self);
1297
- state->quirks_mode = RTEST(enable);
1298
- return Qnil;
1299
- }
1300
-
1301
1404
  /*
1302
1405
  * call-seq: depth
1303
1406
  *
@@ -1357,6 +1460,7 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1357
1460
  */
1358
1461
  void Init_generator(void)
1359
1462
  {
1463
+ #undef rb_intern
1360
1464
  rb_require("json/common");
1361
1465
 
1362
1466
  mJSON = rb_define_module("JSON");
@@ -1365,6 +1469,8 @@ void Init_generator(void)
1365
1469
 
1366
1470
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1367
1471
  eNestingError = rb_path2class("JSON::NestingError");
1472
+ rb_gc_register_mark_object(eGeneratorError);
1473
+ rb_gc_register_mark_object(eNestingError);
1368
1474
 
1369
1475
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1370
1476
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1386,9 +1492,6 @@ void Init_generator(void)
1386
1492
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1387
1493
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1388
1494
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
1389
- rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
1390
- rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
1391
- rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
1392
1495
  rb_define_method(cState, "depth", cState_depth, 0);
1393
1496
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1394
1497
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1408,10 +1511,15 @@ void Init_generator(void)
1408
1511
  rb_define_method(mHash, "to_json", mHash_to_json, -1);
1409
1512
  mArray = rb_define_module_under(mGeneratorMethods, "Array");
1410
1513
  rb_define_method(mArray, "to_json", mArray_to_json, -1);
1514
+ #ifdef RUBY_INTEGER_UNIFICATION
1515
+ mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
1516
+ rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
1517
+ #else
1411
1518
  mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
1412
1519
  rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
1413
1520
  mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
1414
1521
  rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
1522
+ #endif
1415
1523
  mFloat = rb_define_module_under(mGeneratorMethods, "Float");
1416
1524
  rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
1417
1525
  mString = rb_define_module_under(mGeneratorMethods, "String");
@@ -1428,7 +1536,6 @@ void Init_generator(void)
1428
1536
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1429
1537
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1430
1538
 
1431
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1432
1539
  i_to_s = rb_intern("to_s");
1433
1540
  i_to_json = rb_intern("to_json");
1434
1541
  i_new = rb_intern("new");
@@ -1440,7 +1547,6 @@ void Init_generator(void)
1440
1547
  i_max_nesting = rb_intern("max_nesting");
1441
1548
  i_allow_nan = rb_intern("allow_nan");
1442
1549
  i_ascii_only = rb_intern("ascii_only");
1443
- i_quirks_mode = rb_intern("quirks_mode");
1444
1550
  i_depth = rb_intern("depth");
1445
1551
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1446
1552
  i_pack = rb_intern("pack");
@@ -1460,5 +1566,4 @@ void Init_generator(void)
1460
1566
  i_encode = rb_intern("encode");
1461
1567
  #endif
1462
1568
  i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1463
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1464
1569
  }