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