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