json 2.7.5 → 2.9.1
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 +36 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +122 -54
- data/ext/json/ext/generator/generator.c +391 -232
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1597 -596
- data/ext/json/ext/parser/parser.rl +726 -258
- data/json.gemspec +4 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +239 -77
- data/lib/json/ext/generator/state.rb +12 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +173 -124
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -118
- data/ext/json/ext/parser/parser.h +0 -60
- data/lib/json/pure/parser.rb +0 -331
- data/lib/json/pure.rb +0 -16
@@ -1,5 +1,27 @@
|
|
1
|
+
#include "ruby.h"
|
1
2
|
#include "../fbuffer/fbuffer.h"
|
2
|
-
|
3
|
+
|
4
|
+
#include <math.h>
|
5
|
+
#include <ctype.h>
|
6
|
+
|
7
|
+
/* ruby api and some helpers */
|
8
|
+
|
9
|
+
typedef struct JSON_Generator_StateStruct {
|
10
|
+
VALUE indent;
|
11
|
+
VALUE space;
|
12
|
+
VALUE space_before;
|
13
|
+
VALUE object_nl;
|
14
|
+
VALUE array_nl;
|
15
|
+
|
16
|
+
long max_nesting;
|
17
|
+
long depth;
|
18
|
+
long buffer_initial_length;
|
19
|
+
|
20
|
+
bool allow_nan;
|
21
|
+
bool ascii_only;
|
22
|
+
bool script_safe;
|
23
|
+
bool strict;
|
24
|
+
} JSON_Generator_State;
|
3
25
|
|
4
26
|
#ifndef RB_UNLIKELY
|
5
27
|
#define RB_UNLIKELY(cond) (cond)
|
@@ -8,6 +30,71 @@
|
|
8
30
|
static VALUE mJSON, cState, mString_Extend, eGeneratorError, eNestingError, Encoding_UTF_8;
|
9
31
|
|
10
32
|
static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
|
33
|
+
static ID sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan,
|
34
|
+
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict;
|
35
|
+
|
36
|
+
|
37
|
+
#define GET_STATE_TO(self, state) \
|
38
|
+
TypedData_Get_Struct(self, JSON_Generator_State, &JSON_Generator_State_type, state)
|
39
|
+
|
40
|
+
#define GET_STATE(self) \
|
41
|
+
JSON_Generator_State *state; \
|
42
|
+
GET_STATE_TO(self, state)
|
43
|
+
|
44
|
+
struct generate_json_data;
|
45
|
+
|
46
|
+
typedef void (*generator_func)(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
47
|
+
|
48
|
+
struct generate_json_data {
|
49
|
+
FBuffer *buffer;
|
50
|
+
VALUE vstate;
|
51
|
+
JSON_Generator_State *state;
|
52
|
+
VALUE obj;
|
53
|
+
generator_func func;
|
54
|
+
};
|
55
|
+
|
56
|
+
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
57
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
|
58
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
59
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
60
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
61
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
62
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
63
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
64
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
65
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
66
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
67
|
+
#endif
|
68
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
69
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
70
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj);
|
71
|
+
|
72
|
+
static int usascii_encindex, utf8_encindex, binary_encindex;
|
73
|
+
|
74
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
75
|
+
RBIMPL_ATTR_NORETURN()
|
76
|
+
#endif
|
77
|
+
static void raise_generator_error_str(VALUE invalid_object, VALUE str)
|
78
|
+
{
|
79
|
+
VALUE exc = rb_exc_new_str(eGeneratorError, str);
|
80
|
+
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
|
81
|
+
rb_exc_raise(exc);
|
82
|
+
}
|
83
|
+
|
84
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
85
|
+
RBIMPL_ATTR_NORETURN()
|
86
|
+
#endif
|
87
|
+
#ifdef RBIMPL_ATTR_FORMAT
|
88
|
+
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
|
89
|
+
#endif
|
90
|
+
static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
|
91
|
+
{
|
92
|
+
va_list args;
|
93
|
+
va_start(args, fmt);
|
94
|
+
VALUE str = rb_vsprintf(fmt, args);
|
95
|
+
va_end(args);
|
96
|
+
raise_generator_error_str(invalid_object, str);
|
97
|
+
}
|
11
98
|
|
12
99
|
/* Converts in_string to a JSON string (without the wrapping '"'
|
13
100
|
* characters) in FBuffer out_buffer.
|
@@ -44,9 +131,6 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
44
131
|
|
45
132
|
if (RB_UNLIKELY(ch_len)) {
|
46
133
|
switch (ch_len) {
|
47
|
-
case 0:
|
48
|
-
pos++;
|
49
|
-
break;
|
50
134
|
case 1: {
|
51
135
|
FLUSH_POS(1);
|
52
136
|
switch (ch) {
|
@@ -59,8 +143,8 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
59
143
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
60
144
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
61
145
|
default: {
|
62
|
-
scratch[2] =
|
63
|
-
scratch[3] =
|
146
|
+
scratch[2] = '0';
|
147
|
+
scratch[3] = '0';
|
64
148
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
65
149
|
scratch[5] = hexdig[ch & 0xf];
|
66
150
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -71,7 +155,7 @@ static void convert_UTF8_to_JSON(FBuffer *out_buffer, VALUE str, const char esca
|
|
71
155
|
}
|
72
156
|
case 3: {
|
73
157
|
unsigned char b2 = ptr[pos + 1];
|
74
|
-
if (RB_UNLIKELY(out_script_safe && b2 == 0x80)) {
|
158
|
+
if (RB_UNLIKELY(out_script_safe && ch == 0xE2 && b2 == 0x80)) {
|
75
159
|
unsigned char b3 = ptr[pos + 2];
|
76
160
|
if (b3 == 0xA8) {
|
77
161
|
FLUSH_POS(3);
|
@@ -181,8 +265,8 @@ static void convert_ASCII_to_JSON(FBuffer *out_buffer, VALUE str, const char esc
|
|
181
265
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
182
266
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
183
267
|
default:
|
184
|
-
scratch[2] =
|
185
|
-
scratch[3] =
|
268
|
+
scratch[2] = '0';
|
269
|
+
scratch[3] = '0';
|
186
270
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
187
271
|
scratch[5] = hexdig[ch & 0xf];
|
188
272
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -217,9 +301,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
217
301
|
|
218
302
|
if (RB_UNLIKELY(ch_len)) {
|
219
303
|
switch (ch_len) {
|
220
|
-
case 0:
|
221
|
-
pos++;
|
222
|
-
break;
|
223
304
|
case 1: {
|
224
305
|
FLUSH_POS(1);
|
225
306
|
switch (ch) {
|
@@ -232,8 +313,8 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
232
313
|
case '\r': fbuffer_append(out_buffer, "\\r", 2); break;
|
233
314
|
case '\t': fbuffer_append(out_buffer, "\\t", 2); break;
|
234
315
|
default: {
|
235
|
-
scratch[2] =
|
236
|
-
scratch[3] =
|
316
|
+
scratch[2] = '0';
|
317
|
+
scratch[3] = '0';
|
237
318
|
scratch[4] = hexdig[(ch >> 4) & 0xf];
|
238
319
|
scratch[5] = hexdig[ch & 0xf];
|
239
320
|
fbuffer_append(out_buffer, scratch, 6);
|
@@ -303,14 +384,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
|
|
303
384
|
RB_GC_GUARD(str);
|
304
385
|
}
|
305
386
|
|
306
|
-
static char *fstrndup(const char *ptr, unsigned long len) {
|
307
|
-
char *result;
|
308
|
-
if (len <= 0) return NULL;
|
309
|
-
result = ALLOC_N(char, len);
|
310
|
-
memcpy(result, ptr, len);
|
311
|
-
return result;
|
312
|
-
}
|
313
|
-
|
314
387
|
/*
|
315
388
|
* Document-module: JSON::Ext::Generator
|
316
389
|
*
|
@@ -405,7 +478,7 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
405
478
|
{
|
406
479
|
rb_check_arity(argc, 0, 1);
|
407
480
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
408
|
-
return cState_partial_generate(Vstate, self, generate_json_object);
|
481
|
+
return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
|
409
482
|
}
|
410
483
|
|
411
484
|
/*
|
@@ -419,7 +492,7 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
419
492
|
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
420
493
|
rb_check_arity(argc, 0, 1);
|
421
494
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
422
|
-
return cState_partial_generate(Vstate, self, generate_json_array);
|
495
|
+
return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
|
423
496
|
}
|
424
497
|
|
425
498
|
#ifdef RUBY_INTEGER_UNIFICATION
|
@@ -432,7 +505,7 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
432
505
|
{
|
433
506
|
rb_check_arity(argc, 0, 1);
|
434
507
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
435
|
-
return cState_partial_generate(Vstate, self, generate_json_integer);
|
508
|
+
return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
|
436
509
|
}
|
437
510
|
|
438
511
|
#else
|
@@ -445,7 +518,7 @@ static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
445
518
|
{
|
446
519
|
rb_check_arity(argc, 0, 1);
|
447
520
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
448
|
-
return cState_partial_generate(Vstate, self, generate_json_fixnum);
|
521
|
+
return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
|
449
522
|
}
|
450
523
|
|
451
524
|
/*
|
@@ -457,7 +530,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
457
530
|
{
|
458
531
|
rb_check_arity(argc, 0, 1);
|
459
532
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
460
|
-
return cState_partial_generate(Vstate, self, generate_json_bignum);
|
533
|
+
return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
|
461
534
|
}
|
462
535
|
#endif
|
463
536
|
|
@@ -470,7 +543,7 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
470
543
|
{
|
471
544
|
rb_check_arity(argc, 0, 1);
|
472
545
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
473
|
-
return cState_partial_generate(Vstate, self, generate_json_float);
|
546
|
+
return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
|
474
547
|
}
|
475
548
|
|
476
549
|
/*
|
@@ -495,7 +568,7 @@ static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
|
495
568
|
{
|
496
569
|
rb_check_arity(argc, 0, 1);
|
497
570
|
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
498
|
-
return cState_partial_generate(Vstate, self, generate_json_string);
|
571
|
+
return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
|
499
572
|
}
|
500
573
|
|
501
574
|
/*
|
@@ -512,7 +585,7 @@ static VALUE mString_to_json_raw_object(VALUE self)
|
|
512
585
|
VALUE result = rb_hash_new();
|
513
586
|
rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self)));
|
514
587
|
ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*"));
|
515
|
-
rb_hash_aset(result,
|
588
|
+
rb_hash_aset(result, rb_utf8_str_new_lit("raw"), ary);
|
516
589
|
return result;
|
517
590
|
}
|
518
591
|
|
@@ -590,30 +663,38 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
590
663
|
rb_scan_args(argc, argv, "01", &state);
|
591
664
|
Check_Type(string, T_STRING);
|
592
665
|
state = cState_from_state_s(cState, state);
|
593
|
-
return cState_partial_generate(state, string, generate_json_string);
|
666
|
+
return cState_partial_generate(state, string, generate_json_string, Qfalse);
|
667
|
+
}
|
668
|
+
|
669
|
+
static void State_mark(void *ptr)
|
670
|
+
{
|
671
|
+
JSON_Generator_State *state = ptr;
|
672
|
+
rb_gc_mark_movable(state->indent);
|
673
|
+
rb_gc_mark_movable(state->space);
|
674
|
+
rb_gc_mark_movable(state->space_before);
|
675
|
+
rb_gc_mark_movable(state->object_nl);
|
676
|
+
rb_gc_mark_movable(state->array_nl);
|
677
|
+
}
|
678
|
+
|
679
|
+
static void State_compact(void *ptr)
|
680
|
+
{
|
681
|
+
JSON_Generator_State *state = ptr;
|
682
|
+
state->indent = rb_gc_location(state->indent);
|
683
|
+
state->space = rb_gc_location(state->space);
|
684
|
+
state->space_before = rb_gc_location(state->space_before);
|
685
|
+
state->object_nl = rb_gc_location(state->object_nl);
|
686
|
+
state->array_nl = rb_gc_location(state->array_nl);
|
594
687
|
}
|
595
688
|
|
596
689
|
static void State_free(void *ptr)
|
597
690
|
{
|
598
691
|
JSON_Generator_State *state = ptr;
|
599
|
-
if (state->indent) ruby_xfree(state->indent);
|
600
|
-
if (state->space) ruby_xfree(state->space);
|
601
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
602
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
603
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
604
692
|
ruby_xfree(state);
|
605
693
|
}
|
606
694
|
|
607
695
|
static size_t State_memsize(const void *ptr)
|
608
696
|
{
|
609
|
-
|
610
|
-
size_t size = sizeof(*state);
|
611
|
-
if (state->indent) size += state->indent_len + 1;
|
612
|
-
if (state->space) size += state->space_len + 1;
|
613
|
-
if (state->space_before) size += state->space_before_len + 1;
|
614
|
-
if (state->object_nl) size += state->object_nl_len + 1;
|
615
|
-
if (state->array_nl) size += state->array_nl_len + 1;
|
616
|
-
return size;
|
697
|
+
return sizeof(JSON_Generator_State);
|
617
698
|
}
|
618
699
|
|
619
700
|
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
@@ -623,24 +704,54 @@ static size_t State_memsize(const void *ptr)
|
|
623
704
|
|
624
705
|
static const rb_data_type_t JSON_Generator_State_type = {
|
625
706
|
"JSON/Generator/State",
|
626
|
-
{
|
707
|
+
{
|
708
|
+
.dmark = State_mark,
|
709
|
+
.dfree = State_free,
|
710
|
+
.dsize = State_memsize,
|
711
|
+
.dcompact = State_compact,
|
712
|
+
},
|
627
713
|
0, 0,
|
628
714
|
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
629
715
|
};
|
630
716
|
|
717
|
+
static void state_init(JSON_Generator_State *state)
|
718
|
+
{
|
719
|
+
state->max_nesting = 100;
|
720
|
+
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
721
|
+
}
|
722
|
+
|
631
723
|
static VALUE cState_s_allocate(VALUE klass)
|
632
724
|
{
|
633
725
|
JSON_Generator_State *state;
|
634
726
|
VALUE obj = TypedData_Make_Struct(klass, JSON_Generator_State, &JSON_Generator_State_type, state);
|
635
|
-
state
|
636
|
-
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
727
|
+
state_init(state);
|
637
728
|
return obj;
|
638
729
|
}
|
639
730
|
|
731
|
+
static void vstate_spill(struct generate_json_data *data)
|
732
|
+
{
|
733
|
+
VALUE vstate = cState_s_allocate(cState);
|
734
|
+
GET_STATE(vstate);
|
735
|
+
MEMCPY(state, data->state, JSON_Generator_State, 1);
|
736
|
+
data->state = state;
|
737
|
+
data->vstate = vstate;
|
738
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->indent);
|
739
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->space);
|
740
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->space_before);
|
741
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->object_nl);
|
742
|
+
RB_OBJ_WRITTEN(vstate, Qundef, state->array_nl);
|
743
|
+
}
|
744
|
+
|
745
|
+
static inline VALUE vstate_get(struct generate_json_data *data)
|
746
|
+
{
|
747
|
+
if (RB_UNLIKELY(!data->vstate)) {
|
748
|
+
vstate_spill(data);
|
749
|
+
}
|
750
|
+
return data->vstate;
|
751
|
+
}
|
752
|
+
|
640
753
|
struct hash_foreach_arg {
|
641
|
-
|
642
|
-
JSON_Generator_State *state;
|
643
|
-
VALUE Vstate;
|
754
|
+
struct generate_json_data *data;
|
644
755
|
int iter;
|
645
756
|
};
|
646
757
|
|
@@ -648,27 +759,32 @@ static int
|
|
648
759
|
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
649
760
|
{
|
650
761
|
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
651
|
-
|
652
|
-
|
653
|
-
|
762
|
+
struct generate_json_data *data = arg->data;
|
763
|
+
|
764
|
+
FBuffer *buffer = data->buffer;
|
765
|
+
JSON_Generator_State *state = data->state;
|
654
766
|
|
655
767
|
long depth = state->depth;
|
656
768
|
int j;
|
657
769
|
|
658
770
|
if (arg->iter > 0) fbuffer_append_char(buffer, ',');
|
659
771
|
if (RB_UNLIKELY(state->object_nl)) {
|
660
|
-
|
772
|
+
fbuffer_append_str(buffer, state->object_nl);
|
661
773
|
}
|
662
774
|
if (RB_UNLIKELY(state->indent)) {
|
663
775
|
for (j = 0; j < depth; j++) {
|
664
|
-
|
776
|
+
fbuffer_append_str(buffer, state->indent);
|
665
777
|
}
|
666
778
|
}
|
667
779
|
|
668
780
|
VALUE key_to_s;
|
669
781
|
switch(rb_type(key)) {
|
670
782
|
case T_STRING:
|
671
|
-
|
783
|
+
if (RB_LIKELY(RBASIC_CLASS(key) == rb_cString)) {
|
784
|
+
key_to_s = key;
|
785
|
+
} else {
|
786
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
787
|
+
}
|
672
788
|
break;
|
673
789
|
case T_SYMBOL:
|
674
790
|
key_to_s = rb_sym2str(key);
|
@@ -678,47 +794,57 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
678
794
|
break;
|
679
795
|
}
|
680
796
|
|
681
|
-
|
682
|
-
|
797
|
+
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
|
798
|
+
generate_json_string(buffer, data, state, key_to_s);
|
799
|
+
} else {
|
800
|
+
generate_json(buffer, data, state, key_to_s);
|
801
|
+
}
|
802
|
+
if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
|
683
803
|
fbuffer_append_char(buffer, ':');
|
684
|
-
if (RB_UNLIKELY(state->space))
|
685
|
-
generate_json(buffer,
|
804
|
+
if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
|
805
|
+
generate_json(buffer, data, state, val);
|
686
806
|
|
687
807
|
arg->iter++;
|
688
808
|
return ST_CONTINUE;
|
689
809
|
}
|
690
810
|
|
691
|
-
static void generate_json_object(FBuffer *buffer,
|
811
|
+
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
692
812
|
{
|
693
813
|
long max_nesting = state->max_nesting;
|
694
814
|
long depth = ++state->depth;
|
695
815
|
int j;
|
696
|
-
struct hash_foreach_arg arg;
|
697
816
|
|
698
817
|
if (max_nesting != 0 && depth > max_nesting) {
|
699
818
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
700
819
|
}
|
820
|
+
|
821
|
+
if (RHASH_SIZE(obj) == 0) {
|
822
|
+
fbuffer_append(buffer, "{}", 2);
|
823
|
+
--state->depth;
|
824
|
+
return;
|
825
|
+
}
|
826
|
+
|
701
827
|
fbuffer_append_char(buffer, '{');
|
702
828
|
|
703
|
-
arg
|
704
|
-
|
705
|
-
|
706
|
-
|
829
|
+
struct hash_foreach_arg arg = {
|
830
|
+
.data = data,
|
831
|
+
.iter = 0,
|
832
|
+
};
|
707
833
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
708
834
|
|
709
835
|
depth = --state->depth;
|
710
836
|
if (RB_UNLIKELY(state->object_nl)) {
|
711
|
-
|
837
|
+
fbuffer_append_str(buffer, state->object_nl);
|
712
838
|
if (RB_UNLIKELY(state->indent)) {
|
713
839
|
for (j = 0; j < depth; j++) {
|
714
|
-
|
840
|
+
fbuffer_append_str(buffer, state->indent);
|
715
841
|
}
|
716
842
|
}
|
717
843
|
}
|
718
844
|
fbuffer_append_char(buffer, '}');
|
719
845
|
}
|
720
846
|
|
721
|
-
static void generate_json_array(FBuffer *buffer,
|
847
|
+
static void generate_json_array(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
722
848
|
{
|
723
849
|
long max_nesting = state->max_nesting;
|
724
850
|
long depth = ++state->depth;
|
@@ -726,34 +852,39 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
726
852
|
if (max_nesting != 0 && depth > max_nesting) {
|
727
853
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
728
854
|
}
|
855
|
+
|
856
|
+
if (RARRAY_LEN(obj) == 0) {
|
857
|
+
fbuffer_append(buffer, "[]", 2);
|
858
|
+
--state->depth;
|
859
|
+
return;
|
860
|
+
}
|
861
|
+
|
729
862
|
fbuffer_append_char(buffer, '[');
|
730
|
-
if (RB_UNLIKELY(state->array_nl))
|
863
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
731
864
|
for(i = 0; i < RARRAY_LEN(obj); i++) {
|
732
865
|
if (i > 0) {
|
733
866
|
fbuffer_append_char(buffer, ',');
|
734
|
-
if (RB_UNLIKELY(state->array_nl))
|
867
|
+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
|
735
868
|
}
|
736
869
|
if (RB_UNLIKELY(state->indent)) {
|
737
870
|
for (j = 0; j < depth; j++) {
|
738
|
-
|
871
|
+
fbuffer_append_str(buffer, state->indent);
|
739
872
|
}
|
740
873
|
}
|
741
|
-
generate_json(buffer,
|
874
|
+
generate_json(buffer, data, state, RARRAY_AREF(obj, i));
|
742
875
|
}
|
743
876
|
state->depth = --depth;
|
744
877
|
if (RB_UNLIKELY(state->array_nl)) {
|
745
|
-
|
878
|
+
fbuffer_append_str(buffer, state->array_nl);
|
746
879
|
if (RB_UNLIKELY(state->indent)) {
|
747
880
|
for (j = 0; j < depth; j++) {
|
748
|
-
|
881
|
+
fbuffer_append_str(buffer, state->indent);
|
749
882
|
}
|
750
883
|
}
|
751
884
|
}
|
752
885
|
fbuffer_append_char(buffer, ']');
|
753
886
|
}
|
754
887
|
|
755
|
-
static int usascii_encindex, utf8_encindex, binary_encindex;
|
756
|
-
|
757
888
|
static inline int enc_utf8_compatible_p(int enc_idx)
|
758
889
|
{
|
759
890
|
if (enc_idx == usascii_encindex) return 1;
|
@@ -761,30 +892,42 @@ static inline int enc_utf8_compatible_p(int enc_idx)
|
|
761
892
|
return 0;
|
762
893
|
}
|
763
894
|
|
895
|
+
static VALUE encode_json_string_try(VALUE str)
|
896
|
+
{
|
897
|
+
return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
|
898
|
+
}
|
899
|
+
|
900
|
+
static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
901
|
+
{
|
902
|
+
raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
|
903
|
+
return Qundef;
|
904
|
+
}
|
905
|
+
|
764
906
|
static inline VALUE ensure_valid_encoding(VALUE str)
|
765
907
|
{
|
766
908
|
int encindex = RB_ENCODING_GET(str);
|
767
909
|
VALUE utf8_string;
|
768
910
|
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
769
911
|
if (encindex == binary_encindex) {
|
770
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
771
|
-
// TODO: Deprecate in 2.8.0
|
772
|
-
// TODO: Remove in 3.0.0
|
773
912
|
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
774
913
|
switch (rb_enc_str_coderange(utf8_string)) {
|
775
914
|
case ENC_CODERANGE_7BIT:
|
915
|
+
return utf8_string;
|
776
916
|
case ENC_CODERANGE_VALID:
|
917
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
918
|
+
// TODO: Raise in 3.0.0
|
919
|
+
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
777
920
|
return utf8_string;
|
778
921
|
break;
|
779
922
|
}
|
780
923
|
}
|
781
924
|
|
782
|
-
str =
|
925
|
+
str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
783
926
|
}
|
784
927
|
return str;
|
785
928
|
}
|
786
929
|
|
787
|
-
static void generate_json_string(FBuffer *buffer,
|
930
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
788
931
|
{
|
789
932
|
obj = ensure_valid_encoding(obj);
|
790
933
|
|
@@ -802,77 +945,75 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
802
945
|
}
|
803
946
|
break;
|
804
947
|
default:
|
805
|
-
|
948
|
+
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
806
949
|
break;
|
807
950
|
}
|
808
951
|
fbuffer_append_char(buffer, '"');
|
809
952
|
}
|
810
953
|
|
811
|
-
static void generate_json_null(FBuffer *buffer,
|
954
|
+
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
812
955
|
{
|
813
956
|
fbuffer_append(buffer, "null", 4);
|
814
957
|
}
|
815
958
|
|
816
|
-
static void generate_json_false(FBuffer *buffer,
|
959
|
+
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
817
960
|
{
|
818
961
|
fbuffer_append(buffer, "false", 5);
|
819
962
|
}
|
820
963
|
|
821
|
-
static void generate_json_true(FBuffer *buffer,
|
964
|
+
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
822
965
|
{
|
823
966
|
fbuffer_append(buffer, "true", 4);
|
824
967
|
}
|
825
968
|
|
826
|
-
static void generate_json_fixnum(FBuffer *buffer,
|
969
|
+
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
827
970
|
{
|
828
971
|
fbuffer_append_long(buffer, FIX2LONG(obj));
|
829
972
|
}
|
830
973
|
|
831
|
-
static void generate_json_bignum(FBuffer *buffer,
|
974
|
+
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
832
975
|
{
|
833
976
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
834
977
|
fbuffer_append_str(buffer, tmp);
|
835
978
|
}
|
836
979
|
|
837
980
|
#ifdef RUBY_INTEGER_UNIFICATION
|
838
|
-
static void generate_json_integer(FBuffer *buffer,
|
981
|
+
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
839
982
|
{
|
840
983
|
if (FIXNUM_P(obj))
|
841
|
-
generate_json_fixnum(buffer,
|
984
|
+
generate_json_fixnum(buffer, data, state, obj);
|
842
985
|
else
|
843
|
-
generate_json_bignum(buffer,
|
986
|
+
generate_json_bignum(buffer, data, state, obj);
|
844
987
|
}
|
845
988
|
#endif
|
846
989
|
|
847
|
-
static void generate_json_float(FBuffer *buffer,
|
990
|
+
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
848
991
|
{
|
849
992
|
double value = RFLOAT_VALUE(obj);
|
850
993
|
char allow_nan = state->allow_nan;
|
851
994
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
852
995
|
if (!allow_nan) {
|
853
|
-
if (isinf(value)) {
|
854
|
-
|
855
|
-
} else if (isnan(value)) {
|
856
|
-
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", tmp);
|
996
|
+
if (isinf(value) || isnan(value)) {
|
997
|
+
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", tmp);
|
857
998
|
}
|
858
999
|
}
|
859
1000
|
fbuffer_append_str(buffer, tmp);
|
860
1001
|
}
|
861
1002
|
|
862
|
-
static void generate_json(FBuffer *buffer,
|
1003
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)
|
863
1004
|
{
|
864
1005
|
VALUE tmp;
|
865
1006
|
if (obj == Qnil) {
|
866
|
-
generate_json_null(buffer,
|
1007
|
+
generate_json_null(buffer, data, state, obj);
|
867
1008
|
} else if (obj == Qfalse) {
|
868
|
-
generate_json_false(buffer,
|
1009
|
+
generate_json_false(buffer, data, state, obj);
|
869
1010
|
} else if (obj == Qtrue) {
|
870
|
-
generate_json_true(buffer,
|
1011
|
+
generate_json_true(buffer, data, state, obj);
|
871
1012
|
} else if (RB_SPECIAL_CONST_P(obj)) {
|
872
1013
|
if (RB_FIXNUM_P(obj)) {
|
873
|
-
generate_json_fixnum(buffer,
|
1014
|
+
generate_json_fixnum(buffer, data, state, obj);
|
874
1015
|
} else if (RB_FLONUM_P(obj)) {
|
875
|
-
generate_json_float(buffer,
|
1016
|
+
generate_json_float(buffer, data, state, obj);
|
876
1017
|
} else {
|
877
1018
|
goto general;
|
878
1019
|
}
|
@@ -880,63 +1021,46 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
880
1021
|
VALUE klass = RBASIC_CLASS(obj);
|
881
1022
|
switch (RB_BUILTIN_TYPE(obj)) {
|
882
1023
|
case T_BIGNUM:
|
883
|
-
generate_json_bignum(buffer,
|
1024
|
+
generate_json_bignum(buffer, data, state, obj);
|
884
1025
|
break;
|
885
1026
|
case T_HASH:
|
886
1027
|
if (klass != rb_cHash) goto general;
|
887
|
-
generate_json_object(buffer,
|
1028
|
+
generate_json_object(buffer, data, state, obj);
|
888
1029
|
break;
|
889
1030
|
case T_ARRAY:
|
890
1031
|
if (klass != rb_cArray) goto general;
|
891
|
-
generate_json_array(buffer,
|
1032
|
+
generate_json_array(buffer, data, state, obj);
|
892
1033
|
break;
|
893
1034
|
case T_STRING:
|
894
1035
|
if (klass != rb_cString) goto general;
|
895
|
-
generate_json_string(buffer,
|
1036
|
+
generate_json_string(buffer, data, state, obj);
|
896
1037
|
break;
|
897
1038
|
case T_FLOAT:
|
898
1039
|
if (klass != rb_cFloat) goto general;
|
899
|
-
generate_json_float(buffer,
|
1040
|
+
generate_json_float(buffer, data, state, obj);
|
900
1041
|
break;
|
901
1042
|
default:
|
902
1043
|
general:
|
903
1044
|
if (state->strict) {
|
904
|
-
|
1045
|
+
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", CLASS_OF(obj));
|
905
1046
|
} else if (rb_respond_to(obj, i_to_json)) {
|
906
|
-
tmp = rb_funcall(obj, i_to_json, 1,
|
1047
|
+
tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
|
907
1048
|
Check_Type(tmp, T_STRING);
|
908
1049
|
fbuffer_append_str(buffer, tmp);
|
909
1050
|
} else {
|
910
1051
|
tmp = rb_funcall(obj, i_to_s, 0);
|
911
1052
|
Check_Type(tmp, T_STRING);
|
912
|
-
generate_json_string(buffer,
|
1053
|
+
generate_json_string(buffer, data, state, tmp);
|
913
1054
|
}
|
914
1055
|
}
|
915
1056
|
}
|
916
1057
|
}
|
917
1058
|
|
918
|
-
static FBuffer *cState_prepare_buffer(VALUE self)
|
919
|
-
{
|
920
|
-
FBuffer *buffer;
|
921
|
-
GET_STATE(self);
|
922
|
-
buffer = fbuffer_alloc(state->buffer_initial_length);
|
923
|
-
|
924
|
-
return buffer;
|
925
|
-
}
|
926
|
-
|
927
|
-
struct generate_json_data {
|
928
|
-
FBuffer *buffer;
|
929
|
-
VALUE vstate;
|
930
|
-
JSON_Generator_State *state;
|
931
|
-
VALUE obj;
|
932
|
-
void (*func)(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj);
|
933
|
-
};
|
934
|
-
|
935
1059
|
static VALUE generate_json_try(VALUE d)
|
936
1060
|
{
|
937
1061
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
938
1062
|
|
939
|
-
data->func(data->buffer, data
|
1063
|
+
data->func(data->buffer, data, data->state, data->obj);
|
940
1064
|
|
941
1065
|
return Qnil;
|
942
1066
|
}
|
@@ -951,13 +1075,18 @@ static VALUE generate_json_rescue(VALUE d, VALUE exc)
|
|
951
1075
|
return Qundef;
|
952
1076
|
}
|
953
1077
|
|
954
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj,
|
1078
|
+
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
955
1079
|
{
|
956
|
-
FBuffer *buffer = cState_prepare_buffer(self);
|
957
1080
|
GET_STATE(self);
|
958
1081
|
|
1082
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1083
|
+
FBuffer buffer = {
|
1084
|
+
.io = RTEST(io) ? io : Qfalse,
|
1085
|
+
};
|
1086
|
+
fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
1087
|
+
|
959
1088
|
struct generate_json_data data = {
|
960
|
-
.buffer = buffer,
|
1089
|
+
.buffer = &buffer,
|
961
1090
|
.vstate = self,
|
962
1091
|
.state = state,
|
963
1092
|
.obj = obj,
|
@@ -965,19 +1094,12 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, void (*func)(FBuffer
|
|
965
1094
|
};
|
966
1095
|
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
967
1096
|
|
968
|
-
return
|
1097
|
+
return fbuffer_finalize(&buffer);
|
969
1098
|
}
|
970
1099
|
|
971
|
-
|
972
|
-
* call-seq: generate(obj)
|
973
|
-
*
|
974
|
-
* Generates a valid JSON document from object +obj+ and returns the
|
975
|
-
* result. If no valid JSON document can be created this method raises a
|
976
|
-
* GeneratorError exception.
|
977
|
-
*/
|
978
|
-
static VALUE cState_generate(VALUE self, VALUE obj)
|
1100
|
+
static VALUE cState_generate(VALUE self, VALUE obj, VALUE io)
|
979
1101
|
{
|
980
|
-
VALUE result = cState_partial_generate(self, obj, generate_json);
|
1102
|
+
VALUE result = cState_partial_generate(self, obj, generate_json, io);
|
981
1103
|
GET_STATE(self);
|
982
1104
|
(void)state;
|
983
1105
|
return result;
|
@@ -1005,11 +1127,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
|
1005
1127
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
1006
1128
|
|
1007
1129
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
1008
|
-
objState->indent =
|
1009
|
-
objState->space =
|
1010
|
-
objState->space_before =
|
1011
|
-
objState->object_nl =
|
1012
|
-
objState->array_nl =
|
1130
|
+
objState->indent = origState->indent;
|
1131
|
+
objState->space = origState->space;
|
1132
|
+
objState->space_before = origState->space_before;
|
1133
|
+
objState->object_nl = origState->object_nl;
|
1134
|
+
objState->array_nl = origState->array_nl;
|
1013
1135
|
return obj;
|
1014
1136
|
}
|
1015
1137
|
|
@@ -1039,7 +1161,18 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
1039
1161
|
static VALUE cState_indent(VALUE self)
|
1040
1162
|
{
|
1041
1163
|
GET_STATE(self);
|
1042
|
-
return state->indent ?
|
1164
|
+
return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
|
1165
|
+
}
|
1166
|
+
|
1167
|
+
static VALUE string_config(VALUE config)
|
1168
|
+
{
|
1169
|
+
if (RTEST(config)) {
|
1170
|
+
Check_Type(config, T_STRING);
|
1171
|
+
if (RSTRING_LEN(config)) {
|
1172
|
+
return rb_str_new_frozen(config);
|
1173
|
+
}
|
1174
|
+
}
|
1175
|
+
return Qfalse;
|
1043
1176
|
}
|
1044
1177
|
|
1045
1178
|
/*
|
@@ -1049,21 +1182,8 @@ static VALUE cState_indent(VALUE self)
|
|
1049
1182
|
*/
|
1050
1183
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
1051
1184
|
{
|
1052
|
-
unsigned long len;
|
1053
1185
|
GET_STATE(self);
|
1054
|
-
|
1055
|
-
len = RSTRING_LEN(indent);
|
1056
|
-
if (len == 0) {
|
1057
|
-
if (state->indent) {
|
1058
|
-
ruby_xfree(state->indent);
|
1059
|
-
state->indent = NULL;
|
1060
|
-
state->indent_len = 0;
|
1061
|
-
}
|
1062
|
-
} else {
|
1063
|
-
if (state->indent) ruby_xfree(state->indent);
|
1064
|
-
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
1065
|
-
state->indent_len = len;
|
1066
|
-
}
|
1186
|
+
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
1067
1187
|
return Qnil;
|
1068
1188
|
}
|
1069
1189
|
|
@@ -1076,7 +1196,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1076
1196
|
static VALUE cState_space(VALUE self)
|
1077
1197
|
{
|
1078
1198
|
GET_STATE(self);
|
1079
|
-
return state->space ?
|
1199
|
+
return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
|
1080
1200
|
}
|
1081
1201
|
|
1082
1202
|
/*
|
@@ -1087,21 +1207,8 @@ static VALUE cState_space(VALUE self)
|
|
1087
1207
|
*/
|
1088
1208
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
1089
1209
|
{
|
1090
|
-
unsigned long len;
|
1091
1210
|
GET_STATE(self);
|
1092
|
-
|
1093
|
-
len = RSTRING_LEN(space);
|
1094
|
-
if (len == 0) {
|
1095
|
-
if (state->space) {
|
1096
|
-
ruby_xfree(state->space);
|
1097
|
-
state->space = NULL;
|
1098
|
-
state->space_len = 0;
|
1099
|
-
}
|
1100
|
-
} else {
|
1101
|
-
if (state->space) ruby_xfree(state->space);
|
1102
|
-
state->space = fstrndup(RSTRING_PTR(space), len);
|
1103
|
-
state->space_len = len;
|
1104
|
-
}
|
1211
|
+
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
1105
1212
|
return Qnil;
|
1106
1213
|
}
|
1107
1214
|
|
@@ -1113,7 +1220,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1113
1220
|
static VALUE cState_space_before(VALUE self)
|
1114
1221
|
{
|
1115
1222
|
GET_STATE(self);
|
1116
|
-
return state->space_before ?
|
1223
|
+
return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
|
1117
1224
|
}
|
1118
1225
|
|
1119
1226
|
/*
|
@@ -1123,21 +1230,8 @@ static VALUE cState_space_before(VALUE self)
|
|
1123
1230
|
*/
|
1124
1231
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1125
1232
|
{
|
1126
|
-
unsigned long len;
|
1127
1233
|
GET_STATE(self);
|
1128
|
-
|
1129
|
-
len = RSTRING_LEN(space_before);
|
1130
|
-
if (len == 0) {
|
1131
|
-
if (state->space_before) {
|
1132
|
-
ruby_xfree(state->space_before);
|
1133
|
-
state->space_before = NULL;
|
1134
|
-
state->space_before_len = 0;
|
1135
|
-
}
|
1136
|
-
} else {
|
1137
|
-
if (state->space_before) ruby_xfree(state->space_before);
|
1138
|
-
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1139
|
-
state->space_before_len = len;
|
1140
|
-
}
|
1234
|
+
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
1141
1235
|
return Qnil;
|
1142
1236
|
}
|
1143
1237
|
|
@@ -1150,7 +1244,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1150
1244
|
static VALUE cState_object_nl(VALUE self)
|
1151
1245
|
{
|
1152
1246
|
GET_STATE(self);
|
1153
|
-
return state->object_nl ?
|
1247
|
+
return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1154
1248
|
}
|
1155
1249
|
|
1156
1250
|
/*
|
@@ -1161,20 +1255,8 @@ static VALUE cState_object_nl(VALUE self)
|
|
1161
1255
|
*/
|
1162
1256
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
1163
1257
|
{
|
1164
|
-
unsigned long len;
|
1165
1258
|
GET_STATE(self);
|
1166
|
-
|
1167
|
-
len = RSTRING_LEN(object_nl);
|
1168
|
-
if (len == 0) {
|
1169
|
-
if (state->object_nl) {
|
1170
|
-
ruby_xfree(state->object_nl);
|
1171
|
-
state->object_nl = NULL;
|
1172
|
-
}
|
1173
|
-
} else {
|
1174
|
-
if (state->object_nl) ruby_xfree(state->object_nl);
|
1175
|
-
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1176
|
-
state->object_nl_len = len;
|
1177
|
-
}
|
1259
|
+
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
1178
1260
|
return Qnil;
|
1179
1261
|
}
|
1180
1262
|
|
@@ -1186,7 +1268,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1186
1268
|
static VALUE cState_array_nl(VALUE self)
|
1187
1269
|
{
|
1188
1270
|
GET_STATE(self);
|
1189
|
-
return state->array_nl ?
|
1271
|
+
return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
|
1190
1272
|
}
|
1191
1273
|
|
1192
1274
|
/*
|
@@ -1196,20 +1278,8 @@ static VALUE cState_array_nl(VALUE self)
|
|
1196
1278
|
*/
|
1197
1279
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
1198
1280
|
{
|
1199
|
-
unsigned long len;
|
1200
1281
|
GET_STATE(self);
|
1201
|
-
|
1202
|
-
len = RSTRING_LEN(array_nl);
|
1203
|
-
if (len == 0) {
|
1204
|
-
if (state->array_nl) {
|
1205
|
-
ruby_xfree(state->array_nl);
|
1206
|
-
state->array_nl = NULL;
|
1207
|
-
}
|
1208
|
-
} else {
|
1209
|
-
if (state->array_nl) ruby_xfree(state->array_nl);
|
1210
|
-
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1211
|
-
state->array_nl_len = len;
|
1212
|
-
}
|
1282
|
+
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
1213
1283
|
return Qnil;
|
1214
1284
|
}
|
1215
1285
|
|
@@ -1238,6 +1308,11 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1238
1308
|
return LONG2FIX(state->max_nesting);
|
1239
1309
|
}
|
1240
1310
|
|
1311
|
+
static long long_config(VALUE num)
|
1312
|
+
{
|
1313
|
+
return RTEST(num) ? FIX2LONG(num) : 0;
|
1314
|
+
}
|
1315
|
+
|
1241
1316
|
/*
|
1242
1317
|
* call-seq: max_nesting=(depth)
|
1243
1318
|
*
|
@@ -1247,8 +1322,7 @@ static VALUE cState_max_nesting(VALUE self)
|
|
1247
1322
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
1248
1323
|
{
|
1249
1324
|
GET_STATE(self);
|
1250
|
-
|
1251
|
-
state->max_nesting = FIX2LONG(depth);
|
1325
|
+
state->max_nesting = long_config(depth);
|
1252
1326
|
return Qnil;
|
1253
1327
|
}
|
1254
1328
|
|
@@ -1376,8 +1450,7 @@ static VALUE cState_depth(VALUE self)
|
|
1376
1450
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
1377
1451
|
{
|
1378
1452
|
GET_STATE(self);
|
1379
|
-
|
1380
|
-
state->depth = FIX2LONG(depth);
|
1453
|
+
state->depth = long_config(depth);
|
1381
1454
|
return Qnil;
|
1382
1455
|
}
|
1383
1456
|
|
@@ -1392,6 +1465,15 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1392
1465
|
return LONG2FIX(state->buffer_initial_length);
|
1393
1466
|
}
|
1394
1467
|
|
1468
|
+
static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_initial_length)
|
1469
|
+
{
|
1470
|
+
Check_Type(buffer_initial_length, T_FIXNUM);
|
1471
|
+
long initial_length = FIX2LONG(buffer_initial_length);
|
1472
|
+
if (initial_length > 0) {
|
1473
|
+
state->buffer_initial_length = initial_length;
|
1474
|
+
}
|
1475
|
+
}
|
1476
|
+
|
1395
1477
|
/*
|
1396
1478
|
* call-seq: buffer_initial_length=(length)
|
1397
1479
|
*
|
@@ -1400,16 +1482,75 @@ static VALUE cState_buffer_initial_length(VALUE self)
|
|
1400
1482
|
*/
|
1401
1483
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
1402
1484
|
{
|
1403
|
-
long initial_length;
|
1404
1485
|
GET_STATE(self);
|
1405
|
-
|
1406
|
-
initial_length = FIX2LONG(buffer_initial_length);
|
1407
|
-
if (initial_length > 0) {
|
1408
|
-
state->buffer_initial_length = initial_length;
|
1409
|
-
}
|
1486
|
+
buffer_initial_length_set(state, buffer_initial_length);
|
1410
1487
|
return Qnil;
|
1411
1488
|
}
|
1412
1489
|
|
1490
|
+
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
1491
|
+
{
|
1492
|
+
JSON_Generator_State *state = (JSON_Generator_State *)_arg;
|
1493
|
+
|
1494
|
+
if (key == sym_indent) { state->indent = string_config(val); }
|
1495
|
+
else if (key == sym_space) { state->space = string_config(val); }
|
1496
|
+
else if (key == sym_space_before) { state->space_before = string_config(val); }
|
1497
|
+
else if (key == sym_object_nl) { state->object_nl = string_config(val); }
|
1498
|
+
else if (key == sym_array_nl) { state->array_nl = string_config(val); }
|
1499
|
+
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
|
1500
|
+
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
|
1501
|
+
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
|
1502
|
+
else if (key == sym_depth) { state->depth = long_config(val); }
|
1503
|
+
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
1504
|
+
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
1505
|
+
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
1506
|
+
else if (key == sym_strict) { state->strict = RTEST(val); }
|
1507
|
+
return ST_CONTINUE;
|
1508
|
+
}
|
1509
|
+
|
1510
|
+
static void configure_state(JSON_Generator_State *state, VALUE config)
|
1511
|
+
{
|
1512
|
+
if (!RTEST(config)) return;
|
1513
|
+
|
1514
|
+
Check_Type(config, T_HASH);
|
1515
|
+
|
1516
|
+
if (!RHASH_SIZE(config)) return;
|
1517
|
+
|
1518
|
+
// We assume in most cases few keys are set so it's faster to go over
|
1519
|
+
// the provided keys than to check all possible keys.
|
1520
|
+
rb_hash_foreach(config, configure_state_i, (VALUE)state);
|
1521
|
+
}
|
1522
|
+
|
1523
|
+
static VALUE cState_configure(VALUE self, VALUE opts)
|
1524
|
+
{
|
1525
|
+
GET_STATE(self);
|
1526
|
+
configure_state(state, opts);
|
1527
|
+
return self;
|
1528
|
+
}
|
1529
|
+
|
1530
|
+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
1531
|
+
{
|
1532
|
+
JSON_Generator_State state = {0};
|
1533
|
+
state_init(&state);
|
1534
|
+
configure_state(&state, opts);
|
1535
|
+
|
1536
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1537
|
+
FBuffer buffer = {
|
1538
|
+
.io = RTEST(io) ? io : Qfalse,
|
1539
|
+
};
|
1540
|
+
fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
|
1541
|
+
|
1542
|
+
struct generate_json_data data = {
|
1543
|
+
.buffer = &buffer,
|
1544
|
+
.vstate = Qfalse,
|
1545
|
+
.state = &state,
|
1546
|
+
.obj = obj,
|
1547
|
+
.func = generate_json,
|
1548
|
+
};
|
1549
|
+
rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
|
1550
|
+
|
1551
|
+
return fbuffer_finalize(&buffer);
|
1552
|
+
}
|
1553
|
+
|
1413
1554
|
/*
|
1414
1555
|
*
|
1415
1556
|
*/
|
@@ -1426,16 +1567,18 @@ void Init_generator(void)
|
|
1426
1567
|
VALUE mExt = rb_define_module_under(mJSON, "Ext");
|
1427
1568
|
VALUE mGenerator = rb_define_module_under(mExt, "Generator");
|
1428
1569
|
|
1570
|
+
rb_global_variable(&eGeneratorError);
|
1429
1571
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
1572
|
+
|
1573
|
+
rb_global_variable(&eNestingError);
|
1430
1574
|
eNestingError = rb_path2class("JSON::NestingError");
|
1431
|
-
rb_gc_register_mark_object(eGeneratorError);
|
1432
|
-
rb_gc_register_mark_object(eNestingError);
|
1433
1575
|
|
1434
1576
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
1435
1577
|
rb_define_alloc_func(cState, cState_s_allocate);
|
1436
1578
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
1437
1579
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
1438
1580
|
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
1581
|
+
rb_define_private_method(cState, "_configure", cState_configure, 1);
|
1439
1582
|
|
1440
1583
|
rb_define_method(cState, "initialize_copy", cState_init_copy, 1);
|
1441
1584
|
rb_define_method(cState, "indent", cState_indent, 0);
|
@@ -1468,7 +1611,9 @@ void Init_generator(void)
|
|
1468
1611
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
1469
1612
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
1470
1613
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
1471
|
-
|
1614
|
+
rb_define_private_method(cState, "_generate", cState_generate, 2);
|
1615
|
+
|
1616
|
+
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
|
1472
1617
|
|
1473
1618
|
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
1474
1619
|
|
@@ -1524,6 +1669,20 @@ void Init_generator(void)
|
|
1524
1669
|
i_extend = rb_intern("extend");
|
1525
1670
|
i_encode = rb_intern("encode");
|
1526
1671
|
|
1672
|
+
sym_indent = ID2SYM(rb_intern("indent"));
|
1673
|
+
sym_space = ID2SYM(rb_intern("space"));
|
1674
|
+
sym_space_before = ID2SYM(rb_intern("space_before"));
|
1675
|
+
sym_object_nl = ID2SYM(rb_intern("object_nl"));
|
1676
|
+
sym_array_nl = ID2SYM(rb_intern("array_nl"));
|
1677
|
+
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
|
1678
|
+
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
1679
|
+
sym_ascii_only = ID2SYM(rb_intern("ascii_only"));
|
1680
|
+
sym_depth = ID2SYM(rb_intern("depth"));
|
1681
|
+
sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
|
1682
|
+
sym_script_safe = ID2SYM(rb_intern("script_safe"));
|
1683
|
+
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
|
1684
|
+
sym_strict = ID2SYM(rb_intern("strict"));
|
1685
|
+
|
1527
1686
|
usascii_encindex = rb_usascii_encindex();
|
1528
1687
|
utf8_encindex = rb_utf8_encindex();
|
1529
1688
|
binary_encindex = rb_ascii8bit_encindex();
|