oj 2.0.14 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +47 -332
- data/ext/oj/buf.h +103 -0
- data/ext/oj/circarray.c +93 -0
- data/ext/oj/circarray.h +48 -0
- data/ext/oj/compat.c +112 -0
- data/ext/oj/dump.c +2 -1
- data/ext/oj/err.c +82 -0
- data/ext/oj/err.h +64 -0
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/hash.c +149 -0
- data/ext/oj/{cache.h → hash.h} +9 -10
- data/ext/oj/hash_test.c +501 -0
- data/ext/oj/object.c +514 -0
- data/ext/oj/odd.c +159 -0
- data/ext/oj/odd.h +61 -0
- data/ext/oj/oj.c +235 -305
- data/ext/oj/oj.h +18 -23
- data/ext/oj/parse.c +798 -0
- data/ext/oj/parse.h +88 -0
- data/ext/oj/resolve.c +117 -0
- data/ext/oj/resolve.h +38 -0
- data/ext/oj/saj.c +58 -86
- data/ext/oj/scp.c +308 -0
- data/ext/oj/strict.c +166 -0
- data/ext/oj/val_stack.c +48 -0
- data/ext/oj/val_stack.h +167 -0
- data/lib/oj.rb +1 -0
- data/lib/oj/saj.rb +11 -8
- data/lib/oj/schandler.rb +70 -0
- data/lib/oj/version.rb +1 -1
- data/test/bug.rb +14 -22
- data/test/perf_compat.rb +128 -0
- data/test/{perf_obj.rb → perf_object.rb} +18 -6
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +23 -122
- data/test/sample.rb +2 -2
- data/test/test_compat.rb +342 -0
- data/test/test_object.rb +390 -0
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +224 -0
- data/test/test_strict.rb +250 -0
- data/test/tests.rb +8 -18
- metadata +31 -10
- data/ext/oj/cache.c +0 -148
- data/ext/oj/load.c +0 -1089
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
data/ext/oj/parse.h
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
/* parse.h
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
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
|
+
*/
|
30
|
+
|
31
|
+
#ifndef __OJ_PARSE_H__
|
32
|
+
#define __OJ_PARSE_H__
|
33
|
+
|
34
|
+
#include <stdarg.h>
|
35
|
+
|
36
|
+
#include "ruby.h"
|
37
|
+
#include "oj.h"
|
38
|
+
#include "val_stack.h"
|
39
|
+
#include "circarray.h"
|
40
|
+
|
41
|
+
typedef struct _NumInfo {
|
42
|
+
int64_t i;
|
43
|
+
int64_t num;
|
44
|
+
int64_t div;
|
45
|
+
const char *str;
|
46
|
+
size_t len;
|
47
|
+
long exp;
|
48
|
+
int dec_cnt;
|
49
|
+
int big;
|
50
|
+
int infinity;
|
51
|
+
int neg;
|
52
|
+
} *NumInfo;
|
53
|
+
|
54
|
+
typedef struct _ParseInfo {
|
55
|
+
const char *json;
|
56
|
+
const char *cur;
|
57
|
+
struct _Err err;
|
58
|
+
struct _Options options;
|
59
|
+
void *cbc;
|
60
|
+
struct _ValStack stack;
|
61
|
+
CircArray circ_array;
|
62
|
+
int expect_value;
|
63
|
+
VALUE (*start_hash)(struct _ParseInfo *pi);
|
64
|
+
void (*end_hash)(struct _ParseInfo *pi);
|
65
|
+
void (*hash_set_cstr)(struct _ParseInfo *pi, const char *key, size_t klen, const char *str, size_t len, const char *orig);
|
66
|
+
void (*hash_set_num)(struct _ParseInfo *pi, const char *key, size_t klen, NumInfo ni);
|
67
|
+
void (*hash_set_value)(struct _ParseInfo *pi, const char *key, size_t klen, VALUE value);
|
68
|
+
|
69
|
+
VALUE (*start_array)(struct _ParseInfo *pi);
|
70
|
+
void (*end_array)(struct _ParseInfo *pi);
|
71
|
+
void (*array_append_cstr)(struct _ParseInfo *pi, const char *str, size_t len, const char *orig);
|
72
|
+
void (*array_append_num)(struct _ParseInfo *pi, NumInfo ni);
|
73
|
+
void (*array_append_value)(struct _ParseInfo *pi, VALUE value);
|
74
|
+
|
75
|
+
void (*add_cstr)(struct _ParseInfo *pi, const char *str, size_t len, const char *orig);
|
76
|
+
void (*add_num)(struct _ParseInfo *pi, NumInfo ni);
|
77
|
+
void (*add_value)(struct _ParseInfo *pi, VALUE val);
|
78
|
+
} *ParseInfo;
|
79
|
+
|
80
|
+
extern void oj_parse2(ParseInfo pi);
|
81
|
+
extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...);
|
82
|
+
extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json);
|
83
|
+
extern VALUE oj_num_as_value(NumInfo ni);
|
84
|
+
|
85
|
+
extern void oj_set_strict_callbacks(ParseInfo pi);
|
86
|
+
extern void oj_set_compat_callbacks(ParseInfo pi);
|
87
|
+
|
88
|
+
#endif /* __OJ_PARSE_H__ */
|
data/ext/oj/resolve.c
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
/* resolve.c
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
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
|
+
*/
|
30
|
+
|
31
|
+
#include <stdlib.h>
|
32
|
+
#include <stdio.h>
|
33
|
+
#include <string.h>
|
34
|
+
#if SAFE_CACHE
|
35
|
+
#include <pthread.h>
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#include "oj.h"
|
39
|
+
#include "err.h"
|
40
|
+
#include "parse.h"
|
41
|
+
#include "hash.h"
|
42
|
+
|
43
|
+
inline static VALUE
|
44
|
+
resolve_classname(VALUE mod, const char *classname, int auto_define) {
|
45
|
+
VALUE clas;
|
46
|
+
ID ci = rb_intern(classname);
|
47
|
+
|
48
|
+
if (rb_const_defined_at(mod, ci)) {
|
49
|
+
clas = rb_const_get_at(mod, ci);
|
50
|
+
} else if (auto_define) {
|
51
|
+
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
52
|
+
} else {
|
53
|
+
clas = Qundef;
|
54
|
+
}
|
55
|
+
return clas;
|
56
|
+
}
|
57
|
+
|
58
|
+
static VALUE
|
59
|
+
resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define) {
|
60
|
+
char class_name[1024];
|
61
|
+
VALUE clas;
|
62
|
+
char *end = class_name + sizeof(class_name) - 1;
|
63
|
+
char *s;
|
64
|
+
const char *n = name;
|
65
|
+
|
66
|
+
clas = rb_cObject;
|
67
|
+
for (s = class_name; 0 < len; n++, len--) {
|
68
|
+
if (':' == *n) {
|
69
|
+
*s = '\0';
|
70
|
+
n++;
|
71
|
+
len--;
|
72
|
+
if (':' != *n) {
|
73
|
+
return Qundef;
|
74
|
+
}
|
75
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
76
|
+
return Qundef;
|
77
|
+
}
|
78
|
+
s = class_name;
|
79
|
+
} else if (end <= s) {
|
80
|
+
return Qundef;
|
81
|
+
} else {
|
82
|
+
*s++ = *n;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
*s = '\0';
|
86
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
87
|
+
if (sizeof(class_name) - 1 < len) {
|
88
|
+
len = sizeof(class_name) - 1;
|
89
|
+
}
|
90
|
+
memcpy(class_name, name, len);
|
91
|
+
class_name[len] = '\0';
|
92
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "class %s is not defined", class_name);
|
93
|
+
}
|
94
|
+
return clas;
|
95
|
+
}
|
96
|
+
|
97
|
+
VALUE
|
98
|
+
oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define) {
|
99
|
+
VALUE clas;
|
100
|
+
VALUE *slot;
|
101
|
+
|
102
|
+
if (No == pi->options.class_cache) {
|
103
|
+
return resolve_classpath(pi, name, len, auto_define);
|
104
|
+
}
|
105
|
+
#if SAFE_CACHE
|
106
|
+
pthread_mutex_lock(&oj_cache_mutex);
|
107
|
+
#endif
|
108
|
+
if (Qnil == (clas = oj_class_hash_get(name, len, &slot))) {
|
109
|
+
if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define))) {
|
110
|
+
*slot = clas;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
#if SAFE_CACHE
|
114
|
+
pthread_mutex_unlock(&oj_cache_mutex);
|
115
|
+
#endif
|
116
|
+
return clas;
|
117
|
+
}
|
data/ext/oj/resolve.h
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
/* resolve.h
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
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
|
+
*/
|
30
|
+
|
31
|
+
#ifndef __OJ_RESOLVE_H__
|
32
|
+
#define __OJ_RESOLVE_H__
|
33
|
+
|
34
|
+
#include "ruby.h"
|
35
|
+
|
36
|
+
extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define);
|
37
|
+
|
38
|
+
#endif /* __OJ_RESOLVE_H__ */
|
data/ext/oj/saj.c
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
/*
|
1
|
+
/* sajkey.c
|
2
2
|
* Copyright (c) 2012, Peter Ohler
|
3
3
|
* All rights reserved.
|
4
4
|
*
|
@@ -35,6 +35,8 @@
|
|
35
35
|
#include <stdio.h>
|
36
36
|
#include <string.h>
|
37
37
|
#include <math.h>
|
38
|
+
#include <sys/types.h>
|
39
|
+
#include <unistd.h>
|
38
40
|
|
39
41
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
40
42
|
#define OJ_INFINITY (1.0/0.0)
|
@@ -669,8 +671,8 @@ respond_to(VALUE obj, ID method) {
|
|
669
671
|
#endif
|
670
672
|
}
|
671
673
|
|
672
|
-
void
|
673
|
-
|
674
|
+
static void
|
675
|
+
sajkey_parse(VALUE handler, char *json) {
|
674
676
|
VALUE obj = Qnil;
|
675
677
|
struct _ParseInfo pi;
|
676
678
|
|
@@ -718,93 +720,63 @@ oj_saj_parse(VALUE handler, char *json) {
|
|
718
720
|
}
|
719
721
|
}
|
720
722
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
723
|
+
/* call-seq: sajkey_parse(handler, io)
|
724
|
+
*
|
725
|
+
* Parses an IO stream or file containing an JSON document. Raises an exception
|
726
|
+
* if the JSON is malformed.
|
727
|
+
* @param [Oj::SajKey] handler SajKey (responds to Oj::SajKey methods) like handler
|
728
|
+
* @param [IO|String] io IO Object to read from
|
729
|
+
*/
|
730
|
+
VALUE
|
731
|
+
oj_saj_parse(int argc, VALUE *argv, VALUE self) {
|
732
|
+
char *json = 0;
|
733
|
+
size_t len = 0;
|
734
|
+
VALUE input = argv[1];
|
735
|
+
|
736
|
+
if (argc < 2) {
|
737
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
|
738
|
+
}
|
739
|
+
if (rb_type(input) == T_STRING) {
|
740
|
+
// the json string gets modified so make a copy of it
|
741
|
+
len = RSTRING_LEN(input) + 1;
|
742
|
+
json = ALLOC_N(char, len);
|
743
|
+
strcpy(json, StringValuePtr(input));
|
728
744
|
} else {
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
745
|
+
VALUE clas = rb_obj_class(input);
|
746
|
+
VALUE s;
|
747
|
+
|
748
|
+
if (oj_stringio_class == clas) {
|
749
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
750
|
+
len = RSTRING_LEN(s) + 1;
|
751
|
+
json = ALLOC_N(char, len);
|
752
|
+
strcpy(json, StringValuePtr(s));
|
753
|
+
#ifndef JRUBY_RUBY
|
754
|
+
#if !IS_WINDOWS
|
755
|
+
// JRuby gets confused with what is the real fileno.
|
756
|
+
} else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
|
757
|
+
int fd = FIX2INT(s);
|
758
|
+
ssize_t cnt;
|
759
|
+
|
760
|
+
len = lseek(fd, 0, SEEK_END);
|
761
|
+
lseek(fd, 0, SEEK_SET);
|
762
|
+
json = ALLOC_N(char, len + 1);
|
763
|
+
if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
|
764
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
765
|
+
}
|
766
|
+
json[len] = '\0';
|
767
|
+
#endif
|
733
768
|
#endif
|
734
|
-
|
769
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
770
|
+
s = rb_funcall2(input, oj_read_id, 0, 0);
|
771
|
+
len = RSTRING_LEN(s) + 1;
|
772
|
+
json = ALLOC_N(char, len);
|
773
|
+
strcpy(json, StringValuePtr(s));
|
735
774
|
} else {
|
736
|
-
|
737
|
-
}
|
738
|
-
}
|
739
|
-
}
|
740
|
-
|
741
|
-
static void
|
742
|
-
cx_push(CX cx, VALUE obj, const char *key) {
|
743
|
-
if (0 == cx->cur) {
|
744
|
-
cx->cur = cx->stack;
|
745
|
-
} else {
|
746
|
-
if (cx->end <= cx->cur) {
|
747
|
-
rb_raise(oj_parse_error_class, "too deeply nested");
|
775
|
+
rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
|
748
776
|
}
|
749
|
-
cx_add(cx, obj, key);
|
750
|
-
cx->cur++;
|
751
777
|
}
|
752
|
-
*
|
753
|
-
|
754
|
-
|
755
|
-
static void
|
756
|
-
hash_start(void *context, const char *key) {
|
757
|
-
cx_push((CX)context, rb_hash_new(), key);
|
758
|
-
}
|
759
|
-
|
760
|
-
static void
|
761
|
-
col_end(void *context, const char *key) {
|
762
|
-
((CX)context)->cur--;
|
763
|
-
}
|
764
|
-
|
765
|
-
static void
|
766
|
-
array_start(void *context, const char *key) {
|
767
|
-
cx_push((CX)context, rb_ary_new(), key);
|
768
|
-
}
|
769
|
-
|
770
|
-
static void
|
771
|
-
add_str(void *context, const char *str, const char *key) {
|
772
|
-
VALUE s;
|
773
|
-
|
774
|
-
s = rb_str_new2(str);
|
775
|
-
#if HAS_ENCODING_SUPPORT
|
776
|
-
rb_enc_associate(s, oj_utf8_encoding);
|
777
|
-
#endif
|
778
|
-
cx_add((CX)context, s, key);
|
779
|
-
}
|
780
|
-
|
781
|
-
static void
|
782
|
-
add_big(void *context, const char *str, const char *key) {
|
783
|
-
cx_add((CX)context, rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(str)), key);
|
784
|
-
}
|
785
|
-
|
786
|
-
static void
|
787
|
-
add_float(void *context, double num, const char *key) {
|
788
|
-
cx_add((CX)context, rb_float_new(num), key);
|
789
|
-
}
|
790
|
-
|
791
|
-
static void
|
792
|
-
add_fixnum(void *context, int64_t num, const char *key) {
|
793
|
-
cx_add((CX)context, LONG2NUM(num), key);
|
794
|
-
}
|
795
|
-
|
796
|
-
static void
|
797
|
-
add_true(void *context, const char *key) {
|
798
|
-
cx_add((CX)context, Qtrue, key);
|
799
|
-
}
|
800
|
-
|
801
|
-
static void
|
802
|
-
add_false(void *context, const char *key) {
|
803
|
-
cx_add((CX)context, Qfalse, key);
|
804
|
-
}
|
778
|
+
sajkey_parse(*argv, json);
|
779
|
+
xfree(json);
|
805
780
|
|
806
|
-
|
807
|
-
add_nil(void *context, const char *key) {
|
808
|
-
cx_add((CX)context, Qnil, key);
|
781
|
+
return Qnil;
|
809
782
|
}
|
810
|
-
#endif
|
data/ext/oj/scp.c
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
/* scp.c
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
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
|
+
*/
|
30
|
+
|
31
|
+
#include <stdlib.h>
|
32
|
+
#include <stdio.h>
|
33
|
+
#include <string.h>
|
34
|
+
#include <math.h>
|
35
|
+
#include <sys/types.h>
|
36
|
+
#include <unistd.h>
|
37
|
+
|
38
|
+
#include "oj.h"
|
39
|
+
#include "parse.h"
|
40
|
+
|
41
|
+
inline static int
|
42
|
+
respond_to(VALUE obj, ID method) {
|
43
|
+
#ifdef JRUBY_RUBY
|
44
|
+
/* There is a bug in JRuby where rb_respond_to() returns true (1) even if
|
45
|
+
* a method is private. */
|
46
|
+
{
|
47
|
+
VALUE args[1];
|
48
|
+
|
49
|
+
*args = ID2SYM(method);
|
50
|
+
return (Qtrue == rb_funcall2(obj, rb_intern("respond_to?"), 1, args));
|
51
|
+
}
|
52
|
+
#else
|
53
|
+
return rb_respond_to(obj, method);
|
54
|
+
#endif
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE
|
58
|
+
noop_start(ParseInfo pi) {
|
59
|
+
return Qnil;
|
60
|
+
}
|
61
|
+
|
62
|
+
static void
|
63
|
+
noop_end(ParseInfo pi) {
|
64
|
+
}
|
65
|
+
|
66
|
+
static void
|
67
|
+
noop_add_value(ParseInfo pi, VALUE val) {
|
68
|
+
}
|
69
|
+
|
70
|
+
static void
|
71
|
+
noop_add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
72
|
+
}
|
73
|
+
|
74
|
+
static void
|
75
|
+
noop_add_num(ParseInfo pi, NumInfo ni) {
|
76
|
+
}
|
77
|
+
|
78
|
+
static void
|
79
|
+
noop_hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
|
80
|
+
}
|
81
|
+
|
82
|
+
static void
|
83
|
+
noop_hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
|
84
|
+
}
|
85
|
+
|
86
|
+
static void
|
87
|
+
noop_hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
|
88
|
+
}
|
89
|
+
|
90
|
+
static void
|
91
|
+
noop_array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
92
|
+
}
|
93
|
+
|
94
|
+
static void
|
95
|
+
noop_array_append_num(ParseInfo pi, NumInfo ni) {
|
96
|
+
}
|
97
|
+
|
98
|
+
static void
|
99
|
+
noop_array_append_value(ParseInfo pi, VALUE value) {
|
100
|
+
}
|
101
|
+
|
102
|
+
static void
|
103
|
+
add_value(ParseInfo pi, VALUE val) {
|
104
|
+
rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, val);
|
105
|
+
}
|
106
|
+
|
107
|
+
static void
|
108
|
+
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
109
|
+
VALUE rstr = rb_str_new(str, len);
|
110
|
+
|
111
|
+
#if HAS_ENCODING_SUPPORT
|
112
|
+
rb_enc_associate(rstr, oj_utf8_encoding);
|
113
|
+
#endif
|
114
|
+
rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, rstr);
|
115
|
+
}
|
116
|
+
|
117
|
+
static void
|
118
|
+
add_num(ParseInfo pi, NumInfo ni) {
|
119
|
+
rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, oj_num_as_value(ni));
|
120
|
+
}
|
121
|
+
|
122
|
+
static VALUE
|
123
|
+
start_hash(ParseInfo pi) {
|
124
|
+
return rb_funcall((VALUE)pi->cbc, oj_hash_start_id, 0);
|
125
|
+
}
|
126
|
+
|
127
|
+
static void
|
128
|
+
end_hash(ParseInfo pi) {
|
129
|
+
rb_funcall((VALUE)pi->cbc, oj_hash_end_id, 0);
|
130
|
+
}
|
131
|
+
|
132
|
+
static VALUE
|
133
|
+
start_array(ParseInfo pi) {
|
134
|
+
return rb_funcall((VALUE)pi->cbc, oj_array_start_id, 0);
|
135
|
+
}
|
136
|
+
|
137
|
+
static void
|
138
|
+
end_array(ParseInfo pi) {
|
139
|
+
rb_funcall((VALUE)pi->cbc, oj_array_end_id, 0);
|
140
|
+
}
|
141
|
+
|
142
|
+
static VALUE
|
143
|
+
hash_key(ParseInfo pi, const char *key, size_t klen) {
|
144
|
+
VALUE rkey = rb_str_new(key, klen);
|
145
|
+
|
146
|
+
#if HAS_ENCODING_SUPPORT
|
147
|
+
rb_enc_associate(rkey, oj_utf8_encoding);
|
148
|
+
#endif
|
149
|
+
if (Yes == pi->options.sym_key) {
|
150
|
+
rkey = rb_str_intern(rkey);
|
151
|
+
}
|
152
|
+
return rkey;
|
153
|
+
}
|
154
|
+
|
155
|
+
static void
|
156
|
+
hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
|
157
|
+
VALUE rstr = rb_str_new(str, len);
|
158
|
+
|
159
|
+
#if HAS_ENCODING_SUPPORT
|
160
|
+
rb_enc_associate(rstr, oj_utf8_encoding);
|
161
|
+
#endif
|
162
|
+
rb_funcall((VALUE)pi->cbc, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), rstr);
|
163
|
+
}
|
164
|
+
|
165
|
+
static void
|
166
|
+
hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
|
167
|
+
rb_funcall((VALUE)pi->cbc, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), oj_num_as_value(ni));
|
168
|
+
}
|
169
|
+
|
170
|
+
static void
|
171
|
+
hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
|
172
|
+
rb_funcall((VALUE)pi->cbc, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), value);
|
173
|
+
}
|
174
|
+
|
175
|
+
static void
|
176
|
+
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
177
|
+
VALUE rstr = rb_str_new(str, len);
|
178
|
+
|
179
|
+
#if HAS_ENCODING_SUPPORT
|
180
|
+
rb_enc_associate(rstr, oj_utf8_encoding);
|
181
|
+
#endif
|
182
|
+
rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);
|
183
|
+
}
|
184
|
+
|
185
|
+
static void
|
186
|
+
array_append_num(ParseInfo pi, NumInfo ni) {
|
187
|
+
rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, oj_num_as_value(ni));
|
188
|
+
}
|
189
|
+
|
190
|
+
static void
|
191
|
+
array_append_value(ParseInfo pi, VALUE value) {
|
192
|
+
rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, value);
|
193
|
+
}
|
194
|
+
|
195
|
+
static VALUE
|
196
|
+
protect_parse(VALUE pip) {
|
197
|
+
oj_parse2((ParseInfo)pip);
|
198
|
+
|
199
|
+
return Qnil;
|
200
|
+
}
|
201
|
+
|
202
|
+
VALUE
|
203
|
+
oj_sc_parse(int argc, VALUE *argv, VALUE self) {
|
204
|
+
struct _ParseInfo pi;
|
205
|
+
char *buf = 0;
|
206
|
+
VALUE input;
|
207
|
+
VALUE handler;
|
208
|
+
int line = 0;
|
209
|
+
|
210
|
+
if (argc < 2) {
|
211
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.");
|
212
|
+
}
|
213
|
+
handler = *argv;;
|
214
|
+
input = argv[1];
|
215
|
+
pi.json = 0;
|
216
|
+
pi.options = oj_default_options;
|
217
|
+
if (3 == argc) {
|
218
|
+
oj_parse_options(argv[2], &pi.options);
|
219
|
+
}
|
220
|
+
pi.cbc = (void*)handler;
|
221
|
+
|
222
|
+
pi.start_hash = respond_to(handler, oj_hash_start_id) ? start_hash : noop_start;
|
223
|
+
pi.end_hash = respond_to(handler, oj_hash_end_id) ? end_hash : noop_end;
|
224
|
+
pi.start_array = respond_to(handler, oj_array_start_id) ? start_array : noop_start;
|
225
|
+
pi.end_array = respond_to(handler, oj_array_end_id) ? end_array : noop_end;
|
226
|
+
if (respond_to(handler, oj_hash_set_id)) {
|
227
|
+
pi.hash_set_value = hash_set_value;
|
228
|
+
pi.hash_set_cstr = hash_set_cstr;
|
229
|
+
pi.hash_set_num = hash_set_num;
|
230
|
+
pi.expect_value = 1;
|
231
|
+
} else {
|
232
|
+
pi.hash_set_value = noop_hash_set_value;
|
233
|
+
pi.hash_set_cstr = noop_hash_set_cstr;
|
234
|
+
pi.hash_set_num = noop_hash_set_num;
|
235
|
+
pi.expect_value = 0;
|
236
|
+
}
|
237
|
+
if (respond_to(handler, oj_array_append_id)) {
|
238
|
+
pi.array_append_value = array_append_value;
|
239
|
+
pi.array_append_cstr = array_append_cstr;
|
240
|
+
pi.array_append_num = array_append_num;
|
241
|
+
pi.expect_value = 1;
|
242
|
+
} else {
|
243
|
+
pi.array_append_value = noop_array_append_value;
|
244
|
+
pi.array_append_cstr = noop_array_append_cstr;
|
245
|
+
pi.array_append_num = noop_array_append_num;
|
246
|
+
pi.expect_value = 0;
|
247
|
+
}
|
248
|
+
if (respond_to(handler, oj_add_value_id)) {
|
249
|
+
pi.add_cstr = add_cstr;
|
250
|
+
pi.add_num = add_num;
|
251
|
+
pi.add_value = add_value;
|
252
|
+
pi.expect_value = 1;
|
253
|
+
} else {
|
254
|
+
pi.add_cstr = noop_add_cstr;
|
255
|
+
pi.add_num = noop_add_num;
|
256
|
+
pi.add_value = noop_add_value;
|
257
|
+
pi.expect_value = 0;
|
258
|
+
}
|
259
|
+
if (rb_type(input) == T_STRING) {
|
260
|
+
pi.json = StringValuePtr(input);
|
261
|
+
} else {
|
262
|
+
VALUE clas = rb_obj_class(input);
|
263
|
+
VALUE s;
|
264
|
+
|
265
|
+
if (oj_stringio_class == clas) {
|
266
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
267
|
+
pi.json = StringValuePtr(input);
|
268
|
+
#ifndef JRUBY_RUBY
|
269
|
+
#if !IS_WINDOWS
|
270
|
+
// JRuby gets confused with what is the real fileno.
|
271
|
+
} else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
|
272
|
+
int fd = FIX2INT(s);
|
273
|
+
ssize_t cnt;
|
274
|
+
size_t len = lseek(fd, 0, SEEK_END);
|
275
|
+
|
276
|
+
lseek(fd, 0, SEEK_SET);
|
277
|
+
buf = ALLOC_N(char, len + 1);
|
278
|
+
pi.json = buf;
|
279
|
+
if (0 >= (cnt = read(fd, (char*)pi.json, len)) || cnt != (ssize_t)len) {
|
280
|
+
if (0 != buf) {
|
281
|
+
xfree(buf);
|
282
|
+
}
|
283
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
284
|
+
}
|
285
|
+
((char*)pi.json)[len] = '\0';
|
286
|
+
#endif
|
287
|
+
#endif
|
288
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
289
|
+
s = rb_funcall2(input, oj_read_id, 0, 0);
|
290
|
+
pi.json = StringValuePtr(s);
|
291
|
+
} else {
|
292
|
+
rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
|
293
|
+
}
|
294
|
+
}
|
295
|
+
rb_protect(protect_parse, (VALUE)&pi, &line);
|
296
|
+
//oj_parse2(&pi);
|
297
|
+
if (0 != buf) {
|
298
|
+
xfree(buf);
|
299
|
+
}
|
300
|
+
stack_cleanup(&pi.stack);
|
301
|
+
if (0 != line) {
|
302
|
+
rb_jump_tag(line);
|
303
|
+
}
|
304
|
+
if (err_has(&pi.err)) {
|
305
|
+
oj_err_raise(&pi.err);
|
306
|
+
}
|
307
|
+
return Qnil;
|
308
|
+
}
|