json 2.2.0 → 2.5.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 +4 -4
- data/CHANGES.md +51 -0
- data/LICENSE +56 -0
- data/README.md +17 -1
- data/VERSION +1 -1
- data/ext/json/ext/generator/generator.c +222 -48
- data/ext/json/ext/generator/generator.h +5 -2
- data/ext/json/ext/parser/extconf.rb +25 -0
- data/ext/json/ext/parser/parser.c +150 -102
- data/ext/json/ext/parser/parser.h +1 -0
- data/ext/json/ext/parser/parser.rl +80 -32
- data/ext/json/extconf.rb +1 -0
- data/json.gemspec +0 -0
- data/lib/json.rb +549 -29
- data/lib/json/add/bigdecimal.rb +2 -2
- data/lib/json/add/complex.rb +2 -3
- data/lib/json/add/rational.rb +2 -3
- data/lib/json/add/regexp.rb +2 -2
- data/lib/json/common.rb +370 -125
- data/lib/json/pure/generator.rb +31 -10
- data/lib/json/pure/parser.rb +31 -5
- data/lib/json/version.rb +1 -1
- data/tests/fixtures/fail29.json +1 -0
- data/tests/fixtures/fail30.json +1 -0
- data/tests/fixtures/fail31.json +1 -0
- data/tests/fixtures/fail32.json +1 -0
- data/tests/json_addition_test.rb +0 -4
- data/tests/json_common_interface_test.rb +47 -4
- data/tests/json_fixtures_test.rb +9 -1
- data/tests/json_generator_test.rb +30 -8
- data/tests/json_parser_test.rb +39 -14
- data/tests/lib/core_assertions.rb +763 -0
- data/tests/lib/envutil.rb +365 -0
- data/tests/lib/find_executable.rb +22 -0
- data/tests/lib/helper.rb +4 -0
- data/tests/ractor_test.rb +30 -0
- data/tests/test_helper.rb +3 -3
- metadata +30 -40
- data/.gitignore +0 -17
- data/.travis.yml +0 -23
- data/README-json-jruby.md +0 -33
- data/Rakefile +0 -408
- data/diagrams/.keep +0 -0
- data/install.rb +0 -23
- data/java/src/json/ext/ByteListTranscoder.java +0 -166
- data/java/src/json/ext/Generator.java +0 -443
- data/java/src/json/ext/GeneratorMethods.java +0 -231
- data/java/src/json/ext/GeneratorService.java +0 -42
- data/java/src/json/ext/GeneratorState.java +0 -490
- data/java/src/json/ext/OptionsReader.java +0 -113
- data/java/src/json/ext/Parser.java +0 -2362
- data/java/src/json/ext/Parser.rl +0 -893
- data/java/src/json/ext/ParserService.java +0 -34
- data/java/src/json/ext/RuntimeInfo.java +0 -116
- data/java/src/json/ext/StringDecoder.java +0 -166
- data/java/src/json/ext/StringEncoder.java +0 -111
- data/java/src/json/ext/Utils.java +0 -88
- data/json-java.gemspec +0 -38
- data/json_pure.gemspec +0 -38
- data/references/rfc7159.txt +0 -899
- data/tools/diff.sh +0 -18
- data/tools/fuzz.rb +0 -131
- data/tools/server.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae21d647db9c8291ae1fd3137d82feff3c0f7d575c244bd23902332179ef660b
|
4
|
+
data.tar.gz: d51e458a1de384797e9a11ca9413f74ff58f067e4478a4d54d220527387914fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7b8eaa3f4cb78f26cdb0a4629529372baa32b9e30f16bcfe8955581e6e886561f3da4b396fd711a1ffdad04dec9657f4f0953bf4283a99d9c5243353272ad11
|
7
|
+
data.tar.gz: fe145361cd4b6bfd2fdb038ae5ab373d9f641893f43dab26460bc085833687ce78e105f2b18cff2c11d4cf974a32da082954d0117fffbeb8f75548272392201b
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,56 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
## 2020-12-22 (2.5.0)
|
4
|
+
|
5
|
+
* Ready to Ractor-safe at Ruby 3.0.
|
6
|
+
|
7
|
+
## 2020-12-17 (2.4.1)
|
8
|
+
|
9
|
+
* Restore version.rb with 2.4.1
|
10
|
+
|
11
|
+
## 2020-12-15 (2.4.0)
|
12
|
+
|
13
|
+
* Implement a freeze: parser option #447
|
14
|
+
* Fix an issue with generate_pretty and empty objects in the Ruby and Java implementations #449
|
15
|
+
* Fix JSON.load_file doc #448
|
16
|
+
* Fix pure parser with unclosed arrays / objects #425
|
17
|
+
* bundle the LICENSE file in the gem #444
|
18
|
+
* Add an option to escape forward slash character #405
|
19
|
+
* RDoc for JSON #439 #446 #442 #434 #433 #430
|
20
|
+
|
21
|
+
## 2020-06-30 (2.3.1)
|
22
|
+
|
23
|
+
* Spelling and grammar fixes for comments. Pull request #191 by Josh
|
24
|
+
Kline.
|
25
|
+
* Enhance generic JSON and #generate docs. Pull request #347 by Victor
|
26
|
+
Shepelev.
|
27
|
+
* Add :nodoc: for GeneratorMethods. Pull request #349 by Victor Shepelev.
|
28
|
+
* Baseline changes to help (JRuby) development. Pull request #371 by Karol
|
29
|
+
Bucek.
|
30
|
+
* Add metadata for rubygems.org. Pull request #379 by Alexandre ZANNI.
|
31
|
+
* Remove invalid JSON.generate description from JSON module rdoc. Pull
|
32
|
+
request #384 by Jeremy Evans.
|
33
|
+
* Test with TruffleRuby in CI. Pull request #402 by Benoit Daloze.
|
34
|
+
* Rdoc enhancements. Pull request #413 by Burdette Lamar.
|
35
|
+
* Fixtures/ are not being tested... Pull request #416 by Marc-André
|
36
|
+
Lafortune.
|
37
|
+
* Use frozen string for hash key. Pull request #420 by Marc-André
|
38
|
+
Lafortune.
|
39
|
+
* Added :call-seq: to RDoc for some methods. Pull request #422 by Burdette
|
40
|
+
Lamar.
|
41
|
+
* Small typo fix. Pull request #423 by Marc-André Lafortune.
|
42
|
+
|
43
|
+
## 2019-12-11 (2.3.0)
|
44
|
+
* Fix default of `create_additions` to always be `false` for `JSON(user_input)`
|
45
|
+
and `JSON.parse(user_input, nil)`.
|
46
|
+
Note that `JSON.load` remains with default `true` and is meant for internal
|
47
|
+
serialization of trusted data. [CVE-2020-10663]
|
48
|
+
* Fix passing args all #to_json in json/add/*.
|
49
|
+
* Fix encoding issues
|
50
|
+
* Fix issues of keyword vs positional parameter
|
51
|
+
* Fix JSON::Parser against bigdecimal updates
|
52
|
+
* Bug fixes to JRuby port
|
53
|
+
|
3
54
|
## 2019-02-21 (2.2.0)
|
4
55
|
* Adds support for 2.6 BigDecimal and ruby standard library Set datetype.
|
5
56
|
|
data/LICENSE
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the
|
3
|
+
2-clause BSDL (see the file BSDL), or the conditions below:
|
4
|
+
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
6
|
+
software without restriction, provided that you duplicate all of the
|
7
|
+
original copyright notices and associated disclaimers.
|
8
|
+
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
10
|
+
you do at least ONE of the following:
|
11
|
+
|
12
|
+
a) place your modifications in the Public Domain or otherwise
|
13
|
+
make them Freely Available, such as by posting said
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
15
|
+
the author to include your modifications in the software.
|
16
|
+
|
17
|
+
b) use the modified software only within your corporation or
|
18
|
+
organization.
|
19
|
+
|
20
|
+
c) give non-standard binaries non-standard names, with
|
21
|
+
instructions on where to get the original software distribution.
|
22
|
+
|
23
|
+
d) make other distribution arrangements with the author.
|
24
|
+
|
25
|
+
3. You may distribute the software in object code or binary form,
|
26
|
+
provided that you do at least ONE of the following:
|
27
|
+
|
28
|
+
a) distribute the binaries and library files of the software,
|
29
|
+
together with instructions (in the manual page or equivalent)
|
30
|
+
on where to get the original distribution.
|
31
|
+
|
32
|
+
b) accompany the distribution with the machine-readable source of
|
33
|
+
the software.
|
34
|
+
|
35
|
+
c) give non-standard binaries non-standard names, with
|
36
|
+
instructions on where to get the original software distribution.
|
37
|
+
|
38
|
+
d) make other distribution arrangements with the author.
|
39
|
+
|
40
|
+
4. You may modify and include the part of the software into any other
|
41
|
+
software (possibly commercial). But some files in the distribution
|
42
|
+
are not written by the author, so that they are not under these terms.
|
43
|
+
|
44
|
+
For the list of those files and their copying conditions, see the
|
45
|
+
file LEGAL.
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
data/README.md
CHANGED
@@ -390,6 +390,22 @@ Here are the median comparisons for completeness' sake:
|
|
390
390
|
secs/call
|
391
391
|
```
|
392
392
|
|
393
|
+
## Development
|
394
|
+
|
395
|
+
### Release
|
396
|
+
|
397
|
+
Update the json.gemspec and json-java.gemspec.
|
398
|
+
|
399
|
+
```
|
400
|
+
rbenv shell 2.6.5
|
401
|
+
rake build
|
402
|
+
gem push pkg/json-2.3.0.gem
|
403
|
+
|
404
|
+
rbenv shell jruby-9.2.9.0
|
405
|
+
rake build
|
406
|
+
gem push pkg/json-2.3.0-java.gem
|
407
|
+
```
|
408
|
+
|
393
409
|
## Author
|
394
410
|
|
395
411
|
Florian Frank <mailto:flori@ping.de>
|
@@ -406,4 +422,4 @@ The latest version of this library can be downloaded at
|
|
406
422
|
|
407
423
|
Online Documentation should be located at
|
408
424
|
|
409
|
-
*
|
425
|
+
* https://www.rubydoc.info/gems/json
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.5.0
|
@@ -15,14 +15,13 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
|
|
15
15
|
#endif
|
16
16
|
mFloat, mString, mString_Extend,
|
17
17
|
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
|
18
|
-
eNestingError
|
19
|
-
i_SAFE_STATE_PROTOTYPE;
|
18
|
+
eNestingError;
|
20
19
|
|
21
20
|
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
|
22
21
|
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
|
23
22
|
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
|
24
23
|
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
|
25
|
-
i_buffer_initial_length, i_dup;
|
24
|
+
i_buffer_initial_length, i_dup, i_escape_slash;
|
26
25
|
|
27
26
|
/*
|
28
27
|
* Copyright 2001-2004 Unicode, Inc.
|
@@ -130,7 +129,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
|
|
130
129
|
|
131
130
|
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
|
132
131
|
* and control characters are JSON escaped. */
|
133
|
-
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
132
|
+
static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
|
134
133
|
{
|
135
134
|
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
|
136
135
|
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
|
@@ -180,6 +179,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
180
179
|
case '"':
|
181
180
|
fbuffer_append(buffer, "\\\"", 2);
|
182
181
|
break;
|
182
|
+
case '/':
|
183
|
+
if(escape_slash) {
|
184
|
+
fbuffer_append(buffer, "\\/", 2);
|
185
|
+
break;
|
186
|
+
}
|
183
187
|
default:
|
184
188
|
fbuffer_append_char(buffer, (char)ch);
|
185
189
|
break;
|
@@ -229,7 +233,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
229
233
|
* characters required by the JSON standard are JSON escaped. The remaining
|
230
234
|
* characters (should be UTF8) are just passed through and appended to the
|
231
235
|
* result. */
|
232
|
-
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
236
|
+
static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
|
233
237
|
{
|
234
238
|
const char *ptr = RSTRING_PTR(string), *p;
|
235
239
|
unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
|
@@ -237,6 +241,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
237
241
|
int escape_len;
|
238
242
|
unsigned char c;
|
239
243
|
char buf[6] = { '\\', 'u' };
|
244
|
+
int ascii_only = rb_enc_str_asciionly_p(string);
|
240
245
|
|
241
246
|
for (start = 0, end = 0; end < len;) {
|
242
247
|
p = ptr + end;
|
@@ -279,16 +284,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
279
284
|
escape = "\\\"";
|
280
285
|
escape_len = 2;
|
281
286
|
break;
|
287
|
+
case '/':
|
288
|
+
if(escape_slash) {
|
289
|
+
escape = "\\/";
|
290
|
+
escape_len = 2;
|
291
|
+
break;
|
292
|
+
}
|
282
293
|
default:
|
283
294
|
{
|
284
|
-
unsigned short clen =
|
285
|
-
if (
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
295
|
+
unsigned short clen = 1;
|
296
|
+
if (!ascii_only) {
|
297
|
+
clen += trailingBytesForUTF8[c];
|
298
|
+
if (end + clen > len) {
|
299
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
300
|
+
"partial character in source, but hit end");
|
301
|
+
}
|
302
|
+
if (!isLegalUTF8((UTF8 *) p, clen)) {
|
303
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
304
|
+
"source sequence is illegal/malformed utf-8");
|
305
|
+
}
|
292
306
|
}
|
293
307
|
end += clen;
|
294
308
|
}
|
@@ -324,6 +338,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
324
338
|
*
|
325
339
|
*/
|
326
340
|
|
341
|
+
/* Explanation of the following: that's the only way to not pollute
|
342
|
+
* standard library's docs with GeneratorMethods::<ClassName> which
|
343
|
+
* are uninformative and take a large place in a list of classes
|
344
|
+
*/
|
345
|
+
|
346
|
+
/*
|
347
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods
|
348
|
+
* :nodoc:
|
349
|
+
*/
|
350
|
+
|
351
|
+
/*
|
352
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
|
353
|
+
* :nodoc:
|
354
|
+
*/
|
355
|
+
|
356
|
+
/*
|
357
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
|
358
|
+
* :nodoc:
|
359
|
+
*/
|
360
|
+
|
361
|
+
/*
|
362
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
|
363
|
+
* :nodoc:
|
364
|
+
*/
|
365
|
+
|
366
|
+
/*
|
367
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
|
368
|
+
* :nodoc:
|
369
|
+
*/
|
370
|
+
|
371
|
+
/*
|
372
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
|
373
|
+
* :nodoc:
|
374
|
+
*/
|
375
|
+
|
376
|
+
/*
|
377
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
|
378
|
+
* :nodoc:
|
379
|
+
*/
|
380
|
+
|
381
|
+
/*
|
382
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
|
383
|
+
* :nodoc:
|
384
|
+
*/
|
385
|
+
|
386
|
+
/*
|
387
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
|
388
|
+
* :nodoc:
|
389
|
+
*/
|
390
|
+
|
391
|
+
/*
|
392
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
|
393
|
+
* :nodoc:
|
394
|
+
*/
|
395
|
+
|
396
|
+
/*
|
397
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
|
398
|
+
* :nodoc:
|
399
|
+
*/
|
400
|
+
|
401
|
+
/*
|
402
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
|
403
|
+
* :nodoc:
|
404
|
+
*/
|
405
|
+
|
406
|
+
/*
|
407
|
+
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
|
408
|
+
* :nodoc:
|
409
|
+
*/
|
410
|
+
|
327
411
|
/*
|
328
412
|
* call-seq: to_json(state = nil)
|
329
413
|
*
|
@@ -535,13 +619,18 @@ static size_t State_memsize(const void *ptr)
|
|
535
619
|
return size;
|
536
620
|
}
|
537
621
|
|
622
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
623
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
624
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
625
|
+
#endif
|
626
|
+
|
538
627
|
#ifdef NEW_TYPEDDATA_WRAPPER
|
539
628
|
static const rb_data_type_t JSON_Generator_State_type = {
|
540
629
|
"JSON/Generator/State",
|
541
630
|
{NULL, State_free, State_memsize,},
|
542
631
|
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
543
632
|
0, 0,
|
544
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
633
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
545
634
|
#endif
|
546
635
|
};
|
547
636
|
#endif
|
@@ -642,6 +731,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
642
731
|
state->allow_nan = RTEST(tmp);
|
643
732
|
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
644
733
|
state->ascii_only = RTEST(tmp);
|
734
|
+
tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
|
735
|
+
state->escape_slash = RTEST(tmp);
|
645
736
|
return self;
|
646
737
|
}
|
647
738
|
|
@@ -676,6 +767,7 @@ static VALUE cState_to_h(VALUE self)
|
|
676
767
|
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
677
768
|
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
|
678
769
|
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
|
770
|
+
rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
|
679
771
|
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
680
772
|
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
681
773
|
return result;
|
@@ -692,7 +784,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
|
|
692
784
|
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
693
785
|
return rb_funcall(self, i_send, 1, name);
|
694
786
|
} else {
|
695
|
-
return
|
787
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
696
788
|
}
|
697
789
|
}
|
698
790
|
|
@@ -715,43 +807,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
|
715
807
|
return Qnil;
|
716
808
|
}
|
717
809
|
|
718
|
-
|
810
|
+
struct hash_foreach_arg {
|
811
|
+
FBuffer *buffer;
|
812
|
+
JSON_Generator_State *state;
|
813
|
+
VALUE Vstate;
|
814
|
+
int iter;
|
815
|
+
};
|
816
|
+
|
817
|
+
static int
|
818
|
+
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
719
819
|
{
|
820
|
+
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
821
|
+
FBuffer *buffer = arg->buffer;
|
822
|
+
JSON_Generator_State *state = arg->state;
|
823
|
+
VALUE Vstate = arg->Vstate;
|
824
|
+
|
720
825
|
char *object_nl = state->object_nl;
|
721
826
|
long object_nl_len = state->object_nl_len;
|
722
827
|
char *indent = state->indent;
|
723
828
|
long indent_len = state->indent_len;
|
724
|
-
long max_nesting = state->max_nesting;
|
725
829
|
char *delim = FBUFFER_PTR(state->object_delim);
|
726
830
|
long delim_len = FBUFFER_LEN(state->object_delim);
|
727
831
|
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
728
832
|
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
833
|
+
long depth = state->depth;
|
834
|
+
int j;
|
835
|
+
VALUE klass, key_to_s;
|
836
|
+
|
837
|
+
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
|
838
|
+
if (object_nl) {
|
839
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
840
|
+
}
|
841
|
+
if (indent) {
|
842
|
+
for (j = 0; j < depth; j++) {
|
843
|
+
fbuffer_append(buffer, indent, indent_len);
|
844
|
+
}
|
845
|
+
}
|
846
|
+
|
847
|
+
klass = CLASS_OF(key);
|
848
|
+
if (klass == rb_cString) {
|
849
|
+
key_to_s = key;
|
850
|
+
} else if (klass == rb_cSymbol) {
|
851
|
+
key_to_s = rb_id2str(SYM2ID(key));
|
852
|
+
} else {
|
853
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
854
|
+
}
|
855
|
+
Check_Type(key_to_s, T_STRING);
|
856
|
+
generate_json(buffer, Vstate, state, key_to_s);
|
857
|
+
fbuffer_append(buffer, delim2, delim2_len);
|
858
|
+
generate_json(buffer, Vstate, state, val);
|
859
|
+
|
860
|
+
arg->iter++;
|
861
|
+
return ST_CONTINUE;
|
862
|
+
}
|
863
|
+
|
864
|
+
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
865
|
+
{
|
866
|
+
char *object_nl = state->object_nl;
|
867
|
+
long object_nl_len = state->object_nl_len;
|
868
|
+
char *indent = state->indent;
|
869
|
+
long indent_len = state->indent_len;
|
870
|
+
long max_nesting = state->max_nesting;
|
729
871
|
long depth = ++state->depth;
|
730
|
-
int
|
731
|
-
|
872
|
+
int j;
|
873
|
+
struct hash_foreach_arg arg;
|
874
|
+
|
732
875
|
if (max_nesting != 0 && depth > max_nesting) {
|
733
876
|
fbuffer_free(buffer);
|
734
877
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
735
878
|
}
|
736
879
|
fbuffer_append_char(buffer, '{');
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
for (j = 0; j < depth; j++) {
|
745
|
-
fbuffer_append(buffer, indent, indent_len);
|
746
|
-
}
|
747
|
-
}
|
748
|
-
key = rb_ary_entry(keys, i);
|
749
|
-
key_to_s = rb_funcall(key, i_to_s, 0);
|
750
|
-
Check_Type(key_to_s, T_STRING);
|
751
|
-
generate_json(buffer, Vstate, state, key_to_s);
|
752
|
-
fbuffer_append(buffer, delim2, delim2_len);
|
753
|
-
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
|
754
|
-
}
|
880
|
+
|
881
|
+
arg.buffer = buffer;
|
882
|
+
arg.state = state;
|
883
|
+
arg.Vstate = Vstate;
|
884
|
+
arg.iter = 0;
|
885
|
+
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
886
|
+
|
755
887
|
depth = --state->depth;
|
756
888
|
if (object_nl) {
|
757
889
|
fbuffer_append(buffer, object_nl, object_nl_len);
|
@@ -802,16 +934,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
802
934
|
fbuffer_append_char(buffer, ']');
|
803
935
|
}
|
804
936
|
|
937
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
938
|
+
static int enc_utf8_compatible_p(rb_encoding *enc)
|
939
|
+
{
|
940
|
+
if (enc == rb_usascii_encoding()) return 1;
|
941
|
+
if (enc == rb_utf8_encoding()) return 1;
|
942
|
+
return 0;
|
943
|
+
}
|
944
|
+
#endif
|
945
|
+
|
805
946
|
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
806
947
|
{
|
807
948
|
fbuffer_append_char(buffer, '"');
|
808
949
|
#ifdef HAVE_RUBY_ENCODING_H
|
809
|
-
|
950
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
951
|
+
obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
|
952
|
+
}
|
810
953
|
#endif
|
811
954
|
if (state->ascii_only) {
|
812
|
-
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
955
|
+
convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
|
813
956
|
} else {
|
814
|
-
convert_UTF8_to_JSON(buffer, obj);
|
957
|
+
convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
|
815
958
|
}
|
816
959
|
fbuffer_append_char(buffer, '"');
|
817
960
|
}
|
@@ -970,6 +1113,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
970
1113
|
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
971
1114
|
* generated, otherwise an exception is thrown, if these values are
|
972
1115
|
* encountered. This options defaults to false.
|
1116
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
1117
|
+
* option defaults to false.
|
973
1118
|
* * *buffer_initial_length*: sets the initial length of the generator's
|
974
1119
|
* internal buffer.
|
975
1120
|
*/
|
@@ -1025,10 +1170,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1025
1170
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
1026
1171
|
return rb_funcall(self, i_new, 1, opts);
|
1027
1172
|
} else {
|
1028
|
-
|
1029
|
-
CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
|
1030
|
-
}
|
1031
|
-
return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
|
1173
|
+
return rb_class_new_instance(0, NULL, cState);
|
1032
1174
|
}
|
1033
1175
|
}
|
1034
1176
|
|
@@ -1252,6 +1394,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
1252
1394
|
return state->max_nesting = FIX2LONG(depth);
|
1253
1395
|
}
|
1254
1396
|
|
1397
|
+
/*
|
1398
|
+
* call-seq: escape_slash
|
1399
|
+
*
|
1400
|
+
* If this boolean is true, the forward slashes will be escaped in
|
1401
|
+
* the json output.
|
1402
|
+
*/
|
1403
|
+
static VALUE cState_escape_slash(VALUE self)
|
1404
|
+
{
|
1405
|
+
GET_STATE(self);
|
1406
|
+
return state->escape_slash ? Qtrue : Qfalse;
|
1407
|
+
}
|
1408
|
+
|
1409
|
+
/*
|
1410
|
+
* call-seq: escape_slash=(depth)
|
1411
|
+
*
|
1412
|
+
* This sets whether or not the forward slashes will be escaped in
|
1413
|
+
* the json output.
|
1414
|
+
*/
|
1415
|
+
static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
|
1416
|
+
{
|
1417
|
+
GET_STATE(self);
|
1418
|
+
state->escape_slash = RTEST(enable);
|
1419
|
+
return Qnil;
|
1420
|
+
}
|
1421
|
+
|
1255
1422
|
/*
|
1256
1423
|
* call-seq: allow_nan?
|
1257
1424
|
*
|
@@ -1267,7 +1434,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
1267
1434
|
/*
|
1268
1435
|
* call-seq: ascii_only?
|
1269
1436
|
*
|
1270
|
-
* Returns true, if
|
1437
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
1271
1438
|
* returns false.
|
1272
1439
|
*/
|
1273
1440
|
static VALUE cState_ascii_only_p(VALUE self)
|
@@ -1335,6 +1502,10 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
1335
1502
|
*/
|
1336
1503
|
void Init_generator(void)
|
1337
1504
|
{
|
1505
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
1506
|
+
rb_ext_ractor_safe(true);
|
1507
|
+
#endif
|
1508
|
+
|
1338
1509
|
#undef rb_intern
|
1339
1510
|
rb_require("json/common");
|
1340
1511
|
|
@@ -1344,6 +1515,8 @@ void Init_generator(void)
|
|
1344
1515
|
|
1345
1516
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
1346
1517
|
eNestingError = rb_path2class("JSON::NestingError");
|
1518
|
+
rb_gc_register_mark_object(eGeneratorError);
|
1519
|
+
rb_gc_register_mark_object(eNestingError);
|
1347
1520
|
|
1348
1521
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
1349
1522
|
rb_define_alloc_func(cState, cState_s_allocate);
|
@@ -1362,6 +1535,9 @@ void Init_generator(void)
|
|
1362
1535
|
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
|
1363
1536
|
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
|
1364
1537
|
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
|
1538
|
+
rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
|
1539
|
+
rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
|
1540
|
+
rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
|
1365
1541
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
1366
1542
|
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
1367
1543
|
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
|
@@ -1409,7 +1585,6 @@ void Init_generator(void)
|
|
1409
1585
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
1410
1586
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
1411
1587
|
|
1412
|
-
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
1413
1588
|
i_to_s = rb_intern("to_s");
|
1414
1589
|
i_to_json = rb_intern("to_json");
|
1415
1590
|
i_new = rb_intern("new");
|
@@ -1419,6 +1594,7 @@ void Init_generator(void)
|
|
1419
1594
|
i_object_nl = rb_intern("object_nl");
|
1420
1595
|
i_array_nl = rb_intern("array_nl");
|
1421
1596
|
i_max_nesting = rb_intern("max_nesting");
|
1597
|
+
i_escape_slash = rb_intern("escape_slash");
|
1422
1598
|
i_allow_nan = rb_intern("allow_nan");
|
1423
1599
|
i_ascii_only = rb_intern("ascii_only");
|
1424
1600
|
i_depth = rb_intern("depth");
|
@@ -1439,6 +1615,4 @@ void Init_generator(void)
|
|
1439
1615
|
i_encoding = rb_intern("encoding");
|
1440
1616
|
i_encode = rb_intern("encode");
|
1441
1617
|
#endif
|
1442
|
-
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
|
1443
|
-
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
|
1444
1618
|
}
|