json 1.8.6 → 2.6.2

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 (107) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +248 -98
  3. data/LICENSE +56 -0
  4. data/README.md +188 -108
  5. data/VERSION +1 -1
  6. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  7. data/ext/json/ext/generator/generator.c +227 -111
  8. data/ext/json/ext/generator/generator.h +5 -8
  9. data/ext/json/ext/parser/extconf.rb +29 -0
  10. data/ext/json/ext/parser/parser.c +3022 -1915
  11. data/ext/json/ext/parser/parser.h +10 -6
  12. data/ext/json/ext/parser/parser.rl +206 -183
  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 +73 -124
  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 +20 -127
  38. data/.gitignore +0 -17
  39. data/.travis.yml +0 -18
  40. data/Gemfile +0 -7
  41. data/README-json-jruby.markdown +0 -33
  42. data/Rakefile +0 -402
  43. data/TODO +0 -1
  44. data/data/example.json +0 -1
  45. data/data/index.html +0 -38
  46. data/data/prototype.js +0 -4184
  47. data/diagrams/.keep +0 -0
  48. data/install.rb +0 -23
  49. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  50. data/java/src/json/ext/Generator.java +0 -446
  51. data/java/src/json/ext/GeneratorMethods.java +0 -231
  52. data/java/src/json/ext/GeneratorService.java +0 -42
  53. data/java/src/json/ext/GeneratorState.java +0 -542
  54. data/java/src/json/ext/OptionsReader.java +0 -113
  55. data/java/src/json/ext/Parser.java +0 -2644
  56. data/java/src/json/ext/Parser.rl +0 -968
  57. data/java/src/json/ext/ParserService.java +0 -34
  58. data/java/src/json/ext/RuntimeInfo.java +0 -120
  59. data/java/src/json/ext/StringDecoder.java +0 -166
  60. data/java/src/json/ext/StringEncoder.java +0 -111
  61. data/java/src/json/ext/Utils.java +0 -88
  62. data/json-java.gemspec +0 -38
  63. data/json_pure.gemspec +0 -37
  64. data/lib/json/ext/.keep +0 -0
  65. data/tests/fixtures/fail1.json +0 -1
  66. data/tests/fixtures/fail10.json +0 -1
  67. data/tests/fixtures/fail11.json +0 -1
  68. data/tests/fixtures/fail12.json +0 -1
  69. data/tests/fixtures/fail13.json +0 -1
  70. data/tests/fixtures/fail14.json +0 -1
  71. data/tests/fixtures/fail18.json +0 -1
  72. data/tests/fixtures/fail19.json +0 -1
  73. data/tests/fixtures/fail2.json +0 -1
  74. data/tests/fixtures/fail20.json +0 -1
  75. data/tests/fixtures/fail21.json +0 -1
  76. data/tests/fixtures/fail22.json +0 -1
  77. data/tests/fixtures/fail23.json +0 -1
  78. data/tests/fixtures/fail24.json +0 -1
  79. data/tests/fixtures/fail25.json +0 -1
  80. data/tests/fixtures/fail27.json +0 -2
  81. data/tests/fixtures/fail28.json +0 -2
  82. data/tests/fixtures/fail3.json +0 -1
  83. data/tests/fixtures/fail4.json +0 -1
  84. data/tests/fixtures/fail5.json +0 -1
  85. data/tests/fixtures/fail6.json +0 -1
  86. data/tests/fixtures/fail7.json +0 -1
  87. data/tests/fixtures/fail8.json +0 -1
  88. data/tests/fixtures/fail9.json +0 -1
  89. data/tests/fixtures/pass1.json +0 -56
  90. data/tests/fixtures/pass15.json +0 -1
  91. data/tests/fixtures/pass16.json +0 -1
  92. data/tests/fixtures/pass17.json +0 -1
  93. data/tests/fixtures/pass2.json +0 -1
  94. data/tests/fixtures/pass26.json +0 -1
  95. data/tests/fixtures/pass3.json +0 -6
  96. data/tests/setup_variant.rb +0 -11
  97. data/tests/test_json.rb +0 -519
  98. data/tests/test_json_addition.rb +0 -196
  99. data/tests/test_json_encoding.rb +0 -65
  100. data/tests/test_json_fixtures.rb +0 -35
  101. data/tests/test_json_generate.rb +0 -348
  102. data/tests/test_json_generic_object.rb +0 -75
  103. data/tests/test_json_string_matching.rb +0 -39
  104. data/tests/test_json_unicode.rb +0 -72
  105. data/tools/diff.sh +0 -18
  106. data/tools/fuzz.rb +0 -139
  107. data/tools/server.rb +0 -62
@@ -1,11 +1,6 @@
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
5
  mHash, mArray,
11
6
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -15,14 +10,13 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
10
  #endif
16
11
  mFloat, mString, mString_Extend,
17
12
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
19
- i_SAFE_STATE_PROTOTYPE;
13
+ eNestingError;
20
14
 
21
15
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
16
  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,
17
+ i_pack, i_unpack, i_create_id, i_extend, i_key_p,
24
18
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25
- i_buffer_initial_length, i_dup;
19
+ i_buffer_initial_length, i_dup, i_escape_slash;
26
20
 
27
21
  /*
28
22
  * Copyright 2001-2004 Unicode, Inc.
@@ -130,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
130
124
 
131
125
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
132
126
  * and control characters are JSON escaped. */
133
- 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)
134
128
  {
135
129
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
136
130
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -180,6 +174,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
180
174
  case '"':
181
175
  fbuffer_append(buffer, "\\\"", 2);
182
176
  break;
177
+ case '/':
178
+ if(escape_slash) {
179
+ fbuffer_append(buffer, "\\/", 2);
180
+ break;
181
+ }
183
182
  default:
184
183
  fbuffer_append_char(buffer, (char)ch);
185
184
  break;
@@ -222,13 +221,14 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
222
221
  unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
223
222
  }
224
223
  }
224
+ RB_GC_GUARD(string);
225
225
  }
226
226
 
227
227
  /* Converts string to a JSON string in FBuffer buffer, where only the
228
228
  * characters required by the JSON standard are JSON escaped. The remaining
229
229
  * characters (should be UTF8) are just passed through and appended to the
230
230
  * result. */
231
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
231
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
232
232
  {
233
233
  const char *ptr = RSTRING_PTR(string), *p;
234
234
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -236,6 +236,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
236
236
  int escape_len;
237
237
  unsigned char c;
238
238
  char buf[6] = { '\\', 'u' };
239
+ int ascii_only = rb_enc_str_asciionly_p(string);
239
240
 
240
241
  for (start = 0, end = 0; end < len;) {
241
242
  p = ptr + end;
@@ -278,16 +279,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
278
279
  escape = "\\\"";
279
280
  escape_len = 2;
280
281
  break;
282
+ case '/':
283
+ if(escape_slash) {
284
+ escape = "\\/";
285
+ escape_len = 2;
286
+ break;
287
+ }
281
288
  default:
282
289
  {
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");
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
+ }
291
301
  }
292
302
  end += clen;
293
303
  }
@@ -307,7 +317,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
307
317
  char *result;
308
318
  if (len <= 0) return NULL;
309
319
  result = ALLOC_N(char, len);
310
- memccpy(result, ptr, 0, len);
320
+ memcpy(result, ptr, len);
311
321
  return result;
312
322
  }
313
323
 
@@ -323,6 +333,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
323
333
  *
324
334
  */
325
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
+
326
406
  /*
327
407
  * call-seq: to_json(state = nil)
328
408
  *
@@ -534,13 +614,18 @@ static size_t State_memsize(const void *ptr)
534
614
  return size;
535
615
  }
536
616
 
617
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
618
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
619
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
620
+ #endif
621
+
537
622
  #ifdef NEW_TYPEDDATA_WRAPPER
538
623
  static const rb_data_type_t JSON_Generator_State_type = {
539
624
  "JSON/Generator/State",
540
625
  {NULL, State_free, State_memsize,},
541
626
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
542
627
  0, 0,
543
- RUBY_TYPED_FREE_IMMEDIATELY,
628
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
544
629
  #endif
545
630
  };
546
631
  #endif
@@ -641,8 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
641
726
  state->allow_nan = RTEST(tmp);
642
727
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
643
728
  state->ascii_only = RTEST(tmp);
644
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
645
- state->quirks_mode = RTEST(tmp);
729
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
730
+ state->escape_slash = RTEST(tmp);
646
731
  return self;
647
732
  }
648
733
 
@@ -676,8 +761,8 @@ static VALUE cState_to_h(VALUE self)
676
761
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
677
762
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
678
763
  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
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);
681
766
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
682
767
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
683
768
  return result;
@@ -694,7 +779,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
694
779
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
695
780
  return rb_funcall(self, i_send, 1, name);
696
781
  } else {
697
- 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)));
698
783
  }
699
784
  }
700
785
 
@@ -717,43 +802,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
717
802
  return Qnil;
718
803
  }
719
804
 
720
- 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)
721
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
+
722
820
  char *object_nl = state->object_nl;
723
821
  long object_nl_len = state->object_nl_len;
724
822
  char *indent = state->indent;
725
823
  long indent_len = state->indent_len;
726
- long max_nesting = state->max_nesting;
727
824
  char *delim = FBUFFER_PTR(state->object_delim);
728
825
  long delim_len = FBUFFER_LEN(state->object_delim);
729
826
  char *delim2 = FBUFFER_PTR(state->object_delim2);
730
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;
731
866
  long depth = ++state->depth;
732
- int i, j;
733
- VALUE key, key_to_s, keys;
867
+ int j;
868
+ struct hash_foreach_arg arg;
869
+
734
870
  if (max_nesting != 0 && depth > max_nesting) {
735
871
  fbuffer_free(buffer);
736
872
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
737
873
  }
738
874
  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
- }
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
+
757
882
  depth = --state->depth;
758
883
  if (object_nl) {
759
884
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -804,16 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
804
929
  fbuffer_append_char(buffer, ']');
805
930
  }
806
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
+
807
941
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
808
942
  {
809
943
  fbuffer_append_char(buffer, '"');
810
944
  #ifdef HAVE_RUBY_ENCODING_H
811
- 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
+ }
812
948
  #endif
813
949
  if (state->ascii_only) {
814
- convert_UTF8_to_JSON_ASCII(buffer, obj);
950
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
815
951
  } else {
816
- convert_UTF8_to_JSON(buffer, obj);
952
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
817
953
  }
818
954
  fbuffer_append_char(buffer, '"');
819
955
  }
@@ -853,7 +989,6 @@ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_
853
989
  generate_json_bignum(buffer, Vstate, state, obj);
854
990
  }
855
991
  #endif
856
-
857
992
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
858
993
  {
859
994
  double value = RFLOAT_VALUE(obj);
@@ -943,21 +1078,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
943
1078
  return fbuffer_to_s(buffer);
944
1079
  }
945
1080
 
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
1081
  /*
962
1082
  * call-seq: generate(obj)
963
1083
  *
@@ -969,9 +1089,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
969
1089
  {
970
1090
  VALUE result = cState_partial_generate(self, obj);
971
1091
  GET_STATE(self);
972
- if (!state->quirks_mode && !isArrayOrObject(result)) {
973
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
974
- }
1092
+ (void)state;
975
1093
  return result;
976
1094
  }
977
1095
 
@@ -990,8 +1108,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
990
1108
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
991
1109
  * generated, otherwise an exception is thrown, if these values are
992
1110
  * 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.
1111
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1112
+ * option defaults to false.
995
1113
  * * *buffer_initial_length*: sets the initial length of the generator's
996
1114
  * internal buffer.
997
1115
  */
@@ -1047,10 +1165,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1047
1165
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1048
1166
  return rb_funcall(self, i_new, 1, opts);
1049
1167
  } 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);
1168
+ return rb_class_new_instance(0, NULL, cState);
1054
1169
  }
1055
1170
  }
1056
1171
 
@@ -1084,7 +1199,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1084
1199
  }
1085
1200
  } else {
1086
1201
  if (state->indent) ruby_xfree(state->indent);
1087
- state->indent = strdup(RSTRING_PTR(indent));
1202
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1088
1203
  state->indent_len = len;
1089
1204
  }
1090
1205
  return Qnil;
@@ -1122,7 +1237,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1122
1237
  }
1123
1238
  } else {
1124
1239
  if (state->space) ruby_xfree(state->space);
1125
- state->space = strdup(RSTRING_PTR(space));
1240
+ state->space = fstrndup(RSTRING_PTR(space), len);
1126
1241
  state->space_len = len;
1127
1242
  }
1128
1243
  return Qnil;
@@ -1158,7 +1273,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1158
1273
  }
1159
1274
  } else {
1160
1275
  if (state->space_before) ruby_xfree(state->space_before);
1161
- state->space_before = strdup(RSTRING_PTR(space_before));
1276
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1162
1277
  state->space_before_len = len;
1163
1278
  }
1164
1279
  return Qnil;
@@ -1195,7 +1310,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1195
1310
  }
1196
1311
  } else {
1197
1312
  if (state->object_nl) ruby_xfree(state->object_nl);
1198
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1313
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1199
1314
  state->object_nl_len = len;
1200
1315
  }
1201
1316
  return Qnil;
@@ -1230,7 +1345,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1230
1345
  }
1231
1346
  } else {
1232
1347
  if (state->array_nl) ruby_xfree(state->array_nl);
1233
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1348
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1234
1349
  state->array_nl_len = len;
1235
1350
  }
1236
1351
  return Qnil;
@@ -1275,50 +1390,52 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1275
1390
  }
1276
1391
 
1277
1392
  /*
1278
- * call-seq: allow_nan?
1393
+ * call-seq: escape_slash
1279
1394
  *
1280
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1281
- * returns false.
1395
+ * If this boolean is true, the forward slashes will be escaped in
1396
+ * the json output.
1282
1397
  */
1283
- static VALUE cState_allow_nan_p(VALUE self)
1398
+ static VALUE cState_escape_slash(VALUE self)
1284
1399
  {
1285
1400
  GET_STATE(self);
1286
- return state->allow_nan ? Qtrue : Qfalse;
1401
+ return state->escape_slash ? Qtrue : Qfalse;
1287
1402
  }
1288
1403
 
1289
1404
  /*
1290
- * call-seq: ascii_only?
1405
+ * call-seq: escape_slash=(depth)
1291
1406
  *
1292
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1293
- * returns false.
1407
+ * This sets whether or not the forward slashes will be escaped in
1408
+ * the json output.
1294
1409
  */
1295
- static VALUE cState_ascii_only_p(VALUE self)
1410
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1296
1411
  {
1297
1412
  GET_STATE(self);
1298
- return state->ascii_only ? Qtrue : Qfalse;
1413
+ state->escape_slash = RTEST(enable);
1414
+ return Qnil;
1299
1415
  }
1300
1416
 
1301
1417
  /*
1302
- * call-seq: quirks_mode?
1418
+ * call-seq: allow_nan?
1303
1419
  *
1304
- * 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.
1305
1422
  */
1306
- static VALUE cState_quirks_mode_p(VALUE self)
1423
+ static VALUE cState_allow_nan_p(VALUE self)
1307
1424
  {
1308
1425
  GET_STATE(self);
1309
- return state->quirks_mode ? Qtrue : Qfalse;
1426
+ return state->allow_nan ? Qtrue : Qfalse;
1310
1427
  }
1311
1428
 
1312
1429
  /*
1313
- * call-seq: quirks_mode=(enable)
1430
+ * call-seq: ascii_only?
1314
1431
  *
1315
- * If set to true, enables the quirks_mode mode.
1432
+ * Returns true, if only ASCII characters should be generated. Otherwise
1433
+ * returns false.
1316
1434
  */
1317
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1435
+ static VALUE cState_ascii_only_p(VALUE self)
1318
1436
  {
1319
1437
  GET_STATE(self);
1320
- state->quirks_mode = RTEST(enable);
1321
- return Qnil;
1438
+ return state->ascii_only ? Qtrue : Qfalse;
1322
1439
  }
1323
1440
 
1324
1441
  /*
@@ -1380,6 +1497,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1380
1497
  */
1381
1498
  void Init_generator(void)
1382
1499
  {
1500
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1501
+ rb_ext_ractor_safe(true);
1502
+ #endif
1503
+
1504
+ #undef rb_intern
1383
1505
  rb_require("json/common");
1384
1506
 
1385
1507
  mJSON = rb_define_module("JSON");
@@ -1388,6 +1510,8 @@ void Init_generator(void)
1388
1510
 
1389
1511
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1390
1512
  eNestingError = rb_path2class("JSON::NestingError");
1513
+ rb_gc_register_mark_object(eGeneratorError);
1514
+ rb_gc_register_mark_object(eNestingError);
1391
1515
 
1392
1516
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1393
1517
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1406,12 +1530,12 @@ void Init_generator(void)
1406
1530
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1407
1531
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1408
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);
1409
1536
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1410
1537
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1411
1538
  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
1539
  rb_define_method(cState, "depth", cState_depth, 0);
1416
1540
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1417
1541
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1456,7 +1580,6 @@ void Init_generator(void)
1456
1580
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1457
1581
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1458
1582
 
1459
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1460
1583
  i_to_s = rb_intern("to_s");
1461
1584
  i_to_json = rb_intern("to_json");
1462
1585
  i_new = rb_intern("new");
@@ -1466,9 +1589,9 @@ void Init_generator(void)
1466
1589
  i_object_nl = rb_intern("object_nl");
1467
1590
  i_array_nl = rb_intern("array_nl");
1468
1591
  i_max_nesting = rb_intern("max_nesting");
1592
+ i_escape_slash = rb_intern("escape_slash");
1469
1593
  i_allow_nan = rb_intern("allow_nan");
1470
1594
  i_ascii_only = rb_intern("ascii_only");
1471
- i_quirks_mode = rb_intern("quirks_mode");
1472
1595
  i_depth = rb_intern("depth");
1473
1596
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1474
1597
  i_pack = rb_intern("pack");
@@ -1482,11 +1605,4 @@ void Init_generator(void)
1482
1605
  i_match = rb_intern("match");
1483
1606
  i_keys = rb_intern("keys");
1484
1607
  i_dup = rb_intern("dup");
1485
- #ifdef HAVE_RUBY_ENCODING_H
1486
- CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
1487
- i_encoding = rb_intern("encoding");
1488
- i_encode = rb_intern("encode");
1489
- #endif
1490
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1491
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1492
1608
  }
@@ -1,7 +1,6 @@
1
1
  #ifndef _GENERATOR_H_
2
2
  #define _GENERATOR_H_
3
3
 
4
- #include <string.h>
5
4
  #include <math.h>
6
5
  #include <ctype.h>
7
6
 
@@ -21,10 +20,6 @@
21
20
  #define rb_obj_instance_variables(object) rb_funcall(object, rb_intern("instance_variables"), 0)
22
21
  #endif
23
22
 
24
- #ifndef RB_TYPE_P
25
- #define RB_TYPE_P(obj, type) (rb_type(obj) == type)
26
- #endif
27
-
28
23
  #define option_given_p(opts, key) RTEST(rb_funcall(opts, i_key_p, 1, key))
29
24
 
30
25
  /* unicode definitions */
@@ -54,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL;
54
49
  static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
55
50
  static void unicode_escape(char *buf, UTF16 character);
56
51
  static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
57
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string);
58
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string);
52
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash);
53
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash);
59
54
  static char *fstrndup(const char *ptr, unsigned long len);
60
55
 
61
56
  /* ruby api and some helpers */
@@ -77,7 +72,7 @@ typedef struct JSON_Generator_StateStruct {
77
72
  long max_nesting;
78
73
  char allow_nan;
79
74
  char ascii_only;
80
- char quirks_mode;
75
+ char escape_slash;
81
76
  long depth;
82
77
  long buffer_initial_length;
83
78
  } JSON_Generator_State;
@@ -156,6 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
156
151
  static VALUE cState_ascii_only_p(VALUE self);
157
152
  static VALUE cState_depth(VALUE self);
158
153
  static VALUE cState_depth_set(VALUE self, VALUE depth);
154
+ static VALUE cState_escape_slash(VALUE self);
155
+ static VALUE cState_escape_slash_set(VALUE self, VALUE depth);
159
156
  static FBuffer *cState_prepare_buffer(VALUE self);
160
157
  #ifndef ZALLOC
161
158
  #define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))