json 1.8.3 → 2.5.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 (93) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +241 -90
  3. data/Gemfile +10 -6
  4. data/{COPYING-json-jruby → LICENSE} +5 -6
  5. data/{README.rdoc → README.md} +201 -134
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +264 -104
  9. data/ext/json/ext/generator/generator.h +12 -4
  10. data/ext/json/ext/parser/extconf.rb +28 -0
  11. data/ext/json/ext/parser/parser.c +425 -462
  12. data/ext/json/ext/parser/parser.h +5 -5
  13. data/ext/json/ext/parser/parser.rl +181 -181
  14. data/ext/json/extconf.rb +1 -1
  15. data/json.gemspec +0 -0
  16. data/lib/json.rb +550 -29
  17. data/lib/json/add/bigdecimal.rb +3 -2
  18. data/lib/json/add/complex.rb +4 -4
  19. data/lib/json/add/core.rb +1 -0
  20. data/lib/json/add/date.rb +1 -1
  21. data/lib/json/add/date_time.rb +1 -1
  22. data/lib/json/add/exception.rb +1 -1
  23. data/lib/json/add/ostruct.rb +3 -3
  24. data/lib/json/add/range.rb +1 -1
  25. data/lib/json/add/rational.rb +3 -3
  26. data/lib/json/add/regexp.rb +3 -3
  27. data/lib/json/add/set.rb +29 -0
  28. data/lib/json/add/struct.rb +1 -1
  29. data/lib/json/add/symbol.rb +1 -1
  30. data/lib/json/add/time.rb +1 -1
  31. data/lib/json/common.rb +381 -162
  32. data/lib/json/ext.rb +0 -6
  33. data/lib/json/generic_object.rb +5 -4
  34. data/lib/json/pure.rb +2 -8
  35. data/lib/json/pure/generator.rb +83 -126
  36. data/lib/json/pure/parser.rb +62 -84
  37. data/lib/json/version.rb +2 -1
  38. data/tests/fixtures/fail29.json +1 -0
  39. data/tests/fixtures/fail30.json +1 -0
  40. data/tests/fixtures/fail31.json +1 -0
  41. data/tests/fixtures/fail32.json +1 -0
  42. data/tests/fixtures/obsolete_fail1.json +1 -0
  43. data/tests/{test_json_addition.rb → json_addition_test.rb} +28 -25
  44. data/tests/json_common_interface_test.rb +169 -0
  45. data/tests/json_encoding_test.rb +107 -0
  46. data/tests/json_ext_parser_test.rb +15 -0
  47. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +13 -8
  48. data/tests/{test_json_generate.rb → json_generator_test.rb} +109 -47
  49. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  50. data/tests/json_parser_test.rb +497 -0
  51. data/tests/json_string_matching_test.rb +38 -0
  52. data/tests/lib/core_assertions.rb +763 -0
  53. data/tests/lib/envutil.rb +365 -0
  54. data/tests/lib/find_executable.rb +22 -0
  55. data/tests/lib/helper.rb +4 -0
  56. data/tests/ractor_test.rb +30 -0
  57. data/tests/test_helper.rb +17 -0
  58. metadata +48 -76
  59. data/.gitignore +0 -16
  60. data/.travis.yml +0 -26
  61. data/COPYING +0 -58
  62. data/GPL +0 -340
  63. data/README-json-jruby.markdown +0 -33
  64. data/Rakefile +0 -412
  65. data/TODO +0 -1
  66. data/data/example.json +0 -1
  67. data/data/index.html +0 -38
  68. data/data/prototype.js +0 -4184
  69. data/diagrams/.keep +0 -0
  70. data/install.rb +0 -23
  71. data/java/src/json/ext/ByteListTranscoder.java +0 -167
  72. data/java/src/json/ext/Generator.java +0 -444
  73. data/java/src/json/ext/GeneratorMethods.java +0 -232
  74. data/java/src/json/ext/GeneratorService.java +0 -43
  75. data/java/src/json/ext/GeneratorState.java +0 -543
  76. data/java/src/json/ext/OptionsReader.java +0 -114
  77. data/java/src/json/ext/Parser.java +0 -2645
  78. data/java/src/json/ext/Parser.rl +0 -969
  79. data/java/src/json/ext/ParserService.java +0 -35
  80. data/java/src/json/ext/RuntimeInfo.java +0 -121
  81. data/java/src/json/ext/StringDecoder.java +0 -167
  82. data/java/src/json/ext/StringEncoder.java +0 -106
  83. data/java/src/json/ext/Utils.java +0 -89
  84. data/json-java.gemspec +0 -23
  85. data/json_pure.gemspec +0 -40
  86. data/tests/fixtures/fail1.json +0 -1
  87. data/tests/setup_variant.rb +0 -11
  88. data/tests/test_json.rb +0 -553
  89. data/tests/test_json_encoding.rb +0 -65
  90. data/tests/test_json_string_matching.rb +0 -39
  91. data/tests/test_json_unicode.rb +0 -72
  92. data/tools/fuzz.rb +0 -139
  93. data/tools/server.rb +0 -62
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.3
1
+ 2.5.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,16 +7,21 @@ 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,
13
- i_SAFE_STATE_PROTOTYPE;
18
+ eNestingError;
14
19
 
15
20
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
16
21
  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,
22
+ i_pack, i_unpack, i_create_id, i_extend, i_key_p,
18
23
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
19
- i_buffer_initial_length, i_dup;
24
+ i_buffer_initial_length, i_dup, i_escape_slash;
20
25
 
21
26
  /*
22
27
  * Copyright 2001-2004 Unicode, Inc.
@@ -124,7 +129,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
124
129
 
125
130
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
126
131
  * and control characters are JSON escaped. */
127
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
132
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
128
133
  {
129
134
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
130
135
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -174,6 +179,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
174
179
  case '"':
175
180
  fbuffer_append(buffer, "\\\"", 2);
176
181
  break;
182
+ case '/':
183
+ if(escape_slash) {
184
+ fbuffer_append(buffer, "\\/", 2);
185
+ break;
186
+ }
177
187
  default:
178
188
  fbuffer_append_char(buffer, (char)ch);
179
189
  break;
@@ -216,13 +226,14 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
216
226
  unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
217
227
  }
218
228
  }
229
+ RB_GC_GUARD(string);
219
230
  }
220
231
 
221
232
  /* Converts string to a JSON string in FBuffer buffer, where only the
222
233
  * characters required by the JSON standard are JSON escaped. The remaining
223
234
  * characters (should be UTF8) are just passed through and appended to the
224
235
  * result. */
225
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
236
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
226
237
  {
227
238
  const char *ptr = RSTRING_PTR(string), *p;
228
239
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -230,6 +241,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
230
241
  int escape_len;
231
242
  unsigned char c;
232
243
  char buf[6] = { '\\', 'u' };
244
+ int ascii_only = rb_enc_str_asciionly_p(string);
233
245
 
234
246
  for (start = 0, end = 0; end < len;) {
235
247
  p = ptr + end;
@@ -272,16 +284,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
272
284
  escape = "\\\"";
273
285
  escape_len = 2;
274
286
  break;
287
+ case '/':
288
+ if(escape_slash) {
289
+ escape = "\\/";
290
+ escape_len = 2;
291
+ break;
292
+ }
275
293
  default:
276
294
  {
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");
295
+ unsigned short clen = 1;
296
+ if (!ascii_only) {
297
+ clen += trailingBytesForUTF8[c];
298
+ if (end + clen > len) {
299
+ rb_raise(rb_path2class("JSON::GeneratorError"),
300
+ "partial character in source, but hit end");
301
+ }
302
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
303
+ rb_raise(rb_path2class("JSON::GeneratorError"),
304
+ "source sequence is illegal/malformed utf-8");
305
+ }
285
306
  }
286
307
  end += clen;
287
308
  }
@@ -301,7 +322,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
301
322
  char *result;
302
323
  if (len <= 0) return NULL;
303
324
  result = ALLOC_N(char, len);
304
- memccpy(result, ptr, 0, len);
325
+ memcpy(result, ptr, len);
305
326
  return result;
306
327
  }
307
328
 
@@ -317,6 +338,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
317
338
  *
318
339
  */
319
340
 
341
+ /* Explanation of the following: that's the only way to not pollute
342
+ * standard library's docs with GeneratorMethods::<ClassName> which
343
+ * are uninformative and take a large place in a list of classes
344
+ */
345
+
346
+ /*
347
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
348
+ * :nodoc:
349
+ */
350
+
351
+ /*
352
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
353
+ * :nodoc:
354
+ */
355
+
356
+ /*
357
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
358
+ * :nodoc:
359
+ */
360
+
361
+ /*
362
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
363
+ * :nodoc:
364
+ */
365
+
366
+ /*
367
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
368
+ * :nodoc:
369
+ */
370
+
371
+ /*
372
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
373
+ * :nodoc:
374
+ */
375
+
376
+ /*
377
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
378
+ * :nodoc:
379
+ */
380
+
381
+ /*
382
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
383
+ * :nodoc:
384
+ */
385
+
386
+ /*
387
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
388
+ * :nodoc:
389
+ */
390
+
391
+ /*
392
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
393
+ * :nodoc:
394
+ */
395
+
396
+ /*
397
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
398
+ * :nodoc:
399
+ */
400
+
401
+ /*
402
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
403
+ * :nodoc:
404
+ */
405
+
406
+ /*
407
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
408
+ * :nodoc:
409
+ */
410
+
320
411
  /*
321
412
  * call-seq: to_json(state = nil)
322
413
  *
@@ -342,6 +433,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
342
433
  GENERATE_JSON(array);
343
434
  }
344
435
 
436
+ #ifdef RUBY_INTEGER_UNIFICATION
437
+ /*
438
+ * call-seq: to_json(*)
439
+ *
440
+ * Returns a JSON string representation for this Integer number.
441
+ */
442
+ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
443
+ {
444
+ GENERATE_JSON(integer);
445
+ }
446
+
447
+ #else
345
448
  /*
346
449
  * call-seq: to_json(*)
347
450
  *
@@ -361,6 +464,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
361
464
  {
362
465
  GENERATE_JSON(bignum);
363
466
  }
467
+ #endif
364
468
 
365
469
  /*
366
470
  * call-seq: to_json(*)
@@ -515,13 +619,18 @@ static size_t State_memsize(const void *ptr)
515
619
  return size;
516
620
  }
517
621
 
622
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
623
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
624
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
625
+ #endif
626
+
518
627
  #ifdef NEW_TYPEDDATA_WRAPPER
519
628
  static const rb_data_type_t JSON_Generator_State_type = {
520
629
  "JSON/Generator/State",
521
630
  {NULL, State_free, State_memsize,},
522
631
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
523
632
  0, 0,
524
- RUBY_TYPED_FREE_IMMEDIATELY,
633
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
525
634
  #endif
526
635
  };
527
636
  #endif
@@ -622,8 +731,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
622
731
  state->allow_nan = RTEST(tmp);
623
732
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
624
733
  state->ascii_only = RTEST(tmp);
625
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
626
- state->quirks_mode = RTEST(tmp);
734
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
735
+ state->escape_slash = RTEST(tmp);
627
736
  return self;
628
737
  }
629
738
 
@@ -657,8 +766,8 @@ static VALUE cState_to_h(VALUE self)
657
766
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
658
767
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
659
768
  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
769
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
770
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
662
771
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
663
772
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
664
773
  return result;
@@ -675,7 +784,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
675
784
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
676
785
  return rb_funcall(self, i_send, 1, name);
677
786
  } else {
678
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
787
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
679
788
  }
680
789
  }
681
790
 
@@ -698,43 +807,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
698
807
  return Qnil;
699
808
  }
700
809
 
701
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
810
+ struct hash_foreach_arg {
811
+ FBuffer *buffer;
812
+ JSON_Generator_State *state;
813
+ VALUE Vstate;
814
+ int iter;
815
+ };
816
+
817
+ static int
818
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
702
819
  {
820
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
821
+ FBuffer *buffer = arg->buffer;
822
+ JSON_Generator_State *state = arg->state;
823
+ VALUE Vstate = arg->Vstate;
824
+
703
825
  char *object_nl = state->object_nl;
704
826
  long object_nl_len = state->object_nl_len;
705
827
  char *indent = state->indent;
706
828
  long indent_len = state->indent_len;
707
- long max_nesting = state->max_nesting;
708
829
  char *delim = FBUFFER_PTR(state->object_delim);
709
830
  long delim_len = FBUFFER_LEN(state->object_delim);
710
831
  char *delim2 = FBUFFER_PTR(state->object_delim2);
711
832
  long delim2_len = FBUFFER_LEN(state->object_delim2);
833
+ long depth = state->depth;
834
+ int j;
835
+ VALUE klass, key_to_s;
836
+
837
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
838
+ if (object_nl) {
839
+ fbuffer_append(buffer, object_nl, object_nl_len);
840
+ }
841
+ if (indent) {
842
+ for (j = 0; j < depth; j++) {
843
+ fbuffer_append(buffer, indent, indent_len);
844
+ }
845
+ }
846
+
847
+ klass = CLASS_OF(key);
848
+ if (klass == rb_cString) {
849
+ key_to_s = key;
850
+ } else if (klass == rb_cSymbol) {
851
+ key_to_s = rb_id2str(SYM2ID(key));
852
+ } else {
853
+ key_to_s = rb_funcall(key, i_to_s, 0);
854
+ }
855
+ Check_Type(key_to_s, T_STRING);
856
+ generate_json(buffer, Vstate, state, key_to_s);
857
+ fbuffer_append(buffer, delim2, delim2_len);
858
+ generate_json(buffer, Vstate, state, val);
859
+
860
+ arg->iter++;
861
+ return ST_CONTINUE;
862
+ }
863
+
864
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
865
+ {
866
+ char *object_nl = state->object_nl;
867
+ long object_nl_len = state->object_nl_len;
868
+ char *indent = state->indent;
869
+ long indent_len = state->indent_len;
870
+ long max_nesting = state->max_nesting;
712
871
  long depth = ++state->depth;
713
- int i, j;
714
- VALUE key, key_to_s, keys;
872
+ int j;
873
+ struct hash_foreach_arg arg;
874
+
715
875
  if (max_nesting != 0 && depth > max_nesting) {
716
876
  fbuffer_free(buffer);
717
877
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
718
878
  }
719
879
  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
- }
880
+
881
+ arg.buffer = buffer;
882
+ arg.state = state;
883
+ arg.Vstate = Vstate;
884
+ arg.iter = 0;
885
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
886
+
738
887
  depth = --state->depth;
739
888
  if (object_nl) {
740
889
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -785,16 +934,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
785
934
  fbuffer_append_char(buffer, ']');
786
935
  }
787
936
 
937
+ #ifdef HAVE_RUBY_ENCODING_H
938
+ static int enc_utf8_compatible_p(rb_encoding *enc)
939
+ {
940
+ if (enc == rb_usascii_encoding()) return 1;
941
+ if (enc == rb_utf8_encoding()) return 1;
942
+ return 0;
943
+ }
944
+ #endif
945
+
788
946
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
789
947
  {
790
948
  fbuffer_append_char(buffer, '"');
791
949
  #ifdef HAVE_RUBY_ENCODING_H
792
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
950
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
951
+ obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
952
+ }
793
953
  #endif
794
954
  if (state->ascii_only) {
795
- convert_UTF8_to_JSON_ASCII(buffer, obj);
955
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
796
956
  } else {
797
- convert_UTF8_to_JSON(buffer, obj);
957
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
798
958
  }
799
959
  fbuffer_append_char(buffer, '"');
800
960
  }
@@ -825,6 +985,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
825
985
  fbuffer_append_str(buffer, tmp);
826
986
  }
827
987
 
988
+ #ifdef RUBY_INTEGER_UNIFICATION
989
+ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
990
+ {
991
+ if (FIXNUM_P(obj))
992
+ generate_json_fixnum(buffer, Vstate, state, obj);
993
+ else
994
+ generate_json_bignum(buffer, Vstate, state, obj);
995
+ }
996
+ #endif
828
997
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
829
998
  {
830
999
  double value = RFLOAT_VALUE(obj);
@@ -858,9 +1027,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
858
1027
  generate_json_false(buffer, Vstate, state, obj);
859
1028
  } else if (obj == Qtrue) {
860
1029
  generate_json_true(buffer, Vstate, state, obj);
861
- } else if (klass == rb_cFixnum) {
1030
+ } else if (FIXNUM_P(obj)) {
862
1031
  generate_json_fixnum(buffer, Vstate, state, obj);
863
- } else if (klass == rb_cBignum) {
1032
+ } else if (RB_TYPE_P(obj, T_BIGNUM)) {
864
1033
  generate_json_bignum(buffer, Vstate, state, obj);
865
1034
  } else if (klass == rb_cFloat) {
866
1035
  generate_json_float(buffer, Vstate, state, obj);
@@ -871,7 +1040,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
871
1040
  } else {
872
1041
  tmp = rb_funcall(obj, i_to_s, 0);
873
1042
  Check_Type(tmp, T_STRING);
874
- generate_json(buffer, Vstate, state, tmp);
1043
+ generate_json_string(buffer, Vstate, state, tmp);
875
1044
  }
876
1045
  }
877
1046
 
@@ -914,21 +1083,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
914
1083
  return fbuffer_to_s(buffer);
915
1084
  }
916
1085
 
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
1086
  /*
933
1087
  * call-seq: generate(obj)
934
1088
  *
@@ -940,9 +1094,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
940
1094
  {
941
1095
  VALUE result = cState_partial_generate(self, obj);
942
1096
  GET_STATE(self);
943
- if (!state->quirks_mode && !isArrayOrObject(result)) {
944
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
945
- }
1097
+ (void)state;
946
1098
  return result;
947
1099
  }
948
1100
 
@@ -961,8 +1113,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
961
1113
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
962
1114
  * generated, otherwise an exception is thrown, if these values are
963
1115
  * 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.
1116
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1117
+ * option defaults to false.
966
1118
  * * *buffer_initial_length*: sets the initial length of the generator's
967
1119
  * internal buffer.
968
1120
  */
@@ -1018,10 +1170,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1018
1170
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1019
1171
  return rb_funcall(self, i_new, 1, opts);
1020
1172
  } 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);
1173
+ return rb_class_new_instance(0, NULL, cState);
1025
1174
  }
1026
1175
  }
1027
1176
 
@@ -1055,7 +1204,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1055
1204
  }
1056
1205
  } else {
1057
1206
  if (state->indent) ruby_xfree(state->indent);
1058
- state->indent = strdup(RSTRING_PTR(indent));
1207
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1059
1208
  state->indent_len = len;
1060
1209
  }
1061
1210
  return Qnil;
@@ -1093,7 +1242,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1093
1242
  }
1094
1243
  } else {
1095
1244
  if (state->space) ruby_xfree(state->space);
1096
- state->space = strdup(RSTRING_PTR(space));
1245
+ state->space = fstrndup(RSTRING_PTR(space), len);
1097
1246
  state->space_len = len;
1098
1247
  }
1099
1248
  return Qnil;
@@ -1129,7 +1278,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1129
1278
  }
1130
1279
  } else {
1131
1280
  if (state->space_before) ruby_xfree(state->space_before);
1132
- state->space_before = strdup(RSTRING_PTR(space_before));
1281
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1133
1282
  state->space_before_len = len;
1134
1283
  }
1135
1284
  return Qnil;
@@ -1166,7 +1315,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1166
1315
  }
1167
1316
  } else {
1168
1317
  if (state->object_nl) ruby_xfree(state->object_nl);
1169
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1318
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1170
1319
  state->object_nl_len = len;
1171
1320
  }
1172
1321
  return Qnil;
@@ -1201,7 +1350,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1201
1350
  }
1202
1351
  } else {
1203
1352
  if (state->array_nl) ruby_xfree(state->array_nl);
1204
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1353
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1205
1354
  state->array_nl_len = len;
1206
1355
  }
1207
1356
  return Qnil;
@@ -1246,50 +1395,52 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1246
1395
  }
1247
1396
 
1248
1397
  /*
1249
- * call-seq: allow_nan?
1398
+ * call-seq: escape_slash
1250
1399
  *
1251
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1252
- * returns false.
1400
+ * If this boolean is true, the forward slashes will be escaped in
1401
+ * the json output.
1253
1402
  */
1254
- static VALUE cState_allow_nan_p(VALUE self)
1403
+ static VALUE cState_escape_slash(VALUE self)
1255
1404
  {
1256
1405
  GET_STATE(self);
1257
- return state->allow_nan ? Qtrue : Qfalse;
1406
+ return state->escape_slash ? Qtrue : Qfalse;
1258
1407
  }
1259
1408
 
1260
1409
  /*
1261
- * call-seq: ascii_only?
1410
+ * call-seq: escape_slash=(depth)
1262
1411
  *
1263
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1264
- * returns false.
1412
+ * This sets whether or not the forward slashes will be escaped in
1413
+ * the json output.
1265
1414
  */
1266
- static VALUE cState_ascii_only_p(VALUE self)
1415
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1267
1416
  {
1268
1417
  GET_STATE(self);
1269
- return state->ascii_only ? Qtrue : Qfalse;
1418
+ state->escape_slash = RTEST(enable);
1419
+ return Qnil;
1270
1420
  }
1271
1421
 
1272
1422
  /*
1273
- * call-seq: quirks_mode?
1423
+ * call-seq: allow_nan?
1274
1424
  *
1275
- * Returns true, if quirks mode is enabled. Otherwise returns false.
1425
+ * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1426
+ * returns false.
1276
1427
  */
1277
- static VALUE cState_quirks_mode_p(VALUE self)
1428
+ static VALUE cState_allow_nan_p(VALUE self)
1278
1429
  {
1279
1430
  GET_STATE(self);
1280
- return state->quirks_mode ? Qtrue : Qfalse;
1431
+ return state->allow_nan ? Qtrue : Qfalse;
1281
1432
  }
1282
1433
 
1283
1434
  /*
1284
- * call-seq: quirks_mode=(enable)
1435
+ * call-seq: ascii_only?
1285
1436
  *
1286
- * If set to true, enables the quirks_mode mode.
1437
+ * Returns true, if only ASCII characters should be generated. Otherwise
1438
+ * returns false.
1287
1439
  */
1288
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1440
+ static VALUE cState_ascii_only_p(VALUE self)
1289
1441
  {
1290
1442
  GET_STATE(self);
1291
- state->quirks_mode = RTEST(enable);
1292
- return Qnil;
1443
+ return state->ascii_only ? Qtrue : Qfalse;
1293
1444
  }
1294
1445
 
1295
1446
  /*
@@ -1351,6 +1502,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1351
1502
  */
1352
1503
  void Init_generator(void)
1353
1504
  {
1505
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1506
+ rb_ext_ractor_safe(true);
1507
+ #endif
1508
+
1509
+ #undef rb_intern
1354
1510
  rb_require("json/common");
1355
1511
 
1356
1512
  mJSON = rb_define_module("JSON");
@@ -1359,6 +1515,8 @@ void Init_generator(void)
1359
1515
 
1360
1516
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1361
1517
  eNestingError = rb_path2class("JSON::NestingError");
1518
+ rb_gc_register_mark_object(eGeneratorError);
1519
+ rb_gc_register_mark_object(eNestingError);
1362
1520
 
1363
1521
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1364
1522
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1377,12 +1535,12 @@ void Init_generator(void)
1377
1535
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1378
1536
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1379
1537
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1538
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
1539
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
1540
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
1380
1541
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1381
1542
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1382
1543
  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
1544
  rb_define_method(cState, "depth", cState_depth, 0);
1387
1545
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1388
1546
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1402,10 +1560,15 @@ void Init_generator(void)
1402
1560
  rb_define_method(mHash, "to_json", mHash_to_json, -1);
1403
1561
  mArray = rb_define_module_under(mGeneratorMethods, "Array");
1404
1562
  rb_define_method(mArray, "to_json", mArray_to_json, -1);
1563
+ #ifdef RUBY_INTEGER_UNIFICATION
1564
+ mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
1565
+ rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
1566
+ #else
1405
1567
  mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
1406
1568
  rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
1407
1569
  mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
1408
1570
  rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
1571
+ #endif
1409
1572
  mFloat = rb_define_module_under(mGeneratorMethods, "Float");
1410
1573
  rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
1411
1574
  mString = rb_define_module_under(mGeneratorMethods, "String");
@@ -1422,7 +1585,6 @@ void Init_generator(void)
1422
1585
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1423
1586
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1424
1587
 
1425
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1426
1588
  i_to_s = rb_intern("to_s");
1427
1589
  i_to_json = rb_intern("to_json");
1428
1590
  i_new = rb_intern("new");
@@ -1432,9 +1594,9 @@ void Init_generator(void)
1432
1594
  i_object_nl = rb_intern("object_nl");
1433
1595
  i_array_nl = rb_intern("array_nl");
1434
1596
  i_max_nesting = rb_intern("max_nesting");
1597
+ i_escape_slash = rb_intern("escape_slash");
1435
1598
  i_allow_nan = rb_intern("allow_nan");
1436
1599
  i_ascii_only = rb_intern("ascii_only");
1437
- i_quirks_mode = rb_intern("quirks_mode");
1438
1600
  i_depth = rb_intern("depth");
1439
1601
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1440
1602
  i_pack = rb_intern("pack");
@@ -1453,6 +1615,4 @@ void Init_generator(void)
1453
1615
  i_encoding = rb_intern("encoding");
1454
1616
  i_encode = rb_intern("encode");
1455
1617
  #endif
1456
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1457
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1458
1618
  }