json 2.7.5 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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();
|