json 1.8.3 → 2.6.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 (108) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +244 -93
  3. data/{COPYING-json-jruby → LICENSE} +5 -6
  4. data/{README.rdoc → README.md} +202 -135
  5. data/VERSION +1 -1
  6. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  7. data/ext/json/ext/generator/generator.c +264 -114
  8. data/ext/json/ext/generator/generator.h +12 -4
  9. data/ext/json/ext/parser/extconf.rb +29 -0
  10. data/ext/json/ext/parser/parser.c +3002 -1880
  11. data/ext/json/ext/parser/parser.h +10 -6
  12. data/ext/json/ext/parser/parser.rl +230 -192
  13. data/ext/json/extconf.rb +1 -1
  14. data/json.gemspec +0 -0
  15. data/lib/json/add/bigdecimal.rb +3 -2
  16. data/lib/json/add/complex.rb +4 -4
  17. data/lib/json/add/core.rb +1 -0
  18. data/lib/json/add/date.rb +1 -1
  19. data/lib/json/add/date_time.rb +1 -1
  20. data/lib/json/add/exception.rb +1 -1
  21. data/lib/json/add/ostruct.rb +3 -3
  22. data/lib/json/add/range.rb +1 -1
  23. data/lib/json/add/rational.rb +3 -3
  24. data/lib/json/add/regexp.rb +3 -3
  25. data/lib/json/add/set.rb +29 -0
  26. data/lib/json/add/struct.rb +1 -1
  27. data/lib/json/add/symbol.rb +1 -1
  28. data/lib/json/add/time.rb +1 -1
  29. data/lib/json/common.rb +381 -162
  30. data/lib/json/ext.rb +0 -6
  31. data/lib/json/generic_object.rb +5 -4
  32. data/lib/json/pure/generator.rb +83 -126
  33. data/lib/json/pure/parser.rb +63 -85
  34. data/lib/json/pure.rb +2 -8
  35. data/lib/json/version.rb +2 -1
  36. data/lib/json.rb +550 -29
  37. metadata +23 -132
  38. data/.gitignore +0 -16
  39. data/.travis.yml +0 -26
  40. data/COPYING +0 -58
  41. data/GPL +0 -340
  42. data/Gemfile +0 -10
  43. data/README-json-jruby.markdown +0 -33
  44. data/Rakefile +0 -412
  45. data/TODO +0 -1
  46. data/data/example.json +0 -1
  47. data/data/index.html +0 -38
  48. data/data/prototype.js +0 -4184
  49. data/diagrams/.keep +0 -0
  50. data/install.rb +0 -23
  51. data/java/src/json/ext/ByteListTranscoder.java +0 -167
  52. data/java/src/json/ext/Generator.java +0 -444
  53. data/java/src/json/ext/GeneratorMethods.java +0 -232
  54. data/java/src/json/ext/GeneratorService.java +0 -43
  55. data/java/src/json/ext/GeneratorState.java +0 -543
  56. data/java/src/json/ext/OptionsReader.java +0 -114
  57. data/java/src/json/ext/Parser.java +0 -2645
  58. data/java/src/json/ext/Parser.rl +0 -969
  59. data/java/src/json/ext/ParserService.java +0 -35
  60. data/java/src/json/ext/RuntimeInfo.java +0 -121
  61. data/java/src/json/ext/StringDecoder.java +0 -167
  62. data/java/src/json/ext/StringEncoder.java +0 -106
  63. data/java/src/json/ext/Utils.java +0 -89
  64. data/json-java.gemspec +0 -23
  65. data/json_pure.gemspec +0 -40
  66. data/lib/json/ext/.keep +0 -0
  67. data/tests/fixtures/fail1.json +0 -1
  68. data/tests/fixtures/fail10.json +0 -1
  69. data/tests/fixtures/fail11.json +0 -1
  70. data/tests/fixtures/fail12.json +0 -1
  71. data/tests/fixtures/fail13.json +0 -1
  72. data/tests/fixtures/fail14.json +0 -1
  73. data/tests/fixtures/fail18.json +0 -1
  74. data/tests/fixtures/fail19.json +0 -1
  75. data/tests/fixtures/fail2.json +0 -1
  76. data/tests/fixtures/fail20.json +0 -1
  77. data/tests/fixtures/fail21.json +0 -1
  78. data/tests/fixtures/fail22.json +0 -1
  79. data/tests/fixtures/fail23.json +0 -1
  80. data/tests/fixtures/fail24.json +0 -1
  81. data/tests/fixtures/fail25.json +0 -1
  82. data/tests/fixtures/fail27.json +0 -2
  83. data/tests/fixtures/fail28.json +0 -2
  84. data/tests/fixtures/fail3.json +0 -1
  85. data/tests/fixtures/fail4.json +0 -1
  86. data/tests/fixtures/fail5.json +0 -1
  87. data/tests/fixtures/fail6.json +0 -1
  88. data/tests/fixtures/fail7.json +0 -1
  89. data/tests/fixtures/fail8.json +0 -1
  90. data/tests/fixtures/fail9.json +0 -1
  91. data/tests/fixtures/pass1.json +0 -56
  92. data/tests/fixtures/pass15.json +0 -1
  93. data/tests/fixtures/pass16.json +0 -1
  94. data/tests/fixtures/pass17.json +0 -1
  95. data/tests/fixtures/pass2.json +0 -1
  96. data/tests/fixtures/pass26.json +0 -1
  97. data/tests/fixtures/pass3.json +0 -6
  98. data/tests/setup_variant.rb +0 -11
  99. data/tests/test_json.rb +0 -553
  100. data/tests/test_json_addition.rb +0 -196
  101. data/tests/test_json_encoding.rb +0 -65
  102. data/tests/test_json_fixtures.rb +0 -35
  103. data/tests/test_json_generate.rb +0 -337
  104. data/tests/test_json_generic_object.rb +0 -75
  105. data/tests/test_json_string_matching.rb +0 -39
  106. data/tests/test_json_unicode.rb +0 -72
  107. data/tools/fuzz.rb +0 -139
  108. data/tools/server.rb +0 -62
@@ -1,22 +1,22 @@
1
1
  #include "../fbuffer/fbuffer.h"
2
2
  #include "generator.h"
3
3
 
4
- #ifdef HAVE_RUBY_ENCODING_H
5
- static VALUE CEncoding_UTF_8;
6
- static ID i_encoding, i_encode;
7
- #endif
8
-
9
4
  static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
10
- mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,
5
+ mHash, mArray,
6
+ #ifdef RUBY_INTEGER_UNIFICATION
7
+ mInteger,
8
+ #else
9
+ mFixnum, mBignum,
10
+ #endif
11
+ mFloat, mString, mString_Extend,
11
12
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
12
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
13
- i_SAFE_STATE_PROTOTYPE;
13
+ eNestingError;
14
14
 
15
15
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
16
16
  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,
17
+ i_pack, i_unpack, i_create_id, i_extend, i_key_p,
18
18
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
19
- i_buffer_initial_length, i_dup;
19
+ i_buffer_initial_length, i_dup, i_escape_slash;
20
20
 
21
21
  /*
22
22
  * Copyright 2001-2004 Unicode, Inc.
@@ -124,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
124
124
 
125
125
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
126
126
  * and control characters are JSON escaped. */
127
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
127
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
128
128
  {
129
129
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
130
130
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -174,6 +174,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
174
174
  case '"':
175
175
  fbuffer_append(buffer, "\\\"", 2);
176
176
  break;
177
+ case '/':
178
+ if(escape_slash) {
179
+ fbuffer_append(buffer, "\\/", 2);
180
+ break;
181
+ }
177
182
  default:
178
183
  fbuffer_append_char(buffer, (char)ch);
179
184
  break;
@@ -216,13 +221,14 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
216
221
  unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
217
222
  }
218
223
  }
224
+ RB_GC_GUARD(string);
219
225
  }
220
226
 
221
227
  /* Converts string to a JSON string in FBuffer buffer, where only the
222
228
  * characters required by the JSON standard are JSON escaped. The remaining
223
229
  * characters (should be UTF8) are just passed through and appended to the
224
230
  * result. */
225
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
231
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
226
232
  {
227
233
  const char *ptr = RSTRING_PTR(string), *p;
228
234
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -230,6 +236,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
230
236
  int escape_len;
231
237
  unsigned char c;
232
238
  char buf[6] = { '\\', 'u' };
239
+ int ascii_only = rb_enc_str_asciionly_p(string);
233
240
 
234
241
  for (start = 0, end = 0; end < len;) {
235
242
  p = ptr + end;
@@ -272,16 +279,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
272
279
  escape = "\\\"";
273
280
  escape_len = 2;
274
281
  break;
282
+ case '/':
283
+ if(escape_slash) {
284
+ escape = "\\/";
285
+ escape_len = 2;
286
+ break;
287
+ }
275
288
  default:
276
289
  {
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");
290
+ unsigned short clen = 1;
291
+ if (!ascii_only) {
292
+ clen += trailingBytesForUTF8[c];
293
+ if (end + clen > len) {
294
+ rb_raise(rb_path2class("JSON::GeneratorError"),
295
+ "partial character in source, but hit end");
296
+ }
297
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
298
+ rb_raise(rb_path2class("JSON::GeneratorError"),
299
+ "source sequence is illegal/malformed utf-8");
300
+ }
285
301
  }
286
302
  end += clen;
287
303
  }
@@ -301,7 +317,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
301
317
  char *result;
302
318
  if (len <= 0) return NULL;
303
319
  result = ALLOC_N(char, len);
304
- memccpy(result, ptr, 0, len);
320
+ memcpy(result, ptr, len);
305
321
  return result;
306
322
  }
307
323
 
@@ -317,6 +333,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
317
333
  *
318
334
  */
319
335
 
336
+ /* Explanation of the following: that's the only way to not pollute
337
+ * standard library's docs with GeneratorMethods::<ClassName> which
338
+ * are uninformative and take a large place in a list of classes
339
+ */
340
+
341
+ /*
342
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
343
+ * :nodoc:
344
+ */
345
+
346
+ /*
347
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
348
+ * :nodoc:
349
+ */
350
+
351
+ /*
352
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
353
+ * :nodoc:
354
+ */
355
+
356
+ /*
357
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
358
+ * :nodoc:
359
+ */
360
+
361
+ /*
362
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
363
+ * :nodoc:
364
+ */
365
+
366
+ /*
367
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
368
+ * :nodoc:
369
+ */
370
+
371
+ /*
372
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
373
+ * :nodoc:
374
+ */
375
+
376
+ /*
377
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
378
+ * :nodoc:
379
+ */
380
+
381
+ /*
382
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
383
+ * :nodoc:
384
+ */
385
+
386
+ /*
387
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
388
+ * :nodoc:
389
+ */
390
+
391
+ /*
392
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
393
+ * :nodoc:
394
+ */
395
+
396
+ /*
397
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
398
+ * :nodoc:
399
+ */
400
+
401
+ /*
402
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
403
+ * :nodoc:
404
+ */
405
+
320
406
  /*
321
407
  * call-seq: to_json(state = nil)
322
408
  *
@@ -342,6 +428,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
342
428
  GENERATE_JSON(array);
343
429
  }
344
430
 
431
+ #ifdef RUBY_INTEGER_UNIFICATION
432
+ /*
433
+ * call-seq: to_json(*)
434
+ *
435
+ * Returns a JSON string representation for this Integer number.
436
+ */
437
+ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
438
+ {
439
+ GENERATE_JSON(integer);
440
+ }
441
+
442
+ #else
345
443
  /*
346
444
  * call-seq: to_json(*)
347
445
  *
@@ -361,6 +459,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
361
459
  {
362
460
  GENERATE_JSON(bignum);
363
461
  }
462
+ #endif
364
463
 
365
464
  /*
366
465
  * call-seq: to_json(*)
@@ -515,13 +614,18 @@ static size_t State_memsize(const void *ptr)
515
614
  return size;
516
615
  }
517
616
 
617
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
618
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
619
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
620
+ #endif
621
+
518
622
  #ifdef NEW_TYPEDDATA_WRAPPER
519
623
  static const rb_data_type_t JSON_Generator_State_type = {
520
624
  "JSON/Generator/State",
521
625
  {NULL, State_free, State_memsize,},
522
626
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
523
627
  0, 0,
524
- RUBY_TYPED_FREE_IMMEDIATELY,
628
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
525
629
  #endif
526
630
  };
527
631
  #endif
@@ -622,8 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
622
726
  state->allow_nan = RTEST(tmp);
623
727
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
624
728
  state->ascii_only = RTEST(tmp);
625
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
626
- state->quirks_mode = RTEST(tmp);
729
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
730
+ state->escape_slash = RTEST(tmp);
627
731
  return self;
628
732
  }
629
733
 
@@ -657,8 +761,8 @@ static VALUE cState_to_h(VALUE self)
657
761
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
658
762
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
659
763
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
660
- rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
661
764
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
765
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
662
766
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
663
767
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
664
768
  return result;
@@ -675,7 +779,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
675
779
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
676
780
  return rb_funcall(self, i_send, 1, name);
677
781
  } else {
678
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
782
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
679
783
  }
680
784
  }
681
785
 
@@ -698,43 +802,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
698
802
  return Qnil;
699
803
  }
700
804
 
701
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
805
+ struct hash_foreach_arg {
806
+ FBuffer *buffer;
807
+ JSON_Generator_State *state;
808
+ VALUE Vstate;
809
+ int iter;
810
+ };
811
+
812
+ static int
813
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
702
814
  {
815
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
816
+ FBuffer *buffer = arg->buffer;
817
+ JSON_Generator_State *state = arg->state;
818
+ VALUE Vstate = arg->Vstate;
819
+
703
820
  char *object_nl = state->object_nl;
704
821
  long object_nl_len = state->object_nl_len;
705
822
  char *indent = state->indent;
706
823
  long indent_len = state->indent_len;
707
- long max_nesting = state->max_nesting;
708
824
  char *delim = FBUFFER_PTR(state->object_delim);
709
825
  long delim_len = FBUFFER_LEN(state->object_delim);
710
826
  char *delim2 = FBUFFER_PTR(state->object_delim2);
711
827
  long delim2_len = FBUFFER_LEN(state->object_delim2);
828
+ long depth = state->depth;
829
+ int j;
830
+ VALUE klass, key_to_s;
831
+
832
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
833
+ if (object_nl) {
834
+ fbuffer_append(buffer, object_nl, object_nl_len);
835
+ }
836
+ if (indent) {
837
+ for (j = 0; j < depth; j++) {
838
+ fbuffer_append(buffer, indent, indent_len);
839
+ }
840
+ }
841
+
842
+ klass = CLASS_OF(key);
843
+ if (klass == rb_cString) {
844
+ key_to_s = key;
845
+ } else if (klass == rb_cSymbol) {
846
+ key_to_s = rb_id2str(SYM2ID(key));
847
+ } else {
848
+ key_to_s = rb_funcall(key, i_to_s, 0);
849
+ }
850
+ Check_Type(key_to_s, T_STRING);
851
+ generate_json(buffer, Vstate, state, key_to_s);
852
+ fbuffer_append(buffer, delim2, delim2_len);
853
+ generate_json(buffer, Vstate, state, val);
854
+
855
+ arg->iter++;
856
+ return ST_CONTINUE;
857
+ }
858
+
859
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
860
+ {
861
+ char *object_nl = state->object_nl;
862
+ long object_nl_len = state->object_nl_len;
863
+ char *indent = state->indent;
864
+ long indent_len = state->indent_len;
865
+ long max_nesting = state->max_nesting;
712
866
  long depth = ++state->depth;
713
- int i, j;
714
- VALUE key, key_to_s, keys;
867
+ int j;
868
+ struct hash_foreach_arg arg;
869
+
715
870
  if (max_nesting != 0 && depth > max_nesting) {
716
871
  fbuffer_free(buffer);
717
872
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
718
873
  }
719
874
  fbuffer_append_char(buffer, '{');
720
- keys = rb_funcall(obj, i_keys, 0);
721
- for(i = 0; i < RARRAY_LEN(keys); i++) {
722
- if (i > 0) fbuffer_append(buffer, delim, delim_len);
723
- if (object_nl) {
724
- fbuffer_append(buffer, object_nl, object_nl_len);
725
- }
726
- if (indent) {
727
- for (j = 0; j < depth; j++) {
728
- fbuffer_append(buffer, indent, indent_len);
729
- }
730
- }
731
- key = rb_ary_entry(keys, i);
732
- key_to_s = rb_funcall(key, i_to_s, 0);
733
- Check_Type(key_to_s, T_STRING);
734
- generate_json(buffer, Vstate, state, key_to_s);
735
- fbuffer_append(buffer, delim2, delim2_len);
736
- generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
737
- }
875
+
876
+ arg.buffer = buffer;
877
+ arg.state = state;
878
+ arg.Vstate = Vstate;
879
+ arg.iter = 0;
880
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
881
+
738
882
  depth = --state->depth;
739
883
  if (object_nl) {
740
884
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -785,16 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
785
929
  fbuffer_append_char(buffer, ']');
786
930
  }
787
931
 
932
+ #ifdef HAVE_RUBY_ENCODING_H
933
+ static int enc_utf8_compatible_p(rb_encoding *enc)
934
+ {
935
+ if (enc == rb_usascii_encoding()) return 1;
936
+ if (enc == rb_utf8_encoding()) return 1;
937
+ return 0;
938
+ }
939
+ #endif
940
+
788
941
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
789
942
  {
790
943
  fbuffer_append_char(buffer, '"');
791
944
  #ifdef HAVE_RUBY_ENCODING_H
792
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
945
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
946
+ obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
947
+ }
793
948
  #endif
794
949
  if (state->ascii_only) {
795
- convert_UTF8_to_JSON_ASCII(buffer, obj);
950
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
796
951
  } else {
797
- convert_UTF8_to_JSON(buffer, obj);
952
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
798
953
  }
799
954
  fbuffer_append_char(buffer, '"');
800
955
  }
@@ -825,6 +980,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
825
980
  fbuffer_append_str(buffer, tmp);
826
981
  }
827
982
 
983
+ #ifdef RUBY_INTEGER_UNIFICATION
984
+ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
985
+ {
986
+ if (FIXNUM_P(obj))
987
+ generate_json_fixnum(buffer, Vstate, state, obj);
988
+ else
989
+ generate_json_bignum(buffer, Vstate, state, obj);
990
+ }
991
+ #endif
828
992
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
829
993
  {
830
994
  double value = RFLOAT_VALUE(obj);
@@ -858,9 +1022,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
858
1022
  generate_json_false(buffer, Vstate, state, obj);
859
1023
  } else if (obj == Qtrue) {
860
1024
  generate_json_true(buffer, Vstate, state, obj);
861
- } else if (klass == rb_cFixnum) {
1025
+ } else if (FIXNUM_P(obj)) {
862
1026
  generate_json_fixnum(buffer, Vstate, state, obj);
863
- } else if (klass == rb_cBignum) {
1027
+ } else if (RB_TYPE_P(obj, T_BIGNUM)) {
864
1028
  generate_json_bignum(buffer, Vstate, state, obj);
865
1029
  } else if (klass == rb_cFloat) {
866
1030
  generate_json_float(buffer, Vstate, state, obj);
@@ -871,7 +1035,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
871
1035
  } else {
872
1036
  tmp = rb_funcall(obj, i_to_s, 0);
873
1037
  Check_Type(tmp, T_STRING);
874
- generate_json(buffer, Vstate, state, tmp);
1038
+ generate_json_string(buffer, Vstate, state, tmp);
875
1039
  }
876
1040
  }
877
1041
 
@@ -914,21 +1078,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
914
1078
  return fbuffer_to_s(buffer);
915
1079
  }
916
1080
 
917
- /*
918
- * This function returns true if string is either a JSON array or JSON object.
919
- * It might suffer from false positives, e. g. syntactically incorrect JSON in
920
- * the string or certain UTF-8 characters on the right hand side.
921
- */
922
- static int isArrayOrObject(VALUE string)
923
- {
924
- long string_len = RSTRING_LEN(string);
925
- char *p = RSTRING_PTR(string), *q = p + string_len - 1;
926
- if (string_len < 2) return 0;
927
- for (; p < q && isspace((unsigned char)*p); p++);
928
- for (; q > p && isspace((unsigned char)*q); q--);
929
- return (*p == '[' && *q == ']') || (*p == '{' && *q == '}');
930
- }
931
-
932
1081
  /*
933
1082
  * call-seq: generate(obj)
934
1083
  *
@@ -940,9 +1089,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
940
1089
  {
941
1090
  VALUE result = cState_partial_generate(self, obj);
942
1091
  GET_STATE(self);
943
- if (!state->quirks_mode && !isArrayOrObject(result)) {
944
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
945
- }
1092
+ (void)state;
946
1093
  return result;
947
1094
  }
948
1095
 
@@ -961,8 +1108,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
961
1108
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
962
1109
  * generated, otherwise an exception is thrown, if these values are
963
1110
  * encountered. This options defaults to false.
964
- * * *quirks_mode*: Enables quirks_mode for parser, that is for example
965
- * generating single JSON values instead of documents is possible.
1111
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1112
+ * option defaults to false.
966
1113
  * * *buffer_initial_length*: sets the initial length of the generator's
967
1114
  * internal buffer.
968
1115
  */
@@ -1018,10 +1165,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1018
1165
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1019
1166
  return rb_funcall(self, i_new, 1, opts);
1020
1167
  } else {
1021
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
1022
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1023
- }
1024
- return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
1168
+ return rb_class_new_instance(0, NULL, cState);
1025
1169
  }
1026
1170
  }
1027
1171
 
@@ -1055,7 +1199,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1055
1199
  }
1056
1200
  } else {
1057
1201
  if (state->indent) ruby_xfree(state->indent);
1058
- state->indent = strdup(RSTRING_PTR(indent));
1202
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1059
1203
  state->indent_len = len;
1060
1204
  }
1061
1205
  return Qnil;
@@ -1093,7 +1237,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1093
1237
  }
1094
1238
  } else {
1095
1239
  if (state->space) ruby_xfree(state->space);
1096
- state->space = strdup(RSTRING_PTR(space));
1240
+ state->space = fstrndup(RSTRING_PTR(space), len);
1097
1241
  state->space_len = len;
1098
1242
  }
1099
1243
  return Qnil;
@@ -1129,7 +1273,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1129
1273
  }
1130
1274
  } else {
1131
1275
  if (state->space_before) ruby_xfree(state->space_before);
1132
- state->space_before = strdup(RSTRING_PTR(space_before));
1276
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1133
1277
  state->space_before_len = len;
1134
1278
  }
1135
1279
  return Qnil;
@@ -1166,7 +1310,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1166
1310
  }
1167
1311
  } else {
1168
1312
  if (state->object_nl) ruby_xfree(state->object_nl);
1169
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1313
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1170
1314
  state->object_nl_len = len;
1171
1315
  }
1172
1316
  return Qnil;
@@ -1201,7 +1345,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1201
1345
  }
1202
1346
  } else {
1203
1347
  if (state->array_nl) ruby_xfree(state->array_nl);
1204
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1348
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1205
1349
  state->array_nl_len = len;
1206
1350
  }
1207
1351
  return Qnil;
@@ -1246,50 +1390,52 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1246
1390
  }
1247
1391
 
1248
1392
  /*
1249
- * call-seq: allow_nan?
1393
+ * call-seq: escape_slash
1250
1394
  *
1251
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1252
- * returns false.
1395
+ * If this boolean is true, the forward slashes will be escaped in
1396
+ * the json output.
1253
1397
  */
1254
- static VALUE cState_allow_nan_p(VALUE self)
1398
+ static VALUE cState_escape_slash(VALUE self)
1255
1399
  {
1256
1400
  GET_STATE(self);
1257
- return state->allow_nan ? Qtrue : Qfalse;
1401
+ return state->escape_slash ? Qtrue : Qfalse;
1258
1402
  }
1259
1403
 
1260
1404
  /*
1261
- * call-seq: ascii_only?
1405
+ * call-seq: escape_slash=(depth)
1262
1406
  *
1263
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1264
- * returns false.
1407
+ * This sets whether or not the forward slashes will be escaped in
1408
+ * the json output.
1265
1409
  */
1266
- static VALUE cState_ascii_only_p(VALUE self)
1410
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1267
1411
  {
1268
1412
  GET_STATE(self);
1269
- return state->ascii_only ? Qtrue : Qfalse;
1413
+ state->escape_slash = RTEST(enable);
1414
+ return Qnil;
1270
1415
  }
1271
1416
 
1272
1417
  /*
1273
- * call-seq: quirks_mode?
1418
+ * call-seq: allow_nan?
1274
1419
  *
1275
- * Returns true, if quirks mode is enabled. Otherwise returns false.
1420
+ * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1421
+ * returns false.
1276
1422
  */
1277
- static VALUE cState_quirks_mode_p(VALUE self)
1423
+ static VALUE cState_allow_nan_p(VALUE self)
1278
1424
  {
1279
1425
  GET_STATE(self);
1280
- return state->quirks_mode ? Qtrue : Qfalse;
1426
+ return state->allow_nan ? Qtrue : Qfalse;
1281
1427
  }
1282
1428
 
1283
1429
  /*
1284
- * call-seq: quirks_mode=(enable)
1430
+ * call-seq: ascii_only?
1285
1431
  *
1286
- * If set to true, enables the quirks_mode mode.
1432
+ * Returns true, if only ASCII characters should be generated. Otherwise
1433
+ * returns false.
1287
1434
  */
1288
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1435
+ static VALUE cState_ascii_only_p(VALUE self)
1289
1436
  {
1290
1437
  GET_STATE(self);
1291
- state->quirks_mode = RTEST(enable);
1292
- return Qnil;
1438
+ return state->ascii_only ? Qtrue : Qfalse;
1293
1439
  }
1294
1440
 
1295
1441
  /*
@@ -1351,6 +1497,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1351
1497
  */
1352
1498
  void Init_generator(void)
1353
1499
  {
1500
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1501
+ rb_ext_ractor_safe(true);
1502
+ #endif
1503
+
1504
+ #undef rb_intern
1354
1505
  rb_require("json/common");
1355
1506
 
1356
1507
  mJSON = rb_define_module("JSON");
@@ -1359,6 +1510,8 @@ void Init_generator(void)
1359
1510
 
1360
1511
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1361
1512
  eNestingError = rb_path2class("JSON::NestingError");
1513
+ rb_gc_register_mark_object(eGeneratorError);
1514
+ rb_gc_register_mark_object(eNestingError);
1362
1515
 
1363
1516
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1364
1517
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1377,12 +1530,12 @@ void Init_generator(void)
1377
1530
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1378
1531
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1379
1532
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1533
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
1534
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
1535
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
1380
1536
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1381
1537
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1382
1538
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
1383
- rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
1384
- rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
1385
- rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
1386
1539
  rb_define_method(cState, "depth", cState_depth, 0);
1387
1540
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1388
1541
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1402,10 +1555,15 @@ void Init_generator(void)
1402
1555
  rb_define_method(mHash, "to_json", mHash_to_json, -1);
1403
1556
  mArray = rb_define_module_under(mGeneratorMethods, "Array");
1404
1557
  rb_define_method(mArray, "to_json", mArray_to_json, -1);
1558
+ #ifdef RUBY_INTEGER_UNIFICATION
1559
+ mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
1560
+ rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
1561
+ #else
1405
1562
  mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
1406
1563
  rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
1407
1564
  mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
1408
1565
  rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
1566
+ #endif
1409
1567
  mFloat = rb_define_module_under(mGeneratorMethods, "Float");
1410
1568
  rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
1411
1569
  mString = rb_define_module_under(mGeneratorMethods, "String");
@@ -1422,7 +1580,6 @@ void Init_generator(void)
1422
1580
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1423
1581
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1424
1582
 
1425
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1426
1583
  i_to_s = rb_intern("to_s");
1427
1584
  i_to_json = rb_intern("to_json");
1428
1585
  i_new = rb_intern("new");
@@ -1432,9 +1589,9 @@ void Init_generator(void)
1432
1589
  i_object_nl = rb_intern("object_nl");
1433
1590
  i_array_nl = rb_intern("array_nl");
1434
1591
  i_max_nesting = rb_intern("max_nesting");
1592
+ i_escape_slash = rb_intern("escape_slash");
1435
1593
  i_allow_nan = rb_intern("allow_nan");
1436
1594
  i_ascii_only = rb_intern("ascii_only");
1437
- i_quirks_mode = rb_intern("quirks_mode");
1438
1595
  i_depth = rb_intern("depth");
1439
1596
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1440
1597
  i_pack = rb_intern("pack");
@@ -1448,11 +1605,4 @@ void Init_generator(void)
1448
1605
  i_match = rb_intern("match");
1449
1606
  i_keys = rb_intern("keys");
1450
1607
  i_dup = rb_intern("dup");
1451
- #ifdef HAVE_RUBY_ENCODING_H
1452
- CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
1453
- i_encoding = rb_intern("encoding");
1454
- i_encode = rb_intern("encode");
1455
- #endif
1456
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1457
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1458
1608
  }