oj 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|