json 2.18.1 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb2890db4c527125d27bc7c21fc64d3ac532ffbec8080f89a678daf48c36e09e
4
- data.tar.gz: c4b37d085d05d3c43df97b3c24898dc6be61c76ba64c749b5a8a86bf4fc1198d
3
+ metadata.gz: 2e0f63481c8ba1c4f76f44a86ac9f1814e82fb396125e41e95efddc8e259fe64
4
+ data.tar.gz: a070ae0776f2db0519ec672d3a32be7dee2be2ee10d0bc35c9dde6581ec8c4a8
5
5
  SHA512:
6
- metadata.gz: fb55ef5a0aa6961ef0fe3bb30f398834820357045ad27a8fdb7e53eaba3af7c4d356ef26c0e73b7a87d2d9d51e500eae7193d7d1ae3aa1058c7973bcc462674b
7
- data.tar.gz: bfb499789bbcee7f5f8d67e32ded664dc62c632ae39fe80bf4bff3d6aec16eee3730a7c4883216a393326f2ab33e94e5f9c58da4c5b31627347108c36c2b211c
6
+ metadata.gz: fc49905c26e2173018856dba7c4ae10ef74f015233b607f977b42ceea5f1d9e511f9ad4a7c22d4aed66e4ef8c60ad23a506d8bb0e053c0155ea2f7eb40a82d06
7
+ data.tar.gz: 61c1367d7b91621a34c0fc9fc29802534f14d27c1b9c50ecfa09d68d100fcda840847393063ec4c477437261398c559b93f292d2594bdf1e597c4b5e33959322
data/CHANGES.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ### Unreleased
4
4
 
5
+ ### 2026-03-06 (2.19.0)
6
+
7
+ * Fix `allow_blank` parsing option to no longer allow invalid types (e.g. `load([], allow_blank: true)` now raise a type error).
8
+ * Add `allow_invalid_escape` parsing option to ignore backslashes that aren't followed by one of the valid escape characters.
9
+
5
10
  ### 2026-02-03 (2.18.1)
6
11
 
7
12
  * Fix a potential crash in very specific circumstance if GC triggers during a call to `to_json`
@@ -11,11 +11,11 @@ enum fbuffer_type {
11
11
 
12
12
  typedef struct FBufferStruct {
13
13
  enum fbuffer_type type;
14
- unsigned long initial_length;
15
- unsigned long len;
16
- unsigned long capa;
14
+ size_t initial_length;
15
+ size_t len;
16
+ size_t capa;
17
17
  #if JSON_DEBUG
18
- unsigned long requested;
18
+ size_t requested;
19
19
  #endif
20
20
  char *ptr;
21
21
  VALUE io;
@@ -32,12 +32,12 @@ typedef struct FBufferStruct {
32
32
 
33
33
  static void fbuffer_free(FBuffer *fb);
34
34
  static void fbuffer_clear(FBuffer *fb);
35
- static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
35
+ static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len);
36
36
  static void fbuffer_append_long(FBuffer *fb, long number);
37
37
  static inline void fbuffer_append_char(FBuffer *fb, char newchr);
38
38
  static VALUE fbuffer_finalize(FBuffer *fb);
39
39
 
40
- static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
40
+ static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size)
41
41
  {
42
42
  fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
43
43
  if (stack_buffer) {
@@ -50,7 +50,7 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
50
50
  #endif
51
51
  }
52
52
 
53
- static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
53
+ static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
54
54
  {
55
55
  #if JSON_DEBUG
56
56
  if (consumed > fb->requested) {
@@ -79,7 +79,7 @@ static void fbuffer_flush(FBuffer *fb)
79
79
  fbuffer_clear(fb);
80
80
  }
81
81
 
82
- static void fbuffer_realloc(FBuffer *fb, unsigned long required)
82
+ static void fbuffer_realloc(FBuffer *fb, size_t required)
83
83
  {
84
84
  if (required > fb->capa) {
85
85
  if (fb->type == FBUFFER_STACK_ALLOCATED) {
@@ -94,7 +94,7 @@ static void fbuffer_realloc(FBuffer *fb, unsigned long required)
94
94
  }
95
95
  }
96
96
 
97
- static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
97
+ static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
98
98
  {
99
99
  if (RB_UNLIKELY(fb->io)) {
100
100
  if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
@@ -108,7 +108,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
108
108
  }
109
109
  }
110
110
 
111
- unsigned long required;
111
+ size_t required;
112
112
 
113
113
  if (RB_UNLIKELY(!fb->ptr)) {
114
114
  fb->ptr = ALLOC_N(char, fb->initial_length);
@@ -120,7 +120,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
120
120
  fbuffer_realloc(fb, required);
121
121
  }
122
122
 
123
- static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
123
+ static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
124
124
  {
125
125
  #if JSON_DEBUG
126
126
  fb->requested = requested;
@@ -131,13 +131,13 @@ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
131
131
  }
132
132
  }
133
133
 
134
- static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, unsigned long len)
134
+ static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len)
135
135
  {
136
136
  MEMCPY(fb->ptr + fb->len, newstr, char, len);
137
137
  fbuffer_consumed(fb, len);
138
138
  }
139
139
 
140
- static inline void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
140
+ static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len)
141
141
  {
142
142
  if (len > 0) {
143
143
  fbuffer_inc_capa(fb, len);
@@ -162,7 +162,7 @@ static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
162
162
  static void fbuffer_append_str(FBuffer *fb, VALUE str)
163
163
  {
164
164
  const char *ptr;
165
- unsigned long len;
165
+ size_t len;
166
166
  RSTRING_GETMEM(str, ptr, len);
167
167
 
168
168
  fbuffer_append(fb, ptr, len);
@@ -171,7 +171,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
171
171
  static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
172
172
  {
173
173
  const char *ptr;
174
- unsigned long len;
174
+ size_t len;
175
175
  RSTRING_GETMEM(str, ptr, len);
176
176
 
177
177
  fbuffer_inc_capa(fb, repeat * len);
@@ -74,9 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
74
74
  static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
75
75
  static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
76
76
  static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
77
- #ifdef RUBY_INTEGER_UNIFICATION
78
- static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
79
- #endif
80
77
  static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
81
78
  static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
82
79
  static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
@@ -703,233 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
703
700
  }
704
701
  }
705
702
 
706
- /*
707
- * Document-module: JSON::Ext::Generator
708
- *
709
- * This is the JSON generator implemented as a C extension. It can be
710
- * configured to be used by setting
711
- *
712
- * JSON.generator = JSON::Ext::Generator
713
- *
714
- * with the method generator= in JSON.
715
- *
716
- */
717
-
718
- /* Explanation of the following: that's the only way to not pollute
719
- * standard library's docs with GeneratorMethods::<ClassName> which
720
- * are uninformative and take a large place in a list of classes
721
- */
722
-
723
- /*
724
- * Document-module: JSON::Ext::Generator::GeneratorMethods
725
- * :nodoc:
726
- */
727
-
728
- /*
729
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
730
- * :nodoc:
731
- */
732
-
733
- /*
734
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
735
- * :nodoc:
736
- */
737
-
738
- /*
739
- * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
740
- * :nodoc:
741
- */
742
-
743
- /*
744
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
745
- * :nodoc:
746
- */
747
-
748
- /*
749
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
750
- * :nodoc:
751
- */
752
-
753
- /*
754
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
755
- * :nodoc:
756
- */
757
-
758
- /*
759
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
760
- * :nodoc:
761
- */
762
-
763
- /*
764
- * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
765
- * :nodoc:
766
- */
767
-
768
- /*
769
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
770
- * :nodoc:
771
- */
772
-
773
- /*
774
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String
775
- * :nodoc:
776
- */
777
-
778
- /*
779
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
780
- * :nodoc:
781
- */
782
-
783
- /*
784
- * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
785
- * :nodoc:
786
- */
787
-
788
- /*
789
- * call-seq: to_json(state = nil)
790
- *
791
- * Returns a JSON string containing a JSON object, that is generated from
792
- * this Hash instance.
793
- * _state_ is a JSON::State object, that can also be used to configure the
794
- * produced JSON string output further.
795
- */
796
- static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
797
- {
798
- rb_check_arity(argc, 0, 1);
799
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
800
- return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
801
- }
802
-
803
- /*
804
- * call-seq: to_json(state = nil)
805
- *
806
- * Returns a JSON string containing a JSON array, that is generated from
807
- * this Array instance.
808
- * _state_ is a JSON::State object, that can also be used to configure the
809
- * produced JSON string output further.
810
- */
811
- static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
812
- {
813
- rb_check_arity(argc, 0, 1);
814
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
815
- return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
816
- }
817
-
818
- #ifdef RUBY_INTEGER_UNIFICATION
819
- /*
820
- * call-seq: to_json(*)
821
- *
822
- * Returns a JSON string representation for this Integer number.
823
- */
824
- static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
825
- {
826
- rb_check_arity(argc, 0, 1);
827
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
828
- return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
829
- }
830
-
831
- #else
832
- /*
833
- * call-seq: to_json(*)
834
- *
835
- * Returns a JSON string representation for this Integer number.
836
- */
837
- static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
838
- {
839
- rb_check_arity(argc, 0, 1);
840
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
841
- return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
842
- }
843
-
844
- /*
845
- * call-seq: to_json(*)
846
- *
847
- * Returns a JSON string representation for this Integer number.
848
- */
849
- static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
850
- {
851
- rb_check_arity(argc, 0, 1);
852
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
853
- return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
854
- }
855
- #endif
856
-
857
- /*
858
- * call-seq: to_json(*)
859
- *
860
- * Returns a JSON string representation for this Float number.
861
- */
862
- static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
863
- {
864
- rb_check_arity(argc, 0, 1);
865
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
866
- return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
867
- }
868
-
869
- /*
870
- * call-seq: to_json(*)
871
- *
872
- * This string should be encoded with UTF-8 A call to this method
873
- * returns a JSON string encoded with UTF16 big endian characters as
874
- * \u????.
875
- */
876
- static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
877
- {
878
- rb_check_arity(argc, 0, 1);
879
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
880
- return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
881
- }
882
-
883
- /*
884
- * call-seq: to_json(*)
885
- *
886
- * Returns a JSON string for true: 'true'.
887
- */
888
- static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
889
- {
890
- rb_check_arity(argc, 0, 1);
891
- return rb_utf8_str_new("true", 4);
892
- }
893
-
894
- /*
895
- * call-seq: to_json(*)
896
- *
897
- * Returns a JSON string for false: 'false'.
898
- */
899
- static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
900
- {
901
- rb_check_arity(argc, 0, 1);
902
- return rb_utf8_str_new("false", 5);
903
- }
904
-
905
- /*
906
- * call-seq: to_json(*)
907
- *
908
- * Returns a JSON string for nil: 'null'.
909
- */
910
- static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
911
- {
912
- rb_check_arity(argc, 0, 1);
913
- return rb_utf8_str_new("null", 4);
914
- }
915
-
916
- /*
917
- * call-seq: to_json(*)
918
- *
919
- * Converts this object to a string (calling #to_s), converts
920
- * it to a JSON string, and returns the result. This is a fallback, if no
921
- * special method #to_json was defined for some object.
922
- */
923
- static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
924
- {
925
- VALUE state;
926
- VALUE string = rb_funcall(self, i_to_s, 0);
927
- rb_scan_args(argc, argv, "01", &state);
928
- Check_Type(string, T_STRING);
929
- state = cState_from_state_s(cState, state);
930
- return cState_partial_generate(state, string, generate_json_string, Qfalse);
931
- }
932
-
933
703
  static void State_mark(void *ptr)
934
704
  {
935
705
  JSON_Generator_State *state = ptr;
@@ -1377,16 +1147,6 @@ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *dat
1377
1147
  fbuffer_append_str(buffer, StringValue(tmp));
1378
1148
  }
1379
1149
 
1380
- #ifdef RUBY_INTEGER_UNIFICATION
1381
- static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1382
- {
1383
- if (FIXNUM_P(obj))
1384
- generate_json_fixnum(buffer, data, obj);
1385
- else
1386
- generate_json_bignum(buffer, data, obj);
1387
- }
1388
- #endif
1389
-
1390
1150
  static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1391
1151
  {
1392
1152
  double value = RFLOAT_VALUE(obj);
@@ -1430,7 +1190,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
1430
1190
  fbuffer_append_str(buffer, fragment);
1431
1191
  }
1432
1192
 
1433
- static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1193
+ static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
1434
1194
  {
1435
1195
  bool as_json_called = false;
1436
1196
  start:
@@ -1457,15 +1217,15 @@ start:
1457
1217
  generate_json_bignum(buffer, data, obj);
1458
1218
  break;
1459
1219
  case T_HASH:
1460
- if (klass != rb_cHash) goto general;
1220
+ if (fallback && klass != rb_cHash) goto general;
1461
1221
  generate_json_object(buffer, data, obj);
1462
1222
  break;
1463
1223
  case T_ARRAY:
1464
- if (klass != rb_cArray) goto general;
1224
+ if (fallback && klass != rb_cArray) goto general;
1465
1225
  generate_json_array(buffer, data, obj);
1466
1226
  break;
1467
1227
  case T_STRING:
1468
- if (klass != rb_cString) goto general;
1228
+ if (fallback && klass != rb_cString) goto general;
1469
1229
 
1470
1230
  if (RB_LIKELY(valid_json_string_p(obj))) {
1471
1231
  raw_generate_json_string(buffer, data, obj);
@@ -1481,7 +1241,7 @@ start:
1481
1241
  generate_json_symbol(buffer, data, obj);
1482
1242
  break;
1483
1243
  case T_FLOAT:
1484
- if (klass != rb_cFloat) goto general;
1244
+ if (fallback && klass != rb_cFloat) goto general;
1485
1245
  generate_json_float(buffer, data, obj);
1486
1246
  break;
1487
1247
  case T_STRUCT:
@@ -1505,6 +1265,16 @@ start:
1505
1265
  }
1506
1266
  }
1507
1267
 
1268
+ static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1269
+ {
1270
+ generate_json_general(buffer, data, obj, true);
1271
+ }
1272
+
1273
+ static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1274
+ {
1275
+ generate_json_general(buffer, data, obj, false);
1276
+ }
1277
+
1508
1278
  static VALUE generate_json_try(VALUE d)
1509
1279
  {
1510
1280
  struct generate_json_data *data = (struct generate_json_data *)d;
@@ -1522,7 +1292,7 @@ static VALUE generate_json_ensure(VALUE d)
1522
1292
  return Qundef;
1523
1293
  }
1524
1294
 
1525
- static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
1295
+ static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
1526
1296
  {
1527
1297
  GET_STATE(self);
1528
1298
 
@@ -1540,9 +1310,7 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
1540
1310
  .obj = obj,
1541
1311
  .func = func
1542
1312
  };
1543
- VALUE result = rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
1544
- RB_GC_GUARD(self);
1545
- return result;
1313
+ return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
1546
1314
  }
1547
1315
 
1548
1316
  /* call-seq:
@@ -1561,6 +1329,15 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
1561
1329
  return cState_partial_generate(self, obj, generate_json, io);
1562
1330
  }
1563
1331
 
1332
+ /* :nodoc: */
1333
+ static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
1334
+ {
1335
+ rb_check_arity(argc, 1, 2);
1336
+ VALUE obj = argv[0];
1337
+ VALUE io = argc > 1 ? argv[1] : Qnil;
1338
+ return cState_partial_generate(self, obj, generate_json_no_fallback, io);
1339
+ }
1340
+
1564
1341
  static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
1565
1342
  {
1566
1343
  rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
@@ -1798,6 +1575,17 @@ static long long_config(VALUE num)
1798
1575
  return RTEST(num) ? FIX2LONG(num) : 0;
1799
1576
  }
1800
1577
 
1578
+ // depth must never be negative; reject early with a clear error.
1579
+ static long depth_config(VALUE num)
1580
+ {
1581
+ if (!RTEST(num)) return 0;
1582
+ long d = NUM2LONG(num);
1583
+ if (RB_UNLIKELY(d < 0)) {
1584
+ rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
1585
+ }
1586
+ return d;
1587
+ }
1588
+
1801
1589
  /*
1802
1590
  * call-seq: max_nesting=(depth)
1803
1591
  *
@@ -1954,7 +1742,7 @@ static VALUE cState_depth_set(VALUE self, VALUE depth)
1954
1742
  {
1955
1743
  rb_check_frozen(self);
1956
1744
  GET_STATE(self);
1957
- state->depth = long_config(depth);
1745
+ state->depth = depth_config(depth);
1958
1746
  return Qnil;
1959
1747
  }
1960
1748
 
@@ -2019,7 +1807,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
2019
1807
  else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
2020
1808
  else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
2021
1809
  else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
2022
- else if (key == sym_depth) { state->depth = long_config(val); }
1810
+ else if (key == sym_depth) { state->depth = depth_config(val); }
2023
1811
  else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
2024
1812
  else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
2025
1813
  else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
@@ -2059,7 +1847,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
2059
1847
  return self;
2060
1848
  }
2061
1849
 
2062
- static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1850
+ static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
2063
1851
  {
2064
1852
  JSON_Generator_State state = {0};
2065
1853
  state_init(&state);
@@ -2077,14 +1865,21 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
2077
1865
  .state = &state,
2078
1866
  .depth = state.depth,
2079
1867
  .obj = obj,
2080
- .func = generate_json,
1868
+ .func = func,
2081
1869
  };
2082
1870
  return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
2083
1871
  }
2084
1872
 
2085
- /*
2086
- *
2087
- */
1873
+ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1874
+ {
1875
+ return cState_m_do_generate(klass, obj, opts, io, generate_json);
1876
+ }
1877
+
1878
+ static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1879
+ {
1880
+ return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
1881
+ }
1882
+
2088
1883
  void Init_generator(void)
2089
1884
  {
2090
1885
  #ifdef HAVE_RB_EXT_RACTOR_SAFE
@@ -2149,46 +1944,12 @@ void Init_generator(void)
2149
1944
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
2150
1945
  rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
2151
1946
  rb_define_method(cState, "generate", cState_generate, -1);
1947
+ rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
2152
1948
 
2153
1949
  rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
2154
1950
 
2155
1951
  rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
2156
-
2157
- VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
2158
-
2159
- VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
2160
- rb_define_method(mObject, "to_json", mObject_to_json, -1);
2161
-
2162
- VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
2163
- rb_define_method(mHash, "to_json", mHash_to_json, -1);
2164
-
2165
- VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
2166
- rb_define_method(mArray, "to_json", mArray_to_json, -1);
2167
-
2168
- #ifdef RUBY_INTEGER_UNIFICATION
2169
- VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
2170
- rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
2171
- #else
2172
- VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
2173
- rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
2174
-
2175
- VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
2176
- rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
2177
- #endif
2178
- VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
2179
- rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
2180
-
2181
- VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
2182
- rb_define_method(mString, "to_json", mString_to_json, -1);
2183
-
2184
- VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
2185
- rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
2186
-
2187
- VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
2188
- rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
2189
-
2190
- VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
2191
- rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1952
+ rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
2192
1953
 
2193
1954
  rb_global_variable(&Encoding_UTF_8);
2194
1955
  Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
data/ext/json/ext/json.h CHANGED
@@ -55,8 +55,12 @@ typedef unsigned char _Bool;
55
55
  #endif
56
56
 
57
57
  #ifndef NORETURN
58
+ #if defined(__has_attribute) && __has_attribute(noreturn)
59
+ #define NORETURN(x) __attribute__((noreturn)) x
60
+ #else
58
61
  #define NORETURN(x) x
59
62
  #endif
63
+ #endif
60
64
 
61
65
  #ifndef NOINLINE
62
66
  #if defined(__has_attribute) && __has_attribute(noinline)
@@ -7,8 +7,9 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
7
7
 
8
8
  static ID i_new, i_try_convert, i_uminus, i_encode;
9
9
 
10
- static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters, sym_symbolize_names, sym_freeze,
11
- sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
10
+ static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
11
+ sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
12
+ sym_allow_duplicate_key;
12
13
 
13
14
  static int binary_encindex;
14
15
  static int utf8_encindex;
@@ -336,6 +337,7 @@ typedef struct JSON_ParserStruct {
336
337
  bool allow_nan;
337
338
  bool allow_trailing_comma;
338
339
  bool allow_control_characters;
340
+ bool allow_invalid_escape;
339
341
  bool symbolize_names;
340
342
  bool freeze;
341
343
  } JSON_ParserConfig;
@@ -400,10 +402,7 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state)
400
402
 
401
403
  #define PARSE_ERROR_FRAGMENT_LEN 32
402
404
 
403
- #ifdef RBIMPL_ATTR_NORETURN
404
- RBIMPL_ATTR_NORETURN()
405
- #endif
406
- static void raise_parse_error(const char *format, JSON_ParserState *state)
405
+ NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state)
407
406
  {
408
407
  unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
409
408
  long line, column;
@@ -449,10 +448,7 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
449
448
  rb_exc_raise(exc);
450
449
  }
451
450
 
452
- #ifdef RBIMPL_ATTR_NORETURN
453
- RBIMPL_ATTR_NORETURN()
454
- #endif
455
- static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
451
+ NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
456
452
  {
457
453
  state->cursor = at;
458
454
  raise_parse_error(format, state);
@@ -752,6 +748,8 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
752
748
  }
753
749
  raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
754
750
  }
751
+ } else if (config->allow_invalid_escape) {
752
+ APPEND_CHAR(*pe);
755
753
  } else {
756
754
  raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
757
755
  }
@@ -776,20 +774,39 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
776
774
  }
777
775
 
778
776
  #define MAX_FAST_INTEGER_SIZE 18
777
+ #define MAX_NUMBER_STACK_BUFFER 128
778
+
779
+ typedef VALUE (*json_number_decode_func_t)(const char *ptr);
779
780
 
780
- static VALUE json_decode_large_integer(const char *start, long len)
781
+ static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func)
781
782
  {
782
- VALUE buffer_v;
783
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
784
- MEMCPY(buffer, start, char, len);
785
- buffer[len] = '\0';
786
- VALUE number = rb_cstr2inum(buffer, 10);
787
- RB_ALLOCV_END(buffer_v);
788
- return number;
783
+ if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) {
784
+ char buffer[MAX_NUMBER_STACK_BUFFER];
785
+ MEMCPY(buffer, start, char, len);
786
+ buffer[len] = '\0';
787
+ return func(buffer);
788
+ } else {
789
+ VALUE buffer_v = rb_str_tmp_new(len);
790
+ char *buffer = RSTRING_PTR(buffer_v);
791
+ MEMCPY(buffer, start, char, len);
792
+ buffer[len] = '\0';
793
+ VALUE number = func(buffer);
794
+ RB_GC_GUARD(buffer_v);
795
+ return number;
796
+ }
789
797
  }
790
798
 
791
- static inline VALUE
792
- json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
799
+ static VALUE json_decode_inum(const char *buffer)
800
+ {
801
+ return rb_cstr2inum(buffer, 10);
802
+ }
803
+
804
+ NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
805
+ {
806
+ return json_decode_large_number(start, len, json_decode_inum);
807
+ }
808
+
809
+ static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
793
810
  {
794
811
  if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
795
812
  if (negative) {
@@ -801,22 +818,14 @@ json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const
801
818
  return json_decode_large_integer(start, end - start);
802
819
  }
803
820
 
804
- static VALUE json_decode_large_float(const char *start, long len)
821
+ static VALUE json_decode_dnum(const char *buffer)
805
822
  {
806
- if (RB_LIKELY(len < 64)) {
807
- char buffer[64];
808
- MEMCPY(buffer, start, char, len);
809
- buffer[len] = '\0';
810
- return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
811
- }
823
+ return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
824
+ }
812
825
 
813
- VALUE buffer_v;
814
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
815
- MEMCPY(buffer, start, char, len);
816
- buffer[len] = '\0';
817
- VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1));
818
- RB_ALLOCV_END(buffer_v);
819
- return number;
826
+ NOINLINE(static) VALUE json_decode_large_float(const char *start, long len)
827
+ {
828
+ return json_decode_large_number(start, len, json_decode_dnum);
820
829
  }
821
830
 
822
831
  /* Ruby JSON optimized float decoder using vendored Ryu algorithm
@@ -868,7 +877,7 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
868
877
  return Qfalse;
869
878
  }
870
879
 
871
- static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
880
+ NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
872
881
  {
873
882
  VALUE message = rb_sprintf(
874
883
  "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
@@ -879,10 +888,7 @@ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_
879
888
  RB_GC_GUARD(message);
880
889
  }
881
890
 
882
- #ifdef RBIMPL_ATTR_NORETURN
883
- RBIMPL_ATTR_NORETURN()
884
- #endif
885
- static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
891
+ NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
886
892
  {
887
893
  VALUE message = rb_sprintf(
888
894
  "duplicate key %"PRIsVALUE,
@@ -1433,6 +1439,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
1433
1439
  else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
1434
1440
  else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
1435
1441
  else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
1442
+ else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
1436
1443
  else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
1437
1444
  else if (key == sym_freeze) { config->freeze = RTEST(val); }
1438
1445
  else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
@@ -1651,6 +1658,7 @@ void Init_parser(void)
1651
1658
  sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
1652
1659
  sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
1653
1660
  sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
1661
+ sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
1654
1662
  sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
1655
1663
  sym_freeze = ID2SYM(rb_intern("freeze"));
1656
1664
  sym_on_load = ID2SYM(rb_intern("on_load"));
@@ -133,16 +133,6 @@ ALWAYS_INLINE(static) int string_scan_simd_neon(const char **ptr, const char *en
133
133
  return 0;
134
134
  }
135
135
 
136
- static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
137
- {
138
- uint8x16x4_t tab;
139
- tab.val[0] = vld1q_u8(table);
140
- tab.val[1] = vld1q_u8(table+16);
141
- tab.val[2] = vld1q_u8(table+32);
142
- tab.val[3] = vld1q_u8(table+48);
143
- return tab;
144
- }
145
-
146
136
  #endif /* ARM Neon Support.*/
147
137
 
148
138
  #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
data/lib/json/common.rb CHANGED
@@ -156,15 +156,17 @@ module JSON
156
156
  def generator=(generator) # :nodoc:
157
157
  old, $VERBOSE = $VERBOSE, nil
158
158
  @generator = generator
159
- generator_methods = generator::GeneratorMethods
160
- for const in generator_methods.constants
161
- klass = const_get(const)
162
- modul = generator_methods.const_get(const)
163
- klass.class_eval do
164
- instance_methods(false).each do |m|
165
- m.to_s == 'to_json' and remove_method m
159
+ if generator.const_defined?(:GeneratorMethods)
160
+ generator_methods = generator::GeneratorMethods
161
+ for const in generator_methods.constants
162
+ klass = const_get(const)
163
+ modul = generator_methods.const_get(const)
164
+ klass.class_eval do
165
+ instance_methods(false).each do |m|
166
+ m.to_s == 'to_json' and remove_method m
167
+ end
168
+ include modul
166
169
  end
167
- include modul
168
170
  end
169
171
  end
170
172
  self.state = generator::State
@@ -878,7 +880,7 @@ module JSON
878
880
  end
879
881
  end
880
882
 
881
- if opts[:allow_blank] && (source.nil? || source.empty?)
883
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
882
884
  source = 'null'
883
885
  end
884
886
 
@@ -1036,7 +1038,8 @@ module JSON
1036
1038
  # JSON.new(options = nil, &block)
1037
1039
  #
1038
1040
  # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1039
- # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
1041
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
1042
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
1040
1043
  #
1041
1044
  # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1042
1045
  # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
@@ -1095,6 +1098,30 @@ module JSON
1095
1098
  load(File.read(path, encoding: Encoding::UTF_8))
1096
1099
  end
1097
1100
  end
1101
+
1102
+ module GeneratorMethods
1103
+ # call-seq: to_json(*)
1104
+ #
1105
+ # Converts this object into a JSON string.
1106
+ # If this object doesn't directly maps to a JSON native type,
1107
+ # first convert it to a string (calling #to_s), then converts
1108
+ # it to a JSON string, and returns the result.
1109
+ # This is a fallback, if no special method #to_json was defined for some object.
1110
+ def to_json(state = nil, *)
1111
+ obj = case self
1112
+ when nil, false, true, Integer, Float, Array, Hash
1113
+ self
1114
+ else
1115
+ "#{self}"
1116
+ end
1117
+
1118
+ if state.nil?
1119
+ JSON::State._generate_no_fallback(obj, nil, nil)
1120
+ else
1121
+ JSON::State.from_state(state)._generate_no_fallback(obj)
1122
+ end
1123
+ end
1124
+ end
1098
1125
  end
1099
1126
 
1100
1127
  module ::Kernel
@@ -1140,3 +1167,7 @@ module ::Kernel
1140
1167
  JSON[object, opts]
1141
1168
  end
1142
1169
  end
1170
+
1171
+ class Object
1172
+ include JSON::GeneratorMethods
1173
+ end
@@ -9,7 +9,7 @@ module JSON
9
9
  # Instantiates a new State object, configured by _opts_.
10
10
  #
11
11
  # Argument +opts+, if given, contains a \Hash of options for the generation.
12
- # See {Generating Options}[#module-JSON-label-Generating+Options].
12
+ # See {Generating Options}[rdoc-ref:JSON@Generating+Options].
13
13
  def initialize(opts = nil)
14
14
  if opts && !opts.empty?
15
15
  configure(opts)
@@ -211,7 +211,14 @@ module JSON
211
211
 
212
212
  # This integer returns the current depth data structure nesting in the
213
213
  # generated JSON.
214
- attr_accessor :depth
214
+ attr_reader :depth
215
+
216
+ def depth=(depth)
217
+ if depth.negative?
218
+ raise ArgumentError, "depth must be >= 0 (got #{depth})"
219
+ end
220
+ @depth = depth
221
+ end
215
222
 
216
223
  def check_max_nesting # :nodoc:
217
224
  return if @max_nesting.zero?
@@ -260,6 +267,11 @@ module JSON
260
267
  else
261
268
  raise TypeError, "can't convert #{opts.class} into Hash"
262
269
  end
270
+
271
+ if opts[:depth]&.negative?
272
+ raise ArgumentError, "depth must be >= 0 (got #{opts[:depth]})"
273
+ end
274
+
263
275
  opts.each do |key, value|
264
276
  instance_variable_set "@#{key}", value
265
277
  end
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.18.1'
4
+ VERSION = '2.19.0'
5
5
  end
data/lib/json.rb CHANGED
@@ -194,6 +194,18 @@ require 'json/common'
194
194
  # When enabled:
195
195
  # JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
196
196
  #
197
+ # ---
198
+ #
199
+ # Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
200
+ # by an invalid escape character in strings;
201
+ # defaults to +false+.
202
+ #
203
+ # With the default, +false+:
204
+ # JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
205
+ #
206
+ # When enabled:
207
+ # JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
208
+ #
197
209
  # ====== Output Options
198
210
  #
199
211
  # Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.18.1
4
+ version: 2.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  - !ruby/object:Gem::Version
85
85
  version: '0'
86
86
  requirements: []
87
- rubygems_version: 4.1.0.dev
87
+ rubygems_version: 4.0.3
88
88
  specification_version: 4
89
89
  summary: JSON Implementation for Ruby
90
90
  test_files: []