oj 3.11.1 → 3.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/ext/oj/buf.h +34 -38
- data/ext/oj/cache8.c +59 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +33 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +170 -174
- data/ext/oj/code.h +21 -20
- data/ext/oj/compat.c +159 -166
- data/ext/oj/custom.c +802 -851
- data/ext/oj/dump.c +766 -778
- data/ext/oj/dump.h +49 -51
- data/ext/oj/dump_compat.c +1 -0
- data/ext/oj/dump_leaf.c +116 -157
- data/ext/oj/dump_object.c +609 -628
- data/ext/oj/dump_strict.c +318 -327
- data/ext/oj/encode.h +3 -4
- data/ext/oj/err.c +39 -25
- data/ext/oj/err.h +24 -15
- data/ext/oj/extconf.rb +2 -1
- data/ext/oj/fast.c +1042 -1041
- data/ext/oj/hash.c +62 -66
- data/ext/oj/hash.h +7 -6
- data/ext/oj/hash_test.c +450 -443
- data/ext/oj/mimic_json.c +412 -402
- data/ext/oj/object.c +559 -528
- data/ext/oj/odd.c +123 -128
- data/ext/oj/odd.h +27 -25
- data/ext/oj/oj.c +1123 -924
- data/ext/oj/oj.h +286 -298
- data/ext/oj/parse.c +938 -930
- data/ext/oj/parse.h +70 -69
- data/ext/oj/rails.c +836 -839
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +135 -140
- data/ext/oj/reader.h +66 -79
- data/ext/oj/resolve.c +43 -43
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -68
- data/ext/oj/rxclass.h +12 -10
- data/ext/oj/saj.c +451 -479
- data/ext/oj/scp.c +93 -103
- data/ext/oj/sparse.c +770 -730
- data/ext/oj/stream_writer.c +120 -149
- data/ext/oj/strict.c +71 -86
- data/ext/oj/string_writer.c +198 -243
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +14 -11
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +47 -47
- data/ext/oj/val_stack.h +79 -86
- data/ext/oj/wab.c +291 -309
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/mimic.rb +0 -12
- data/lib/oj/version.rb +1 -1
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +35 -32
- data/test/test_fast.rb +32 -2
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +10 -0
- data/test/test_scp.rb +1 -1
- metadata +4 -2
data/ext/oj/resolve.c
CHANGED
@@ -1,76 +1,76 @@
|
|
1
1
|
// Copyright (c) 2012 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
2
3
|
|
3
|
-
#include <stdlib.h>
|
4
4
|
#include <stdio.h>
|
5
|
+
#include <stdlib.h>
|
5
6
|
#include <string.h>
|
6
7
|
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
7
8
|
#include <pthread.h>
|
8
9
|
#endif
|
9
10
|
|
10
|
-
#include "oj.h"
|
11
11
|
#include "err.h"
|
12
|
-
#include "parse.h"
|
13
12
|
#include "hash.h"
|
13
|
+
#include "oj.h"
|
14
|
+
#include "parse.h"
|
14
15
|
|
15
|
-
inline static VALUE
|
16
|
-
|
17
|
-
|
18
|
-
ID ci = rb_intern(classname);
|
16
|
+
inline static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
|
17
|
+
VALUE clas;
|
18
|
+
ID ci = rb_intern(classname);
|
19
19
|
|
20
20
|
if (rb_const_defined_at(mod, ci)) {
|
21
|
-
|
21
|
+
clas = rb_const_get_at(mod, ci);
|
22
22
|
} else if (auto_define) {
|
23
|
-
|
23
|
+
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
24
24
|
} else {
|
25
|
-
|
25
|
+
clas = Qundef;
|
26
26
|
}
|
27
27
|
return clas;
|
28
28
|
}
|
29
29
|
|
30
30
|
static VALUE
|
31
31
|
resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
32
|
-
char
|
33
|
-
VALUE
|
34
|
-
char
|
35
|
-
char
|
36
|
-
const char
|
32
|
+
char class_name[1024];
|
33
|
+
VALUE clas;
|
34
|
+
char * end = class_name + sizeof(class_name) - 1;
|
35
|
+
char * s;
|
36
|
+
const char *n = name;
|
37
37
|
|
38
38
|
clas = rb_cObject;
|
39
39
|
for (s = class_name; 0 < len; n++, len--) {
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
40
|
+
if (':' == *n) {
|
41
|
+
*s = '\0';
|
42
|
+
n++;
|
43
|
+
len--;
|
44
|
+
if (':' != *n) {
|
45
|
+
return Qundef;
|
46
|
+
}
|
47
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
48
|
+
return Qundef;
|
49
|
+
}
|
50
|
+
s = class_name;
|
51
|
+
} else if (end <= s) {
|
52
|
+
return Qundef;
|
53
|
+
} else {
|
54
|
+
*s++ = *n;
|
55
|
+
}
|
56
56
|
}
|
57
57
|
*s = '\0';
|
58
58
|
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
|
60
|
+
if (Qnil != error_class) {
|
61
|
+
pi->err_class = error_class;
|
62
|
+
}
|
63
63
|
}
|
64
64
|
return clas;
|
65
65
|
}
|
66
66
|
|
67
67
|
VALUE
|
68
68
|
oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
69
|
-
VALUE
|
70
|
-
VALUE
|
69
|
+
VALUE clas;
|
70
|
+
VALUE *slot;
|
71
71
|
|
72
72
|
if (No == pi->options.class_cache) {
|
73
|
-
|
73
|
+
return resolve_classpath(pi, name, len, auto_define, error_class);
|
74
74
|
}
|
75
75
|
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
76
76
|
pthread_mutex_lock(&oj_cache_mutex);
|
@@ -78,9 +78,9 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
|
|
78
78
|
rb_mutex_lock(oj_cache_mutex);
|
79
79
|
#endif
|
80
80
|
if (Qnil == (clas = oj_class_hash_get(name, len, &slot))) {
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define, error_class))) {
|
82
|
+
*slot = clas;
|
83
|
+
}
|
84
84
|
}
|
85
85
|
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
86
86
|
pthread_mutex_unlock(&oj_cache_mutex);
|
@@ -92,8 +92,8 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
|
|
92
92
|
|
93
93
|
VALUE
|
94
94
|
oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class) {
|
95
|
-
size_t
|
96
|
-
const char
|
95
|
+
size_t len = RSTRING_LEN(nameVal);
|
96
|
+
const char *str = StringValuePtr(nameVal);
|
97
97
|
|
98
98
|
return resolve_classpath(pi, str, len, 0, error_class);
|
99
99
|
}
|
data/ext/oj/resolve.h
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
// Copyright (c) 2011 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
2
3
|
|
3
4
|
#ifndef OJ_RESOLVE_H
|
4
5
|
#define OJ_RESOLVE_H
|
5
6
|
|
6
7
|
#include "ruby.h"
|
7
8
|
|
8
|
-
extern VALUE
|
9
|
-
extern VALUE
|
9
|
+
extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class);
|
10
|
+
extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class);
|
10
11
|
|
11
12
|
#endif /* OJ_RESOLVE_H */
|
data/ext/oj/rxclass.c
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
// Copyright (c) 2017 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
2
3
|
|
3
|
-
#include <sys/types.h>
|
4
|
-
#include <stdlib.h>
|
5
4
|
#include <errno.h>
|
6
|
-
#include <string.h>
|
7
5
|
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
#include <string.h>
|
8
|
+
#include <sys/types.h>
|
8
9
|
#if !IS_WINDOWS
|
9
10
|
#include <regex.h>
|
10
11
|
#endif
|
@@ -12,65 +13,64 @@
|
|
12
13
|
#include "rxclass.h"
|
13
14
|
|
14
15
|
typedef struct _rxC {
|
15
|
-
struct _rxC
|
16
|
-
VALUE
|
16
|
+
struct _rxC *next;
|
17
|
+
VALUE rrx;
|
17
18
|
#if !IS_WINDOWS
|
18
|
-
regex_t
|
19
|
+
regex_t rx;
|
19
20
|
#endif
|
20
|
-
VALUE
|
21
|
-
char
|
22
|
-
} *RxC;
|
21
|
+
VALUE clas;
|
22
|
+
char src[256];
|
23
|
+
} * RxC;
|
23
24
|
|
24
|
-
void
|
25
|
-
oj_rxclass_init(RxClass rc) {
|
25
|
+
void oj_rxclass_init(RxClass rc) {
|
26
26
|
*rc->err = '\0';
|
27
27
|
rc->head = NULL;
|
28
28
|
rc->tail = NULL;
|
29
29
|
}
|
30
30
|
|
31
|
-
void
|
32
|
-
|
33
|
-
RxC rxc;
|
31
|
+
void oj_rxclass_cleanup(RxClass rc) {
|
32
|
+
RxC rxc;
|
34
33
|
|
35
34
|
while (NULL != (rxc = rc->head)) {
|
36
|
-
|
35
|
+
rc->head = rc->head->next;
|
37
36
|
#if !IS_WINDOWS
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
if (Qnil == rxc->rrx) {
|
38
|
+
regfree(&rxc->rx);
|
39
|
+
}
|
40
|
+
xfree(rxc);
|
42
41
|
#endif
|
43
42
|
}
|
44
43
|
}
|
45
44
|
|
46
|
-
void
|
47
|
-
|
48
|
-
RxC rxc = ALLOC_N(struct _rxC, 1);
|
45
|
+
void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) {
|
46
|
+
RxC rxc = ALLOC_N(struct _rxC, 1);
|
49
47
|
|
50
48
|
memset(rxc, 0, sizeof(struct _rxC));
|
51
|
-
rxc->rrx
|
49
|
+
rxc->rrx = rx;
|
52
50
|
rxc->clas = clas;
|
53
51
|
if (NULL == rc->tail) {
|
54
|
-
|
52
|
+
rc->head = rxc;
|
55
53
|
} else {
|
56
|
-
|
54
|
+
rc->tail->next = rxc;
|
57
55
|
}
|
58
56
|
rc->tail = rxc;
|
59
57
|
}
|
60
58
|
|
61
59
|
// Attempt to compile the expression. If it fails populate the error code..
|
62
|
-
int
|
63
|
-
|
64
|
-
RxC rxc;
|
60
|
+
int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
|
61
|
+
RxC rxc;
|
65
62
|
#if !IS_WINDOWS
|
66
|
-
int
|
67
|
-
int
|
63
|
+
int err;
|
64
|
+
int flags = 0;
|
68
65
|
#endif
|
69
66
|
if (sizeof(rxc->src) <= strlen(expr)) {
|
70
|
-
|
71
|
-
|
67
|
+
snprintf(rc->err,
|
68
|
+
sizeof(rc->err),
|
69
|
+
"expressions must be less than %lu characters",
|
70
|
+
(unsigned long)sizeof(rxc->src));
|
71
|
+
return EINVAL;
|
72
72
|
}
|
73
|
-
rxc
|
73
|
+
rxc = ALLOC_N(struct _rxC, 1);
|
74
74
|
rxc->next = 0;
|
75
75
|
rxc->clas = clas;
|
76
76
|
|
@@ -79,15 +79,15 @@ oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
|
|
79
79
|
#else
|
80
80
|
rxc->rrx = Qnil;
|
81
81
|
if (0 != (err = regcomp(&rxc->rx, expr, flags))) {
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
regerror(err, &rxc->rx, rc->err, sizeof(rc->err));
|
83
|
+
free(rxc);
|
84
|
+
return err;
|
85
85
|
}
|
86
86
|
#endif
|
87
87
|
if (NULL == rc->tail) {
|
88
|
-
|
88
|
+
rc->head = rxc;
|
89
89
|
} else {
|
90
|
-
|
90
|
+
rc->tail->next = rxc;
|
91
91
|
}
|
92
92
|
rc->tail = rxc;
|
93
93
|
|
@@ -96,49 +96,48 @@ oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
|
|
96
96
|
|
97
97
|
VALUE
|
98
98
|
oj_rxclass_match(RxClass rc, const char *str, int len) {
|
99
|
-
RxC
|
100
|
-
char
|
99
|
+
RxC rxc;
|
100
|
+
char buf[4096];
|
101
101
|
|
102
102
|
for (rxc = rc->head; NULL != rxc; rxc = rxc->next) {
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
103
|
+
if (Qnil != rxc->rrx) {
|
104
|
+
// Must use a valiabel for this to work.
|
105
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
106
|
+
|
107
|
+
// if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) {
|
108
|
+
if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) {
|
109
|
+
return rxc->clas;
|
110
|
+
}
|
111
|
+
} else if (len < (int)sizeof(buf)) {
|
112
112
|
#if !IS_WINDOWS
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
113
|
+
// string is not \0 terminated so copy and atempt a match
|
114
|
+
memcpy(buf, str, len);
|
115
|
+
buf[len] = '\0';
|
116
|
+
if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match
|
117
|
+
return rxc->clas;
|
118
|
+
}
|
119
119
|
#endif
|
120
|
-
|
121
|
-
|
122
|
-
|
120
|
+
} else {
|
121
|
+
// TBD allocate a larger buffer and attempt
|
122
|
+
}
|
123
123
|
}
|
124
124
|
return Qnil;
|
125
125
|
}
|
126
126
|
|
127
|
-
void
|
128
|
-
oj_rxclass_copy(RxClass src, RxClass dest) {
|
127
|
+
void oj_rxclass_copy(RxClass src, RxClass dest) {
|
129
128
|
dest->head = NULL;
|
130
129
|
dest->tail = NULL;
|
131
130
|
if (NULL != src->head) {
|
132
|
-
|
131
|
+
RxC rxc;
|
133
132
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
133
|
+
for (rxc = src->head; NULL != rxc; rxc = rxc->next) {
|
134
|
+
if (Qnil != rxc->rrx) {
|
135
|
+
oj_rxclass_rappend(dest, rxc->rrx, rxc->clas);
|
136
|
+
} else {
|
138
137
|
#if !IS_WINDOWS
|
139
|
-
|
138
|
+
oj_rxclass_append(dest, rxc->src, rxc->clas);
|
140
139
|
#endif
|
141
|
-
|
142
|
-
|
140
|
+
}
|
141
|
+
}
|
143
142
|
}
|
144
143
|
}
|
data/ext/oj/rxclass.h
CHANGED
@@ -1,24 +1,26 @@
|
|
1
1
|
// Copyright (c) 2017 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
2
3
|
|
3
4
|
#ifndef OJ_RXCLASS_H
|
4
5
|
#define OJ_RXCLASS_H
|
5
6
|
|
6
7
|
#include <stdbool.h>
|
8
|
+
|
7
9
|
#include "ruby.h"
|
8
10
|
|
9
11
|
struct _rxC;
|
10
12
|
|
11
13
|
typedef struct _rxClass {
|
12
|
-
struct _rxC
|
13
|
-
struct _rxC
|
14
|
-
char
|
15
|
-
} *RxClass;
|
14
|
+
struct _rxC *head;
|
15
|
+
struct _rxC *tail;
|
16
|
+
char err[128];
|
17
|
+
} * RxClass;
|
16
18
|
|
17
|
-
extern void
|
18
|
-
extern void
|
19
|
-
extern int
|
20
|
-
extern VALUE
|
21
|
-
extern void
|
22
|
-
extern void
|
19
|
+
extern void oj_rxclass_init(RxClass rc);
|
20
|
+
extern void oj_rxclass_cleanup(RxClass rc);
|
21
|
+
extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
|
22
|
+
extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
|
23
|
+
extern void oj_rxclass_copy(RxClass src, RxClass dest);
|
24
|
+
extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
|
23
25
|
|
24
26
|
#endif /* OJ_RXCLASS_H */
|
data/ext/oj/saj.c
CHANGED
@@ -1,45 +1,46 @@
|
|
1
1
|
// Copyright (c) 2012 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
2
3
|
|
3
4
|
#if !IS_WINDOWS
|
4
|
-
#include <sys/resource.h>
|
5
|
+
#include <sys/resource.h> /* for getrlimit() on linux */
|
5
6
|
#endif
|
6
|
-
#include <
|
7
|
+
#include <math.h>
|
7
8
|
#include <stdio.h>
|
9
|
+
#include <stdlib.h>
|
8
10
|
#include <string.h>
|
9
|
-
#include <math.h>
|
10
11
|
#include <sys/types.h>
|
11
12
|
#include <unistd.h>
|
12
13
|
|
13
14
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
14
|
-
#define OJ_INFINITY (1.0/0.0)
|
15
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
15
16
|
|
16
|
-
#include "oj.h"
|
17
17
|
#include "encode.h"
|
18
|
+
#include "oj.h"
|
18
19
|
|
19
20
|
typedef struct _parseInfo {
|
20
|
-
char
|
21
|
-
char
|
22
|
-
void
|
23
|
-
VALUE
|
24
|
-
int
|
25
|
-
int
|
26
|
-
int
|
27
|
-
int
|
28
|
-
int
|
29
|
-
int
|
30
|
-
} *ParseInfo;
|
31
|
-
|
32
|
-
static void
|
33
|
-
static void
|
34
|
-
static void
|
35
|
-
static void
|
36
|
-
static void
|
37
|
-
static void
|
38
|
-
static void
|
39
|
-
static void
|
40
|
-
static void
|
41
|
-
static char*
|
42
|
-
static void
|
21
|
+
char *str; /* buffer being read from */
|
22
|
+
char *s; /* current position in buffer */
|
23
|
+
void *stack_min;
|
24
|
+
VALUE handler;
|
25
|
+
int has_hash_start;
|
26
|
+
int has_hash_end;
|
27
|
+
int has_array_start;
|
28
|
+
int has_array_end;
|
29
|
+
int has_add_value;
|
30
|
+
int has_error;
|
31
|
+
} * ParseInfo;
|
32
|
+
|
33
|
+
static void read_next(ParseInfo pi, const char *key);
|
34
|
+
static void read_hash(ParseInfo pi, const char *key);
|
35
|
+
static void read_array(ParseInfo pi, const char *key);
|
36
|
+
static void read_str(ParseInfo pi, const char *key);
|
37
|
+
static void read_num(ParseInfo pi, const char *key);
|
38
|
+
static void read_true(ParseInfo pi, const char *key);
|
39
|
+
static void read_false(ParseInfo pi, const char *key);
|
40
|
+
static void read_nil(ParseInfo pi, const char *key);
|
41
|
+
static void next_non_white(ParseInfo pi);
|
42
|
+
static char *read_quoted_value(ParseInfo pi);
|
43
|
+
static void skip_comment(ParseInfo pi);
|
43
44
|
|
44
45
|
/* This JSON parser is a single pass, destructive, callback parser. It is a
|
45
46
|
* single pass parse since it only make one pass over the characters in the
|
@@ -54,126 +55,108 @@ static void skip_comment(ParseInfo pi);
|
|
54
55
|
* all cases to parse the string.
|
55
56
|
*/
|
56
57
|
|
57
|
-
inline static void
|
58
|
-
|
59
|
-
char
|
60
|
-
|
61
|
-
int
|
62
|
-
int col = 1;
|
58
|
+
inline static void call_error(const char *msg, ParseInfo pi, const char *file, int line) {
|
59
|
+
char buf[128];
|
60
|
+
const char *s = pi->s;
|
61
|
+
int jline = 1;
|
62
|
+
int col = 1;
|
63
63
|
|
64
64
|
for (; pi->str < s && '\n' != *s; s--) {
|
65
|
-
|
65
|
+
col++;
|
66
66
|
}
|
67
67
|
for (; pi->str < s; s--) {
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
if ('\n' == *s) {
|
69
|
+
jline++;
|
70
|
+
}
|
71
71
|
}
|
72
72
|
sprintf(buf, "%s at line %d, column %d [%s:%d]", msg, jline, col, file, line);
|
73
73
|
rb_funcall(pi->handler, oj_error_id, 3, rb_str_new2(buf), LONG2NUM(jline), LONG2NUM(col));
|
74
74
|
}
|
75
75
|
|
76
|
-
inline static void
|
77
|
-
next_non_white(ParseInfo pi) {
|
76
|
+
inline static void next_non_white(ParseInfo pi) {
|
78
77
|
for (; 1; pi->s++) {
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
break;
|
89
|
-
default:
|
90
|
-
return;
|
91
|
-
}
|
78
|
+
switch (*pi->s) {
|
79
|
+
case ' ':
|
80
|
+
case '\t':
|
81
|
+
case '\f':
|
82
|
+
case '\n':
|
83
|
+
case '\r': break;
|
84
|
+
case '/': skip_comment(pi); break;
|
85
|
+
default: return;
|
86
|
+
}
|
92
87
|
}
|
93
88
|
}
|
94
89
|
|
95
|
-
inline static void
|
96
|
-
|
97
|
-
volatile VALUE k;
|
90
|
+
inline static void call_add_value(VALUE handler, VALUE value, const char *key) {
|
91
|
+
volatile VALUE k;
|
98
92
|
|
99
93
|
if (0 == key) {
|
100
|
-
|
94
|
+
k = Qnil;
|
101
95
|
} else {
|
102
|
-
|
103
|
-
|
96
|
+
k = rb_str_new2(key);
|
97
|
+
k = oj_encode(k);
|
104
98
|
}
|
105
99
|
rb_funcall(handler, oj_add_value_id, 2, value, k);
|
106
100
|
}
|
107
101
|
|
108
|
-
inline static void
|
109
|
-
|
110
|
-
volatile VALUE k;
|
102
|
+
inline static void call_no_value(VALUE handler, ID method, const char *key) {
|
103
|
+
volatile VALUE k;
|
111
104
|
|
112
105
|
if (0 == key) {
|
113
|
-
|
106
|
+
k = Qnil;
|
114
107
|
} else {
|
115
|
-
|
116
|
-
|
108
|
+
k = rb_str_new2(key);
|
109
|
+
k = oj_encode(k);
|
117
110
|
}
|
118
111
|
rb_funcall(handler, method, 1, k);
|
119
112
|
}
|
120
113
|
|
121
|
-
static void
|
122
|
-
skip_comment(ParseInfo pi) {
|
114
|
+
static void skip_comment(ParseInfo pi) {
|
123
115
|
pi->s++; /* skip first / */
|
124
116
|
if ('*' == *pi->s) {
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
117
|
+
pi->s++;
|
118
|
+
for (; '\0' != *pi->s; pi->s++) {
|
119
|
+
if ('*' == *pi->s && '/' == *(pi->s + 1)) {
|
120
|
+
pi->s++;
|
121
|
+
return;
|
122
|
+
} else if ('\0' == *pi->s) {
|
123
|
+
if (pi->has_error) {
|
124
|
+
call_error("comment not terminated", pi, __FILE__, __LINE__);
|
125
|
+
} else {
|
126
|
+
raise_error("comment not terminated", pi->str, pi->s);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
138
130
|
} else if ('/' == *pi->s) {
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
}
|
149
|
-
}
|
131
|
+
for (; 1; pi->s++) {
|
132
|
+
switch (*pi->s) {
|
133
|
+
case '\n':
|
134
|
+
case '\r':
|
135
|
+
case '\f':
|
136
|
+
case '\0': return;
|
137
|
+
default: break;
|
138
|
+
}
|
139
|
+
}
|
150
140
|
} else {
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
141
|
+
if (pi->has_error) {
|
142
|
+
call_error("invalid comment", pi, __FILE__, __LINE__);
|
143
|
+
} else {
|
144
|
+
raise_error("invalid comment", pi->str, pi->s);
|
145
|
+
}
|
156
146
|
}
|
157
147
|
}
|
158
148
|
|
159
|
-
static void
|
160
|
-
|
161
|
-
VALUE obj;
|
149
|
+
static void read_next(ParseInfo pi, const char *key) {
|
150
|
+
VALUE obj;
|
162
151
|
|
163
|
-
if ((void*)&obj < pi->stack_min) {
|
164
|
-
|
152
|
+
if ((void *)&obj < pi->stack_min) {
|
153
|
+
rb_raise(rb_eSysStackError, "JSON is too deeply nested");
|
165
154
|
}
|
166
|
-
next_non_white(pi);
|
155
|
+
next_non_white(pi); /* skip white space */
|
167
156
|
switch (*pi->s) {
|
168
|
-
case '{':
|
169
|
-
|
170
|
-
|
171
|
-
case '[':
|
172
|
-
read_array(pi, key);
|
173
|
-
break;
|
174
|
-
case '"':
|
175
|
-
read_str(pi, key);
|
176
|
-
break;
|
157
|
+
case '{': read_hash(pi, key); break;
|
158
|
+
case '[': read_array(pi, key); break;
|
159
|
+
case '"': read_str(pi, key); break;
|
177
160
|
case '+':
|
178
161
|
case '-':
|
179
162
|
case '0':
|
@@ -185,113 +168,104 @@ read_next(ParseInfo pi, const char *key) {
|
|
185
168
|
case '6':
|
186
169
|
case '7':
|
187
170
|
case '8':
|
188
|
-
case '9':
|
189
|
-
|
190
|
-
|
191
|
-
case '
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
read_true(pi, key);
|
196
|
-
break;
|
197
|
-
case 'f':
|
198
|
-
read_false(pi, key);
|
199
|
-
break;
|
200
|
-
case 'n':
|
201
|
-
read_nil(pi, key);
|
202
|
-
break;
|
203
|
-
case '\0':
|
204
|
-
return;
|
205
|
-
default:
|
206
|
-
return;
|
171
|
+
case '9': read_num(pi, key); break;
|
172
|
+
case 'I': read_num(pi, key); break;
|
173
|
+
case 't': read_true(pi, key); break;
|
174
|
+
case 'f': read_false(pi, key); break;
|
175
|
+
case 'n': read_nil(pi, key); break;
|
176
|
+
case '\0': return;
|
177
|
+
default: return;
|
207
178
|
}
|
208
179
|
}
|
209
180
|
|
210
|
-
static void
|
211
|
-
|
212
|
-
const char *ks;
|
181
|
+
static void read_hash(ParseInfo pi, const char *key) {
|
182
|
+
const char *ks;
|
213
183
|
|
214
184
|
if (pi->has_hash_start) {
|
215
|
-
|
185
|
+
call_no_value(pi->handler, oj_hash_start_id, key);
|
216
186
|
}
|
217
187
|
pi->s++;
|
218
188
|
next_non_white(pi);
|
219
189
|
if ('}' == *pi->s) {
|
220
|
-
|
190
|
+
pi->s++;
|
221
191
|
} else {
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
192
|
+
while (1) {
|
193
|
+
next_non_white(pi);
|
194
|
+
ks = read_quoted_value(pi);
|
195
|
+
next_non_white(pi);
|
196
|
+
if (':' == *pi->s) {
|
197
|
+
pi->s++;
|
198
|
+
} else {
|
199
|
+
if (pi->has_error) {
|
200
|
+
call_error("invalid format, expected :", pi, __FILE__, __LINE__);
|
201
|
+
}
|
202
|
+
raise_error("invalid format, expected :", pi->str, pi->s);
|
203
|
+
}
|
204
|
+
read_next(pi, ks);
|
205
|
+
next_non_white(pi);
|
206
|
+
if ('}' == *pi->s) {
|
207
|
+
pi->s++;
|
208
|
+
break;
|
209
|
+
} else if (',' == *pi->s) {
|
210
|
+
pi->s++;
|
211
|
+
} else {
|
212
|
+
if (pi->has_error) {
|
213
|
+
call_error("invalid format, expected , or } while in an object",
|
214
|
+
pi,
|
215
|
+
__FILE__,
|
216
|
+
__LINE__);
|
217
|
+
}
|
218
|
+
raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
|
219
|
+
}
|
220
|
+
}
|
248
221
|
}
|
249
222
|
if (pi->has_hash_end) {
|
250
|
-
|
223
|
+
call_no_value(pi->handler, oj_hash_end_id, key);
|
251
224
|
}
|
252
225
|
}
|
253
226
|
|
254
|
-
static void
|
255
|
-
read_array(ParseInfo pi, const char *key) {
|
227
|
+
static void read_array(ParseInfo pi, const char *key) {
|
256
228
|
if (pi->has_array_start) {
|
257
|
-
|
229
|
+
call_no_value(pi->handler, oj_array_start_id, key);
|
258
230
|
}
|
259
231
|
pi->s++;
|
260
232
|
next_non_white(pi);
|
261
233
|
if (']' == *pi->s) {
|
262
|
-
|
234
|
+
pi->s++;
|
263
235
|
} else {
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
236
|
+
while (1) {
|
237
|
+
read_next(pi, 0);
|
238
|
+
next_non_white(pi);
|
239
|
+
if (',' == *pi->s) {
|
240
|
+
pi->s++;
|
241
|
+
} else if (']' == *pi->s) {
|
242
|
+
pi->s++;
|
243
|
+
break;
|
244
|
+
} else {
|
245
|
+
if (pi->has_error) {
|
246
|
+
call_error("invalid format, expected , or ] while in an array",
|
247
|
+
pi,
|
248
|
+
__FILE__,
|
249
|
+
__LINE__);
|
250
|
+
}
|
251
|
+
raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
|
252
|
+
}
|
253
|
+
}
|
279
254
|
}
|
280
255
|
if (pi->has_array_end) {
|
281
|
-
|
256
|
+
call_no_value(pi->handler, oj_array_end_id, key);
|
282
257
|
}
|
283
258
|
}
|
284
259
|
|
285
|
-
static void
|
286
|
-
|
287
|
-
char *text;
|
260
|
+
static void read_str(ParseInfo pi, const char *key) {
|
261
|
+
char *text;
|
288
262
|
|
289
263
|
text = read_quoted_value(pi);
|
290
264
|
if (pi->has_add_value) {
|
291
|
-
|
265
|
+
VALUE s = rb_str_new2(text);
|
292
266
|
|
293
|
-
|
294
|
-
|
267
|
+
s = oj_encode(s);
|
268
|
+
call_add_value(pi->handler, s, key);
|
295
269
|
}
|
296
270
|
}
|
297
271
|
|
@@ -301,230 +275,228 @@ read_str(ParseInfo pi, const char *key) {
|
|
301
275
|
#define NUM_MAX (FIXNUM_MAX >> 8)
|
302
276
|
#endif
|
303
277
|
|
304
|
-
static void
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
long
|
309
|
-
long
|
310
|
-
|
311
|
-
int
|
312
|
-
int
|
313
|
-
int big = 0;
|
278
|
+
static void read_num(ParseInfo pi, const char *key) {
|
279
|
+
char * start = pi->s;
|
280
|
+
int64_t n = 0;
|
281
|
+
long a = 0;
|
282
|
+
long div = 1;
|
283
|
+
long e = 0;
|
284
|
+
int neg = 0;
|
285
|
+
int eneg = 0;
|
286
|
+
int big = 0;
|
314
287
|
|
315
288
|
if ('-' == *pi->s) {
|
316
|
-
|
317
|
-
|
289
|
+
pi->s++;
|
290
|
+
neg = 1;
|
318
291
|
} else if ('+' == *pi->s) {
|
319
|
-
|
292
|
+
pi->s++;
|
320
293
|
}
|
321
294
|
if ('I' == *pi->s) {
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
295
|
+
if (0 != strncmp("Infinity", pi->s, 8)) {
|
296
|
+
if (pi->has_error) {
|
297
|
+
call_error("number or other value", pi, __FILE__, __LINE__);
|
298
|
+
}
|
299
|
+
raise_error("number or other value", pi->str, pi->s);
|
300
|
+
}
|
301
|
+
pi->s += 8;
|
302
|
+
if (neg) {
|
303
|
+
if (pi->has_add_value) {
|
304
|
+
call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key);
|
305
|
+
}
|
306
|
+
} else {
|
307
|
+
if (pi->has_add_value) {
|
308
|
+
call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key);
|
309
|
+
}
|
310
|
+
}
|
311
|
+
return;
|
339
312
|
}
|
340
313
|
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
314
|
+
if (big) {
|
315
|
+
big++;
|
316
|
+
} else {
|
317
|
+
n = n * 10 + (*pi->s - '0');
|
318
|
+
if (NUM_MAX <= n) {
|
319
|
+
big = 1;
|
320
|
+
}
|
321
|
+
}
|
349
322
|
}
|
350
323
|
if ('.' == *pi->s) {
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
324
|
+
pi->s++;
|
325
|
+
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
326
|
+
a = a * 10 + (*pi->s - '0');
|
327
|
+
div *= 10;
|
328
|
+
if (NUM_MAX <= div) {
|
329
|
+
big = 1;
|
330
|
+
}
|
331
|
+
}
|
359
332
|
}
|
360
333
|
if ('e' == *pi->s || 'E' == *pi->s) {
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
334
|
+
pi->s++;
|
335
|
+
if ('-' == *pi->s) {
|
336
|
+
pi->s++;
|
337
|
+
eneg = 1;
|
338
|
+
} else if ('+' == *pi->s) {
|
339
|
+
pi->s++;
|
340
|
+
}
|
341
|
+
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
342
|
+
e = e * 10 + (*pi->s - '0');
|
343
|
+
if (NUM_MAX <= e) {
|
344
|
+
big = 1;
|
345
|
+
}
|
346
|
+
}
|
374
347
|
}
|
375
348
|
if (0 == e && 0 == a && 1 == div) {
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
349
|
+
if (big) {
|
350
|
+
char c = *pi->s;
|
351
|
+
|
352
|
+
*pi->s = '\0';
|
353
|
+
if (pi->has_add_value) {
|
354
|
+
call_add_value(pi->handler,
|
355
|
+
rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)),
|
356
|
+
key);
|
357
|
+
}
|
358
|
+
*pi->s = c;
|
359
|
+
} else {
|
360
|
+
if (neg) {
|
361
|
+
n = -n;
|
362
|
+
}
|
363
|
+
if (pi->has_add_value) {
|
364
|
+
call_add_value(pi->handler, LONG2NUM(n), key);
|
365
|
+
}
|
366
|
+
}
|
367
|
+
return;
|
393
368
|
} else { /* decimal */
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
369
|
+
if (big) {
|
370
|
+
char c = *pi->s;
|
371
|
+
|
372
|
+
*pi->s = '\0';
|
373
|
+
if (pi->has_add_value) {
|
374
|
+
call_add_value(pi->handler,
|
375
|
+
rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)),
|
376
|
+
key);
|
377
|
+
}
|
378
|
+
*pi->s = c;
|
379
|
+
} else {
|
380
|
+
double d = (double)n + (double)a / (double)div;
|
381
|
+
|
382
|
+
if (neg) {
|
383
|
+
d = -d;
|
384
|
+
}
|
385
|
+
if (1 < big) {
|
386
|
+
e += big - 1;
|
387
|
+
}
|
388
|
+
if (0 != e) {
|
389
|
+
if (eneg) {
|
390
|
+
e = -e;
|
391
|
+
}
|
392
|
+
d *= pow(10.0, e);
|
393
|
+
}
|
394
|
+
if (pi->has_add_value) {
|
395
|
+
call_add_value(pi->handler, rb_float_new(d), key);
|
396
|
+
}
|
397
|
+
}
|
421
398
|
}
|
422
399
|
}
|
423
400
|
|
424
|
-
static void
|
425
|
-
read_true(ParseInfo pi, const char *key) {
|
401
|
+
static void read_true(ParseInfo pi, const char *key) {
|
426
402
|
pi->s++;
|
427
403
|
if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
404
|
+
if (pi->has_error) {
|
405
|
+
call_error("invalid format, expected 'true'", pi, __FILE__, __LINE__);
|
406
|
+
}
|
407
|
+
raise_error("invalid format, expected 'true'", pi->str, pi->s);
|
432
408
|
}
|
433
409
|
pi->s += 3;
|
434
410
|
if (pi->has_add_value) {
|
435
|
-
|
411
|
+
call_add_value(pi->handler, Qtrue, key);
|
436
412
|
}
|
437
413
|
}
|
438
414
|
|
439
|
-
static void
|
440
|
-
read_false(ParseInfo pi, const char *key) {
|
415
|
+
static void read_false(ParseInfo pi, const char *key) {
|
441
416
|
pi->s++;
|
442
417
|
if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
418
|
+
if (pi->has_error) {
|
419
|
+
call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__);
|
420
|
+
}
|
421
|
+
raise_error("invalid format, expected 'false'", pi->str, pi->s);
|
447
422
|
}
|
448
423
|
pi->s += 4;
|
449
424
|
if (pi->has_add_value) {
|
450
|
-
|
425
|
+
call_add_value(pi->handler, Qfalse, key);
|
451
426
|
}
|
452
427
|
}
|
453
428
|
|
454
|
-
static void
|
455
|
-
read_nil(ParseInfo pi, const char *key) {
|
429
|
+
static void read_nil(ParseInfo pi, const char *key) {
|
456
430
|
pi->s++;
|
457
431
|
if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
432
|
+
if (pi->has_error) {
|
433
|
+
call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__);
|
434
|
+
}
|
435
|
+
raise_error("invalid format, expected 'null'", pi->str, pi->s);
|
462
436
|
}
|
463
437
|
pi->s += 3;
|
464
438
|
if (pi->has_add_value) {
|
465
|
-
|
439
|
+
call_add_value(pi->handler, Qnil, key);
|
466
440
|
}
|
467
441
|
}
|
468
442
|
|
469
|
-
static uint32_t
|
470
|
-
|
471
|
-
|
472
|
-
int i;
|
443
|
+
static uint32_t read_hex(ParseInfo pi, char *h) {
|
444
|
+
uint32_t b = 0;
|
445
|
+
int i;
|
473
446
|
|
474
447
|
/* TBD this can be made faster with a table */
|
475
448
|
for (i = 0; i < 4; i++, h++) {
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
449
|
+
b = b << 4;
|
450
|
+
if ('0' <= *h && *h <= '9') {
|
451
|
+
b += *h - '0';
|
452
|
+
} else if ('A' <= *h && *h <= 'F') {
|
453
|
+
b += *h - 'A' + 10;
|
454
|
+
} else if ('a' <= *h && *h <= 'f') {
|
455
|
+
b += *h - 'a' + 10;
|
456
|
+
} else {
|
457
|
+
pi->s = h;
|
458
|
+
if (pi->has_error) {
|
459
|
+
call_error("invalid hex character", pi, __FILE__, __LINE__);
|
460
|
+
}
|
461
|
+
raise_error("invalid hex character", pi->str, pi->s);
|
462
|
+
}
|
490
463
|
}
|
491
464
|
return b;
|
492
465
|
}
|
493
466
|
|
494
|
-
static char*
|
495
|
-
unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
467
|
+
static char *unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
496
468
|
if (0x0000007F >= code) {
|
497
|
-
|
469
|
+
*t = (char)code;
|
498
470
|
} else if (0x000007FF >= code) {
|
499
|
-
|
500
|
-
|
471
|
+
*t++ = 0xC0 | (code >> 6);
|
472
|
+
*t = 0x80 | (0x3F & code);
|
501
473
|
} else if (0x0000FFFF >= code) {
|
502
|
-
|
503
|
-
|
504
|
-
|
474
|
+
*t++ = 0xE0 | (code >> 12);
|
475
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
476
|
+
*t = 0x80 | (0x3F & code);
|
505
477
|
} else if (0x001FFFFF >= code) {
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
478
|
+
*t++ = 0xF0 | (code >> 18);
|
479
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
480
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
481
|
+
*t = 0x80 | (0x3F & code);
|
510
482
|
} else if (0x03FFFFFF >= code) {
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
483
|
+
*t++ = 0xF8 | (code >> 24);
|
484
|
+
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
485
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
486
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
487
|
+
*t = 0x80 | (0x3F & code);
|
516
488
|
} else if (0x7FFFFFFF >= code) {
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
489
|
+
*t++ = 0xFC | (code >> 30);
|
490
|
+
*t++ = 0x80 | ((code >> 24) & 0x3F);
|
491
|
+
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
492
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
493
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
494
|
+
*t = 0x80 | (0x3F & code);
|
523
495
|
} else {
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
496
|
+
if (pi->has_error) {
|
497
|
+
call_error("invalid Unicode", pi, __FILE__, __LINE__);
|
498
|
+
}
|
499
|
+
raise_error("invalid Unicode", pi->str, pi->s);
|
528
500
|
}
|
529
501
|
return t;
|
530
502
|
}
|
@@ -532,119 +504,119 @@ unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
|
532
504
|
/* Assume the value starts immediately and goes until the quote character is
|
533
505
|
* reached again. Do not read the character after the terminating quote.
|
534
506
|
*/
|
535
|
-
static char*
|
536
|
-
|
537
|
-
char
|
538
|
-
char
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
h++; /* skip quote character */
|
507
|
+
static char *read_quoted_value(ParseInfo pi) {
|
508
|
+
char * value = 0;
|
509
|
+
char * h = pi->s; /* head */
|
510
|
+
char * t = h; /* tail */
|
511
|
+
uint32_t code;
|
512
|
+
|
513
|
+
h++; /* skip quote character */
|
543
514
|
t++;
|
544
515
|
value = h;
|
545
516
|
for (; '"' != *h; h++, t++) {
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
}
|
596
|
-
*t
|
517
|
+
if ('\0' == *h) {
|
518
|
+
pi->s = h;
|
519
|
+
raise_error("quoted string not terminated", pi->str, pi->s);
|
520
|
+
} else if ('\\' == *h) {
|
521
|
+
h++;
|
522
|
+
switch (*h) {
|
523
|
+
case 'n': *t = '\n'; break;
|
524
|
+
case 'r': *t = '\r'; break;
|
525
|
+
case 't': *t = '\t'; break;
|
526
|
+
case 'f': *t = '\f'; break;
|
527
|
+
case 'b': *t = '\b'; break;
|
528
|
+
case '"': *t = '"'; break;
|
529
|
+
case '/': *t = '/'; break;
|
530
|
+
case '\\': *t = '\\'; break;
|
531
|
+
case 'u':
|
532
|
+
h++;
|
533
|
+
code = read_hex(pi, h);
|
534
|
+
h += 3;
|
535
|
+
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
536
|
+
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
537
|
+
uint32_t c2;
|
538
|
+
|
539
|
+
h++;
|
540
|
+
if ('\\' != *h || 'u' != *(h + 1)) {
|
541
|
+
pi->s = h;
|
542
|
+
if (pi->has_error) {
|
543
|
+
call_error("invalid escaped character", pi, __FILE__, __LINE__);
|
544
|
+
}
|
545
|
+
raise_error("invalid escaped character", pi->str, pi->s);
|
546
|
+
}
|
547
|
+
h += 2;
|
548
|
+
c2 = read_hex(pi, h);
|
549
|
+
h += 3;
|
550
|
+
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
551
|
+
code = ((c1 << 10) | c2) + 0x00010000;
|
552
|
+
}
|
553
|
+
t = unicode_to_chars(pi, t, code);
|
554
|
+
break;
|
555
|
+
default:
|
556
|
+
pi->s = h;
|
557
|
+
if (pi->has_error) {
|
558
|
+
call_error("invalid escaped character", pi, __FILE__, __LINE__);
|
559
|
+
}
|
560
|
+
raise_error("invalid escaped character", pi->str, pi->s);
|
561
|
+
break;
|
562
|
+
}
|
563
|
+
} else if (t != h) {
|
564
|
+
*t = *h;
|
565
|
+
}
|
566
|
+
}
|
567
|
+
*t = '\0'; /* terminate value */
|
597
568
|
pi->s = h + 1;
|
598
569
|
|
599
570
|
return value;
|
600
571
|
}
|
601
572
|
|
602
|
-
static void
|
603
|
-
|
604
|
-
|
605
|
-
struct _parseInfo pi;
|
573
|
+
static void saj_parse(VALUE handler, char *json) {
|
574
|
+
volatile VALUE obj = Qnil;
|
575
|
+
struct _parseInfo pi;
|
606
576
|
|
607
577
|
if (0 == json) {
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
578
|
+
if (pi.has_error) {
|
579
|
+
call_error("Invalid arg, xml string can not be null", &pi, __FILE__, __LINE__);
|
580
|
+
}
|
581
|
+
raise_error("Invalid arg, xml string can not be null", json, 0);
|
612
582
|
}
|
613
583
|
/* skip UTF-8 BOM if present */
|
614
584
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
615
|
-
|
585
|
+
json += 3;
|
616
586
|
}
|
617
587
|
/* initialize parse info */
|
618
588
|
pi.str = json;
|
619
|
-
pi.s
|
589
|
+
pi.s = json;
|
620
590
|
#if IS_WINDOWS
|
621
|
-
pi.stack_min = (void*)((char*)&obj -
|
591
|
+
pi.stack_min = (void *)((char *)&obj -
|
592
|
+
(512 * 1024)); /* assume a 1M stack and give half to ruby */
|
622
593
|
#else
|
623
594
|
{
|
624
|
-
|
595
|
+
struct rlimit lim;
|
625
596
|
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
597
|
+
if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
|
598
|
+
pi.stack_min = (void *)((char *)&obj - (lim.rlim_cur / 4 *
|
599
|
+
3)); /* let 3/4ths of the stack be used only */
|
600
|
+
} else {
|
601
|
+
pi.stack_min = 0; /* indicates not to check stack limit */
|
602
|
+
}
|
631
603
|
}
|
632
604
|
#endif
|
633
|
-
pi.handler
|
634
|
-
pi.has_hash_start
|
635
|
-
pi.has_hash_end
|
605
|
+
pi.handler = handler;
|
606
|
+
pi.has_hash_start = rb_respond_to(handler, oj_hash_start_id);
|
607
|
+
pi.has_hash_end = rb_respond_to(handler, oj_hash_end_id);
|
636
608
|
pi.has_array_start = rb_respond_to(handler, oj_array_start_id);
|
637
|
-
pi.has_array_end
|
638
|
-
pi.has_add_value
|
639
|
-
pi.has_error
|
609
|
+
pi.has_array_end = rb_respond_to(handler, oj_array_end_id);
|
610
|
+
pi.has_add_value = rb_respond_to(handler, oj_add_value_id);
|
611
|
+
pi.has_error = rb_respond_to(handler, oj_error_id);
|
640
612
|
read_next(&pi, 0);
|
641
613
|
next_non_white(&pi);
|
642
614
|
if ('\0' != *pi.s) {
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
615
|
+
if (pi.has_error) {
|
616
|
+
call_error("invalid format, extra characters", &pi, __FILE__, __LINE__);
|
617
|
+
} else {
|
618
|
+
raise_error("invalid format, extra characters", pi.str, pi.s);
|
619
|
+
}
|
648
620
|
}
|
649
621
|
}
|
650
622
|
|
@@ -661,48 +633,48 @@ saj_parse(VALUE handler, char *json) {
|
|
661
633
|
*/
|
662
634
|
VALUE
|
663
635
|
oj_saj_parse(int argc, VALUE *argv, VALUE self) {
|
664
|
-
char
|
665
|
-
size_t
|
666
|
-
VALUE
|
636
|
+
char * json = 0;
|
637
|
+
size_t len = 0;
|
638
|
+
VALUE input = argv[1];
|
667
639
|
|
668
640
|
if (argc < 2) {
|
669
|
-
|
641
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
|
670
642
|
}
|
671
643
|
if (rb_type(input) == T_STRING) {
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
644
|
+
// the json string gets modified so make a copy of it
|
645
|
+
len = RSTRING_LEN(input) + 1;
|
646
|
+
json = ALLOC_N(char, len);
|
647
|
+
strcpy(json, StringValuePtr(input));
|
676
648
|
} else {
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
649
|
+
VALUE clas = rb_obj_class(input);
|
650
|
+
volatile VALUE s;
|
651
|
+
|
652
|
+
if (oj_stringio_class == clas) {
|
653
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
654
|
+
len = RSTRING_LEN(s) + 1;
|
655
|
+
json = ALLOC_N(char, len);
|
656
|
+
strcpy(json, rb_string_value_cstr((VALUE *)&s));
|
685
657
|
#if !IS_WINDOWS
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
658
|
+
} else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
|
659
|
+
int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
|
660
|
+
ssize_t cnt;
|
661
|
+
|
662
|
+
len = lseek(fd, 0, SEEK_END);
|
663
|
+
lseek(fd, 0, SEEK_SET);
|
664
|
+
json = ALLOC_N(char, len + 1);
|
665
|
+
if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
|
666
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
667
|
+
}
|
668
|
+
json[len] = '\0';
|
697
669
|
#endif
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
670
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
671
|
+
s = rb_funcall2(input, oj_read_id, 0, 0);
|
672
|
+
len = RSTRING_LEN(s) + 1;
|
673
|
+
json = ALLOC_N(char, len);
|
674
|
+
strcpy(json, rb_string_value_cstr((VALUE *)&s));
|
675
|
+
} else {
|
676
|
+
rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
|
677
|
+
}
|
706
678
|
}
|
707
679
|
saj_parse(*argv, json);
|
708
680
|
xfree(json);
|