oj 3.11.5 → 3.16.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1421 -0
- data/README.md +19 -5
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +20 -6
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +10 -9
- data/ext/oj/circarray.c +8 -6
- data/ext/oj/circarray.h +2 -2
- data/ext/oj/code.c +19 -33
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +27 -77
- data/ext/oj/custom.c +86 -179
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +256 -249
- data/ext/oj/dump.h +26 -12
- data/ext/oj/dump_compat.c +565 -642
- data/ext/oj/dump_leaf.c +17 -63
- data/ext/oj/dump_object.c +65 -187
- data/ext/oj/dump_strict.c +27 -51
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +2 -13
- data/ext/oj/err.h +24 -8
- data/ext/oj/extconf.rb +21 -6
- data/ext/oj/fast.c +149 -149
- data/ext/oj/intern.c +313 -0
- data/ext/oj/intern.h +22 -0
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +121 -106
- data/ext/oj/object.c +85 -162
- data/ext/oj/odd.c +89 -67
- data/ext/oj/odd.h +15 -15
- data/ext/oj/oj.c +542 -411
- data/ext/oj/oj.h +99 -73
- data/ext/oj/parse.c +175 -187
- data/ext/oj/parse.h +26 -24
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +101 -0
- data/ext/oj/rails.c +112 -159
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +11 -14
- data/ext/oj/reader.h +4 -2
- data/ext/oj/resolve.c +5 -24
- data/ext/oj/rxclass.c +7 -6
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/saj.c +22 -33
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +5 -28
- data/ext/oj/sparse.c +28 -72
- data/ext/oj/stream_writer.c +50 -40
- data/ext/oj/strict.c +56 -61
- data/ext/oj/string_writer.c +72 -39
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +14 -3
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +63 -88
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +7 -1
- data/lib/oj/easy_hash.rb +4 -5
- data/lib/oj/error.rb +1 -2
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +9 -7
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +12 -8
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +8 -3
- data/pages/Options.md +43 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +14 -2
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +5 -6
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +16 -45
- data/test/helper.rb +11 -8
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +8 -6
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +56 -38
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +7 -3
- data/test/mem.rb +34 -0
- data/test/perf.rb +22 -27
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +59 -0
- data/test/perf_parser.rb +183 -0
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +58 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +74 -82
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +5 -5
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +95 -43
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +135 -79
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -5
- data/test/test_generate.rb +5 -5
- data/test/test_hash.rb +5 -5
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +99 -96
- data/test/test_parser.rb +11 -0
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +337 -0
- data/test/test_parser_usual.rb +251 -0
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +37 -39
- data/test/test_strict.rb +40 -32
- data/test/test_various.rb +165 -84
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -5
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +74 -128
- data/ext/oj/hash.c +0 -131
- data/ext/oj/hash.h +0 -19
- data/ext/oj/hash_test.c +0 -491
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/bar.rb +0 -35
- data/test/baz.rb +0 -16
- data/test/zoo.rb +0 -13
data/ext/oj/fast.c
CHANGED
@@ -11,13 +11,15 @@
|
|
11
11
|
#include <stdlib.h>
|
12
12
|
#include <string.h>
|
13
13
|
|
14
|
+
#include "dump.h"
|
14
15
|
#include "encode.h"
|
16
|
+
#include "mem.h"
|
15
17
|
#include "oj.h"
|
16
18
|
|
17
19
|
// maximum to allocate on the stack, arbitrary limit
|
18
20
|
#define SMALL_JSON 65536
|
19
21
|
#define MAX_STACK 100
|
20
|
-
|
22
|
+
// #define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1)
|
21
23
|
#define BATCH_SIZE 100
|
22
24
|
|
23
25
|
// Support for compaction
|
@@ -31,25 +33,25 @@ typedef struct _batch {
|
|
31
33
|
struct _batch *next;
|
32
34
|
int next_avail;
|
33
35
|
struct _leaf leaves[BATCH_SIZE];
|
34
|
-
} *
|
36
|
+
} *Batch;
|
35
37
|
|
36
38
|
typedef struct _doc {
|
37
39
|
Leaf data;
|
38
|
-
Leaf
|
40
|
+
Leaf *where; // points to current location
|
39
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
40
|
-
char
|
42
|
+
char *json;
|
41
43
|
unsigned long size; // number of leaves/branches in the doc
|
42
44
|
VALUE self;
|
43
45
|
Batch batches;
|
44
46
|
struct _batch batch0;
|
45
|
-
} *
|
47
|
+
} *Doc;
|
46
48
|
|
47
49
|
typedef struct _parseInfo {
|
48
50
|
char *str; // buffer being read from
|
49
51
|
char *s; // current position in buffer
|
50
52
|
Doc doc;
|
51
53
|
void *stack_min;
|
52
|
-
} *
|
54
|
+
} *ParseInfo;
|
53
55
|
|
54
56
|
static void leaf_init(Leaf leaf, int type);
|
55
57
|
static Leaf leaf_new(Doc doc, int type);
|
@@ -73,29 +75,13 @@ static char *read_quoted_value(ParseInfo pi);
|
|
73
75
|
static void skip_comment(ParseInfo pi);
|
74
76
|
|
75
77
|
static VALUE protect_open_proc(VALUE x);
|
76
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
78
|
+
static VALUE parse_json(VALUE clas, char *json, bool given);
|
77
79
|
static void each_leaf(Doc doc, VALUE self);
|
78
80
|
static int move_step(Doc doc, const char *path, int loc);
|
79
81
|
static Leaf get_doc_leaf(Doc doc, const char *path);
|
80
82
|
static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
|
81
83
|
static void each_value(Doc doc, Leaf leaf);
|
82
84
|
|
83
|
-
static void doc_init(Doc doc);
|
84
|
-
static void doc_free(Doc doc);
|
85
|
-
static VALUE doc_open(VALUE clas, VALUE str);
|
86
|
-
static VALUE doc_open_file(VALUE clas, VALUE filename);
|
87
|
-
static VALUE doc_where(VALUE self);
|
88
|
-
static VALUE doc_local_key(VALUE self);
|
89
|
-
static VALUE doc_home(VALUE self);
|
90
|
-
static VALUE doc_type(int argc, VALUE *argv, VALUE self);
|
91
|
-
static VALUE doc_fetch(int argc, VALUE *argv, VALUE self);
|
92
|
-
static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self);
|
93
|
-
static VALUE doc_move(VALUE self, VALUE str);
|
94
|
-
static VALUE doc_each_child(int argc, VALUE *argv, VALUE self);
|
95
|
-
static VALUE doc_each_value(int argc, VALUE *argv, VALUE self);
|
96
|
-
static VALUE doc_dump(int argc, VALUE *argv, VALUE self);
|
97
|
-
static VALUE doc_size(VALUE self);
|
98
|
-
|
99
85
|
VALUE oj_doc_class = Qundef;
|
100
86
|
|
101
87
|
// This is only for CentOS 5.4 with Ruby 1.9.3-p0.
|
@@ -128,10 +114,7 @@ inline static char *ulong_fill(char *s, size_t num) {
|
|
128
114
|
char *b = buf + sizeof(buf) - 1;
|
129
115
|
|
130
116
|
*b-- = '\0';
|
131
|
-
|
132
|
-
*b = (num % 10) + '0';
|
133
|
-
}
|
134
|
-
b++;
|
117
|
+
b = oj_longlong_to_string((long long)num, false, b);
|
135
118
|
if ('\0' == *b) {
|
136
119
|
b--;
|
137
120
|
*b = '0';
|
@@ -175,7 +158,7 @@ inline static Leaf leaf_new(Doc doc, int type) {
|
|
175
158
|
Leaf leaf;
|
176
159
|
|
177
160
|
if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
|
178
|
-
Batch b =
|
161
|
+
Batch b = OJ_R_ALLOC(struct _batch);
|
179
162
|
|
180
163
|
// Initializes all leaves with a NO_VAL value_type
|
181
164
|
memset(b, 0, sizeof(struct _batch));
|
@@ -216,9 +199,7 @@ static VALUE leaf_value(Doc doc, Leaf leaf) {
|
|
216
199
|
break;
|
217
200
|
case T_ARRAY: return leaf_array_value(doc, leaf); break;
|
218
201
|
case T_HASH: return leaf_hash_value(doc, leaf); break;
|
219
|
-
default:
|
220
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
|
221
|
-
break;
|
202
|
+
default: rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype); break;
|
222
203
|
}
|
223
204
|
}
|
224
205
|
return leaf->value;
|
@@ -267,7 +248,7 @@ static void skip_comment(ParseInfo pi) {
|
|
267
248
|
#endif
|
268
249
|
|
269
250
|
static void leaf_fixnum_value(Leaf leaf) {
|
270
|
-
char
|
251
|
+
char *s = leaf->str;
|
271
252
|
int64_t n = 0;
|
272
253
|
int neg = 0;
|
273
254
|
int big = 0;
|
@@ -373,7 +354,7 @@ static Leaf read_next(ParseInfo pi) {
|
|
373
354
|
|
374
355
|
static Leaf read_obj(ParseInfo pi) {
|
375
356
|
Leaf h = leaf_new(pi->doc, T_HASH);
|
376
|
-
char
|
357
|
+
char *end;
|
377
358
|
const char *key = 0;
|
378
359
|
Leaf val = 0;
|
379
360
|
|
@@ -665,10 +646,11 @@ static void doc_free(Doc doc) {
|
|
665
646
|
while (0 != (b = doc->batches)) {
|
666
647
|
doc->batches = doc->batches->next;
|
667
648
|
if (&doc->batch0 != b) {
|
668
|
-
|
649
|
+
OJ_R_FREE(b);
|
669
650
|
}
|
670
651
|
}
|
671
|
-
|
652
|
+
OJ_R_FREE(doc->json);
|
653
|
+
OJ_R_FREE(doc);
|
672
654
|
}
|
673
655
|
}
|
674
656
|
|
@@ -688,27 +670,28 @@ static void free_doc_cb(void *x) {
|
|
688
670
|
Doc doc = (Doc)x;
|
689
671
|
|
690
672
|
if (0 != doc) {
|
691
|
-
xfree(doc->json);
|
692
673
|
doc_free(doc);
|
693
674
|
}
|
694
675
|
}
|
695
676
|
|
696
677
|
static void mark_leaf(Leaf leaf) {
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
678
|
+
if (NULL != leaf) {
|
679
|
+
switch (leaf->value_type) {
|
680
|
+
case COL_VAL:
|
681
|
+
if (NULL != leaf->elements) {
|
682
|
+
Leaf first = leaf->elements->next;
|
683
|
+
Leaf e = first;
|
702
684
|
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
685
|
+
do {
|
686
|
+
mark_leaf(e);
|
687
|
+
e = e->next;
|
688
|
+
} while (e != first);
|
689
|
+
}
|
690
|
+
break;
|
691
|
+
case RUBY_VAL: mark(leaf->value); break;
|
710
692
|
|
711
|
-
|
693
|
+
default: break;
|
694
|
+
}
|
712
695
|
}
|
713
696
|
}
|
714
697
|
|
@@ -764,20 +747,15 @@ static const rb_data_type_t oj_doc_type = {
|
|
764
747
|
0,
|
765
748
|
};
|
766
749
|
|
767
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
750
|
+
static VALUE parse_json(VALUE clas, char *json, bool given) {
|
768
751
|
struct _parseInfo pi;
|
769
752
|
volatile VALUE result = Qnil;
|
770
753
|
Doc doc;
|
771
754
|
int ex = 0;
|
772
755
|
volatile VALUE self;
|
773
756
|
|
774
|
-
|
757
|
+
doc = OJ_R_ALLOC_N(struct _doc, 1);
|
775
758
|
|
776
|
-
if (given) {
|
777
|
-
doc = ALLOCA_N(struct _doc, 1);
|
778
|
-
} else {
|
779
|
-
doc = ALLOC(struct _doc);
|
780
|
-
}
|
781
759
|
// skip UTF-8 BOM if present
|
782
760
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
783
761
|
pi.str = json + 3;
|
@@ -787,9 +765,9 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
787
765
|
pi.s = pi.str;
|
788
766
|
doc_init(doc);
|
789
767
|
pi.doc = doc;
|
790
|
-
#if IS_WINDOWS
|
768
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
791
769
|
// assume a 1M stack and give half to ruby
|
792
|
-
pi.stack_min = (void *)((char *)&pi - (
|
770
|
+
pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
|
793
771
|
#else
|
794
772
|
{
|
795
773
|
struct rlimit lim;
|
@@ -802,18 +780,19 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
802
780
|
}
|
803
781
|
}
|
804
782
|
#endif
|
805
|
-
|
806
|
-
|
807
|
-
doc->
|
808
|
-
|
809
|
-
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
783
|
+
doc->json = json;
|
784
|
+
self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
|
785
|
+
doc->self = self;
|
786
|
+
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
810
787
|
if (given || 0 != ex) {
|
811
788
|
DATA_PTR(doc->self) = NULL;
|
789
|
+
// TBD is this needed?
|
790
|
+
/*
|
812
791
|
doc_free(pi.doc);
|
813
|
-
if (
|
814
|
-
|
792
|
+
if (0 != ex) { // will jump so caller will not free
|
793
|
+
OJ_R_FREE(json);
|
815
794
|
}
|
816
|
-
|
795
|
+
*/
|
817
796
|
} else {
|
818
797
|
result = doc->self;
|
819
798
|
}
|
@@ -841,9 +820,7 @@ static Leaf get_doc_leaf(Doc doc, const char *path) {
|
|
841
820
|
size_t cnt = doc->where - doc->where_path;
|
842
821
|
|
843
822
|
if (MAX_STACK <= cnt) {
|
844
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
845
|
-
"Path too deep. Limit is %d levels.",
|
846
|
-
MAX_STACK);
|
823
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
847
824
|
}
|
848
825
|
memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
|
849
826
|
lp = stack + cnt;
|
@@ -884,9 +861,7 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
884
861
|
Leaf leaf = *lp;
|
885
862
|
|
886
863
|
if (MAX_STACK <= lp - stack) {
|
887
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
888
|
-
"Path too deep. Limit is %d levels.",
|
889
|
-
MAX_STACK);
|
864
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
890
865
|
}
|
891
866
|
if ('\0' != *path) {
|
892
867
|
if ('.' == *path && '.' == *(path + 1)) {
|
@@ -899,12 +874,18 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
899
874
|
} else {
|
900
875
|
return 0;
|
901
876
|
}
|
902
|
-
} else if (
|
877
|
+
} else if (NULL == leaf->elements) {
|
878
|
+
leaf = NULL;
|
879
|
+
} else if (STR_VAL == leaf->value_type || RUBY_VAL == leaf->value_type) {
|
880
|
+
// We are trying to get a children of a leaf, which
|
881
|
+
// doesn't exist.
|
882
|
+
leaf = NULL;
|
883
|
+
} else if (COL_VAL == leaf->value_type) {
|
903
884
|
Leaf first = leaf->elements->next;
|
904
885
|
Leaf e = first;
|
905
886
|
int type = leaf->rtype;
|
906
887
|
|
907
|
-
leaf =
|
888
|
+
leaf = NULL;
|
908
889
|
if (T_ARRAY == type) {
|
909
890
|
int cnt = 0;
|
910
891
|
|
@@ -929,6 +910,7 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
929
910
|
const char *slash = next_slash(path);
|
930
911
|
int klen;
|
931
912
|
|
913
|
+
leaf = NULL;
|
932
914
|
if (0 == slash) {
|
933
915
|
klen = (int)strlen(key);
|
934
916
|
path += klen;
|
@@ -959,9 +941,7 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
959
941
|
|
960
942
|
doc->where++;
|
961
943
|
if (MAX_STACK <= doc->where - doc->where_path) {
|
962
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
963
|
-
"Path too deep. Limit is %d levels.",
|
964
|
-
MAX_STACK);
|
944
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
965
945
|
}
|
966
946
|
do {
|
967
947
|
*doc->where = e;
|
@@ -977,9 +957,7 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
977
957
|
|
978
958
|
static int move_step(Doc doc, const char *path, int loc) {
|
979
959
|
if (MAX_STACK <= doc->where - doc->where_path) {
|
980
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
981
|
-
"Path too deep. Limit is %d levels.",
|
982
|
-
MAX_STACK);
|
960
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
983
961
|
}
|
984
962
|
if ('\0' == *path) {
|
985
963
|
loc = 0;
|
@@ -1104,31 +1082,23 @@ static void each_value(Doc doc, Leaf leaf) {
|
|
1104
1082
|
* doc.close()
|
1105
1083
|
*/
|
1106
1084
|
static VALUE doc_open(VALUE clas, VALUE str) {
|
1107
|
-
char
|
1085
|
+
char *json;
|
1108
1086
|
size_t len;
|
1109
1087
|
volatile VALUE obj;
|
1110
1088
|
int given = rb_block_given_p();
|
1111
|
-
int allocate;
|
1112
1089
|
|
1113
1090
|
Check_Type(str, T_STRING);
|
1114
|
-
len
|
1115
|
-
|
1116
|
-
|
1117
|
-
json = ALLOC_N(char, len);
|
1118
|
-
} else {
|
1119
|
-
json = ALLOCA_N(char, len);
|
1120
|
-
}
|
1121
|
-
// It should not be necessaary to stop GC but if it is not stopped and a
|
1122
|
-
// large string is parsed that string is corrupted or freed during
|
1123
|
-
// parsing. I'm not sure what is going on exactly but disabling GC avoids
|
1124
|
-
// the issue.
|
1125
|
-
rb_gc_disable();
|
1091
|
+
len = (int)RSTRING_LEN(str) + 1;
|
1092
|
+
json = OJ_R_ALLOC_N(char, len);
|
1093
|
+
|
1126
1094
|
memcpy(json, StringValuePtr(str), len);
|
1127
|
-
obj = parse_json(clas, json, given
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1095
|
+
obj = parse_json(clas, json, given);
|
1096
|
+
// TBD is this needed
|
1097
|
+
/*
|
1098
|
+
if (given) {
|
1099
|
+
OJ_R_FREE(json);
|
1131
1100
|
}
|
1101
|
+
*/
|
1132
1102
|
return obj;
|
1133
1103
|
}
|
1134
1104
|
|
@@ -1152,27 +1122,21 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
1152
1122
|
* doc.close()
|
1153
1123
|
*/
|
1154
1124
|
static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
1155
|
-
char
|
1156
|
-
char
|
1157
|
-
FILE
|
1125
|
+
char *path;
|
1126
|
+
char *json;
|
1127
|
+
FILE *f;
|
1158
1128
|
size_t len;
|
1159
1129
|
volatile VALUE obj;
|
1160
1130
|
int given = rb_block_given_p();
|
1161
|
-
int allocate;
|
1162
1131
|
|
1163
|
-
Check_Type(filename, T_STRING);
|
1164
1132
|
path = StringValuePtr(filename);
|
1165
1133
|
if (0 == (f = fopen(path, "r"))) {
|
1166
1134
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
1167
1135
|
}
|
1168
1136
|
fseek(f, 0, SEEK_END);
|
1169
|
-
len
|
1170
|
-
|
1171
|
-
|
1172
|
-
json = ALLOC_N(char, len + 1);
|
1173
|
-
} else {
|
1174
|
-
json = ALLOCA_N(char, len + 1);
|
1175
|
-
}
|
1137
|
+
len = ftell(f);
|
1138
|
+
json = OJ_R_ALLOC_N(char, len + 1);
|
1139
|
+
|
1176
1140
|
fseek(f, 0, SEEK_SET);
|
1177
1141
|
if (len != fread(json, 1, len, f)) {
|
1178
1142
|
fclose(f);
|
@@ -1183,12 +1147,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1183
1147
|
}
|
1184
1148
|
fclose(f);
|
1185
1149
|
json[len] = '\0';
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
if (given
|
1190
|
-
|
1150
|
+
obj = parse_json(clas, json, given);
|
1151
|
+
// TBD is this needed
|
1152
|
+
/*
|
1153
|
+
if (given) {
|
1154
|
+
OJ_R_FREE(json);
|
1191
1155
|
}
|
1156
|
+
*/
|
1192
1157
|
return obj;
|
1193
1158
|
}
|
1194
1159
|
|
@@ -1217,7 +1182,7 @@ static char *append_key(char *p, const char *key) {
|
|
1217
1182
|
* @see Oj::Doc.open
|
1218
1183
|
*/
|
1219
1184
|
|
1220
|
-
/* @overload where
|
1185
|
+
/* @overload where() => String
|
1221
1186
|
*
|
1222
1187
|
* Returns a String that describes the absolute path to the current location
|
1223
1188
|
* in the JSON document.
|
@@ -1228,11 +1193,11 @@ static VALUE doc_where(VALUE self) {
|
|
1228
1193
|
if (0 == *doc->where_path || doc->where == doc->where_path) {
|
1229
1194
|
return oj_slash_string;
|
1230
1195
|
} else {
|
1231
|
-
Leaf
|
1196
|
+
Leaf *lp;
|
1232
1197
|
Leaf leaf;
|
1233
1198
|
size_t size = 3; // leading / and terminating \0
|
1234
|
-
char
|
1235
|
-
char
|
1199
|
+
char *path;
|
1200
|
+
char *p;
|
1236
1201
|
|
1237
1202
|
for (lp = doc->where_path; lp <= doc->where; lp++) {
|
1238
1203
|
leaf = *lp;
|
@@ -1259,6 +1224,24 @@ static VALUE doc_where(VALUE self) {
|
|
1259
1224
|
}
|
1260
1225
|
}
|
1261
1226
|
|
1227
|
+
/* @overload where?() => String
|
1228
|
+
* @deprecated
|
1229
|
+
* Returns a String that describes the absolute path to the current location
|
1230
|
+
* in the JSON document.
|
1231
|
+
*/
|
1232
|
+
static VALUE doc_where_q(VALUE self) {
|
1233
|
+
return doc_where(self);
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
/* @overload path() => String
|
1237
|
+
*
|
1238
|
+
* Returns a String that describes the absolute path to the current location
|
1239
|
+
* in the JSON document.
|
1240
|
+
*/
|
1241
|
+
static VALUE doc_path(VALUE self) {
|
1242
|
+
return doc_where(self);
|
1243
|
+
}
|
1244
|
+
|
1262
1245
|
/* @overload local_key() => String, Fixnum, nil
|
1263
1246
|
*
|
1264
1247
|
* Returns the final key to the current location.
|
@@ -1317,7 +1300,6 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1317
1300
|
VALUE type = Qnil;
|
1318
1301
|
|
1319
1302
|
if (1 <= argc) {
|
1320
|
-
Check_Type(*argv, T_STRING);
|
1321
1303
|
path = StringValuePtr(*argv);
|
1322
1304
|
}
|
1323
1305
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
@@ -1326,11 +1308,7 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1326
1308
|
case T_TRUE: type = rb_cTrueClass; break;
|
1327
1309
|
case T_FALSE: type = rb_cFalseClass; break;
|
1328
1310
|
case T_STRING: type = rb_cString; break;
|
1329
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
1330
1311
|
case T_FIXNUM: type = rb_cInteger; break;
|
1331
|
-
#else
|
1332
|
-
case T_FIXNUM: type = rb_cFixnum; break;
|
1333
|
-
#endif
|
1334
1312
|
case T_FLOAT: type = rb_cFloat; break;
|
1335
1313
|
case T_ARRAY: type = rb_cArray; break;
|
1336
1314
|
case T_HASH: type = rb_cHash; break;
|
@@ -1340,14 +1318,14 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1340
1318
|
return type;
|
1341
1319
|
}
|
1342
1320
|
|
1343
|
-
/* @overload fetch(path=nil) => nil, true, false, Fixnum, Float, String, Array,
|
1321
|
+
/* @overload fetch(path=nil,default=nil) => nil, true, false, Fixnum, Float, String, Array,
|
1344
1322
|
* Hash
|
1345
1323
|
*
|
1346
1324
|
* Returns the value at the location identified by the path or the current
|
1347
1325
|
* location if the path is nil or not provided. This method will create and
|
1348
1326
|
* return an Array or Hash if that is the type of Object at the location
|
1349
1327
|
* specified. This is more expensive than navigating to the leaves of the JSON
|
1350
|
-
* document.
|
1328
|
+
* document. If a default is provided that is used if no value if found.
|
1351
1329
|
* @param [String] path path to the location to get the type of if provided
|
1352
1330
|
* @example
|
1353
1331
|
* Oj::Doc.open('[1,2]') { |doc| doc.fetch() } #=> [1, 2]
|
@@ -1357,11 +1335,10 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
|
|
1357
1335
|
Doc doc;
|
1358
1336
|
Leaf leaf;
|
1359
1337
|
volatile VALUE val = Qnil;
|
1360
|
-
const char
|
1338
|
+
const char *path = 0;
|
1361
1339
|
|
1362
1340
|
doc = self_doc(self);
|
1363
1341
|
if (1 <= argc) {
|
1364
|
-
Check_Type(*argv, T_STRING);
|
1365
1342
|
path = StringValuePtr(*argv);
|
1366
1343
|
if (2 == argc) {
|
1367
1344
|
val = argv[1];
|
@@ -1373,6 +1350,27 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
|
|
1373
1350
|
return val;
|
1374
1351
|
}
|
1375
1352
|
|
1353
|
+
/* @overload exists?(path) => true, false
|
1354
|
+
*
|
1355
|
+
* Returns true if the value at the location identified by the path exists.
|
1356
|
+
* @param [String] path path to the location
|
1357
|
+
* @example
|
1358
|
+
* Oj::Doc.open('[1,2]') { |doc| doc.exists?('/1') } #=> true
|
1359
|
+
* Oj::Doc.open('[1,2]') { |doc| doc.exists?('/3') } #=> false
|
1360
|
+
*/
|
1361
|
+
static VALUE doc_exists(VALUE self, VALUE str) {
|
1362
|
+
Doc doc;
|
1363
|
+
Leaf leaf;
|
1364
|
+
|
1365
|
+
doc = self_doc(self);
|
1366
|
+
if (0 != (leaf = get_doc_leaf(doc, StringValuePtr(str)))) {
|
1367
|
+
if (NULL != leaf) {
|
1368
|
+
return Qtrue;
|
1369
|
+
}
|
1370
|
+
}
|
1371
|
+
return Qfalse;
|
1372
|
+
}
|
1373
|
+
|
1376
1374
|
/* @overload each_leaf(path=nil) => nil
|
1377
1375
|
*
|
1378
1376
|
* Yields to the provided block for each leaf node with the identified
|
@@ -1401,7 +1399,6 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
1401
1399
|
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
1402
1400
|
}
|
1403
1401
|
if (1 <= argc) {
|
1404
|
-
Check_Type(*argv, T_STRING);
|
1405
1402
|
path = StringValuePtr(*argv);
|
1406
1403
|
if ('/' == *path) {
|
1407
1404
|
doc->where = doc->where_path;
|
@@ -1436,7 +1433,6 @@ static VALUE doc_move(VALUE self, VALUE str) {
|
|
1436
1433
|
const char *path;
|
1437
1434
|
int loc;
|
1438
1435
|
|
1439
|
-
Check_Type(str, T_STRING);
|
1440
1436
|
path = StringValuePtr(str);
|
1441
1437
|
if ('/' == *path) {
|
1442
1438
|
doc->where = doc->where_path;
|
@@ -1455,7 +1451,7 @@ static VALUE doc_move(VALUE self, VALUE str) {
|
|
1455
1451
|
* to the block on yield is the Doc instance after moving to the child
|
1456
1452
|
* location.
|
1457
1453
|
* @param [String] path if provided it identified the top of the branch to
|
1458
|
-
* process the
|
1454
|
+
* process the children of
|
1459
1455
|
* @yieldparam [Doc] Doc at the child location
|
1460
1456
|
* @example
|
1461
1457
|
* Oj::Doc.open('[3,[2,1]]') { |doc|
|
@@ -1471,13 +1467,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1471
1467
|
Doc doc = self_doc(self);
|
1472
1468
|
const char *path = 0;
|
1473
1469
|
size_t wlen;
|
1470
|
+
Leaf *where_orig = doc->where;
|
1474
1471
|
|
1475
1472
|
wlen = doc->where - doc->where_path;
|
1476
1473
|
if (0 < wlen) {
|
1477
1474
|
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
1478
1475
|
}
|
1479
1476
|
if (1 <= argc) {
|
1480
|
-
Check_Type(*argv, T_STRING);
|
1481
1477
|
path = StringValuePtr(*argv);
|
1482
1478
|
if ('/' == *path) {
|
1483
1479
|
doc->where = doc->where_path;
|
@@ -1487,9 +1483,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1487
1483
|
if (0 < wlen) {
|
1488
1484
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1489
1485
|
}
|
1486
|
+
doc->where = where_orig;
|
1490
1487
|
return Qnil;
|
1491
1488
|
}
|
1492
1489
|
}
|
1490
|
+
if (NULL == doc->where || NULL == *doc->where) {
|
1491
|
+
return Qnil;
|
1492
|
+
}
|
1493
1493
|
if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) {
|
1494
1494
|
Leaf first = (*doc->where)->elements->next;
|
1495
1495
|
Leaf e = first;
|
@@ -1504,6 +1504,7 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1504
1504
|
if (0 < wlen) {
|
1505
1505
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1506
1506
|
}
|
1507
|
+
doc->where = where_orig;
|
1507
1508
|
}
|
1508
1509
|
return Qnil;
|
1509
1510
|
}
|
@@ -1539,7 +1540,6 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
1539
1540
|
Leaf leaf;
|
1540
1541
|
|
1541
1542
|
if (1 <= argc) {
|
1542
|
-
Check_Type(*argv, T_STRING);
|
1543
1543
|
path = StringValuePtr(*argv);
|
1544
1544
|
}
|
1545
1545
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
@@ -1571,11 +1571,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1571
1571
|
|
1572
1572
|
if (1 <= argc) {
|
1573
1573
|
if (Qnil != *argv) {
|
1574
|
-
Check_Type(*argv, T_STRING);
|
1575
1574
|
path = StringValuePtr(*argv);
|
1576
1575
|
}
|
1577
1576
|
if (2 <= argc) {
|
1578
|
-
Check_Type(argv[1], T_STRING);
|
1579
1577
|
filename = StringValuePtr(argv[1]);
|
1580
1578
|
}
|
1581
1579
|
}
|
@@ -1583,18 +1581,15 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1583
1581
|
volatile VALUE rjson;
|
1584
1582
|
|
1585
1583
|
if (0 == filename) {
|
1586
|
-
char buf[4096];
|
1587
1584
|
struct _out out;
|
1588
1585
|
|
1589
|
-
out
|
1590
|
-
|
1591
|
-
out.
|
1592
|
-
out.omit_nil = oj_default_options.dump_opts.omit_nil;
|
1586
|
+
oj_out_init(&out);
|
1587
|
+
|
1588
|
+
out.omit_nil = oj_default_options.dump_opts.omit_nil;
|
1593
1589
|
oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
|
1594
1590
|
rjson = rb_str_new2(out.buf);
|
1595
|
-
|
1596
|
-
|
1597
|
-
}
|
1591
|
+
|
1592
|
+
oj_out_free(&out);
|
1598
1593
|
} else {
|
1599
1594
|
oj_write_leaf_to_file(leaf, filename, &oj_default_options);
|
1600
1595
|
rjson = Qnil;
|
@@ -1613,7 +1608,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1613
1608
|
* Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
|
1614
1609
|
*/
|
1615
1610
|
static VALUE doc_size(VALUE self) {
|
1616
|
-
|
1611
|
+
Doc d;
|
1612
|
+
TypedData_Get_Struct(self, struct _doc, &oj_doc_type, d);
|
1613
|
+
return ULONG2NUM(d->size);
|
1617
1614
|
}
|
1618
1615
|
|
1619
1616
|
/* @overload close() => nil
|
@@ -1629,11 +1626,9 @@ static VALUE doc_close(VALUE self) {
|
|
1629
1626
|
Doc doc = self_doc(self);
|
1630
1627
|
|
1631
1628
|
rb_gc_unregister_address(&doc->self);
|
1632
|
-
DATA_PTR(doc->self) =
|
1629
|
+
DATA_PTR(doc->self) = NULL;
|
1633
1630
|
if (0 != doc) {
|
1634
|
-
xfree(doc->json);
|
1635
1631
|
doc_free(doc);
|
1636
|
-
xfree(doc);
|
1637
1632
|
}
|
1638
1633
|
return Qnil;
|
1639
1634
|
}
|
@@ -1690,16 +1685,21 @@ static VALUE doc_not_implemented(VALUE self) {
|
|
1690
1685
|
* # Now try again using a path to Oj::Doc.fetch() directly and not using a
|
1691
1686
|
* block. doc = Oj::Doc.open(json) doc.fetch('/2/three') #=> 3 doc.close()
|
1692
1687
|
*/
|
1693
|
-
void oj_init_doc() {
|
1688
|
+
void oj_init_doc(void) {
|
1694
1689
|
oj_doc_class = rb_define_class_under(Oj, "Doc", rb_cObject);
|
1690
|
+
rb_gc_register_address(&oj_doc_class);
|
1691
|
+
rb_undef_alloc_func(oj_doc_class);
|
1695
1692
|
rb_define_singleton_method(oj_doc_class, "open", doc_open, 1);
|
1696
1693
|
rb_define_singleton_method(oj_doc_class, "open_file", doc_open_file, 1);
|
1697
1694
|
rb_define_singleton_method(oj_doc_class, "parse", doc_open, 1);
|
1698
|
-
rb_define_method(oj_doc_class, "where?",
|
1695
|
+
rb_define_method(oj_doc_class, "where?", doc_where_q, 0);
|
1696
|
+
rb_define_method(oj_doc_class, "where", doc_where, 0);
|
1697
|
+
rb_define_method(oj_doc_class, "path", doc_path, 0);
|
1699
1698
|
rb_define_method(oj_doc_class, "local_key", doc_local_key, 0);
|
1700
1699
|
rb_define_method(oj_doc_class, "home", doc_home, 0);
|
1701
1700
|
rb_define_method(oj_doc_class, "type", doc_type, -1);
|
1702
1701
|
rb_define_method(oj_doc_class, "fetch", doc_fetch, -1);
|
1702
|
+
rb_define_method(oj_doc_class, "exists?", doc_exists, 1);
|
1703
1703
|
rb_define_method(oj_doc_class, "each_leaf", doc_each_leaf, -1);
|
1704
1704
|
rb_define_method(oj_doc_class, "move", doc_move, 1);
|
1705
1705
|
rb_define_method(oj_doc_class, "each_child", doc_each_child, -1);
|