json 2.2.0 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +71 -5
- data/LICENSE +56 -0
- data/README.md +20 -4
- data/VERSION +1 -1
- data/ext/json/ext/generator/generator.c +222 -58
- data/ext/json/ext/generator/generator.h +5 -2
- data/ext/json/ext/parser/extconf.rb +26 -0
- data/ext/json/ext/parser/parser.c +2980 -1764
- data/ext/json/ext/parser/parser.h +6 -1
- data/ext/json/ext/parser/parser.rl +138 -43
- data/ext/json/extconf.rb +1 -0
- data/json.gemspec +0 -0
- data/lib/json/add/bigdecimal.rb +2 -2
- data/lib/json/add/complex.rb +2 -3
- data/lib/json/add/rational.rb +2 -3
- data/lib/json/add/regexp.rb +2 -2
- data/lib/json/common.rb +372 -125
- data/lib/json/pure/generator.rb +31 -10
- data/lib/json/pure/parser.rb +32 -6
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +549 -29
- metadata +18 -109
- data/.gitignore +0 -17
- data/.travis.yml +0 -23
- data/Gemfile +0 -14
- data/README-json-jruby.md +0 -33
- data/Rakefile +0 -408
- data/diagrams/.keep +0 -0
- data/install.rb +0 -23
- data/java/src/json/ext/ByteListTranscoder.java +0 -166
- data/java/src/json/ext/Generator.java +0 -443
- data/java/src/json/ext/GeneratorMethods.java +0 -231
- data/java/src/json/ext/GeneratorService.java +0 -42
- data/java/src/json/ext/GeneratorState.java +0 -490
- data/java/src/json/ext/OptionsReader.java +0 -113
- data/java/src/json/ext/Parser.java +0 -2362
- data/java/src/json/ext/Parser.rl +0 -893
- data/java/src/json/ext/ParserService.java +0 -34
- data/java/src/json/ext/RuntimeInfo.java +0 -116
- data/java/src/json/ext/StringDecoder.java +0 -166
- data/java/src/json/ext/StringEncoder.java +0 -111
- data/java/src/json/ext/Utils.java +0 -88
- data/json-java.gemspec +0 -38
- data/json_pure.gemspec +0 -38
- data/lib/json/ext/.keep +0 -0
- data/references/rfc7159.txt +0 -899
- data/tests/fixtures/fail10.json +0 -1
- data/tests/fixtures/fail11.json +0 -1
- data/tests/fixtures/fail12.json +0 -1
- data/tests/fixtures/fail13.json +0 -1
- data/tests/fixtures/fail14.json +0 -1
- data/tests/fixtures/fail18.json +0 -1
- data/tests/fixtures/fail19.json +0 -1
- data/tests/fixtures/fail2.json +0 -1
- data/tests/fixtures/fail20.json +0 -1
- data/tests/fixtures/fail21.json +0 -1
- data/tests/fixtures/fail22.json +0 -1
- data/tests/fixtures/fail23.json +0 -1
- data/tests/fixtures/fail24.json +0 -1
- data/tests/fixtures/fail25.json +0 -1
- data/tests/fixtures/fail27.json +0 -2
- data/tests/fixtures/fail28.json +0 -2
- data/tests/fixtures/fail3.json +0 -1
- data/tests/fixtures/fail4.json +0 -1
- data/tests/fixtures/fail5.json +0 -1
- data/tests/fixtures/fail6.json +0 -1
- data/tests/fixtures/fail7.json +0 -1
- data/tests/fixtures/fail8.json +0 -1
- data/tests/fixtures/fail9.json +0 -1
- data/tests/fixtures/obsolete_fail1.json +0 -1
- data/tests/fixtures/pass1.json +0 -56
- data/tests/fixtures/pass15.json +0 -1
- data/tests/fixtures/pass16.json +0 -1
- data/tests/fixtures/pass17.json +0 -1
- data/tests/fixtures/pass2.json +0 -1
- data/tests/fixtures/pass26.json +0 -1
- data/tests/fixtures/pass3.json +0 -6
- data/tests/json_addition_test.rb +0 -203
- data/tests/json_common_interface_test.rb +0 -126
- data/tests/json_encoding_test.rb +0 -107
- data/tests/json_ext_parser_test.rb +0 -15
- data/tests/json_fixtures_test.rb +0 -32
- data/tests/json_generator_test.rb +0 -377
- data/tests/json_generic_object_test.rb +0 -82
- data/tests/json_parser_test.rb +0 -472
- data/tests/json_string_matching_test.rb +0 -38
- data/tests/test_helper.rb +0 -17
- data/tools/diff.sh +0 -18
- data/tools/fuzz.rb +0 -131
- 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
|
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
17
|
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
|
24
18
|
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
|
25
|
-
i_buffer_initial_length, i_dup;
|
19
|
+
i_buffer_initial_length, i_dup, i_escape_slash;
|
26
20
|
|
27
21
|
/*
|
28
22
|
* Copyright 2001-2004 Unicode, Inc.
|
@@ -130,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
|
|
130
124
|
|
131
125
|
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
|
132
126
|
* and control characters are JSON escaped. */
|
133
|
-
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
127
|
+
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
|
134
128
|
{
|
135
129
|
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
|
136
130
|
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
|
@@ -180,6 +174,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
180
174
|
case '"':
|
181
175
|
fbuffer_append(buffer, "\\\"", 2);
|
182
176
|
break;
|
177
|
+
case '/':
|
178
|
+
if(escape_slash) {
|
179
|
+
fbuffer_append(buffer, "\\/", 2);
|
180
|
+
break;
|
181
|
+
}
|
183
182
|
default:
|
184
183
|
fbuffer_append_char(buffer, (char)ch);
|
185
184
|
break;
|
@@ -229,7 +228,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
229
228
|
* characters required by the JSON standard are JSON escaped. The remaining
|
230
229
|
* characters (should be UTF8) are just passed through and appended to the
|
231
230
|
* result. */
|
232
|
-
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
231
|
+
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
|
233
232
|
{
|
234
233
|
const char *ptr = RSTRING_PTR(string), *p;
|
235
234
|
unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
|
@@ -237,6 +236,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
237
236
|
int escape_len;
|
238
237
|
unsigned char c;
|
239
238
|
char buf[6] = { '\\', 'u' };
|
239
|
+
int ascii_only = rb_enc_str_asciionly_p(string);
|
240
240
|
|
241
241
|
for (start = 0, end = 0; end < len;) {
|
242
242
|
p = ptr + end;
|
@@ -279,16 +279,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
279
279
|
escape = "\\\"";
|
280
280
|
escape_len = 2;
|
281
281
|
break;
|
282
|
+
case '/':
|
283
|
+
if(escape_slash) {
|
284
|
+
escape = "\\/";
|
285
|
+
escape_len = 2;
|
286
|
+
break;
|
287
|
+
}
|
282
288
|
default:
|
283
289
|
{
|
284
|
-
unsigned short clen =
|
285
|
-
if (
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
290
|
+
unsigned short clen = 1;
|
291
|
+
if (!ascii_only) {
|
292
|
+
clen += trailingBytesForUTF8[c];
|
293
|
+
if (end + clen > len) {
|
294
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
295
|
+
"partial character in source, but hit end");
|
296
|
+
}
|
297
|
+
if (!isLegalUTF8((UTF8 *) p, clen)) {
|
298
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
299
|
+
"source sequence is illegal/malformed utf-8");
|
300
|
+
}
|
292
301
|
}
|
293
302
|
end += clen;
|
294
303
|
}
|
@@ -324,6 +333,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
324
333
|
*
|
325
334
|
*/
|
326
335
|
|
336
|
+
/* Explanation of the following: that's the only way to not pollute
|
337
|
+
* standard library's docs with GeneratorMethods::<ClassName> which
|
338
|
+
* are uninformative and take a large place in a list of classes
|
339
|
+
*/
|
340
|
+
|
341
|
+
/*
|
342
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods
|
343
|
+
* :nodoc:
|
344
|
+
*/
|
345
|
+
|
346
|
+
/*
|
347
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
|
348
|
+
* :nodoc:
|
349
|
+
*/
|
350
|
+
|
351
|
+
/*
|
352
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
|
353
|
+
* :nodoc:
|
354
|
+
*/
|
355
|
+
|
356
|
+
/*
|
357
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
|
358
|
+
* :nodoc:
|
359
|
+
*/
|
360
|
+
|
361
|
+
/*
|
362
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
|
363
|
+
* :nodoc:
|
364
|
+
*/
|
365
|
+
|
366
|
+
/*
|
367
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
|
368
|
+
* :nodoc:
|
369
|
+
*/
|
370
|
+
|
371
|
+
/*
|
372
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
|
373
|
+
* :nodoc:
|
374
|
+
*/
|
375
|
+
|
376
|
+
/*
|
377
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
|
378
|
+
* :nodoc:
|
379
|
+
*/
|
380
|
+
|
381
|
+
/*
|
382
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
|
383
|
+
* :nodoc:
|
384
|
+
*/
|
385
|
+
|
386
|
+
/*
|
387
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
|
388
|
+
* :nodoc:
|
389
|
+
*/
|
390
|
+
|
391
|
+
/*
|
392
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
|
393
|
+
* :nodoc:
|
394
|
+
*/
|
395
|
+
|
396
|
+
/*
|
397
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
|
398
|
+
* :nodoc:
|
399
|
+
*/
|
400
|
+
|
401
|
+
/*
|
402
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
|
403
|
+
* :nodoc:
|
404
|
+
*/
|
405
|
+
|
327
406
|
/*
|
328
407
|
* call-seq: to_json(state = nil)
|
329
408
|
*
|
@@ -535,13 +614,18 @@ static size_t State_memsize(const void *ptr)
|
|
535
614
|
return size;
|
536
615
|
}
|
537
616
|
|
617
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
618
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
619
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
620
|
+
#endif
|
621
|
+
|
538
622
|
#ifdef NEW_TYPEDDATA_WRAPPER
|
539
623
|
static const rb_data_type_t JSON_Generator_State_type = {
|
540
624
|
"JSON/Generator/State",
|
541
625
|
{NULL, State_free, State_memsize,},
|
542
626
|
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
543
627
|
0, 0,
|
544
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
628
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
545
629
|
#endif
|
546
630
|
};
|
547
631
|
#endif
|
@@ -642,6 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
642
726
|
state->allow_nan = RTEST(tmp);
|
643
727
|
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
644
728
|
state->ascii_only = RTEST(tmp);
|
729
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
|
730
|
+
state->escape_slash = RTEST(tmp);
|
645
731
|
return self;
|
646
732
|
}
|
647
733
|
|
@@ -676,6 +762,7 @@ static VALUE cState_to_h(VALUE self)
|
|
676
762
|
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
677
763
|
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
|
678
764
|
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
|
765
|
+
rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
|
679
766
|
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
680
767
|
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
681
768
|
return result;
|
@@ -692,7 +779,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
|
|
692
779
|
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
693
780
|
return rb_funcall(self, i_send, 1, name);
|
694
781
|
} else {
|
695
|
-
return
|
782
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
696
783
|
}
|
697
784
|
}
|
698
785
|
|
@@ -715,43 +802,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
|
715
802
|
return Qnil;
|
716
803
|
}
|
717
804
|
|
718
|
-
|
805
|
+
struct hash_foreach_arg {
|
806
|
+
FBuffer *buffer;
|
807
|
+
JSON_Generator_State *state;
|
808
|
+
VALUE Vstate;
|
809
|
+
int iter;
|
810
|
+
};
|
811
|
+
|
812
|
+
static int
|
813
|
+
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
719
814
|
{
|
815
|
+
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
816
|
+
FBuffer *buffer = arg->buffer;
|
817
|
+
JSON_Generator_State *state = arg->state;
|
818
|
+
VALUE Vstate = arg->Vstate;
|
819
|
+
|
720
820
|
char *object_nl = state->object_nl;
|
721
821
|
long object_nl_len = state->object_nl_len;
|
722
822
|
char *indent = state->indent;
|
723
823
|
long indent_len = state->indent_len;
|
724
|
-
long max_nesting = state->max_nesting;
|
725
824
|
char *delim = FBUFFER_PTR(state->object_delim);
|
726
825
|
long delim_len = FBUFFER_LEN(state->object_delim);
|
727
826
|
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
728
827
|
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
828
|
+
long depth = state->depth;
|
829
|
+
int j;
|
830
|
+
VALUE klass, key_to_s;
|
831
|
+
|
832
|
+
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
|
833
|
+
if (object_nl) {
|
834
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
835
|
+
}
|
836
|
+
if (indent) {
|
837
|
+
for (j = 0; j < depth; j++) {
|
838
|
+
fbuffer_append(buffer, indent, indent_len);
|
839
|
+
}
|
840
|
+
}
|
841
|
+
|
842
|
+
klass = CLASS_OF(key);
|
843
|
+
if (klass == rb_cString) {
|
844
|
+
key_to_s = key;
|
845
|
+
} else if (klass == rb_cSymbol) {
|
846
|
+
key_to_s = rb_id2str(SYM2ID(key));
|
847
|
+
} else {
|
848
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
849
|
+
}
|
850
|
+
Check_Type(key_to_s, T_STRING);
|
851
|
+
generate_json(buffer, Vstate, state, key_to_s);
|
852
|
+
fbuffer_append(buffer, delim2, delim2_len);
|
853
|
+
generate_json(buffer, Vstate, state, val);
|
854
|
+
|
855
|
+
arg->iter++;
|
856
|
+
return ST_CONTINUE;
|
857
|
+
}
|
858
|
+
|
859
|
+
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
860
|
+
{
|
861
|
+
char *object_nl = state->object_nl;
|
862
|
+
long object_nl_len = state->object_nl_len;
|
863
|
+
char *indent = state->indent;
|
864
|
+
long indent_len = state->indent_len;
|
865
|
+
long max_nesting = state->max_nesting;
|
729
866
|
long depth = ++state->depth;
|
730
|
-
int
|
731
|
-
|
867
|
+
int j;
|
868
|
+
struct hash_foreach_arg arg;
|
869
|
+
|
732
870
|
if (max_nesting != 0 && depth > max_nesting) {
|
733
871
|
fbuffer_free(buffer);
|
734
872
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
735
873
|
}
|
736
874
|
fbuffer_append_char(buffer, '{');
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
for (j = 0; j < depth; j++) {
|
745
|
-
fbuffer_append(buffer, indent, indent_len);
|
746
|
-
}
|
747
|
-
}
|
748
|
-
key = rb_ary_entry(keys, i);
|
749
|
-
key_to_s = rb_funcall(key, i_to_s, 0);
|
750
|
-
Check_Type(key_to_s, T_STRING);
|
751
|
-
generate_json(buffer, Vstate, state, key_to_s);
|
752
|
-
fbuffer_append(buffer, delim2, delim2_len);
|
753
|
-
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
|
754
|
-
}
|
875
|
+
|
876
|
+
arg.buffer = buffer;
|
877
|
+
arg.state = state;
|
878
|
+
arg.Vstate = Vstate;
|
879
|
+
arg.iter = 0;
|
880
|
+
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
881
|
+
|
755
882
|
depth = --state->depth;
|
756
883
|
if (object_nl) {
|
757
884
|
fbuffer_append(buffer, object_nl, object_nl_len);
|
@@ -802,16 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
802
929
|
fbuffer_append_char(buffer, ']');
|
803
930
|
}
|
804
931
|
|
932
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
933
|
+
static int enc_utf8_compatible_p(rb_encoding *enc)
|
934
|
+
{
|
935
|
+
if (enc == rb_usascii_encoding()) return 1;
|
936
|
+
if (enc == rb_utf8_encoding()) return 1;
|
937
|
+
return 0;
|
938
|
+
}
|
939
|
+
#endif
|
940
|
+
|
805
941
|
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
806
942
|
{
|
807
943
|
fbuffer_append_char(buffer, '"');
|
808
944
|
#ifdef HAVE_RUBY_ENCODING_H
|
809
|
-
|
945
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
946
|
+
obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
|
947
|
+
}
|
810
948
|
#endif
|
811
949
|
if (state->ascii_only) {
|
812
|
-
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
950
|
+
convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
|
813
951
|
} else {
|
814
|
-
convert_UTF8_to_JSON(buffer, obj);
|
952
|
+
convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
|
815
953
|
}
|
816
954
|
fbuffer_append_char(buffer, '"');
|
817
955
|
}
|
@@ -970,6 +1108,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
970
1108
|
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
971
1109
|
* generated, otherwise an exception is thrown, if these values are
|
972
1110
|
* encountered. This options defaults to false.
|
1111
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
1112
|
+
* option defaults to false.
|
973
1113
|
* * *buffer_initial_length*: sets the initial length of the generator's
|
974
1114
|
* internal buffer.
|
975
1115
|
*/
|
@@ -1025,10 +1165,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1025
1165
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
1026
1166
|
return rb_funcall(self, i_new, 1, opts);
|
1027
1167
|
} else {
|
1028
|
-
|
1029
|
-
CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
|
1030
|
-
}
|
1031
|
-
return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
|
1168
|
+
return rb_class_new_instance(0, NULL, cState);
|
1032
1169
|
}
|
1033
1170
|
}
|
1034
1171
|
|
@@ -1252,6 +1389,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
1252
1389
|
return state->max_nesting = FIX2LONG(depth);
|
1253
1390
|
}
|
1254
1391
|
|
1392
|
+
/*
|
1393
|
+
* call-seq: escape_slash
|
1394
|
+
*
|
1395
|
+
* If this boolean is true, the forward slashes will be escaped in
|
1396
|
+
* the json output.
|
1397
|
+
*/
|
1398
|
+
static VALUE cState_escape_slash(VALUE self)
|
1399
|
+
{
|
1400
|
+
GET_STATE(self);
|
1401
|
+
return state->escape_slash ? Qtrue : Qfalse;
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
/*
|
1405
|
+
* call-seq: escape_slash=(depth)
|
1406
|
+
*
|
1407
|
+
* This sets whether or not the forward slashes will be escaped in
|
1408
|
+
* the json output.
|
1409
|
+
*/
|
1410
|
+
static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
|
1411
|
+
{
|
1412
|
+
GET_STATE(self);
|
1413
|
+
state->escape_slash = RTEST(enable);
|
1414
|
+
return Qnil;
|
1415
|
+
}
|
1416
|
+
|
1255
1417
|
/*
|
1256
1418
|
* call-seq: allow_nan?
|
1257
1419
|
*
|
@@ -1267,7 +1429,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
1267
1429
|
/*
|
1268
1430
|
* call-seq: ascii_only?
|
1269
1431
|
*
|
1270
|
-
* Returns true, if
|
1432
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
1271
1433
|
* returns false.
|
1272
1434
|
*/
|
1273
1435
|
static VALUE cState_ascii_only_p(VALUE self)
|
@@ -1335,6 +1497,10 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
1335
1497
|
*/
|
1336
1498
|
void Init_generator(void)
|
1337
1499
|
{
|
1500
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
1501
|
+
rb_ext_ractor_safe(true);
|
1502
|
+
#endif
|
1503
|
+
|
1338
1504
|
#undef rb_intern
|
1339
1505
|
rb_require("json/common");
|
1340
1506
|
|
@@ -1344,6 +1510,8 @@ void Init_generator(void)
|
|
1344
1510
|
|
1345
1511
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
1346
1512
|
eNestingError = rb_path2class("JSON::NestingError");
|
1513
|
+
rb_gc_register_mark_object(eGeneratorError);
|
1514
|
+
rb_gc_register_mark_object(eNestingError);
|
1347
1515
|
|
1348
1516
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
1349
1517
|
rb_define_alloc_func(cState, cState_s_allocate);
|
@@ -1362,6 +1530,9 @@ void Init_generator(void)
|
|
1362
1530
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
1363
1531
|
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
1364
1532
|
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
|
1533
|
+
rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
|
1534
|
+
rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
|
1535
|
+
rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
|
1365
1536
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
1366
1537
|
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
1367
1538
|
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
|
@@ -1409,7 +1580,6 @@ void Init_generator(void)
|
|
1409
1580
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
1410
1581
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
1411
1582
|
|
1412
|
-
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
1413
1583
|
i_to_s = rb_intern("to_s");
|
1414
1584
|
i_to_json = rb_intern("to_json");
|
1415
1585
|
i_new = rb_intern("new");
|
@@ -1419,6 +1589,7 @@ void Init_generator(void)
|
|
1419
1589
|
i_object_nl = rb_intern("object_nl");
|
1420
1590
|
i_array_nl = rb_intern("array_nl");
|
1421
1591
|
i_max_nesting = rb_intern("max_nesting");
|
1592
|
+
i_escape_slash = rb_intern("escape_slash");
|
1422
1593
|
i_allow_nan = rb_intern("allow_nan");
|
1423
1594
|
i_ascii_only = rb_intern("ascii_only");
|
1424
1595
|
i_depth = rb_intern("depth");
|
@@ -1434,11 +1605,4 @@ void Init_generator(void)
|
|
1434
1605
|
i_match = rb_intern("match");
|
1435
1606
|
i_keys = rb_intern("keys");
|
1436
1607
|
i_dup = rb_intern("dup");
|
1437
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
1438
|
-
CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
|
1439
|
-
i_encoding = rb_intern("encoding");
|
1440
|
-
i_encode = rb_intern("encode");
|
1441
|
-
#endif
|
1442
|
-
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
|
1443
|
-
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
|
1444
1608
|
}
|
@@ -49,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL;
|
|
49
49
|
static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
|
50
50
|
static void unicode_escape(char *buf, UTF16 character);
|
51
51
|
static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
|
52
|
-
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string);
|
53
|
-
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string);
|
52
|
+
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash);
|
53
|
+
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash);
|
54
54
|
static char *fstrndup(const char *ptr, unsigned long len);
|
55
55
|
|
56
56
|
/* ruby api and some helpers */
|
@@ -72,6 +72,7 @@ typedef struct JSON_Generator_StateStruct {
|
|
72
72
|
long max_nesting;
|
73
73
|
char allow_nan;
|
74
74
|
char ascii_only;
|
75
|
+
char escape_slash;
|
75
76
|
long depth;
|
76
77
|
long buffer_initial_length;
|
77
78
|
} JSON_Generator_State;
|
@@ -150,6 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
|
|
150
151
|
static VALUE cState_ascii_only_p(VALUE self);
|
151
152
|
static VALUE cState_depth(VALUE self);
|
152
153
|
static VALUE cState_depth_set(VALUE self, VALUE depth);
|
154
|
+
static VALUE cState_escape_slash(VALUE self);
|
155
|
+
static VALUE cState_escape_slash_set(VALUE self, VALUE depth);
|
153
156
|
static FBuffer *cState_prepare_buffer(VALUE self);
|
154
157
|
#ifndef ZALLOC
|
155
158
|
#define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))
|
@@ -2,5 +2,31 @@
|
|
2
2
|
require 'mkmf'
|
3
3
|
|
4
4
|
have_func("rb_enc_raise", "ruby.h")
|
5
|
+
have_func("rb_enc_interned_str", "ruby.h")
|
6
|
+
|
7
|
+
# checking if String#-@ (str_uminus) dedupes... '
|
8
|
+
begin
|
9
|
+
a = -(%w(t e s t).join)
|
10
|
+
b = -(%w(t e s t).join)
|
11
|
+
if a.equal?(b)
|
12
|
+
$CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
|
13
|
+
else
|
14
|
+
$CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
|
15
|
+
end
|
16
|
+
rescue NoMethodError
|
17
|
+
$CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
|
18
|
+
end
|
19
|
+
|
20
|
+
# checking if String#-@ (str_uminus) directly interns frozen strings... '
|
21
|
+
begin
|
22
|
+
s = rand.to_s.freeze
|
23
|
+
if (-s).equal?(s) && (-s.dup).equal?(s)
|
24
|
+
$CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
|
25
|
+
else
|
26
|
+
$CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
|
27
|
+
end
|
28
|
+
rescue NoMethodError
|
29
|
+
$CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
|
30
|
+
end
|
5
31
|
|
6
32
|
create_makefile 'json/ext/parser'
|