json 1.8.6 → 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 +5 -5
- data/{CHANGES → CHANGES.md} +248 -98
- data/LICENSE +56 -0
- data/README.md +188 -108
- data/VERSION +1 -1
- data/ext/json/ext/fbuffer/fbuffer.h +0 -3
- data/ext/json/ext/generator/generator.c +227 -111
- data/ext/json/ext/generator/generator.h +5 -8
- data/ext/json/ext/parser/extconf.rb +29 -0
- data/ext/json/ext/parser/parser.c +3022 -1915
- data/ext/json/ext/parser/parser.h +10 -6
- data/ext/json/ext/parser/parser.rl +206 -183
- data/ext/json/extconf.rb +1 -1
- data/json.gemspec +0 -0
- 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/generator.rb +73 -124
- data/lib/json/pure/parser.rb +63 -85
- data/lib/json/pure.rb +2 -8
- data/lib/json/version.rb +2 -1
- data/lib/json.rb +550 -29
- metadata +20 -127
- 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/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_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;
|
|
@@ -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 escape_slash)
|
|
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,25 @@ 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(escape_slash) {
|
|
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
|
+
if (!isLegalUTF8((UTF8 *) p, clen)) {
|
|
298
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
|
299
|
+
"source sequence is illegal/malformed utf-8");
|
|
300
|
+
}
|
|
291
301
|
}
|
|
292
302
|
end += clen;
|
|
293
303
|
}
|
|
@@ -307,7 +317,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
|
307
317
|
char *result;
|
|
308
318
|
if (len <= 0) return NULL;
|
|
309
319
|
result = ALLOC_N(char, len);
|
|
310
|
-
|
|
320
|
+
memcpy(result, ptr, len);
|
|
311
321
|
return result;
|
|
312
322
|
}
|
|
313
323
|
|
|
@@ -323,6 +333,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
|
323
333
|
*
|
|
324
334
|
*/
|
|
325
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
|
+
|
|
326
406
|
/*
|
|
327
407
|
* call-seq: to_json(state = nil)
|
|
328
408
|
*
|
|
@@ -534,13 +614,18 @@ static size_t State_memsize(const void *ptr)
|
|
|
534
614
|
return size;
|
|
535
615
|
}
|
|
536
616
|
|
|
617
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
618
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
619
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
620
|
+
#endif
|
|
621
|
+
|
|
537
622
|
#ifdef NEW_TYPEDDATA_WRAPPER
|
|
538
623
|
static const rb_data_type_t JSON_Generator_State_type = {
|
|
539
624
|
"JSON/Generator/State",
|
|
540
625
|
{NULL, State_free, State_memsize,},
|
|
541
626
|
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
542
627
|
0, 0,
|
|
543
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
628
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
544
629
|
#endif
|
|
545
630
|
};
|
|
546
631
|
#endif
|
|
@@ -641,8 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
|
641
726
|
state->allow_nan = RTEST(tmp);
|
|
642
727
|
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
|
643
728
|
state->ascii_only = RTEST(tmp);
|
|
644
|
-
tmp = rb_hash_aref(opts, ID2SYM(
|
|
645
|
-
state->
|
|
729
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
|
|
730
|
+
state->escape_slash = RTEST(tmp);
|
|
646
731
|
return self;
|
|
647
732
|
}
|
|
648
733
|
|
|
@@ -676,8 +761,8 @@ static VALUE cState_to_h(VALUE self)
|
|
|
676
761
|
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
|
|
677
762
|
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
|
678
763
|
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
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);
|
|
681
766
|
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
|
682
767
|
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
|
683
768
|
return result;
|
|
@@ -694,7 +779,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
|
|
|
694
779
|
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
|
695
780
|
return rb_funcall(self, i_send, 1, name);
|
|
696
781
|
} else {
|
|
697
|
-
return
|
|
782
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
|
698
783
|
}
|
|
699
784
|
}
|
|
700
785
|
|
|
@@ -717,43 +802,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
|
|
717
802
|
return Qnil;
|
|
718
803
|
}
|
|
719
804
|
|
|
720
|
-
|
|
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)
|
|
721
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
|
+
|
|
722
820
|
char *object_nl = state->object_nl;
|
|
723
821
|
long object_nl_len = state->object_nl_len;
|
|
724
822
|
char *indent = state->indent;
|
|
725
823
|
long indent_len = state->indent_len;
|
|
726
|
-
long max_nesting = state->max_nesting;
|
|
727
824
|
char *delim = FBUFFER_PTR(state->object_delim);
|
|
728
825
|
long delim_len = FBUFFER_LEN(state->object_delim);
|
|
729
826
|
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
|
730
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;
|
|
731
866
|
long depth = ++state->depth;
|
|
732
|
-
int
|
|
733
|
-
|
|
867
|
+
int j;
|
|
868
|
+
struct hash_foreach_arg arg;
|
|
869
|
+
|
|
734
870
|
if (max_nesting != 0 && depth > max_nesting) {
|
|
735
871
|
fbuffer_free(buffer);
|
|
736
872
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
|
737
873
|
}
|
|
738
874
|
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
|
-
}
|
|
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
|
+
|
|
757
882
|
depth = --state->depth;
|
|
758
883
|
if (object_nl) {
|
|
759
884
|
fbuffer_append(buffer, object_nl, object_nl_len);
|
|
@@ -804,16 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
|
804
929
|
fbuffer_append_char(buffer, ']');
|
|
805
930
|
}
|
|
806
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
|
+
|
|
807
941
|
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
808
942
|
{
|
|
809
943
|
fbuffer_append_char(buffer, '"');
|
|
810
944
|
#ifdef HAVE_RUBY_ENCODING_H
|
|
811
|
-
|
|
945
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
|
946
|
+
obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
|
|
947
|
+
}
|
|
812
948
|
#endif
|
|
813
949
|
if (state->ascii_only) {
|
|
814
|
-
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
|
950
|
+
convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
|
|
815
951
|
} else {
|
|
816
|
-
convert_UTF8_to_JSON(buffer, obj);
|
|
952
|
+
convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
|
|
817
953
|
}
|
|
818
954
|
fbuffer_append_char(buffer, '"');
|
|
819
955
|
}
|
|
@@ -853,7 +989,6 @@ static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_
|
|
|
853
989
|
generate_json_bignum(buffer, Vstate, state, obj);
|
|
854
990
|
}
|
|
855
991
|
#endif
|
|
856
|
-
|
|
857
992
|
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
858
993
|
{
|
|
859
994
|
double value = RFLOAT_VALUE(obj);
|
|
@@ -943,21 +1078,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|
|
943
1078
|
return fbuffer_to_s(buffer);
|
|
944
1079
|
}
|
|
945
1080
|
|
|
946
|
-
/*
|
|
947
|
-
* This function returns true if string is either a JSON array or JSON object.
|
|
948
|
-
* It might suffer from false positives, e. g. syntactically incorrect JSON in
|
|
949
|
-
* the string or certain UTF-8 characters on the right hand side.
|
|
950
|
-
*/
|
|
951
|
-
static int isArrayOrObject(VALUE string)
|
|
952
|
-
{
|
|
953
|
-
long string_len = RSTRING_LEN(string);
|
|
954
|
-
char *p = RSTRING_PTR(string), *q = p + string_len - 1;
|
|
955
|
-
if (string_len < 2) return 0;
|
|
956
|
-
for (; p < q && isspace((unsigned char)*p); p++);
|
|
957
|
-
for (; q > p && isspace((unsigned char)*q); q--);
|
|
958
|
-
return (*p == '[' && *q == ']') || (*p == '{' && *q == '}');
|
|
959
|
-
}
|
|
960
|
-
|
|
961
1081
|
/*
|
|
962
1082
|
* call-seq: generate(obj)
|
|
963
1083
|
*
|
|
@@ -969,9 +1089,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
|
969
1089
|
{
|
|
970
1090
|
VALUE result = cState_partial_generate(self, obj);
|
|
971
1091
|
GET_STATE(self);
|
|
972
|
-
|
|
973
|
-
rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
|
|
974
|
-
}
|
|
1092
|
+
(void)state;
|
|
975
1093
|
return result;
|
|
976
1094
|
}
|
|
977
1095
|
|
|
@@ -990,8 +1108,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
|
990
1108
|
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
991
1109
|
* generated, otherwise an exception is thrown, if these values are
|
|
992
1110
|
* encountered. This options defaults to false.
|
|
993
|
-
* * *
|
|
994
|
-
*
|
|
1111
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
|
1112
|
+
* option defaults to false.
|
|
995
1113
|
* * *buffer_initial_length*: sets the initial length of the generator's
|
|
996
1114
|
* internal buffer.
|
|
997
1115
|
*/
|
|
@@ -1047,10 +1165,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
|
1047
1165
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
|
1048
1166
|
return rb_funcall(self, i_new, 1, opts);
|
|
1049
1167
|
} 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);
|
|
1168
|
+
return rb_class_new_instance(0, NULL, cState);
|
|
1054
1169
|
}
|
|
1055
1170
|
}
|
|
1056
1171
|
|
|
@@ -1084,7 +1199,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
|
1084
1199
|
}
|
|
1085
1200
|
} else {
|
|
1086
1201
|
if (state->indent) ruby_xfree(state->indent);
|
|
1087
|
-
state->indent =
|
|
1202
|
+
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
|
1088
1203
|
state->indent_len = len;
|
|
1089
1204
|
}
|
|
1090
1205
|
return Qnil;
|
|
@@ -1122,7 +1237,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
|
1122
1237
|
}
|
|
1123
1238
|
} else {
|
|
1124
1239
|
if (state->space) ruby_xfree(state->space);
|
|
1125
|
-
state->space =
|
|
1240
|
+
state->space = fstrndup(RSTRING_PTR(space), len);
|
|
1126
1241
|
state->space_len = len;
|
|
1127
1242
|
}
|
|
1128
1243
|
return Qnil;
|
|
@@ -1158,7 +1273,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
|
1158
1273
|
}
|
|
1159
1274
|
} else {
|
|
1160
1275
|
if (state->space_before) ruby_xfree(state->space_before);
|
|
1161
|
-
state->space_before =
|
|
1276
|
+
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
|
1162
1277
|
state->space_before_len = len;
|
|
1163
1278
|
}
|
|
1164
1279
|
return Qnil;
|
|
@@ -1195,7 +1310,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
|
1195
1310
|
}
|
|
1196
1311
|
} else {
|
|
1197
1312
|
if (state->object_nl) ruby_xfree(state->object_nl);
|
|
1198
|
-
state->object_nl =
|
|
1313
|
+
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
|
1199
1314
|
state->object_nl_len = len;
|
|
1200
1315
|
}
|
|
1201
1316
|
return Qnil;
|
|
@@ -1230,7 +1345,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
|
1230
1345
|
}
|
|
1231
1346
|
} else {
|
|
1232
1347
|
if (state->array_nl) ruby_xfree(state->array_nl);
|
|
1233
|
-
state->array_nl =
|
|
1348
|
+
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
|
1234
1349
|
state->array_nl_len = len;
|
|
1235
1350
|
}
|
|
1236
1351
|
return Qnil;
|
|
@@ -1275,50 +1390,52 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
|
1275
1390
|
}
|
|
1276
1391
|
|
|
1277
1392
|
/*
|
|
1278
|
-
* call-seq:
|
|
1393
|
+
* call-seq: escape_slash
|
|
1279
1394
|
*
|
|
1280
|
-
*
|
|
1281
|
-
*
|
|
1395
|
+
* If this boolean is true, the forward slashes will be escaped in
|
|
1396
|
+
* the json output.
|
|
1282
1397
|
*/
|
|
1283
|
-
static VALUE
|
|
1398
|
+
static VALUE cState_escape_slash(VALUE self)
|
|
1284
1399
|
{
|
|
1285
1400
|
GET_STATE(self);
|
|
1286
|
-
return state->
|
|
1401
|
+
return state->escape_slash ? Qtrue : Qfalse;
|
|
1287
1402
|
}
|
|
1288
1403
|
|
|
1289
1404
|
/*
|
|
1290
|
-
* call-seq:
|
|
1405
|
+
* call-seq: escape_slash=(depth)
|
|
1291
1406
|
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1407
|
+
* This sets whether or not the forward slashes will be escaped in
|
|
1408
|
+
* the json output.
|
|
1294
1409
|
*/
|
|
1295
|
-
static VALUE
|
|
1410
|
+
static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
|
|
1296
1411
|
{
|
|
1297
1412
|
GET_STATE(self);
|
|
1298
|
-
|
|
1413
|
+
state->escape_slash = RTEST(enable);
|
|
1414
|
+
return Qnil;
|
|
1299
1415
|
}
|
|
1300
1416
|
|
|
1301
1417
|
/*
|
|
1302
|
-
* call-seq:
|
|
1418
|
+
* call-seq: allow_nan?
|
|
1303
1419
|
*
|
|
1304
|
-
* Returns true, if
|
|
1420
|
+
* Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
|
|
1421
|
+
* returns false.
|
|
1305
1422
|
*/
|
|
1306
|
-
static VALUE
|
|
1423
|
+
static VALUE cState_allow_nan_p(VALUE self)
|
|
1307
1424
|
{
|
|
1308
1425
|
GET_STATE(self);
|
|
1309
|
-
return state->
|
|
1426
|
+
return state->allow_nan ? Qtrue : Qfalse;
|
|
1310
1427
|
}
|
|
1311
1428
|
|
|
1312
1429
|
/*
|
|
1313
|
-
* call-seq:
|
|
1430
|
+
* call-seq: ascii_only?
|
|
1314
1431
|
*
|
|
1315
|
-
*
|
|
1432
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
|
1433
|
+
* returns false.
|
|
1316
1434
|
*/
|
|
1317
|
-
static VALUE
|
|
1435
|
+
static VALUE cState_ascii_only_p(VALUE self)
|
|
1318
1436
|
{
|
|
1319
1437
|
GET_STATE(self);
|
|
1320
|
-
state->
|
|
1321
|
-
return Qnil;
|
|
1438
|
+
return state->ascii_only ? Qtrue : Qfalse;
|
|
1322
1439
|
}
|
|
1323
1440
|
|
|
1324
1441
|
/*
|
|
@@ -1380,6 +1497,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
|
1380
1497
|
*/
|
|
1381
1498
|
void Init_generator(void)
|
|
1382
1499
|
{
|
|
1500
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
1501
|
+
rb_ext_ractor_safe(true);
|
|
1502
|
+
#endif
|
|
1503
|
+
|
|
1504
|
+
#undef rb_intern
|
|
1383
1505
|
rb_require("json/common");
|
|
1384
1506
|
|
|
1385
1507
|
mJSON = rb_define_module("JSON");
|
|
@@ -1388,6 +1510,8 @@ void Init_generator(void)
|
|
|
1388
1510
|
|
|
1389
1511
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
|
1390
1512
|
eNestingError = rb_path2class("JSON::NestingError");
|
|
1513
|
+
rb_gc_register_mark_object(eGeneratorError);
|
|
1514
|
+
rb_gc_register_mark_object(eNestingError);
|
|
1391
1515
|
|
|
1392
1516
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
|
1393
1517
|
rb_define_alloc_func(cState, cState_s_allocate);
|
|
@@ -1406,12 +1530,12 @@ void Init_generator(void)
|
|
|
1406
1530
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
|
1407
1531
|
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
|
1408
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);
|
|
1409
1536
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
|
1410
1537
|
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
|
1411
1538
|
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
1539
|
rb_define_method(cState, "depth", cState_depth, 0);
|
|
1416
1540
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
|
1417
1541
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
@@ -1456,7 +1580,6 @@ void Init_generator(void)
|
|
|
1456
1580
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
1457
1581
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
1458
1582
|
|
|
1459
|
-
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
|
1460
1583
|
i_to_s = rb_intern("to_s");
|
|
1461
1584
|
i_to_json = rb_intern("to_json");
|
|
1462
1585
|
i_new = rb_intern("new");
|
|
@@ -1466,9 +1589,9 @@ void Init_generator(void)
|
|
|
1466
1589
|
i_object_nl = rb_intern("object_nl");
|
|
1467
1590
|
i_array_nl = rb_intern("array_nl");
|
|
1468
1591
|
i_max_nesting = rb_intern("max_nesting");
|
|
1592
|
+
i_escape_slash = rb_intern("escape_slash");
|
|
1469
1593
|
i_allow_nan = rb_intern("allow_nan");
|
|
1470
1594
|
i_ascii_only = rb_intern("ascii_only");
|
|
1471
|
-
i_quirks_mode = rb_intern("quirks_mode");
|
|
1472
1595
|
i_depth = rb_intern("depth");
|
|
1473
1596
|
i_buffer_initial_length = rb_intern("buffer_initial_length");
|
|
1474
1597
|
i_pack = rb_intern("pack");
|
|
@@ -1482,11 +1605,4 @@ void Init_generator(void)
|
|
|
1482
1605
|
i_match = rb_intern("match");
|
|
1483
1606
|
i_keys = rb_intern("keys");
|
|
1484
1607
|
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
1608
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#ifndef _GENERATOR_H_
|
|
2
2
|
#define _GENERATOR_H_
|
|
3
3
|
|
|
4
|
-
#include <string.h>
|
|
5
4
|
#include <math.h>
|
|
6
5
|
#include <ctype.h>
|
|
7
6
|
|
|
@@ -21,10 +20,6 @@
|
|
|
21
20
|
#define rb_obj_instance_variables(object) rb_funcall(object, rb_intern("instance_variables"), 0)
|
|
22
21
|
#endif
|
|
23
22
|
|
|
24
|
-
#ifndef RB_TYPE_P
|
|
25
|
-
#define RB_TYPE_P(obj, type) (rb_type(obj) == type)
|
|
26
|
-
#endif
|
|
27
|
-
|
|
28
23
|
#define option_given_p(opts, key) RTEST(rb_funcall(opts, i_key_p, 1, key))
|
|
29
24
|
|
|
30
25
|
/* unicode definitions */
|
|
@@ -54,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL;
|
|
|
54
49
|
static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
|
|
55
50
|
static void unicode_escape(char *buf, UTF16 character);
|
|
56
51
|
static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
|
|
57
|
-
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string);
|
|
58
|
-
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);
|
|
59
54
|
static char *fstrndup(const char *ptr, unsigned long len);
|
|
60
55
|
|
|
61
56
|
/* ruby api and some helpers */
|
|
@@ -77,7 +72,7 @@ typedef struct JSON_Generator_StateStruct {
|
|
|
77
72
|
long max_nesting;
|
|
78
73
|
char allow_nan;
|
|
79
74
|
char ascii_only;
|
|
80
|
-
char
|
|
75
|
+
char escape_slash;
|
|
81
76
|
long depth;
|
|
82
77
|
long buffer_initial_length;
|
|
83
78
|
} JSON_Generator_State;
|
|
@@ -156,6 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
|
|
|
156
151
|
static VALUE cState_ascii_only_p(VALUE self);
|
|
157
152
|
static VALUE cState_depth(VALUE self);
|
|
158
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);
|
|
159
156
|
static FBuffer *cState_prepare_buffer(VALUE self);
|
|
160
157
|
#ifndef ZALLOC
|
|
161
158
|
#define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))
|