oj 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +17 -23
- data/README.md +74 -425
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +4 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +227 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +243 -0
- data/ext/oj/custom.c +1097 -0
- data/ext/oj/dump.c +766 -1534
- data/ext/oj/dump.h +92 -0
- data/ext/oj/dump_compat.c +937 -0
- data/ext/oj/dump_leaf.c +254 -0
- data/ext/oj/dump_object.c +810 -0
- data/ext/oj/dump_rails.c +329 -0
- data/ext/oj/dump_strict.c +416 -0
- data/ext/oj/encode.h +51 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +17 -7
- data/ext/oj/fast.c +213 -180
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +817 -0
- data/ext/oj/mimic_rails.c +806 -0
- data/ext/oj/mimic_rails.h +17 -0
- data/ext/oj/object.c +752 -0
- data/ext/oj/odd.c +230 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1288 -929
- data/ext/oj/oj.h +240 -69
- data/ext/oj/parse.c +1014 -0
- data/ext/oj/parse.h +92 -0
- data/ext/oj/reader.c +223 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +127 -0
- data/ext/oj/{cache.h → resolve.h} +6 -13
- data/ext/oj/rxclass.c +133 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +77 -175
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +911 -0
- data/ext/oj/stream_writer.c +301 -0
- data/ext/oj/strict.c +162 -0
- data/ext/oj/string_writer.c +480 -0
- data/ext/oj/val_stack.c +98 -0
- data/ext/oj/val_stack.h +188 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +6 -10
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/json.rb +172 -0
- data/lib/oj/mimic.rb +260 -5
- data/lib/oj/saj.rb +13 -10
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +11 -23
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +79 -0
- data/pages/Modes.md +140 -0
- data/pages/Options.md +250 -0
- data/pages/Rails.md +60 -0
- data/pages/Security.md +20 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activesupport4/decoding_test.rb +105 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +483 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/helper.rb +27 -0
- data/test/isolated/shared.rb +310 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +143 -0
- data/test/json_gem/json_encoding_test.rb +109 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +9 -9
- data/test/perf_file.rb +64 -0
- data/test/{perf_obj.rb → perf_object.rb} +24 -10
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +32 -113
- data/test/sample.rb +2 -3
- data/test/test_compat.rb +474 -0
- data/test/test_custom.rb +355 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +66 -16
- data/test/test_file.rb +237 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1010 -0
- data/test/test_saj.rb +16 -16
- data/test/test_scp.rb +417 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +815 -0
- data/test/test_writer.rb +308 -0
- data/test/tests.rb +9 -902
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +253 -38
- data/ext/oj/cache.c +0 -148
- data/ext/oj/foo.rb +0 -6
- data/ext/oj/load.c +0 -1049
- data/test/a.rb +0 -38
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
- data/test/test_mimic.rb +0 -208
data/ext/oj/rxclass.c
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* rxclass.c
|
|
2
|
+
* Copyright (c) 2017, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <sys/types.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <errno.h>
|
|
9
|
+
#include <regex.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
|
|
13
|
+
#include "rxclass.h"
|
|
14
|
+
|
|
15
|
+
typedef struct _RxC {
|
|
16
|
+
struct _RxC *next;
|
|
17
|
+
VALUE rrx;
|
|
18
|
+
regex_t rx;
|
|
19
|
+
VALUE clas;
|
|
20
|
+
char src[256];
|
|
21
|
+
} *RxC;
|
|
22
|
+
|
|
23
|
+
void
|
|
24
|
+
oj_rxclass_init(RxClass rc) {
|
|
25
|
+
*rc->err = '\0';
|
|
26
|
+
rc->head = NULL;
|
|
27
|
+
rc->tail = NULL;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
void
|
|
31
|
+
oj_rxclass_cleanup(RxClass rc) {
|
|
32
|
+
RxC rxc;
|
|
33
|
+
|
|
34
|
+
while (NULL != (rxc = rc->head)) {
|
|
35
|
+
rc->head = rc->head->next;
|
|
36
|
+
if (Qnil == rxc->rrx) {
|
|
37
|
+
regfree(&rxc->rx);
|
|
38
|
+
}
|
|
39
|
+
xfree(rxc);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void
|
|
44
|
+
oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) {
|
|
45
|
+
RxC rxc = ALLOC_N(struct _RxC, 1);
|
|
46
|
+
|
|
47
|
+
memset(rxc, 0, sizeof(struct _RxC));
|
|
48
|
+
rxc->rrx = rx;
|
|
49
|
+
rxc->clas = clas;
|
|
50
|
+
if (NULL == rc->tail) {
|
|
51
|
+
rc->head = rxc;
|
|
52
|
+
} else {
|
|
53
|
+
rc->tail->next = rxc;
|
|
54
|
+
}
|
|
55
|
+
rc->tail = rxc;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Attempt to compile the expression. If it fails populate the error code..
|
|
59
|
+
int
|
|
60
|
+
oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
|
|
61
|
+
// Use mallow and not ALLOC_N to avoid pulliing ruby.h which conflicts
|
|
62
|
+
// with regex_t.
|
|
63
|
+
RxC rxc;
|
|
64
|
+
int err;
|
|
65
|
+
int flags = 0;
|
|
66
|
+
|
|
67
|
+
if (sizeof(rxc->src) <= strlen(expr)) {
|
|
68
|
+
snprintf(rc->err, sizeof(rc->err), "expressions must be less than %lu chracter", sizeof(rxc->src));
|
|
69
|
+
return EINVAL;
|
|
70
|
+
}
|
|
71
|
+
rxc = ALLOC_N(struct _RxC, 1);
|
|
72
|
+
rxc->next = 0;
|
|
73
|
+
rxc->rrx = Qnil;
|
|
74
|
+
rxc->clas = clas;
|
|
75
|
+
if (0 != (err = regcomp(&rxc->rx, expr, flags))) {
|
|
76
|
+
regerror(err, &rxc->rx, rc->err, sizeof(rc->err));
|
|
77
|
+
free(rxc);
|
|
78
|
+
return err;
|
|
79
|
+
}
|
|
80
|
+
if (NULL == rc->tail) {
|
|
81
|
+
rc->head = rxc;
|
|
82
|
+
} else {
|
|
83
|
+
rc->tail->next = rxc;
|
|
84
|
+
}
|
|
85
|
+
rc->tail = rxc;
|
|
86
|
+
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
VALUE
|
|
91
|
+
oj_rxclass_match(RxClass rc, const char *str, int len) {
|
|
92
|
+
RxC rxc;
|
|
93
|
+
char buf[4096];
|
|
94
|
+
|
|
95
|
+
for (rxc = rc->head; NULL != rxc; rxc = rxc->next) {
|
|
96
|
+
if (Qnil != rxc->rrx) {
|
|
97
|
+
// Must use a valiabel for this to work.
|
|
98
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
|
99
|
+
|
|
100
|
+
//if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) {
|
|
101
|
+
if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) {
|
|
102
|
+
return rxc->clas;
|
|
103
|
+
}
|
|
104
|
+
} else if (len < (int)sizeof(buf)) {
|
|
105
|
+
// string is not \0 terminated so copy and atempt a match
|
|
106
|
+
memcpy(buf, str, len);
|
|
107
|
+
buf[len] = '\0';
|
|
108
|
+
if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match
|
|
109
|
+
return rxc->clas;
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
// TBD allocate a larger buffer and attempt
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return Qnil;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
void
|
|
119
|
+
oj_rxclass_copy(RxClass src, RxClass dest) {
|
|
120
|
+
dest->head = NULL;
|
|
121
|
+
dest->tail = NULL;
|
|
122
|
+
if (NULL != src->head) {
|
|
123
|
+
RxC rxc;
|
|
124
|
+
|
|
125
|
+
for (rxc = src->head; NULL != rxc; rxc = rxc->next) {
|
|
126
|
+
if (Qnil != rxc->rrx) {
|
|
127
|
+
oj_rxclass_rappend(dest, rxc->rrx, rxc->clas);
|
|
128
|
+
} else {
|
|
129
|
+
oj_rxclass_append(dest, rxc->src, rxc->clas);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
data/ext/oj/rxclass.h
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* rxclass.h
|
|
2
|
+
* Copyright (c) 2017, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef __OJ_RXCLASS_H__
|
|
7
|
+
#define __OJ_RXCLASS_H__
|
|
8
|
+
|
|
9
|
+
#include <stdbool.h>
|
|
10
|
+
#include "ruby.h"
|
|
11
|
+
|
|
12
|
+
struct _RxC;
|
|
13
|
+
|
|
14
|
+
typedef struct _RxClass {
|
|
15
|
+
struct _RxC *head;
|
|
16
|
+
struct _RxC *tail;
|
|
17
|
+
char err[128];
|
|
18
|
+
} *RxClass;
|
|
19
|
+
|
|
20
|
+
extern void oj_rxclass_init(RxClass rc);
|
|
21
|
+
extern void oj_rxclass_cleanup(RxClass rc);
|
|
22
|
+
extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
|
|
23
|
+
extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
|
|
24
|
+
extern void oj_rxclass_copy(RxClass src, RxClass dest);
|
|
25
|
+
extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
|
|
26
|
+
|
|
27
|
+
#endif /* __OJ_RXCLASS_H__ */
|
data/ext/oj/saj.c
CHANGED
|
@@ -1,31 +1,6 @@
|
|
|
1
1
|
/* saj.c
|
|
2
2
|
* Copyright (c) 2012, Peter Ohler
|
|
3
3
|
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* Redistribution and use in source and binary forms, with or without
|
|
6
|
-
* modification, are permitted provided that the following conditions are met:
|
|
7
|
-
*
|
|
8
|
-
* - Redistributions of source code must retain the above copyright notice, this
|
|
9
|
-
* list of conditions and the following disclaimer.
|
|
10
|
-
*
|
|
11
|
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
-
* this list of conditions and the following disclaimer in the documentation
|
|
13
|
-
* and/or other materials provided with the distribution.
|
|
14
|
-
*
|
|
15
|
-
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
|
16
|
-
* used to endorse or promote products derived from this software without
|
|
17
|
-
* specific prior written permission.
|
|
18
|
-
*
|
|
19
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
4
|
*/
|
|
30
5
|
|
|
31
6
|
#if !IS_WINDOWS
|
|
@@ -35,19 +10,14 @@
|
|
|
35
10
|
#include <stdio.h>
|
|
36
11
|
#include <string.h>
|
|
37
12
|
#include <math.h>
|
|
13
|
+
#include <sys/types.h>
|
|
14
|
+
#include <unistd.h>
|
|
38
15
|
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
#define INFINITY (1.0/0.0)
|
|
42
|
-
#endif
|
|
16
|
+
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
|
17
|
+
#define OJ_INFINITY (1.0/0.0)
|
|
43
18
|
|
|
44
19
|
#include "oj.h"
|
|
45
|
-
|
|
46
|
-
typedef struct _CX {
|
|
47
|
-
VALUE *cur;
|
|
48
|
-
VALUE *end;
|
|
49
|
-
VALUE stack[1024];
|
|
50
|
-
} *CX;
|
|
20
|
+
#include "encode.h"
|
|
51
21
|
|
|
52
22
|
typedef struct _ParseInfo {
|
|
53
23
|
char *str; /* buffer being read from */
|
|
@@ -74,9 +44,9 @@ static void next_non_white(ParseInfo pi);
|
|
|
74
44
|
static char* read_quoted_value(ParseInfo pi);
|
|
75
45
|
static void skip_comment(ParseInfo pi);
|
|
76
46
|
|
|
77
|
-
/* This
|
|
47
|
+
/* This JSON parser is a single pass, destructive, callback parser. It is a
|
|
78
48
|
* single pass parse since it only make one pass over the characters in the
|
|
79
|
-
*
|
|
49
|
+
* JSON document string. It is destructive because it re-uses the content of
|
|
80
50
|
* the string for values in the callback and places \0 characters at various
|
|
81
51
|
* places to mark the end of tokens and strings. It is a callback parser like
|
|
82
52
|
* a SAX parser because it uses callback when document elements are
|
|
@@ -125,49 +95,28 @@ next_non_white(ParseInfo pi) {
|
|
|
125
95
|
}
|
|
126
96
|
}
|
|
127
97
|
|
|
128
|
-
inline static void
|
|
129
|
-
next_white(ParseInfo pi) {
|
|
130
|
-
for (; 1; pi->s++) {
|
|
131
|
-
switch(*pi->s) {
|
|
132
|
-
case ' ':
|
|
133
|
-
case '\t':
|
|
134
|
-
case '\f':
|
|
135
|
-
case '\n':
|
|
136
|
-
case '\r':
|
|
137
|
-
case '\0':
|
|
138
|
-
return;
|
|
139
|
-
default:
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
98
|
inline static void
|
|
146
99
|
call_add_value(VALUE handler, VALUE value, const char *key) {
|
|
147
|
-
VALUE k;
|
|
100
|
+
volatile VALUE k;
|
|
148
101
|
|
|
149
102
|
if (0 == key) {
|
|
150
103
|
k = Qnil;
|
|
151
104
|
} else {
|
|
152
105
|
k = rb_str_new2(key);
|
|
153
|
-
|
|
154
|
-
rb_enc_associate(k, oj_utf8_encoding);
|
|
155
|
-
#endif
|
|
106
|
+
k = oj_encode(k);
|
|
156
107
|
}
|
|
157
108
|
rb_funcall(handler, oj_add_value_id, 2, value, k);
|
|
158
109
|
}
|
|
159
110
|
|
|
160
111
|
inline static void
|
|
161
112
|
call_no_value(VALUE handler, ID method, const char *key) {
|
|
162
|
-
VALUE k;
|
|
113
|
+
volatile VALUE k;
|
|
163
114
|
|
|
164
115
|
if (0 == key) {
|
|
165
116
|
k = Qnil;
|
|
166
117
|
} else {
|
|
167
118
|
k = rb_str_new2(key);
|
|
168
|
-
|
|
169
|
-
rb_enc_associate(k, oj_utf8_encoding);
|
|
170
|
-
#endif
|
|
119
|
+
k = oj_encode(k);
|
|
171
120
|
}
|
|
172
121
|
rb_funcall(handler, method, 1, k);
|
|
173
122
|
}
|
|
@@ -344,9 +293,7 @@ read_str(ParseInfo pi, const char *key) {
|
|
|
344
293
|
if (pi->has_add_value) {
|
|
345
294
|
VALUE s = rb_str_new2(text);
|
|
346
295
|
|
|
347
|
-
|
|
348
|
-
rb_enc_associate(s, oj_utf8_encoding);
|
|
349
|
-
#endif
|
|
296
|
+
s = oj_encode(s);
|
|
350
297
|
call_add_value(pi->handler, s, key);
|
|
351
298
|
}
|
|
352
299
|
}
|
|
@@ -384,11 +331,11 @@ read_num(ParseInfo pi, const char *key) {
|
|
|
384
331
|
pi->s += 8;
|
|
385
332
|
if (neg) {
|
|
386
333
|
if (pi->has_add_value) {
|
|
387
|
-
call_add_value(pi->handler, rb_float_new(-
|
|
334
|
+
call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key);
|
|
388
335
|
}
|
|
389
336
|
} else {
|
|
390
337
|
if (pi->has_add_value) {
|
|
391
|
-
call_add_value(pi->handler, rb_float_new(
|
|
338
|
+
call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key);
|
|
392
339
|
}
|
|
393
340
|
}
|
|
394
341
|
return;
|
|
@@ -655,25 +602,9 @@ read_quoted_value(ParseInfo pi) {
|
|
|
655
602
|
return value;
|
|
656
603
|
}
|
|
657
604
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
/* There is a bug in JRuby where rb_respond_to() returns true (1) even if
|
|
662
|
-
* a method is private. */
|
|
663
|
-
{
|
|
664
|
-
VALUE args[1];
|
|
665
|
-
|
|
666
|
-
*args = ID2SYM(method);
|
|
667
|
-
return (Qtrue == rb_funcall2(obj, rb_intern("respond_to?"), 1, args));
|
|
668
|
-
}
|
|
669
|
-
#else
|
|
670
|
-
return rb_respond_to(obj, method);
|
|
671
|
-
#endif
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
void
|
|
675
|
-
oj_saj_parse(VALUE handler, char *json) {
|
|
676
|
-
VALUE obj = Qnil;
|
|
605
|
+
static void
|
|
606
|
+
saj_parse(VALUE handler, char *json) {
|
|
607
|
+
volatile VALUE obj = Qnil;
|
|
677
608
|
struct _ParseInfo pi;
|
|
678
609
|
|
|
679
610
|
if (0 == json) {
|
|
@@ -703,12 +634,12 @@ oj_saj_parse(VALUE handler, char *json) {
|
|
|
703
634
|
}
|
|
704
635
|
#endif
|
|
705
636
|
pi.handler = handler;
|
|
706
|
-
pi.has_hash_start =
|
|
707
|
-
pi.has_hash_end =
|
|
708
|
-
pi.has_array_start =
|
|
709
|
-
pi.has_array_end =
|
|
710
|
-
pi.has_add_value =
|
|
711
|
-
pi.has_error =
|
|
637
|
+
pi.has_hash_start = rb_respond_to(handler, oj_hash_start_id);
|
|
638
|
+
pi.has_hash_end = rb_respond_to(handler, oj_hash_end_id);
|
|
639
|
+
pi.has_array_start = rb_respond_to(handler, oj_array_start_id);
|
|
640
|
+
pi.has_array_end = rb_respond_to(handler, oj_array_end_id);
|
|
641
|
+
pi.has_add_value = rb_respond_to(handler, oj_add_value_id);
|
|
642
|
+
pi.has_error = rb_respond_to(handler, oj_error_id);
|
|
712
643
|
read_next(&pi, 0);
|
|
713
644
|
next_non_white(&pi);
|
|
714
645
|
if ('\0' != *pi.s) {
|
|
@@ -720,93 +651,64 @@ oj_saj_parse(VALUE handler, char *json) {
|
|
|
720
651
|
}
|
|
721
652
|
}
|
|
722
653
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
654
|
+
/* call-seq: saj_parse(handler, io)
|
|
655
|
+
*
|
|
656
|
+
* Parses an IO stream or file containing an JSON document. Raises an exception
|
|
657
|
+
* if the JSON is malformed.
|
|
658
|
+
* @param [Oj::Saj] handler Saj (responds to Oj::Saj methods) like handler
|
|
659
|
+
* @param [IO|String] io IO Object to read from
|
|
660
|
+
* @deprecated The sc_parse() method along with the ScHandler is the preferred
|
|
661
|
+
* callback parser. It is slightly faster and handles streams while the
|
|
662
|
+
* saj_parse() methos requires a complete read before parsing.
|
|
663
|
+
* @see sc_parse
|
|
664
|
+
*/
|
|
665
|
+
VALUE
|
|
666
|
+
oj_saj_parse(int argc, VALUE *argv, VALUE self) {
|
|
667
|
+
char *json = 0;
|
|
668
|
+
size_t len = 0;
|
|
669
|
+
VALUE input = argv[1];
|
|
670
|
+
|
|
671
|
+
if (argc < 2) {
|
|
672
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
|
|
673
|
+
}
|
|
674
|
+
if (rb_type(input) == T_STRING) {
|
|
675
|
+
// the json string gets modified so make a copy of it
|
|
676
|
+
len = RSTRING_LEN(input) + 1;
|
|
677
|
+
json = ALLOC_N(char, len);
|
|
678
|
+
strcpy(json, StringValuePtr(input));
|
|
730
679
|
} else {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
680
|
+
VALUE clas = rb_obj_class(input);
|
|
681
|
+
volatile VALUE s;
|
|
682
|
+
|
|
683
|
+
if (oj_stringio_class == clas) {
|
|
684
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
|
685
|
+
len = RSTRING_LEN(s) + 1;
|
|
686
|
+
json = ALLOC_N(char, len);
|
|
687
|
+
strcpy(json, rb_string_value_cstr((VALUE*)&s));
|
|
688
|
+
#if !IS_WINDOWS
|
|
689
|
+
} else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
|
|
690
|
+
int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
|
|
691
|
+
ssize_t cnt;
|
|
692
|
+
|
|
693
|
+
len = lseek(fd, 0, SEEK_END);
|
|
694
|
+
lseek(fd, 0, SEEK_SET);
|
|
695
|
+
json = ALLOC_N(char, len + 1);
|
|
696
|
+
if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
|
|
697
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
|
698
|
+
}
|
|
699
|
+
json[len] = '\0';
|
|
735
700
|
#endif
|
|
736
|
-
|
|
701
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
|
702
|
+
s = rb_funcall2(input, oj_read_id, 0, 0);
|
|
703
|
+
len = RSTRING_LEN(s) + 1;
|
|
704
|
+
json = ALLOC_N(char, len);
|
|
705
|
+
strcpy(json, rb_string_value_cstr((VALUE*)&s));
|
|
737
706
|
} else {
|
|
738
|
-
|
|
707
|
+
rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
|
|
739
708
|
}
|
|
740
709
|
}
|
|
741
|
-
|
|
710
|
+
saj_parse(*argv, json);
|
|
711
|
+
xfree(json);
|
|
742
712
|
|
|
743
|
-
|
|
744
|
-
cx_push(CX cx, VALUE obj, const char *key) {
|
|
745
|
-
if (0 == cx->cur) {
|
|
746
|
-
cx->cur = cx->stack;
|
|
747
|
-
} else {
|
|
748
|
-
if (cx->end <= cx->cur) {
|
|
749
|
-
rb_raise(oj_parse_error_class, "too deeply nested");
|
|
750
|
-
}
|
|
751
|
-
cx_add(cx, obj, key);
|
|
752
|
-
cx->cur++;
|
|
753
|
-
}
|
|
754
|
-
*cx->cur = obj;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
static void
|
|
758
|
-
hash_start(void *context, const char *key) {
|
|
759
|
-
cx_push((CX)context, rb_hash_new(), key);
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
static void
|
|
763
|
-
col_end(void *context, const char *key) {
|
|
764
|
-
((CX)context)->cur--;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
static void
|
|
768
|
-
array_start(void *context, const char *key) {
|
|
769
|
-
cx_push((CX)context, rb_ary_new(), key);
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
static void
|
|
773
|
-
add_str(void *context, const char *str, const char *key) {
|
|
774
|
-
VALUE s;
|
|
775
|
-
|
|
776
|
-
s = rb_str_new2(str);
|
|
777
|
-
#if HAS_ENCODING_SUPPORT
|
|
778
|
-
rb_enc_associate(s, oj_utf8_encoding);
|
|
779
|
-
#endif
|
|
780
|
-
cx_add((CX)context, s, key);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
static void
|
|
784
|
-
add_big(void *context, const char *str, const char *key) {
|
|
785
|
-
cx_add((CX)context, rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(str)), key);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
static void
|
|
789
|
-
add_float(void *context, double num, const char *key) {
|
|
790
|
-
cx_add((CX)context, rb_float_new(num), key);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
static void
|
|
794
|
-
add_fixnum(void *context, int64_t num, const char *key) {
|
|
795
|
-
cx_add((CX)context, LONG2NUM(num), key);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
static void
|
|
799
|
-
add_true(void *context, const char *key) {
|
|
800
|
-
cx_add((CX)context, Qtrue, key);
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
static void
|
|
804
|
-
add_false(void *context, const char *key) {
|
|
805
|
-
cx_add((CX)context, Qfalse, key);
|
|
713
|
+
return Qnil;
|
|
806
714
|
}
|
|
807
|
-
|
|
808
|
-
static void
|
|
809
|
-
add_nil(void *context, const char *key) {
|
|
810
|
-
cx_add((CX)context, Qnil, key);
|
|
811
|
-
}
|
|
812
|
-
#endif
|