json 1.8.2 → 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 (82) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.travis.yml +9 -9
  4. data/{CHANGES → CHANGES.md} +187 -89
  5. data/Gemfile +10 -6
  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 +41 -40
  10. data/VERSION +1 -1
  11. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  12. data/ext/json/ext/generator/generator.c +145 -110
  13. data/ext/json/ext/generator/generator.h +18 -5
  14. data/ext/json/ext/parser/extconf.rb +3 -0
  15. data/ext/json/ext/parser/parser.c +419 -506
  16. data/ext/json/ext/parser/parser.h +15 -8
  17. data/ext/json/ext/parser/parser.rl +150 -200
  18. data/ext/json/extconf.rb +0 -1
  19. data/java/src/json/ext/ByteListTranscoder.java +1 -2
  20. data/java/src/json/ext/Generator.java +44 -22
  21. data/java/src/json/ext/GeneratorMethods.java +1 -2
  22. data/java/src/json/ext/GeneratorService.java +1 -2
  23. data/java/src/json/ext/GeneratorState.java +3 -56
  24. data/java/src/json/ext/OptionsReader.java +2 -3
  25. data/java/src/json/ext/Parser.java +132 -415
  26. data/java/src/json/ext/Parser.rl +48 -124
  27. data/java/src/json/ext/ParserService.java +1 -2
  28. data/java/src/json/ext/RuntimeInfo.java +1 -6
  29. data/java/src/json/ext/StringDecoder.java +1 -2
  30. data/java/src/json/ext/StringEncoder.java +5 -0
  31. data/java/src/json/ext/Utils.java +1 -2
  32. data/json-java.gemspec +16 -2
  33. data/json.gemspec +0 -0
  34. data/json_pure.gemspec +24 -26
  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 +26 -54
  50. data/lib/json/ext.rb +0 -6
  51. data/lib/json/generic_object.rb +5 -4
  52. data/lib/json/pure/generator.rb +63 -126
  53. data/lib/json/pure/parser.rb +41 -81
  54. data/lib/json/pure.rb +2 -8
  55. data/lib/json/version.rb +2 -1
  56. data/lib/json.rb +1 -0
  57. data/references/rfc7159.txt +899 -0
  58. data/tests/fixtures/obsolete_fail1.json +1 -0
  59. data/tests/{test_json_addition.rb → json_addition_test.rb} +32 -25
  60. data/tests/json_common_interface_test.rb +126 -0
  61. data/tests/json_encoding_test.rb +107 -0
  62. data/tests/json_ext_parser_test.rb +15 -0
  63. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
  64. data/tests/{test_json_generate.rb → json_generator_test.rb} +123 -39
  65. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  66. data/tests/json_parser_test.rb +472 -0
  67. data/tests/json_string_matching_test.rb +38 -0
  68. data/tests/{setup_variant.rb → test_helper.rb} +6 -0
  69. data/tools/diff.sh +18 -0
  70. data/tools/fuzz.rb +1 -9
  71. metadata +30 -47
  72. data/COPYING +0 -58
  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
@@ -87,25 +88,25 @@ if defined?(Gem) and defined?(Gem::PackageTask)
87
88
  s.files = PKG_FILES
88
89
 
89
90
  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'
91
+ s.add_development_dependency 'rake'
92
+ s.add_development_dependency 'test-unit', '~> 2.0'
93
93
 
94
- s.extra_rdoc_files << 'README.rdoc'
94
+ s.extra_rdoc_files << 'README.md'
95
95
  s.rdoc_options <<
96
- '--title' << 'JSON implemention for ruby' << '--main' << 'README.rdoc'
96
+ '--title' << 'JSON implemention for ruby' << '--main' << 'README.md'
97
97
  s.test_files.concat Dir['./tests/test_*.rb']
98
98
 
99
99
  s.author = "Florian Frank"
100
100
  s.email = "flori@ping.de"
101
101
  s.homepage = "http://flori.github.com/#{PKG_NAME}"
102
102
  s.license = 'Ruby'
103
+ s.required_ruby_version = '>= 1.9'
103
104
  end
104
105
 
105
106
  desc 'Creates a json_pure.gemspec file'
106
107
  task :gemspec_pure => :version do
107
108
  File.open('json_pure.gemspec', 'w') do |gemspec|
108
- gemspec.write skip_sdoc(spec_pure.to_ruby)
109
+ gemspec.write spec_pure.to_ruby
109
110
  end
110
111
  end
111
112
 
@@ -125,24 +126,25 @@ if defined?(Gem) and defined?(Gem::PackageTask)
125
126
  s.extensions = FileList['ext/**/extconf.rb']
126
127
 
127
128
  s.require_path = 'lib'
128
- s.add_development_dependency 'permutation'
129
- s.add_development_dependency 'sdoc', '~>0.3.16'
129
+ s.add_development_dependency 'rake'
130
+ s.add_development_dependency 'test-unit', '~> 2.0'
130
131
 
131
- s.extra_rdoc_files << 'README.rdoc'
132
+ s.extra_rdoc_files << 'README.md'
132
133
  s.rdoc_options <<
133
- '--title' << 'JSON implemention for Ruby' << '--main' << 'README.rdoc'
134
+ '--title' << 'JSON implemention for Ruby' << '--main' << 'README.md'
134
135
  s.test_files.concat Dir['./tests/test_*.rb']
135
136
 
136
137
  s.author = "Florian Frank"
137
138
  s.email = "flori@ping.de"
138
139
  s.homepage = "http://flori.github.com/#{PKG_NAME}"
139
140
  s.license = 'Ruby'
141
+ s.required_ruby_version = '>= 1.9'
140
142
  end
141
143
 
142
144
  desc 'Creates a json.gemspec file'
143
145
  task :gemspec_ext => :version do
144
146
  File.open('json.gemspec', 'w') do |gemspec|
145
- gemspec.write skip_sdoc(spec_ext.to_ruby)
147
+ gemspec.write spec_ext.to_ruby
146
148
  end
147
149
  end
148
150
 
@@ -161,6 +163,7 @@ task :version do
161
163
  puts m
162
164
  File.open(File.join('lib', 'json', 'version.rb'), 'w') do |v|
163
165
  v.puts <<EOT
166
+ # frozen_string_literal: false
164
167
  module JSON
165
168
  # JSON version
166
169
  VERSION = '#{PKG_VERSION}'
@@ -173,13 +176,17 @@ EOT
173
176
  end
174
177
  end
175
178
 
179
+ task :check_env do
180
+ ENV.key?('JSON') or fail "JSON env var is required"
181
+ end
182
+
176
183
  desc "Testing library (pure ruby)"
177
- task :test_pure => [ :clean, :do_test_pure ]
184
+ task :test_pure => [ :clean, :check_env, :do_test_pure ]
178
185
 
179
186
  UndocumentedTestTask.new do |t|
180
187
  t.name = 'do_test_pure'
181
- t.libs << 'lib'
182
- t.test_files = FileList['tests/test_*.rb']
188
+ t.libs << 'lib' << 'tests'
189
+ t.test_files = FileList['tests/*_test.rb']
183
190
  t.verbose = true
184
191
  t.options = '-v'
185
192
  end
@@ -198,13 +205,11 @@ namespace :gems do
198
205
  end
199
206
 
200
207
  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
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) }
208
213
  if ENV['JAVA_HOME']
209
214
  warn " *** JAVA_HOME is set to #{ENV['JAVA_HOME'].inspect}"
210
215
  ENV['PATH'] = ENV['PATH'].split(/:/).unshift(java_path = "#{ENV['JAVA_HOME']}/bin") * ':'
@@ -238,7 +243,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
238
243
  classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
239
244
  obj = src.sub(/\.java\Z/, '.class')
240
245
  file obj => src do
241
- sh 'javac', '-classpath', classpath, '-source', '1.5', '-target', '1.5', src
246
+ sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
242
247
  end
243
248
  JAVA_CLASSES << obj
244
249
  end
@@ -257,12 +262,12 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
257
262
  end
258
263
 
259
264
  desc "Testing library (jruby)"
260
- task :test_ext => [ :create_jar, :do_test_ext ]
265
+ task :test_ext => [ :check_env, :create_jar, :do_test_ext ]
261
266
 
262
267
  UndocumentedTestTask.new do |t|
263
268
  t.name = 'do_test_ext'
264
- t.libs << 'lib'
265
- t.test_files = FileList['tests/test_*.rb']
269
+ t.libs << 'lib' << 'tests'
270
+ t.test_files = FileList['tests/*_test.rb']
266
271
  t.verbose = true
267
272
  t.options = '-v'
268
273
  end
@@ -331,21 +336,16 @@ else
331
336
  end
332
337
 
333
338
  desc "Testing library (extension)"
334
- task :test_ext => [ :compile, :do_test_ext ]
339
+ task :test_ext => [ :check_env, :compile, :do_test_ext ]
335
340
 
336
341
  UndocumentedTestTask.new do |t|
337
342
  t.name = 'do_test_ext'
338
- t.libs << 'ext' << 'lib'
339
- t.test_files = FileList['tests/test_*.rb']
343
+ t.libs << 'ext' << 'lib' << 'tests'
344
+ t.test_files = FileList['tests/*_test.rb']
340
345
  t.verbose = true
341
346
  t.options = '-v'
342
347
  end
343
348
 
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
349
  desc "Generate parser with ragel"
350
350
  task :ragel => EXT_PARSER_SRC
351
351
 
@@ -367,6 +367,7 @@ else
367
367
  sh "ragel -x parser.rl | #{RAGEL_CODEGEN} -G2"
368
368
  end
369
369
  src = File.read("parser.c").gsub(/[ \t]+$/, '')
370
+ src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
370
371
  File.open("parser.c", "w") {|f| f.print src}
371
372
  end
372
373
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.2
1
+ 2.3.0
@@ -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
 
@@ -342,6 +353,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
342
353
  GENERATE_JSON(array);
343
354
  }
344
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
345
368
  /*
346
369
  * call-seq: to_json(*)
347
370
  *
@@ -361,6 +384,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
361
384
  {
362
385
  GENERATE_JSON(bignum);
363
386
  }
387
+ #endif
364
388
 
365
389
  /*
366
390
  * call-seq: to_json(*)
@@ -526,17 +550,11 @@ static const rb_data_type_t JSON_Generator_State_type = {
526
550
  };
527
551
  #endif
528
552
 
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
553
  static VALUE cState_s_allocate(VALUE klass)
537
554
  {
538
- JSON_Generator_State *state = State_allocate();
539
- return TypedData_Wrap_Struct(klass, &JSON_Generator_State_type, state);
555
+ JSON_Generator_State *state;
556
+ return TypedData_Make_Struct(klass, JSON_Generator_State,
557
+ &JSON_Generator_State_type, state);
540
558
  }
541
559
 
542
560
  /*
@@ -628,8 +646,6 @@ static VALUE cState_configure(VALUE self, VALUE opts)
628
646
  state->allow_nan = RTEST(tmp);
629
647
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
630
648
  state->ascii_only = RTEST(tmp);
631
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
632
- state->quirks_mode = RTEST(tmp);
633
649
  return self;
634
650
  }
635
651
 
@@ -663,7 +679,6 @@ static VALUE cState_to_h(VALUE self)
663
679
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
664
680
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
665
681
  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
682
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
668
683
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
669
684
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
@@ -681,7 +696,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
681
696
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
682
697
  return rb_funcall(self, i_send, 1, name);
683
698
  } else {
684
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
699
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
685
700
  }
686
701
  }
687
702
 
@@ -704,43 +719,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
704
719
  return Qnil;
705
720
  }
706
721
 
707
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
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)
708
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
+
709
737
  char *object_nl = state->object_nl;
710
738
  long object_nl_len = state->object_nl_len;
711
739
  char *indent = state->indent;
712
740
  long indent_len = state->indent_len;
713
- long max_nesting = state->max_nesting;
714
741
  char *delim = FBUFFER_PTR(state->object_delim);
715
742
  long delim_len = FBUFFER_LEN(state->object_delim);
716
743
  char *delim2 = FBUFFER_PTR(state->object_delim2);
717
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;
718
783
  long depth = ++state->depth;
719
- int i, j;
720
- VALUE key, key_to_s, keys;
784
+ int j;
785
+ struct hash_foreach_arg arg;
786
+
721
787
  if (max_nesting != 0 && depth > max_nesting) {
722
788
  fbuffer_free(buffer);
723
789
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
724
790
  }
725
791
  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
- }
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
+
744
799
  depth = --state->depth;
745
800
  if (object_nl) {
746
801
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -791,11 +846,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
791
846
  fbuffer_append_char(buffer, ']');
792
847
  }
793
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
+
794
858
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
795
859
  {
796
860
  fbuffer_append_char(buffer, '"');
797
861
  #ifdef HAVE_RUBY_ENCODING_H
798
- 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
+ }
799
865
  #endif
800
866
  if (state->ascii_only) {
801
867
  convert_UTF8_to_JSON_ASCII(buffer, obj);
@@ -831,6 +897,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
831
897
  fbuffer_append_str(buffer, tmp);
832
898
  }
833
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
834
909
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
835
910
  {
836
911
  double value = RFLOAT_VALUE(obj);
@@ -864,9 +939,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
864
939
  generate_json_false(buffer, Vstate, state, obj);
865
940
  } else if (obj == Qtrue) {
866
941
  generate_json_true(buffer, Vstate, state, obj);
867
- } else if (klass == rb_cFixnum) {
942
+ } else if (FIXNUM_P(obj)) {
868
943
  generate_json_fixnum(buffer, Vstate, state, obj);
869
- } else if (klass == rb_cBignum) {
944
+ } else if (RB_TYPE_P(obj, T_BIGNUM)) {
870
945
  generate_json_bignum(buffer, Vstate, state, obj);
871
946
  } else if (klass == rb_cFloat) {
872
947
  generate_json_float(buffer, Vstate, state, obj);
@@ -877,7 +952,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
877
952
  } else {
878
953
  tmp = rb_funcall(obj, i_to_s, 0);
879
954
  Check_Type(tmp, T_STRING);
880
- generate_json(buffer, Vstate, state, tmp);
955
+ generate_json_string(buffer, Vstate, state, tmp);
881
956
  }
882
957
  }
883
958
 
@@ -920,21 +995,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
920
995
  return fbuffer_to_s(buffer);
921
996
  }
922
997
 
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
998
  /*
939
999
  * call-seq: generate(obj)
940
1000
  *
@@ -946,9 +1006,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
946
1006
  {
947
1007
  VALUE result = cState_partial_generate(self, obj);
948
1008
  GET_STATE(self);
949
- if (!state->quirks_mode && !isArrayOrObject(result)) {
950
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
951
- }
1009
+ (void)state;
952
1010
  return result;
953
1011
  }
954
1012
 
@@ -967,8 +1025,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
967
1025
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
968
1026
  * generated, otherwise an exception is thrown, if these values are
969
1027
  * 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.
1028
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1029
+ * ontions defaults to false.
972
1030
  * * *buffer_initial_length*: sets the initial length of the generator's
973
1031
  * internal buffer.
974
1032
  */
@@ -1024,10 +1082,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1024
1082
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1025
1083
  return rb_funcall(self, i_new, 1, opts);
1026
1084
  } 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);
1085
+ VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1086
+ return rb_funcall(prototype, i_dup, 0);
1031
1087
  }
1032
1088
  }
1033
1089
 
@@ -1061,7 +1117,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1061
1117
  }
1062
1118
  } else {
1063
1119
  if (state->indent) ruby_xfree(state->indent);
1064
- state->indent = strdup(RSTRING_PTR(indent));
1120
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1065
1121
  state->indent_len = len;
1066
1122
  }
1067
1123
  return Qnil;
@@ -1099,7 +1155,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1099
1155
  }
1100
1156
  } else {
1101
1157
  if (state->space) ruby_xfree(state->space);
1102
- state->space = strdup(RSTRING_PTR(space));
1158
+ state->space = fstrndup(RSTRING_PTR(space), len);
1103
1159
  state->space_len = len;
1104
1160
  }
1105
1161
  return Qnil;
@@ -1135,7 +1191,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1135
1191
  }
1136
1192
  } else {
1137
1193
  if (state->space_before) ruby_xfree(state->space_before);
1138
- state->space_before = strdup(RSTRING_PTR(space_before));
1194
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1139
1195
  state->space_before_len = len;
1140
1196
  }
1141
1197
  return Qnil;
@@ -1172,7 +1228,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1172
1228
  }
1173
1229
  } else {
1174
1230
  if (state->object_nl) ruby_xfree(state->object_nl);
1175
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1231
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1176
1232
  state->object_nl_len = len;
1177
1233
  }
1178
1234
  return Qnil;
@@ -1207,7 +1263,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1207
1263
  }
1208
1264
  } else {
1209
1265
  if (state->array_nl) ruby_xfree(state->array_nl);
1210
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1266
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1211
1267
  state->array_nl_len = len;
1212
1268
  }
1213
1269
  return Qnil;
@@ -1266,7 +1322,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1266
1322
  /*
1267
1323
  * call-seq: ascii_only?
1268
1324
  *
1269
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1325
+ * Returns true, if only ASCII characters should be generated. Otherwise
1270
1326
  * returns false.
1271
1327
  */
1272
1328
  static VALUE cState_ascii_only_p(VALUE self)
@@ -1275,29 +1331,6 @@ static VALUE cState_ascii_only_p(VALUE self)
1275
1331
  return state->ascii_only ? Qtrue : Qfalse;
1276
1332
  }
1277
1333
 
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
1334
  /*
1302
1335
  * call-seq: depth
1303
1336
  *
@@ -1357,6 +1390,7 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1357
1390
  */
1358
1391
  void Init_generator(void)
1359
1392
  {
1393
+ #undef rb_intern
1360
1394
  rb_require("json/common");
1361
1395
 
1362
1396
  mJSON = rb_define_module("JSON");
@@ -1365,6 +1399,8 @@ void Init_generator(void)
1365
1399
 
1366
1400
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1367
1401
  eNestingError = rb_path2class("JSON::NestingError");
1402
+ rb_gc_register_mark_object(eGeneratorError);
1403
+ rb_gc_register_mark_object(eNestingError);
1368
1404
 
1369
1405
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1370
1406
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1386,9 +1422,6 @@ void Init_generator(void)
1386
1422
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1387
1423
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1388
1424
  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
1425
  rb_define_method(cState, "depth", cState_depth, 0);
1393
1426
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1394
1427
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1408,10 +1441,15 @@ void Init_generator(void)
1408
1441
  rb_define_method(mHash, "to_json", mHash_to_json, -1);
1409
1442
  mArray = rb_define_module_under(mGeneratorMethods, "Array");
1410
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
1411
1448
  mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
1412
1449
  rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
1413
1450
  mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
1414
1451
  rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
1452
+ #endif
1415
1453
  mFloat = rb_define_module_under(mGeneratorMethods, "Float");
1416
1454
  rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
1417
1455
  mString = rb_define_module_under(mGeneratorMethods, "String");
@@ -1428,7 +1466,6 @@ void Init_generator(void)
1428
1466
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1429
1467
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1430
1468
 
1431
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1432
1469
  i_to_s = rb_intern("to_s");
1433
1470
  i_to_json = rb_intern("to_json");
1434
1471
  i_new = rb_intern("new");
@@ -1440,7 +1477,6 @@ void Init_generator(void)
1440
1477
  i_max_nesting = rb_intern("max_nesting");
1441
1478
  i_allow_nan = rb_intern("allow_nan");
1442
1479
  i_ascii_only = rb_intern("ascii_only");
1443
- i_quirks_mode = rb_intern("quirks_mode");
1444
1480
  i_depth = rb_intern("depth");
1445
1481
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1446
1482
  i_pack = rb_intern("pack");
@@ -1460,5 +1496,4 @@ void Init_generator(void)
1460
1496
  i_encode = rb_intern("encode");
1461
1497
  #endif
1462
1498
  i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1463
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1464
1499
  }