json 1.8.3 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/{CHANGES → CHANGES.md} +244 -93
- data/{COPYING-json-jruby → LICENSE} +5 -6
- data/{README.rdoc → README.md} +202 -135
- data/VERSION +1 -1
- data/ext/json/ext/fbuffer/fbuffer.h +0 -3
- data/ext/json/ext/generator/generator.c +264 -114
- data/ext/json/ext/generator/generator.h +12 -4
- data/ext/json/ext/parser/extconf.rb +29 -0
- data/ext/json/ext/parser/parser.c +3002 -1880
- data/ext/json/ext/parser/parser.h +10 -6
- data/ext/json/ext/parser/parser.rl +230 -192
- 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 +83 -126
- 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 +23 -132
- data/.gitignore +0 -16
- data/.travis.yml +0 -26
- data/COPYING +0 -58
- data/GPL +0 -340
- data/Gemfile +0 -10
- 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/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 -553
- 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 -337
- 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/fuzz.rb +0 -139
- data/tools/server.rb +0 -62
|
@@ -1,22 +1,22 @@
|
|
|
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
|
-
mHash, mArray,
|
|
5
|
+
mHash, mArray,
|
|
6
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
|
7
|
+
mInteger,
|
|
8
|
+
#else
|
|
9
|
+
mFixnum, mBignum,
|
|
10
|
+
#endif
|
|
11
|
+
mFloat, mString, mString_Extend,
|
|
11
12
|
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
|
|
12
|
-
eNestingError
|
|
13
|
-
i_SAFE_STATE_PROTOTYPE;
|
|
13
|
+
eNestingError;
|
|
14
14
|
|
|
15
15
|
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
|
|
16
16
|
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
|
|
17
|
-
|
|
17
|
+
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
|
|
18
18
|
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
|
|
19
|
-
i_buffer_initial_length, i_dup;
|
|
19
|
+
i_buffer_initial_length, i_dup, i_escape_slash;
|
|
20
20
|
|
|
21
21
|
/*
|
|
22
22
|
* Copyright 2001-2004 Unicode, Inc.
|
|
@@ -124,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
|
|
|
124
124
|
|
|
125
125
|
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
|
|
126
126
|
* and control characters are JSON escaped. */
|
|
127
|
-
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)
|
|
128
128
|
{
|
|
129
129
|
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
|
|
130
130
|
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
|
|
@@ -174,6 +174,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
|
174
174
|
case '"':
|
|
175
175
|
fbuffer_append(buffer, "\\\"", 2);
|
|
176
176
|
break;
|
|
177
|
+
case '/':
|
|
178
|
+
if(escape_slash) {
|
|
179
|
+
fbuffer_append(buffer, "\\/", 2);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
177
182
|
default:
|
|
178
183
|
fbuffer_append_char(buffer, (char)ch);
|
|
179
184
|
break;
|
|
@@ -216,13 +221,14 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
|
216
221
|
unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
|
|
217
222
|
}
|
|
218
223
|
}
|
|
224
|
+
RB_GC_GUARD(string);
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
/* Converts string to a JSON string in FBuffer buffer, where only the
|
|
222
228
|
* characters required by the JSON standard are JSON escaped. The remaining
|
|
223
229
|
* characters (should be UTF8) are just passed through and appended to the
|
|
224
230
|
* result. */
|
|
225
|
-
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
231
|
+
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
|
|
226
232
|
{
|
|
227
233
|
const char *ptr = RSTRING_PTR(string), *p;
|
|
228
234
|
unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
|
|
@@ -230,6 +236,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
|
230
236
|
int escape_len;
|
|
231
237
|
unsigned char c;
|
|
232
238
|
char buf[6] = { '\\', 'u' };
|
|
239
|
+
int ascii_only = rb_enc_str_asciionly_p(string);
|
|
233
240
|
|
|
234
241
|
for (start = 0, end = 0; end < len;) {
|
|
235
242
|
p = ptr + end;
|
|
@@ -272,16 +279,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
|
272
279
|
escape = "\\\"";
|
|
273
280
|
escape_len = 2;
|
|
274
281
|
break;
|
|
282
|
+
case '/':
|
|
283
|
+
if(escape_slash) {
|
|
284
|
+
escape = "\\/";
|
|
285
|
+
escape_len = 2;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
275
288
|
default:
|
|
276
289
|
{
|
|
277
|
-
unsigned short clen =
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
+
}
|
|
285
301
|
}
|
|
286
302
|
end += clen;
|
|
287
303
|
}
|
|
@@ -301,7 +317,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
|
301
317
|
char *result;
|
|
302
318
|
if (len <= 0) return NULL;
|
|
303
319
|
result = ALLOC_N(char, len);
|
|
304
|
-
|
|
320
|
+
memcpy(result, ptr, len);
|
|
305
321
|
return result;
|
|
306
322
|
}
|
|
307
323
|
|
|
@@ -317,6 +333,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
|
317
333
|
*
|
|
318
334
|
*/
|
|
319
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
|
+
|
|
320
406
|
/*
|
|
321
407
|
* call-seq: to_json(state = nil)
|
|
322
408
|
*
|
|
@@ -342,6 +428,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
|
342
428
|
GENERATE_JSON(array);
|
|
343
429
|
}
|
|
344
430
|
|
|
431
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
|
432
|
+
/*
|
|
433
|
+
* call-seq: to_json(*)
|
|
434
|
+
*
|
|
435
|
+
* Returns a JSON string representation for this Integer number.
|
|
436
|
+
*/
|
|
437
|
+
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
438
|
+
{
|
|
439
|
+
GENERATE_JSON(integer);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
#else
|
|
345
443
|
/*
|
|
346
444
|
* call-seq: to_json(*)
|
|
347
445
|
*
|
|
@@ -361,6 +459,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
|
361
459
|
{
|
|
362
460
|
GENERATE_JSON(bignum);
|
|
363
461
|
}
|
|
462
|
+
#endif
|
|
364
463
|
|
|
365
464
|
/*
|
|
366
465
|
* call-seq: to_json(*)
|
|
@@ -515,13 +614,18 @@ static size_t State_memsize(const void *ptr)
|
|
|
515
614
|
return size;
|
|
516
615
|
}
|
|
517
616
|
|
|
617
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
618
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
619
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
620
|
+
#endif
|
|
621
|
+
|
|
518
622
|
#ifdef NEW_TYPEDDATA_WRAPPER
|
|
519
623
|
static const rb_data_type_t JSON_Generator_State_type = {
|
|
520
624
|
"JSON/Generator/State",
|
|
521
625
|
{NULL, State_free, State_memsize,},
|
|
522
626
|
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
523
627
|
0, 0,
|
|
524
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
628
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
525
629
|
#endif
|
|
526
630
|
};
|
|
527
631
|
#endif
|
|
@@ -622,8 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
|
622
726
|
state->allow_nan = RTEST(tmp);
|
|
623
727
|
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
|
624
728
|
state->ascii_only = RTEST(tmp);
|
|
625
|
-
tmp = rb_hash_aref(opts, ID2SYM(
|
|
626
|
-
state->
|
|
729
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
|
|
730
|
+
state->escape_slash = RTEST(tmp);
|
|
627
731
|
return self;
|
|
628
732
|
}
|
|
629
733
|
|
|
@@ -657,8 +761,8 @@ static VALUE cState_to_h(VALUE self)
|
|
|
657
761
|
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
|
|
658
762
|
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
|
659
763
|
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
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);
|
|
662
766
|
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
|
663
767
|
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
|
664
768
|
return result;
|
|
@@ -675,7 +779,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
|
|
|
675
779
|
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
|
676
780
|
return rb_funcall(self, i_send, 1, name);
|
|
677
781
|
} else {
|
|
678
|
-
return
|
|
782
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
|
679
783
|
}
|
|
680
784
|
}
|
|
681
785
|
|
|
@@ -698,43 +802,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
|
|
698
802
|
return Qnil;
|
|
699
803
|
}
|
|
700
804
|
|
|
701
|
-
|
|
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)
|
|
702
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
|
+
|
|
703
820
|
char *object_nl = state->object_nl;
|
|
704
821
|
long object_nl_len = state->object_nl_len;
|
|
705
822
|
char *indent = state->indent;
|
|
706
823
|
long indent_len = state->indent_len;
|
|
707
|
-
long max_nesting = state->max_nesting;
|
|
708
824
|
char *delim = FBUFFER_PTR(state->object_delim);
|
|
709
825
|
long delim_len = FBUFFER_LEN(state->object_delim);
|
|
710
826
|
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
|
711
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;
|
|
712
866
|
long depth = ++state->depth;
|
|
713
|
-
int
|
|
714
|
-
|
|
867
|
+
int j;
|
|
868
|
+
struct hash_foreach_arg arg;
|
|
869
|
+
|
|
715
870
|
if (max_nesting != 0 && depth > max_nesting) {
|
|
716
871
|
fbuffer_free(buffer);
|
|
717
872
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
|
718
873
|
}
|
|
719
874
|
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
|
-
}
|
|
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
|
+
|
|
738
882
|
depth = --state->depth;
|
|
739
883
|
if (object_nl) {
|
|
740
884
|
fbuffer_append(buffer, object_nl, object_nl_len);
|
|
@@ -785,16 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
|
785
929
|
fbuffer_append_char(buffer, ']');
|
|
786
930
|
}
|
|
787
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
|
+
|
|
788
941
|
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
789
942
|
{
|
|
790
943
|
fbuffer_append_char(buffer, '"');
|
|
791
944
|
#ifdef HAVE_RUBY_ENCODING_H
|
|
792
|
-
|
|
945
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
|
946
|
+
obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
|
|
947
|
+
}
|
|
793
948
|
#endif
|
|
794
949
|
if (state->ascii_only) {
|
|
795
|
-
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
|
950
|
+
convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
|
|
796
951
|
} else {
|
|
797
|
-
convert_UTF8_to_JSON(buffer, obj);
|
|
952
|
+
convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
|
|
798
953
|
}
|
|
799
954
|
fbuffer_append_char(buffer, '"');
|
|
800
955
|
}
|
|
@@ -825,6 +980,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
|
825
980
|
fbuffer_append_str(buffer, tmp);
|
|
826
981
|
}
|
|
827
982
|
|
|
983
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
|
984
|
+
static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
985
|
+
{
|
|
986
|
+
if (FIXNUM_P(obj))
|
|
987
|
+
generate_json_fixnum(buffer, Vstate, state, obj);
|
|
988
|
+
else
|
|
989
|
+
generate_json_bignum(buffer, Vstate, state, obj);
|
|
990
|
+
}
|
|
991
|
+
#endif
|
|
828
992
|
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
829
993
|
{
|
|
830
994
|
double value = RFLOAT_VALUE(obj);
|
|
@@ -858,9 +1022,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
|
858
1022
|
generate_json_false(buffer, Vstate, state, obj);
|
|
859
1023
|
} else if (obj == Qtrue) {
|
|
860
1024
|
generate_json_true(buffer, Vstate, state, obj);
|
|
861
|
-
} else if (
|
|
1025
|
+
} else if (FIXNUM_P(obj)) {
|
|
862
1026
|
generate_json_fixnum(buffer, Vstate, state, obj);
|
|
863
|
-
} else if (
|
|
1027
|
+
} else if (RB_TYPE_P(obj, T_BIGNUM)) {
|
|
864
1028
|
generate_json_bignum(buffer, Vstate, state, obj);
|
|
865
1029
|
} else if (klass == rb_cFloat) {
|
|
866
1030
|
generate_json_float(buffer, Vstate, state, obj);
|
|
@@ -871,7 +1035,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
|
871
1035
|
} else {
|
|
872
1036
|
tmp = rb_funcall(obj, i_to_s, 0);
|
|
873
1037
|
Check_Type(tmp, T_STRING);
|
|
874
|
-
|
|
1038
|
+
generate_json_string(buffer, Vstate, state, tmp);
|
|
875
1039
|
}
|
|
876
1040
|
}
|
|
877
1041
|
|
|
@@ -914,21 +1078,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|
|
914
1078
|
return fbuffer_to_s(buffer);
|
|
915
1079
|
}
|
|
916
1080
|
|
|
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
1081
|
/*
|
|
933
1082
|
* call-seq: generate(obj)
|
|
934
1083
|
*
|
|
@@ -940,9 +1089,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
|
940
1089
|
{
|
|
941
1090
|
VALUE result = cState_partial_generate(self, obj);
|
|
942
1091
|
GET_STATE(self);
|
|
943
|
-
|
|
944
|
-
rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
|
|
945
|
-
}
|
|
1092
|
+
(void)state;
|
|
946
1093
|
return result;
|
|
947
1094
|
}
|
|
948
1095
|
|
|
@@ -961,8 +1108,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
|
961
1108
|
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
962
1109
|
* generated, otherwise an exception is thrown, if these values are
|
|
963
1110
|
* encountered. This options defaults to false.
|
|
964
|
-
* * *
|
|
965
|
-
*
|
|
1111
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
|
1112
|
+
* option defaults to false.
|
|
966
1113
|
* * *buffer_initial_length*: sets the initial length of the generator's
|
|
967
1114
|
* internal buffer.
|
|
968
1115
|
*/
|
|
@@ -1018,10 +1165,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
|
1018
1165
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
|
1019
1166
|
return rb_funcall(self, i_new, 1, opts);
|
|
1020
1167
|
} 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);
|
|
1168
|
+
return rb_class_new_instance(0, NULL, cState);
|
|
1025
1169
|
}
|
|
1026
1170
|
}
|
|
1027
1171
|
|
|
@@ -1055,7 +1199,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
|
1055
1199
|
}
|
|
1056
1200
|
} else {
|
|
1057
1201
|
if (state->indent) ruby_xfree(state->indent);
|
|
1058
|
-
state->indent =
|
|
1202
|
+
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
|
1059
1203
|
state->indent_len = len;
|
|
1060
1204
|
}
|
|
1061
1205
|
return Qnil;
|
|
@@ -1093,7 +1237,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
|
1093
1237
|
}
|
|
1094
1238
|
} else {
|
|
1095
1239
|
if (state->space) ruby_xfree(state->space);
|
|
1096
|
-
state->space =
|
|
1240
|
+
state->space = fstrndup(RSTRING_PTR(space), len);
|
|
1097
1241
|
state->space_len = len;
|
|
1098
1242
|
}
|
|
1099
1243
|
return Qnil;
|
|
@@ -1129,7 +1273,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
|
1129
1273
|
}
|
|
1130
1274
|
} else {
|
|
1131
1275
|
if (state->space_before) ruby_xfree(state->space_before);
|
|
1132
|
-
state->space_before =
|
|
1276
|
+
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
|
1133
1277
|
state->space_before_len = len;
|
|
1134
1278
|
}
|
|
1135
1279
|
return Qnil;
|
|
@@ -1166,7 +1310,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
|
1166
1310
|
}
|
|
1167
1311
|
} else {
|
|
1168
1312
|
if (state->object_nl) ruby_xfree(state->object_nl);
|
|
1169
|
-
state->object_nl =
|
|
1313
|
+
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
|
1170
1314
|
state->object_nl_len = len;
|
|
1171
1315
|
}
|
|
1172
1316
|
return Qnil;
|
|
@@ -1201,7 +1345,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
|
1201
1345
|
}
|
|
1202
1346
|
} else {
|
|
1203
1347
|
if (state->array_nl) ruby_xfree(state->array_nl);
|
|
1204
|
-
state->array_nl =
|
|
1348
|
+
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
|
1205
1349
|
state->array_nl_len = len;
|
|
1206
1350
|
}
|
|
1207
1351
|
return Qnil;
|
|
@@ -1246,50 +1390,52 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
|
1246
1390
|
}
|
|
1247
1391
|
|
|
1248
1392
|
/*
|
|
1249
|
-
* call-seq:
|
|
1393
|
+
* call-seq: escape_slash
|
|
1250
1394
|
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1395
|
+
* If this boolean is true, the forward slashes will be escaped in
|
|
1396
|
+
* the json output.
|
|
1253
1397
|
*/
|
|
1254
|
-
static VALUE
|
|
1398
|
+
static VALUE cState_escape_slash(VALUE self)
|
|
1255
1399
|
{
|
|
1256
1400
|
GET_STATE(self);
|
|
1257
|
-
return state->
|
|
1401
|
+
return state->escape_slash ? Qtrue : Qfalse;
|
|
1258
1402
|
}
|
|
1259
1403
|
|
|
1260
1404
|
/*
|
|
1261
|
-
* call-seq:
|
|
1405
|
+
* call-seq: escape_slash=(depth)
|
|
1262
1406
|
*
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1407
|
+
* This sets whether or not the forward slashes will be escaped in
|
|
1408
|
+
* the json output.
|
|
1265
1409
|
*/
|
|
1266
|
-
static VALUE
|
|
1410
|
+
static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
|
|
1267
1411
|
{
|
|
1268
1412
|
GET_STATE(self);
|
|
1269
|
-
|
|
1413
|
+
state->escape_slash = RTEST(enable);
|
|
1414
|
+
return Qnil;
|
|
1270
1415
|
}
|
|
1271
1416
|
|
|
1272
1417
|
/*
|
|
1273
|
-
* call-seq:
|
|
1418
|
+
* call-seq: allow_nan?
|
|
1274
1419
|
*
|
|
1275
|
-
* Returns true, if
|
|
1420
|
+
* Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
|
|
1421
|
+
* returns false.
|
|
1276
1422
|
*/
|
|
1277
|
-
static VALUE
|
|
1423
|
+
static VALUE cState_allow_nan_p(VALUE self)
|
|
1278
1424
|
{
|
|
1279
1425
|
GET_STATE(self);
|
|
1280
|
-
return state->
|
|
1426
|
+
return state->allow_nan ? Qtrue : Qfalse;
|
|
1281
1427
|
}
|
|
1282
1428
|
|
|
1283
1429
|
/*
|
|
1284
|
-
* call-seq:
|
|
1430
|
+
* call-seq: ascii_only?
|
|
1285
1431
|
*
|
|
1286
|
-
*
|
|
1432
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
|
1433
|
+
* returns false.
|
|
1287
1434
|
*/
|
|
1288
|
-
static VALUE
|
|
1435
|
+
static VALUE cState_ascii_only_p(VALUE self)
|
|
1289
1436
|
{
|
|
1290
1437
|
GET_STATE(self);
|
|
1291
|
-
state->
|
|
1292
|
-
return Qnil;
|
|
1438
|
+
return state->ascii_only ? Qtrue : Qfalse;
|
|
1293
1439
|
}
|
|
1294
1440
|
|
|
1295
1441
|
/*
|
|
@@ -1351,6 +1497,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
|
1351
1497
|
*/
|
|
1352
1498
|
void Init_generator(void)
|
|
1353
1499
|
{
|
|
1500
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
1501
|
+
rb_ext_ractor_safe(true);
|
|
1502
|
+
#endif
|
|
1503
|
+
|
|
1504
|
+
#undef rb_intern
|
|
1354
1505
|
rb_require("json/common");
|
|
1355
1506
|
|
|
1356
1507
|
mJSON = rb_define_module("JSON");
|
|
@@ -1359,6 +1510,8 @@ void Init_generator(void)
|
|
|
1359
1510
|
|
|
1360
1511
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
|
1361
1512
|
eNestingError = rb_path2class("JSON::NestingError");
|
|
1513
|
+
rb_gc_register_mark_object(eGeneratorError);
|
|
1514
|
+
rb_gc_register_mark_object(eNestingError);
|
|
1362
1515
|
|
|
1363
1516
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
|
1364
1517
|
rb_define_alloc_func(cState, cState_s_allocate);
|
|
@@ -1377,12 +1530,12 @@ void Init_generator(void)
|
|
|
1377
1530
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
|
1378
1531
|
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
|
1379
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);
|
|
1380
1536
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
|
1381
1537
|
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
|
1382
1538
|
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
1539
|
rb_define_method(cState, "depth", cState_depth, 0);
|
|
1387
1540
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
|
1388
1541
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
@@ -1402,10 +1555,15 @@ void Init_generator(void)
|
|
|
1402
1555
|
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
|
1403
1556
|
mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
|
1404
1557
|
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
|
1558
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
|
1559
|
+
mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
|
|
1560
|
+
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
|
|
1561
|
+
#else
|
|
1405
1562
|
mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
|
1406
1563
|
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
|
1407
1564
|
mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
|
1408
1565
|
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
|
1566
|
+
#endif
|
|
1409
1567
|
mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
|
1410
1568
|
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
|
1411
1569
|
mString = rb_define_module_under(mGeneratorMethods, "String");
|
|
@@ -1422,7 +1580,6 @@ void Init_generator(void)
|
|
|
1422
1580
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
1423
1581
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
1424
1582
|
|
|
1425
|
-
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
|
1426
1583
|
i_to_s = rb_intern("to_s");
|
|
1427
1584
|
i_to_json = rb_intern("to_json");
|
|
1428
1585
|
i_new = rb_intern("new");
|
|
@@ -1432,9 +1589,9 @@ void Init_generator(void)
|
|
|
1432
1589
|
i_object_nl = rb_intern("object_nl");
|
|
1433
1590
|
i_array_nl = rb_intern("array_nl");
|
|
1434
1591
|
i_max_nesting = rb_intern("max_nesting");
|
|
1592
|
+
i_escape_slash = rb_intern("escape_slash");
|
|
1435
1593
|
i_allow_nan = rb_intern("allow_nan");
|
|
1436
1594
|
i_ascii_only = rb_intern("ascii_only");
|
|
1437
|
-
i_quirks_mode = rb_intern("quirks_mode");
|
|
1438
1595
|
i_depth = rb_intern("depth");
|
|
1439
1596
|
i_buffer_initial_length = rb_intern("buffer_initial_length");
|
|
1440
1597
|
i_pack = rb_intern("pack");
|
|
@@ -1448,11 +1605,4 @@ void Init_generator(void)
|
|
|
1448
1605
|
i_match = rb_intern("match");
|
|
1449
1606
|
i_keys = rb_intern("keys");
|
|
1450
1607
|
i_dup = rb_intern("dup");
|
|
1451
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
|
1452
|
-
CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
|
|
1453
|
-
i_encoding = rb_intern("encoding");
|
|
1454
|
-
i_encode = rb_intern("encode");
|
|
1455
|
-
#endif
|
|
1456
|
-
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
|
|
1457
|
-
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
|
|
1458
1608
|
}
|