json 1.8.6 → 2.7.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} +292 -96
  3. data/LICENSE +56 -0
  4. data/README.md +185 -114
  5. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  6. data/ext/json/ext/generator/generator.c +328 -117
  7. data/ext/json/ext/generator/generator.h +8 -8
  8. data/ext/json/ext/parser/extconf.rb +29 -0
  9. data/ext/json/ext/parser/parser.c +540 -569
  10. data/ext/json/ext/parser/parser.h +10 -6
  11. data/ext/json/ext/parser/parser.rl +269 -261
  12. data/ext/json/extconf.rb +1 -1
  13. data/json.gemspec +0 -0
  14. data/lib/json/add/bigdecimal.rb +40 -10
  15. data/lib/json/add/complex.rb +32 -9
  16. data/lib/json/add/core.rb +1 -0
  17. data/lib/json/add/date.rb +27 -7
  18. data/lib/json/add/date_time.rb +26 -9
  19. data/lib/json/add/exception.rb +25 -7
  20. data/lib/json/add/ostruct.rb +32 -9
  21. data/lib/json/add/range.rb +33 -8
  22. data/lib/json/add/rational.rb +30 -8
  23. data/lib/json/add/regexp.rb +28 -10
  24. data/lib/json/add/set.rb +48 -0
  25. data/lib/json/add/struct.rb +29 -7
  26. data/lib/json/add/symbol.rb +28 -5
  27. data/lib/json/add/time.rb +27 -6
  28. data/lib/json/common.rb +402 -188
  29. data/lib/json/ext.rb +0 -6
  30. data/lib/json/generic_object.rb +11 -6
  31. data/lib/json/pure/generator.rb +120 -137
  32. data/lib/json/pure/parser.rb +64 -86
  33. data/lib/json/pure.rb +2 -8
  34. data/lib/json/version.rb +2 -1
  35. data/lib/json.rb +559 -29
  36. metadata +18 -129
  37. data/.gitignore +0 -17
  38. data/.travis.yml +0 -18
  39. data/Gemfile +0 -7
  40. data/README-json-jruby.markdown +0 -33
  41. data/Rakefile +0 -402
  42. data/TODO +0 -1
  43. data/VERSION +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_script_safe, i_escape_slash, i_strict;
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 script_safe)
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(script_safe) {
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 script_safe)
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,41 @@ 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(script_safe) {
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
+
298
+ if (script_safe && c == 0xE2) {
299
+ unsigned char c2 = (unsigned char) *(p+1);
300
+ unsigned char c3 = (unsigned char) *(p+2);
301
+ if (c2 == 0x80 && (c3 == 0xA8 || c3 == 0xA9)) {
302
+ fbuffer_append(buffer, ptr + start, end - start);
303
+ start = end = (end + clen);
304
+ if (c3 == 0xA8) {
305
+ fbuffer_append(buffer, "\\u2028", 6);
306
+ } else {
307
+ fbuffer_append(buffer, "\\u2029", 6);
308
+ }
309
+ continue;
310
+ }
311
+ }
312
+
313
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
314
+ rb_raise(rb_path2class("JSON::GeneratorError"),
315
+ "source sequence is illegal/malformed utf-8");
316
+ }
291
317
  }
292
318
  end += clen;
293
319
  }
@@ -307,7 +333,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
307
333
  char *result;
308
334
  if (len <= 0) return NULL;
309
335
  result = ALLOC_N(char, len);
310
- memccpy(result, ptr, 0, len);
336
+ memcpy(result, ptr, len);
311
337
  return result;
312
338
  }
313
339
 
@@ -323,6 +349,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
323
349
  *
324
350
  */
325
351
 
352
+ /* Explanation of the following: that's the only way to not pollute
353
+ * standard library's docs with GeneratorMethods::<ClassName> which
354
+ * are uninformative and take a large place in a list of classes
355
+ */
356
+
357
+ /*
358
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
359
+ * :nodoc:
360
+ */
361
+
362
+ /*
363
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
364
+ * :nodoc:
365
+ */
366
+
367
+ /*
368
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
369
+ * :nodoc:
370
+ */
371
+
372
+ /*
373
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
374
+ * :nodoc:
375
+ */
376
+
377
+ /*
378
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
379
+ * :nodoc:
380
+ */
381
+
382
+ /*
383
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
384
+ * :nodoc:
385
+ */
386
+
387
+ /*
388
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
389
+ * :nodoc:
390
+ */
391
+
392
+ /*
393
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
394
+ * :nodoc:
395
+ */
396
+
397
+ /*
398
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
399
+ * :nodoc:
400
+ */
401
+
402
+ /*
403
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
404
+ * :nodoc:
405
+ */
406
+
407
+ /*
408
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
409
+ * :nodoc:
410
+ */
411
+
412
+ /*
413
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
414
+ * :nodoc:
415
+ */
416
+
417
+ /*
418
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
419
+ * :nodoc:
420
+ */
421
+
326
422
  /*
327
423
  * call-seq: to_json(state = nil)
328
424
  *
@@ -398,6 +494,7 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
398
494
  */
399
495
  static VALUE mString_included_s(VALUE self, VALUE modul) {
400
496
  VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
497
+ rb_call_super(1, &modul);
401
498
  return result;
402
499
  }
403
500
 
@@ -534,13 +631,18 @@ static size_t State_memsize(const void *ptr)
534
631
  return size;
535
632
  }
536
633
 
634
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
635
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
636
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
637
+ #endif
638
+
537
639
  #ifdef NEW_TYPEDDATA_WRAPPER
538
640
  static const rb_data_type_t JSON_Generator_State_type = {
539
641
  "JSON/Generator/State",
540
642
  {NULL, State_free, State_memsize,},
541
643
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
542
644
  0, 0,
543
- RUBY_TYPED_FREE_IMMEDIATELY,
645
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
544
646
  #endif
545
647
  };
546
648
  #endif
@@ -641,8 +743,14 @@ static VALUE cState_configure(VALUE self, VALUE opts)
641
743
  state->allow_nan = RTEST(tmp);
642
744
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
643
745
  state->ascii_only = RTEST(tmp);
644
- tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
645
- state->quirks_mode = RTEST(tmp);
746
+ tmp = rb_hash_aref(opts, ID2SYM(i_script_safe));
747
+ state->script_safe = RTEST(tmp);
748
+ if (!state->script_safe) {
749
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
750
+ state->script_safe = RTEST(tmp);
751
+ }
752
+ tmp = rb_hash_aref(opts, ID2SYM(i_strict));
753
+ state->strict = RTEST(tmp);
646
754
  return self;
647
755
  }
648
756
 
@@ -676,8 +784,9 @@ static VALUE cState_to_h(VALUE self)
676
784
  rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
677
785
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
678
786
  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
787
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
788
+ rb_hash_aset(result, ID2SYM(i_script_safe), state->script_safe ? Qtrue : Qfalse);
789
+ rb_hash_aset(result, ID2SYM(i_strict), state->strict ? Qtrue : Qfalse);
681
790
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
682
791
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
683
792
  return result;
@@ -694,7 +803,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
694
803
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
695
804
  return rb_funcall(self, i_send, 1, name);
696
805
  } else {
697
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
806
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
698
807
  }
699
808
  }
700
809
 
@@ -717,43 +826,82 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
717
826
  return Qnil;
718
827
  }
719
828
 
720
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
829
+ struct hash_foreach_arg {
830
+ FBuffer *buffer;
831
+ JSON_Generator_State *state;
832
+ VALUE Vstate;
833
+ int iter;
834
+ };
835
+
836
+ static int
837
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
721
838
  {
839
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
840
+ FBuffer *buffer = arg->buffer;
841
+ JSON_Generator_State *state = arg->state;
842
+ VALUE Vstate = arg->Vstate;
843
+
722
844
  char *object_nl = state->object_nl;
723
845
  long object_nl_len = state->object_nl_len;
724
846
  char *indent = state->indent;
725
847
  long indent_len = state->indent_len;
726
- long max_nesting = state->max_nesting;
727
848
  char *delim = FBUFFER_PTR(state->object_delim);
728
849
  long delim_len = FBUFFER_LEN(state->object_delim);
729
850
  char *delim2 = FBUFFER_PTR(state->object_delim2);
730
851
  long delim2_len = FBUFFER_LEN(state->object_delim2);
852
+ long depth = state->depth;
853
+ int j;
854
+ VALUE klass, key_to_s;
855
+
856
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
857
+ if (object_nl) {
858
+ fbuffer_append(buffer, object_nl, object_nl_len);
859
+ }
860
+ if (indent) {
861
+ for (j = 0; j < depth; j++) {
862
+ fbuffer_append(buffer, indent, indent_len);
863
+ }
864
+ }
865
+
866
+ klass = CLASS_OF(key);
867
+ if (klass == rb_cString) {
868
+ key_to_s = key;
869
+ } else if (klass == rb_cSymbol) {
870
+ key_to_s = rb_sym2str(key);
871
+ } else {
872
+ key_to_s = rb_funcall(key, i_to_s, 0);
873
+ }
874
+ Check_Type(key_to_s, T_STRING);
875
+ generate_json(buffer, Vstate, state, key_to_s);
876
+ fbuffer_append(buffer, delim2, delim2_len);
877
+ generate_json(buffer, Vstate, state, val);
878
+
879
+ arg->iter++;
880
+ return ST_CONTINUE;
881
+ }
882
+
883
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
884
+ {
885
+ char *object_nl = state->object_nl;
886
+ long object_nl_len = state->object_nl_len;
887
+ char *indent = state->indent;
888
+ long indent_len = state->indent_len;
889
+ long max_nesting = state->max_nesting;
731
890
  long depth = ++state->depth;
732
- int i, j;
733
- VALUE key, key_to_s, keys;
891
+ int j;
892
+ struct hash_foreach_arg arg;
893
+
734
894
  if (max_nesting != 0 && depth > max_nesting) {
735
- fbuffer_free(buffer);
736
895
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
737
896
  }
738
897
  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
- }
898
+
899
+ arg.buffer = buffer;
900
+ arg.state = state;
901
+ arg.Vstate = Vstate;
902
+ arg.iter = 0;
903
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
904
+
757
905
  depth = --state->depth;
758
906
  if (object_nl) {
759
907
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -778,7 +926,6 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
778
926
  long depth = ++state->depth;
779
927
  int i, j;
780
928
  if (max_nesting != 0 && depth > max_nesting) {
781
- fbuffer_free(buffer);
782
929
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
783
930
  }
784
931
  fbuffer_append_char(buffer, '[');
@@ -804,16 +951,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
804
951
  fbuffer_append_char(buffer, ']');
805
952
  }
806
953
 
954
+ #ifdef HAVE_RUBY_ENCODING_H
955
+ static int enc_utf8_compatible_p(rb_encoding *enc)
956
+ {
957
+ if (enc == rb_usascii_encoding()) return 1;
958
+ if (enc == rb_utf8_encoding()) return 1;
959
+ return 0;
960
+ }
961
+ #endif
962
+
807
963
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
808
964
  {
809
965
  fbuffer_append_char(buffer, '"');
810
966
  #ifdef HAVE_RUBY_ENCODING_H
811
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
967
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
968
+ obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
969
+ }
812
970
  #endif
813
971
  if (state->ascii_only) {
814
- convert_UTF8_to_JSON_ASCII(buffer, obj);
972
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->script_safe);
815
973
  } else {
816
- convert_UTF8_to_JSON(buffer, obj);
974
+ convert_UTF8_to_JSON(buffer, obj, state->script_safe);
817
975
  }
818
976
  fbuffer_append_char(buffer, '"');
819
977
  }
@@ -853,7 +1011,6 @@ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_
853
1011
  generate_json_bignum(buffer, Vstate, state, obj);
854
1012
  }
855
1013
  #endif
856
-
857
1014
  static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
858
1015
  {
859
1016
  double value = RFLOAT_VALUE(obj);
@@ -861,11 +1018,9 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
861
1018
  VALUE tmp = rb_funcall(obj, i_to_s, 0);
862
1019
  if (!allow_nan) {
863
1020
  if (isinf(value)) {
864
- fbuffer_free(buffer);
865
- rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp));
1021
+ rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
866
1022
  } else if (isnan(value)) {
867
- fbuffer_free(buffer);
868
- rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp));
1023
+ rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
869
1024
  }
870
1025
  }
871
1026
  fbuffer_append_str(buffer, tmp);
@@ -893,6 +1048,8 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
893
1048
  generate_json_bignum(buffer, Vstate, state, obj);
894
1049
  } else if (klass == rb_cFloat) {
895
1050
  generate_json_float(buffer, Vstate, state, obj);
1051
+ } else if (state->strict) {
1052
+ rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj)));
896
1053
  } else if (rb_respond_to(obj, i_to_json)) {
897
1054
  tmp = rb_funcall(obj, i_to_json, 1, Vstate);
898
1055
  Check_Type(tmp, T_STRING);
@@ -935,27 +1092,46 @@ static FBuffer *cState_prepare_buffer(VALUE self)
935
1092
  return buffer;
936
1093
  }
937
1094
 
1095
+ struct generate_json_data {
1096
+ FBuffer *buffer;
1097
+ VALUE vstate;
1098
+ JSON_Generator_State *state;
1099
+ VALUE obj;
1100
+ };
1101
+
1102
+ static VALUE generate_json_try(VALUE d)
1103
+ {
1104
+ struct generate_json_data *data = (struct generate_json_data *)d;
1105
+
1106
+ generate_json(data->buffer, data->vstate, data->state, data->obj);
1107
+
1108
+ return Qnil;
1109
+ }
1110
+
1111
+ static VALUE generate_json_rescue(VALUE d, VALUE exc)
1112
+ {
1113
+ struct generate_json_data *data = (struct generate_json_data *)d;
1114
+ fbuffer_free(data->buffer);
1115
+
1116
+ rb_exc_raise(exc);
1117
+
1118
+ return Qundef;
1119
+ }
1120
+
938
1121
  static VALUE cState_partial_generate(VALUE self, VALUE obj)
939
1122
  {
940
1123
  FBuffer *buffer = cState_prepare_buffer(self);
941
1124
  GET_STATE(self);
942
- generate_json(buffer, self, state, obj);
943
- return fbuffer_to_s(buffer);
944
- }
945
1125
 
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 == '}');
1126
+ struct generate_json_data data = {
1127
+ .buffer = buffer,
1128
+ .vstate = self,
1129
+ .state = state,
1130
+ .obj = obj
1131
+ };
1132
+ rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
1133
+
1134
+ return fbuffer_to_s(buffer);
959
1135
  }
960
1136
 
961
1137
  /*
@@ -969,9 +1145,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
969
1145
  {
970
1146
  VALUE result = cState_partial_generate(self, obj);
971
1147
  GET_STATE(self);
972
- if (!state->quirks_mode && !isArrayOrObject(result)) {
973
- rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
974
- }
1148
+ (void)state;
975
1149
  return result;
976
1150
  }
977
1151
 
@@ -990,8 +1164,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
990
1164
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
991
1165
  * generated, otherwise an exception is thrown, if these values are
992
1166
  * 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.
1167
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1168
+ * option defaults to false.
995
1169
  * * *buffer_initial_length*: sets the initial length of the generator's
996
1170
  * internal buffer.
997
1171
  */
@@ -1047,10 +1221,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1047
1221
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1048
1222
  return rb_funcall(self, i_new, 1, opts);
1049
1223
  } 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);
1224
+ return rb_class_new_instance(0, NULL, cState);
1054
1225
  }
1055
1226
  }
1056
1227
 
@@ -1084,7 +1255,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
1084
1255
  }
1085
1256
  } else {
1086
1257
  if (state->indent) ruby_xfree(state->indent);
1087
- state->indent = strdup(RSTRING_PTR(indent));
1258
+ state->indent = fstrndup(RSTRING_PTR(indent), len);
1088
1259
  state->indent_len = len;
1089
1260
  }
1090
1261
  return Qnil;
@@ -1122,7 +1293,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
1122
1293
  }
1123
1294
  } else {
1124
1295
  if (state->space) ruby_xfree(state->space);
1125
- state->space = strdup(RSTRING_PTR(space));
1296
+ state->space = fstrndup(RSTRING_PTR(space), len);
1126
1297
  state->space_len = len;
1127
1298
  }
1128
1299
  return Qnil;
@@ -1158,7 +1329,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1158
1329
  }
1159
1330
  } else {
1160
1331
  if (state->space_before) ruby_xfree(state->space_before);
1161
- state->space_before = strdup(RSTRING_PTR(space_before));
1332
+ state->space_before = fstrndup(RSTRING_PTR(space_before), len);
1162
1333
  state->space_before_len = len;
1163
1334
  }
1164
1335
  return Qnil;
@@ -1195,7 +1366,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1195
1366
  }
1196
1367
  } else {
1197
1368
  if (state->object_nl) ruby_xfree(state->object_nl);
1198
- state->object_nl = strdup(RSTRING_PTR(object_nl));
1369
+ state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
1199
1370
  state->object_nl_len = len;
1200
1371
  }
1201
1372
  return Qnil;
@@ -1230,7 +1401,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1230
1401
  }
1231
1402
  } else {
1232
1403
  if (state->array_nl) ruby_xfree(state->array_nl);
1233
- state->array_nl = strdup(RSTRING_PTR(array_nl));
1404
+ state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
1234
1405
  state->array_nl_len = len;
1235
1406
  }
1236
1407
  return Qnil;
@@ -1275,52 +1446,85 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1275
1446
  }
1276
1447
 
1277
1448
  /*
1278
- * call-seq: allow_nan?
1449
+ * call-seq: script_safe
1279
1450
  *
1280
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1281
- * returns false.
1451
+ * If this boolean is true, the forward slashes will be escaped in
1452
+ * the json output.
1282
1453
  */
1283
- static VALUE cState_allow_nan_p(VALUE self)
1454
+ static VALUE cState_script_safe(VALUE self)
1284
1455
  {
1285
1456
  GET_STATE(self);
1286
- return state->allow_nan ? Qtrue : Qfalse;
1457
+ return state->script_safe ? Qtrue : Qfalse;
1287
1458
  }
1288
1459
 
1289
1460
  /*
1290
- * call-seq: ascii_only?
1461
+ * call-seq: script_safe=(enable)
1291
1462
  *
1292
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1293
- * returns false.
1463
+ * This sets whether or not the forward slashes will be escaped in
1464
+ * the json output.
1294
1465
  */
1295
- static VALUE cState_ascii_only_p(VALUE self)
1466
+ static VALUE cState_script_safe_set(VALUE self, VALUE enable)
1296
1467
  {
1297
1468
  GET_STATE(self);
1298
- return state->ascii_only ? Qtrue : Qfalse;
1469
+ state->script_safe = RTEST(enable);
1470
+ return Qnil;
1299
1471
  }
1300
1472
 
1301
1473
  /*
1302
- * call-seq: quirks_mode?
1474
+ * call-seq: strict
1303
1475
  *
1304
- * Returns true, if quirks mode is enabled. Otherwise returns false.
1476
+ * If this boolean is false, types unsupported by the JSON format will
1477
+ * be serialized as strings.
1478
+ * If this boolean is true, types unsupported by the JSON format will
1479
+ * raise a JSON::GeneratorError.
1305
1480
  */
1306
- static VALUE cState_quirks_mode_p(VALUE self)
1481
+ static VALUE cState_strict(VALUE self)
1307
1482
  {
1308
1483
  GET_STATE(self);
1309
- return state->quirks_mode ? Qtrue : Qfalse;
1484
+ return state->strict ? Qtrue : Qfalse;
1310
1485
  }
1311
1486
 
1312
1487
  /*
1313
- * call-seq: quirks_mode=(enable)
1488
+ * call-seq: strict=(enable)
1314
1489
  *
1315
- * If set to true, enables the quirks_mode mode.
1490
+ * This sets whether or not to serialize types unsupported by the
1491
+ * JSON format as strings.
1492
+ * If this boolean is false, types unsupported by the JSON format will
1493
+ * be serialized as strings.
1494
+ * If this boolean is true, types unsupported by the JSON format will
1495
+ * raise a JSON::GeneratorError.
1316
1496
  */
1317
- static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
1497
+ static VALUE cState_strict_set(VALUE self, VALUE enable)
1318
1498
  {
1319
1499
  GET_STATE(self);
1320
- state->quirks_mode = RTEST(enable);
1500
+ state->strict = RTEST(enable);
1321
1501
  return Qnil;
1322
1502
  }
1323
1503
 
1504
+ /*
1505
+ * call-seq: allow_nan?
1506
+ *
1507
+ * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1508
+ * returns false.
1509
+ */
1510
+ static VALUE cState_allow_nan_p(VALUE self)
1511
+ {
1512
+ GET_STATE(self);
1513
+ return state->allow_nan ? Qtrue : Qfalse;
1514
+ }
1515
+
1516
+ /*
1517
+ * call-seq: ascii_only?
1518
+ *
1519
+ * Returns true, if only ASCII characters should be generated. Otherwise
1520
+ * returns false.
1521
+ */
1522
+ static VALUE cState_ascii_only_p(VALUE self)
1523
+ {
1524
+ GET_STATE(self);
1525
+ return state->ascii_only ? Qtrue : Qfalse;
1526
+ }
1527
+
1324
1528
  /*
1325
1529
  * call-seq: depth
1326
1530
  *
@@ -1380,6 +1584,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1380
1584
  */
1381
1585
  void Init_generator(void)
1382
1586
  {
1587
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1588
+ rb_ext_ractor_safe(true);
1589
+ #endif
1590
+
1591
+ #undef rb_intern
1383
1592
  rb_require("json/common");
1384
1593
 
1385
1594
  mJSON = rb_define_module("JSON");
@@ -1388,6 +1597,8 @@ void Init_generator(void)
1388
1597
 
1389
1598
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1390
1599
  eNestingError = rb_path2class("JSON::NestingError");
1600
+ rb_gc_register_mark_object(eGeneratorError);
1601
+ rb_gc_register_mark_object(eNestingError);
1391
1602
 
1392
1603
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1393
1604
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1406,12 +1617,18 @@ void Init_generator(void)
1406
1617
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1407
1618
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1408
1619
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1620
+ rb_define_method(cState, "script_safe", cState_script_safe, 0);
1621
+ rb_define_method(cState, "script_safe?", cState_script_safe, 0);
1622
+ rb_define_method(cState, "script_safe=", cState_script_safe_set, 1);
1623
+ rb_define_alias(cState, "escape_slash", "script_safe");
1624
+ rb_define_alias(cState, "escape_slash?", "script_safe?");
1625
+ rb_define_alias(cState, "escape_slash=", "script_safe=");
1626
+ rb_define_method(cState, "strict", cState_strict, 0);
1627
+ rb_define_method(cState, "strict?", cState_strict, 0);
1628
+ rb_define_method(cState, "strict=", cState_strict_set, 1);
1409
1629
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1410
1630
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1411
1631
  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
1632
  rb_define_method(cState, "depth", cState_depth, 0);
1416
1633
  rb_define_method(cState, "depth=", cState_depth_set, 1);
1417
1634
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
@@ -1456,7 +1673,6 @@ void Init_generator(void)
1456
1673
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1457
1674
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1458
1675
 
1459
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1460
1676
  i_to_s = rb_intern("to_s");
1461
1677
  i_to_json = rb_intern("to_json");
1462
1678
  i_new = rb_intern("new");
@@ -1466,9 +1682,11 @@ void Init_generator(void)
1466
1682
  i_object_nl = rb_intern("object_nl");
1467
1683
  i_array_nl = rb_intern("array_nl");
1468
1684
  i_max_nesting = rb_intern("max_nesting");
1685
+ i_script_safe = rb_intern("script_safe");
1686
+ i_escape_slash = rb_intern("escape_slash");
1687
+ i_strict = rb_intern("strict");
1469
1688
  i_allow_nan = rb_intern("allow_nan");
1470
1689
  i_ascii_only = rb_intern("ascii_only");
1471
- i_quirks_mode = rb_intern("quirks_mode");
1472
1690
  i_depth = rb_intern("depth");
1473
1691
  i_buffer_initial_length = rb_intern("buffer_initial_length");
1474
1692
  i_pack = rb_intern("pack");
@@ -1482,11 +1700,4 @@ void Init_generator(void)
1482
1700
  i_match = rb_intern("match");
1483
1701
  i_keys = rb_intern("keys");
1484
1702
  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
1703
  }