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.

@@ -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__ */
@@ -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
+ }
@@ -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__ */
@@ -1,4 +1,4 @@
1
- /* saj.c
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
- oj_saj_parse(VALUE handler, char *json) {
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
- #if 0
723
- static void
724
- cx_add(CX cx, VALUE obj, const char *key) {
725
- if (0 == cx->cur) {
726
- cx->cur = cx->stack;
727
- *cx->cur = obj;
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
- if (0 != key) {
730
- VALUE ks = rb_str_new2(key);
731
- #if HAS_ENCODING_SUPPORT
732
- rb_enc_associate(ks, oj_utf8_encoding);
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
- rb_hash_aset(*cx->cur, ks, obj);
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
- rb_ary_push(*cx->cur, obj);
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
- *cx->cur = obj;
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
- static void
807
- add_nil(void *context, const char *key) {
808
- cx_add((CX)context, Qnil, key);
781
+ return Qnil;
809
782
  }
810
- #endif
@@ -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
+ }