json 1.8.6 → 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 (72) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +11 -5
  4. data/{CHANGES → CHANGES.md} +179 -95
  5. data/Gemfile +10 -3
  6. data/LICENSE +56 -0
  7. data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
  8. data/README.md +171 -107
  9. data/Rakefile +33 -22
  10. data/VERSION +1 -1
  11. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  12. data/ext/json/ext/generator/generator.c +105 -98
  13. data/ext/json/ext/generator/generator.h +0 -6
  14. data/ext/json/ext/parser/extconf.rb +3 -0
  15. data/ext/json/ext/parser/parser.c +376 -480
  16. data/ext/json/ext/parser/parser.h +4 -5
  17. data/ext/json/ext/parser/parser.rl +108 -175
  18. data/ext/json/extconf.rb +0 -1
  19. data/java/src/json/ext/Generator.java +35 -15
  20. data/java/src/json/ext/GeneratorState.java +2 -54
  21. data/java/src/json/ext/OptionsReader.java +1 -1
  22. data/java/src/json/ext/Parser.java +131 -413
  23. data/java/src/json/ext/Parser.rl +47 -122
  24. data/java/src/json/ext/RuntimeInfo.java +0 -4
  25. data/json-java.gemspec +1 -2
  26. data/json.gemspec +0 -0
  27. data/json_pure.gemspec +8 -7
  28. data/lib/json.rb +1 -0
  29. data/lib/json/add/bigdecimal.rb +3 -2
  30. data/lib/json/add/complex.rb +4 -3
  31. data/lib/json/add/core.rb +1 -0
  32. data/lib/json/add/date.rb +1 -1
  33. data/lib/json/add/date_time.rb +1 -1
  34. data/lib/json/add/exception.rb +1 -1
  35. data/lib/json/add/ostruct.rb +3 -3
  36. data/lib/json/add/range.rb +1 -1
  37. data/lib/json/add/rational.rb +3 -2
  38. data/lib/json/add/regexp.rb +3 -3
  39. data/lib/json/add/set.rb +29 -0
  40. data/lib/json/add/struct.rb +1 -1
  41. data/lib/json/add/symbol.rb +1 -1
  42. data/lib/json/add/time.rb +1 -1
  43. data/lib/json/common.rb +26 -54
  44. data/lib/json/ext.rb +0 -6
  45. data/lib/json/generic_object.rb +5 -4
  46. data/lib/json/pure.rb +2 -8
  47. data/lib/json/pure/generator.rb +53 -124
  48. data/lib/json/pure/parser.rb +41 -81
  49. data/lib/json/version.rb +2 -1
  50. data/references/rfc7159.txt +899 -0
  51. data/tests/fixtures/obsolete_fail1.json +1 -0
  52. data/tests/{test_json_addition.rb → json_addition_test.rb} +32 -25
  53. data/tests/json_common_interface_test.rb +126 -0
  54. data/tests/json_encoding_test.rb +107 -0
  55. data/tests/json_ext_parser_test.rb +15 -0
  56. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
  57. data/tests/{test_json_generate.rb → json_generator_test.rb} +112 -39
  58. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  59. data/tests/json_parser_test.rb +472 -0
  60. data/tests/json_string_matching_test.rb +38 -0
  61. data/tests/{setup_variant.rb → test_helper.rb} +6 -0
  62. data/tools/fuzz.rb +1 -9
  63. metadata +22 -37
  64. data/TODO +0 -1
  65. data/data/example.json +0 -1
  66. data/data/index.html +0 -38
  67. data/data/prototype.js +0 -4184
  68. data/tests/fixtures/fail1.json +0 -1
  69. data/tests/test_json.rb +0 -519
  70. data/tests/test_json_encoding.rb +0 -65
  71. data/tests/test_json_string_matching.rb +0 -39
  72. 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
@@ -88,13 +93,14 @@ if defined?(Gem) and defined?(Gem::PackageTask)
88
93
 
89
94
  s.extra_rdoc_files << 'README.md'
90
95
  s.rdoc_options <<
91
- '--title' << 'JSON implemention for Ruby' << '--main' << 'README.md'
96
+ '--title' << 'JSON implemention for ruby' << '--main' << 'README.md'
92
97
  s.test_files.concat Dir['./tests/test_*.rb']
93
98
 
94
99
  s.author = "Florian Frank"
95
100
  s.email = "flori@ping.de"
96
101
  s.homepage = "http://flori.github.com/#{PKG_NAME}"
97
102
  s.license = 'Ruby'
103
+ s.required_ruby_version = '>= 1.9'
98
104
  end
99
105
 
100
106
  desc 'Creates a json_pure.gemspec file'
@@ -132,6 +138,7 @@ if defined?(Gem) and defined?(Gem::PackageTask)
132
138
  s.email = "flori@ping.de"
133
139
  s.homepage = "http://flori.github.com/#{PKG_NAME}"
134
140
  s.license = 'Ruby'
141
+ s.required_ruby_version = '>= 1.9'
135
142
  end
136
143
 
137
144
  desc 'Creates a json.gemspec file'
@@ -156,6 +163,7 @@ task :version do
156
163
  puts m
157
164
  File.open(File.join('lib', 'json', 'version.rb'), 'w') do |v|
158
165
  v.puts <<EOT
166
+ # frozen_string_literal: false
159
167
  module JSON
160
168
  # JSON version
161
169
  VERSION = '#{PKG_VERSION}'
@@ -168,13 +176,17 @@ EOT
168
176
  end
169
177
  end
170
178
 
179
+ task :check_env do
180
+ ENV.key?('JSON') or fail "JSON env var is required"
181
+ end
182
+
171
183
  desc "Testing library (pure ruby)"
172
- task :test_pure => [ :clean, :do_test_pure ]
184
+ task :test_pure => [ :clean, :check_env, :do_test_pure ]
173
185
 
174
186
  UndocumentedTestTask.new do |t|
175
187
  t.name = 'do_test_pure'
176
- t.libs << 'lib'
177
- t.test_files = FileList['tests/test_*.rb']
188
+ t.libs << 'lib' << 'tests'
189
+ t.test_files = FileList['tests/*_test.rb']
178
190
  t.verbose = true
179
191
  t.options = '-v'
180
192
  end
@@ -193,13 +205,11 @@ namespace :gems do
193
205
  end
194
206
 
195
207
  if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
196
- if ENV.key?('JAVA_HOME')
197
- warn " *** JAVA_HOME was set to #{ENV['JAVA_HOME'].inspect}"
198
- elsif File.directory?(local_java = '/usr/local/java/jdk') ||
199
- File.directory?(local_java = '/usr/lib/jvm/java-6-openjdk')
200
- then
201
- ENV['JAVA_HOME'] = local_java
202
- 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) }
203
213
  if ENV['JAVA_HOME']
204
214
  warn " *** JAVA_HOME is set to #{ENV['JAVA_HOME'].inspect}"
205
215
  ENV['PATH'] = ENV['PATH'].split(/:/).unshift(java_path = "#{ENV['JAVA_HOME']}/bin") * ':'
@@ -233,7 +243,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
233
243
  classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
234
244
  obj = src.sub(/\.java\Z/, '.class')
235
245
  file obj => src do
236
- sh 'javac', '-classpath', classpath, '-source', '1.5', '-target', '1.5', src
246
+ sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
237
247
  end
238
248
  JAVA_CLASSES << obj
239
249
  end
@@ -252,12 +262,12 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
252
262
  end
253
263
 
254
264
  desc "Testing library (jruby)"
255
- task :test_ext => [ :create_jar, :do_test_ext ]
265
+ task :test_ext => [ :check_env, :create_jar, :do_test_ext ]
256
266
 
257
267
  UndocumentedTestTask.new do |t|
258
268
  t.name = 'do_test_ext'
259
- t.libs << 'lib'
260
- t.test_files = FileList['tests/test_*.rb']
269
+ t.libs << 'lib' << 'tests'
270
+ t.test_files = FileList['tests/*_test.rb']
261
271
  t.verbose = true
262
272
  t.options = '-v'
263
273
  end
@@ -326,12 +336,12 @@ else
326
336
  end
327
337
 
328
338
  desc "Testing library (extension)"
329
- task :test_ext => [ :compile, :do_test_ext ]
339
+ task :test_ext => [ :check_env, :compile, :do_test_ext ]
330
340
 
331
341
  UndocumentedTestTask.new do |t|
332
342
  t.name = 'do_test_ext'
333
- t.libs << 'ext' << 'lib'
334
- t.test_files = FileList['tests/test_*.rb']
343
+ t.libs << 'ext' << 'lib' << 'tests'
344
+ t.test_files = FileList['tests/*_test.rb']
335
345
  t.verbose = true
336
346
  t.options = '-v'
337
347
  end
@@ -357,6 +367,7 @@ else
357
367
  sh "ragel -x parser.rl | #{RAGEL_CODEGEN} -G2"
358
368
  end
359
369
  src = File.read("parser.c").gsub(/[ \t]+$/, '')
370
+ src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
360
371
  File.open("parser.c", "w") {|f| f.print src}
361
372
  end
362
373
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.6
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
@@ -15,12 +15,12 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
15
  #endif
16
16
  mFloat, mString, mString_Extend,
17
17
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
18
+ eNestingError,
19
19
  i_SAFE_STATE_PROTOTYPE;
20
20
 
21
21
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
22
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
23
- 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,
24
24
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25
25
  i_buffer_initial_length, i_dup;
26
26
 
@@ -222,6 +222,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
222
222
  unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
223
223
  }
224
224
  }
225
+ RB_GC_GUARD(string);
225
226
  }
226
227
 
227
228
  /* Converts string to a JSON string in FBuffer buffer, where only the
@@ -236,6 +237,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
236
237
  int escape_len;
237
238
  unsigned char c;
238
239
  char buf[6] = { '\\', 'u' };
240
+ int ascii_only = rb_enc_str_asciionly_p(string);
239
241
 
240
242
  for (start = 0, end = 0; end < len;) {
241
243
  p = ptr + end;
@@ -280,14 +282,17 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
280
282
  break;
281
283
  default:
282
284
  {
283
- unsigned short clen = trailingBytesForUTF8[c] + 1;
284
- if (end + clen > len) {
285
- rb_raise(rb_path2class("JSON::GeneratorError"),
286
- "partial character in source, but hit end");
287
- }
288
- if (!isLegalUTF8((UTF8 *) p, clen)) {
289
- rb_raise(rb_path2class("JSON::GeneratorError"),
290
- "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
+ }
291
296
  }
292
297
  end += clen;
293
298
  }
@@ -307,7 +312,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
307
312
  char *result;
308
313
  if (len <= 0) return NULL;
309
314
  result = ALLOC_N(char, len);
310
- memccpy(result, ptr, 0, len);
315
+ memcpy(result, ptr, len);
311
316
  return result;
312
317
  }
313
318
 
@@ -641,8 +646,6 @@ static VALUE cState_configure(VALUE self, VALUE opts)
641
646
  state->allow_nan = RTEST(tmp);
642
647
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
643
648
  state->ascii_only = RTEST(tmp);
644
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
645
- state->quirks_mode = RTEST(tmp);
646
649
  return self;
647
650
  }
648
651
 
@@ -676,7 +679,6 @@ static VALUE cState_to_h(VALUE self)
676
679
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
677
680
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
678
681
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
679
- rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
680
682
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
681
683
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
682
684
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
@@ -694,7 +696,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
694
696
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
695
697
  return rb_funcall(self, i_send, 1, name);
696
698
  } else {
697
- 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)));
698
700
  }
699
701
  }
700
702
 
@@ -717,43 +719,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
717
719
  return Qnil;
718
720
  }
719
721
 
720
- 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)
721
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
+
722
737
  char *object_nl = state->object_nl;
723
738
  long object_nl_len = state->object_nl_len;
724
739
  char *indent = state->indent;
725
740
  long indent_len = state->indent_len;
726
- long max_nesting = state->max_nesting;
727
741
  char *delim = FBUFFER_PTR(state->object_delim);
728
742
  long delim_len = FBUFFER_LEN(state->object_delim);
729
743
  char *delim2 = FBUFFER_PTR(state->object_delim2);
730
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;
731
783
  long depth = ++state->depth;
732
- int i, j;
733
- VALUE key, key_to_s, keys;
784
+ int j;
785
+ struct hash_foreach_arg arg;
786
+
734
787
  if (max_nesting != 0 && depth > max_nesting) {
735
788
  fbuffer_free(buffer);
736
789
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
737
790
  }
738
791
  fbuffer_append_char(buffer, '{');
739
- keys = rb_funcall(obj, i_keys, 0);
740
- for(i = 0; i < RARRAY_LEN(keys); i++) {
741
- if (i > 0) fbuffer_append(buffer, delim, delim_len);
742
- if (object_nl) {
743
- fbuffer_append(buffer, object_nl, object_nl_len);
744
- }
745
- if (indent) {
746
- for (j = 0; j < depth; j++) {
747
- fbuffer_append(buffer, indent, indent_len);
748
- }
749
- }
750
- key = rb_ary_entry(keys, i);
751
- key_to_s = rb_funcall(key, i_to_s, 0);
752
- Check_Type(key_to_s, T_STRING);
753
- generate_json(buffer, Vstate, state, key_to_s);
754
- fbuffer_append(buffer, delim2, delim2_len);
755
- generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
756
- }
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
+
757
799
  depth = --state->depth;
758
800
  if (object_nl) {
759
801
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -804,11 +846,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
804
846
  fbuffer_append_char(buffer, ']');
805
847
  }
806
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
+
807
858
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
808
859
  {
809
860
  fbuffer_append_char(buffer, '"');
810
861
  #ifdef HAVE_RUBY_ENCODING_H
811
- 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
+ }
812
865
  #endif
813
866
  if (state->ascii_only) {
814
867
  convert_UTF8_to_JSON_ASCII(buffer, obj);
@@ -853,7 +906,6 @@ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_
853
906
  generate_json_bignum(buffer, Vstate, state, obj);
854
907
  }
855
908
  #endif
856
-
857
909
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
858
910
  {
859
911
  double value = RFLOAT_VALUE(obj);
@@ -943,21 +995,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
943
995
  return fbuffer_to_s(buffer);
944
996
  }
945
997
 
946
- /*
947
- * This function returns true if string is either a JSON array or JSON object.
948
- * It might suffer from false positives, e. g. syntactically incorrect JSON in
949
- * the string or certain UTF-8 characters on the right hand side.
950
- */
951
- static int isArrayOrObject(VALUE string)
952
- {
953
- long string_len = RSTRING_LEN(string);
954
- char *p = RSTRING_PTR(string), *q = p + string_len - 1;
955
- if (string_len < 2) return 0;
956
- for (; p < q && isspace((unsigned char)*p); p++);
957
- for (; q > p && isspace((unsigned char)*q); q--);
958
- return (*p == '[' && *q == ']') || (*p == '{' && *q == '}');
959
- }
960
-
961
998
  /*
962
999
  * call-seq: generate(obj)
963
1000
  *
@@ -969,9 +1006,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
969
1006
  {
970
1007
  VALUE result = cState_partial_generate(self, obj);
971
1008
  GET_STATE(self);
972
- if (!state->quirks_mode && !isArrayOrObject(result)) {
973
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
974
- }
1009
+ (void)state;
975
1010
  return result;
976
1011
  }
977
1012
 
@@ -990,8 +1025,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
990
1025
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
991
1026
  * generated, otherwise an exception is thrown, if these values are
992
1027
  * encountered. This options defaults to false.
993
- * * *quirks_mode*: Enables quirks_mode for parser, that is for example
994
- * 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.
995
1030
  * * *buffer_initial_length*: sets the initial length of the generator's
996
1031
  * internal buffer.
997
1032
  */
@@ -1047,10 +1082,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1047
1082
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1048
1083
  return rb_funcall(self, i_new, 1, opts);
1049
1084
  } else {
1050
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
1051
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1052
- }
1053
- 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);
1054
1087
  }
1055
1088
  }
1056
1089
 
@@ -1084,7 +1117,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1084
1117
  }
1085
1118
  } else {
1086
1119
  if (state->indent) ruby_xfree(state->indent);
1087
- state->indent = strdup(RSTRING_PTR(indent));
1120
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1088
1121
  state->indent_len = len;
1089
1122
  }
1090
1123
  return Qnil;
@@ -1122,7 +1155,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1122
1155
  }
1123
1156
  } else {
1124
1157
  if (state->space) ruby_xfree(state->space);
1125
- state->space = strdup(RSTRING_PTR(space));
1158
+ state->space = fstrndup(RSTRING_PTR(space), len);
1126
1159
  state->space_len = len;
1127
1160
  }
1128
1161
  return Qnil;
@@ -1158,7 +1191,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1158
1191
  }
1159
1192
  } else {
1160
1193
  if (state->space_before) ruby_xfree(state->space_before);
1161
- state->space_before = strdup(RSTRING_PTR(space_before));
1194
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1162
1195
  state->space_before_len = len;
1163
1196
  }
1164
1197
  return Qnil;
@@ -1195,7 +1228,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1195
1228
  }
1196
1229
  } else {
1197
1230
  if (state->object_nl) ruby_xfree(state->object_nl);
1198
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1231
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1199
1232
  state->object_nl_len = len;
1200
1233
  }
1201
1234
  return Qnil;
@@ -1230,7 +1263,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1230
1263
  }
1231
1264
  } else {
1232
1265
  if (state->array_nl) ruby_xfree(state->array_nl);
1233
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1266
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1234
1267
  state->array_nl_len = len;
1235
1268
  }
1236
1269
  return Qnil;
@@ -1289,7 +1322,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1289
1322
  /*
1290
1323
  * call-seq: ascii_only?
1291
1324
  *
1292
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1325
+ * Returns true, if only ASCII characters should be generated. Otherwise
1293
1326
  * returns false.
1294
1327
  */
1295
1328
  static VALUE cState_ascii_only_p(VALUE self)
@@ -1298,29 +1331,6 @@ static VALUE cState_ascii_only_p(VALUE self)
1298
1331
  return state->ascii_only ? Qtrue : Qfalse;
1299
1332
  }
1300
1333
 
1301
- /*
1302
- * call-seq: quirks_mode?
1303
- *
1304
- * Returns true, if quirks mode is enabled. Otherwise returns false.
1305
- */
1306
- static VALUE cState_quirks_mode_p(VALUE self)
1307
- {
1308
- GET_STATE(self);
1309
- return state->quirks_mode ? Qtrue : Qfalse;
1310
- }
1311
-
1312
- /*
1313
- * call-seq: quirks_mode=(enable)
1314
- *
1315
- * If set to true, enables the quirks_mode mode.
1316
- */
1317
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1318
- {
1319
- GET_STATE(self);
1320
- state->quirks_mode = RTEST(enable);
1321
- return Qnil;
1322
- }
1323
-
1324
1334
  /*
1325
1335
  * call-seq: depth
1326
1336
  *
@@ -1380,6 +1390,7 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1380
1390
  */
1381
1391
  void Init_generator(void)
1382
1392
  {
1393
+ #undef rb_intern
1383
1394
  rb_require("json/common");
1384
1395
 
1385
1396
  mJSON = rb_define_module("JSON");
@@ -1388,6 +1399,8 @@ void Init_generator(void)
1388
1399
 
1389
1400
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1390
1401
  eNestingError = rb_path2class("JSON::NestingError");
1402
+ rb_gc_register_mark_object(eGeneratorError);
1403
+ rb_gc_register_mark_object(eNestingError);
1391
1404
 
1392
1405
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1393
1406
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1409,9 +1422,6 @@ void Init_generator(void)
1409
1422
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1410
1423
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1411
1424
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
1412
- rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
1413
- rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
1414
- rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
1415
1425
  rb_define_method(cState, "depth", cState_depth, 0);
1416
1426
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1417
1427
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1456,7 +1466,6 @@ void Init_generator(void)
1456
1466
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1457
1467
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1458
1468
 
1459
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1460
1469
  i_to_s = rb_intern("to_s");
1461
1470
  i_to_json = rb_intern("to_json");
1462
1471
  i_new = rb_intern("new");
@@ -1468,7 +1477,6 @@ void Init_generator(void)
1468
1477
  i_max_nesting = rb_intern("max_nesting");
1469
1478
  i_allow_nan = rb_intern("allow_nan");
1470
1479
  i_ascii_only = rb_intern("ascii_only");
1471
- i_quirks_mode = rb_intern("quirks_mode");
1472
1480
  i_depth = rb_intern("depth");
1473
1481
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1474
1482
  i_pack = rb_intern("pack");
@@ -1488,5 +1496,4 @@ void Init_generator(void)
1488
1496
  i_encode = rb_intern("encode");
1489
1497
  #endif
1490
1498
  i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1491
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1492
1499
  }