oj 2.9.8 → 2.9.9

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.

data/README.md CHANGED
@@ -26,7 +26,26 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
26
26
 
27
27
  [![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
28
28
 
29
- ### Current Release 2.9.8
29
+ ### Current Release 2.9.9
30
+
31
+ - Missed a character map entry. / in ascii mode is now output as / and not \/
32
+
33
+ - Fixed SC parser to not treat all IO that respond to fileno as a file. It not
34
+ checks stat and asks if it is a file.
35
+
36
+ - Tightened object parsing of non-string hash keys so that just "^#x" is parsed
37
+ as a hash pair and not "~#x".
38
+
39
+ - Using echo to STDIN as an IO input works around the exception raised when
40
+ asking the IO for it's position (IO.pos).
41
+
42
+ - Simple Callback Parser now uses the new stream parser for handling files and
43
+ IO so that larger files are handled more efficiently and streams are read as
44
+ data arrives instead of on close.
45
+
46
+ - Handles file FIFO pipes correctly now.
47
+
48
+ ### Release 2.9.8
30
49
 
31
50
  - Changed escaping back to previous release and added a new escape mode.
32
51
 
@@ -90,6 +90,7 @@ oj_compat_parse(int argc, VALUE *argv, VALUE self) {
90
90
  struct _ParseInfo pi;
91
91
 
92
92
  pi.options = oj_default_options;
93
+ pi.handler = Qnil;
93
94
  oj_set_compat_callbacks(&pi);
94
95
 
95
96
  if (T_STRING == rb_type(*argv)) {
@@ -104,6 +105,7 @@ oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
104
105
  struct _ParseInfo pi;
105
106
 
106
107
  pi.options = oj_default_options;
108
+ pi.handler = Qnil;
107
109
  oj_set_strict_callbacks(&pi);
108
110
  pi.end_hash = end_hash;
109
111
  pi.hash_set_cstr = hash_set_cstr;
@@ -137,7 +137,7 @@ static char hibit_friendly_chars[256] = "\
137
137
  // bytes per character in the output. That makes this conservative.
138
138
  static char ascii_friendly_chars[256] = "\
139
139
  66666666222622666666666666666666\
140
- 11211111111111121111111111111111\
140
+ 11211111111111111111111111111111\
141
141
  11111111111111111111111111112111\
142
142
  11111111111111111111111111111116\
143
143
  33333333333333333333333333333333\
@@ -420,7 +420,6 @@ hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
420
420
  }
421
421
  break;
422
422
  case T_HASH:
423
-
424
423
  if (rb_cHash != rb_obj_class(parent->val)) {
425
424
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
426
425
  rb_funcall(parent->val, oj_replace_id, 1, value);
@@ -428,7 +427,7 @@ hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
428
427
  set_obj_ivar(parent, key, klen, value);
429
428
  }
430
429
  } else {
431
- if (3 <= klen && '#' == key[1] && T_ARRAY == rb_type(value)) {
430
+ if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
432
431
  long len = RARRAY_LEN(value);
433
432
  VALUE *a = RARRAY_PTR(value);
434
433
 
@@ -551,6 +550,7 @@ oj_object_parse(int argc, VALUE *argv, VALUE self) {
551
550
  struct _ParseInfo pi;
552
551
 
553
552
  pi.options = oj_default_options;
553
+ pi.handler = Qnil;
554
554
  oj_set_object_callbacks(&pi);
555
555
 
556
556
  if (T_STRING == rb_type(*argv)) {
@@ -565,6 +565,7 @@ oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
565
565
  struct _ParseInfo pi;
566
566
 
567
567
  pi.options = oj_default_options;
568
+ pi.handler = Qnil;
568
569
  oj_set_strict_callbacks(&pi);
569
570
  pi.end_hash = end_hash;
570
571
  pi.start_hash = start_hash;
@@ -58,7 +58,9 @@ ID oj_array_end_id;
58
58
  ID oj_array_start_id;
59
59
  ID oj_as_json_id;
60
60
  ID oj_error_id;
61
+ ID oj_file_id;
61
62
  ID oj_fileno_id;
63
+ ID oj_ftype_id;
62
64
  ID oj_hash_end_id;
63
65
  ID oj_hash_set_id;
64
66
  ID oj_hash_start_id;
@@ -71,6 +73,7 @@ ID oj_pos_id;
71
73
  ID oj_read_id;
72
74
  ID oj_readpartial_id;
73
75
  ID oj_replace_id;
76
+ ID oj_stat_id;
74
77
  ID oj_string_id;
75
78
  ID oj_to_hash_id;
76
79
  ID oj_to_json_id;
@@ -353,7 +356,7 @@ set_def_opts(VALUE self, VALUE opts) {
353
356
  } else if (ascii_sym == v) {
354
357
  oj_default_options.escape_mode = ASCIIEsc;
355
358
  } else {
356
- rb_raise(rb_eArgError, ":encoding must be :json, :rails, or :ascii.");
359
+ rb_raise(rb_eArgError, ":encoding must be :json, :xss_safe, or :ascii.");
357
360
  }
358
361
 
359
362
  v = rb_hash_lookup(opts, bigdecimal_load_sym);
@@ -715,6 +718,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
715
718
  }
716
719
  Check_Type(*argv, T_STRING);
717
720
  pi.options = oj_default_options;
721
+ pi.handler = Qnil;
718
722
  if (2 <= argc) {
719
723
  VALUE ropts = argv[1];
720
724
  VALUE v;
@@ -1951,7 +1955,9 @@ void Init_oj() {
1951
1955
  oj_array_start_id = rb_intern("array_start");
1952
1956
  oj_as_json_id = rb_intern("as_json");
1953
1957
  oj_error_id = rb_intern("error");
1958
+ oj_file_id = rb_intern("file?");
1954
1959
  oj_fileno_id = rb_intern("fileno");
1960
+ oj_ftype_id = rb_intern("ftype");
1955
1961
  oj_hash_end_id = rb_intern("hash_end");
1956
1962
  oj_hash_set_id = rb_intern("hash_set");
1957
1963
  oj_hash_start_id = rb_intern("hash_start");
@@ -1964,6 +1970,7 @@ void Init_oj() {
1964
1970
  oj_read_id = rb_intern("read");
1965
1971
  oj_readpartial_id = rb_intern("readpartial");
1966
1972
  oj_replace_id = rb_intern("replace");
1973
+ oj_stat_id = rb_intern("stat");
1967
1974
  oj_string_id = rb_intern("string");
1968
1975
  oj_to_hash_id = rb_intern("to_hash");
1969
1976
  oj_to_json_id = rb_intern("to_json");
@@ -255,7 +255,9 @@ extern ID oj_array_end_id;
255
255
  extern ID oj_array_start_id;
256
256
  extern ID oj_as_json_id;
257
257
  extern ID oj_error_id;
258
+ extern ID oj_file_id;
258
259
  extern ID oj_fileno_id;
260
+ extern ID oj_ftype_id;
259
261
  extern ID oj_hash_end_id;
260
262
  extern ID oj_hash_set_id;
261
263
  extern ID oj_hash_start_id;
@@ -268,6 +270,7 @@ extern ID oj_pos_id;
268
270
  extern ID oj_read_id;
269
271
  extern ID oj_readpartial_id;
270
272
  extern ID oj_replace_id;
273
+ extern ID oj_stat_id;
271
274
  extern ID oj_string_id;
272
275
  extern ID oj_to_hash_id;
273
276
  extern ID oj_to_json_id;
@@ -766,7 +766,6 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
766
766
  } else {
767
767
  pi->proc = Qundef;
768
768
  }
769
- pi->cbc = (void*)0;
770
769
  if (0 != json) {
771
770
  pi->json = json;
772
771
  pi->end = json + len;
@@ -778,17 +777,13 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
778
777
  } else {
779
778
  VALUE clas = rb_obj_class(input);
780
779
  volatile VALUE s;
781
- #if !IS_WINDOWS
782
- int fd;
783
- #endif
784
780
 
785
781
  if (oj_stringio_class == clas) {
786
782
  s = rb_funcall2(input, oj_string_id, 0, 0);
787
783
  oj_pi_set_input_str(pi, s);
788
784
  #if !IS_WINDOWS
789
- } else if (rb_respond_to(input, oj_fileno_id) &&
790
- Qnil != (s = rb_funcall(input, oj_fileno_id, 0)) &&
791
- 0 != (fd = FIX2INT(s))) {
785
+ } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
786
+ int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
792
787
  ssize_t cnt;
793
788
  size_t len = lseek(fd, 0, SEEK_END);
794
789
 
@@ -65,7 +65,7 @@ typedef struct _ParseInfo {
65
65
 
66
66
  struct _Err err;
67
67
  struct _Options options;
68
- void *cbc;
68
+ VALUE handler;
69
69
  struct _ValStack stack;
70
70
  CircArray circ_array;
71
71
  int expect_value;
@@ -55,6 +55,10 @@ static int read_from_str(Reader reader);
55
55
 
56
56
  void
57
57
  oj_reader_init(Reader reader, VALUE io, int fd) {
58
+ VALUE io_class = rb_obj_class(io);
59
+ VALUE stat;
60
+ VALUE ftype;
61
+
58
62
  reader->head = reader->base;
59
63
  *((char*)reader->head) = '\0';
60
64
  reader->end = reader->head + sizeof(reader->base) - BUF_PAD;
@@ -69,13 +73,13 @@ oj_reader_init(Reader reader, VALUE io, int fd) {
69
73
  if (0 != fd) {
70
74
  reader->read_func = read_from_fd;
71
75
  reader->fd = fd;
72
- } else if (rb_cString == rb_obj_class(io)) {
76
+ } else if (rb_cString == io_class) {
73
77
  reader->read_func = read_from_str;
74
78
  reader->in_str = StringValuePtr(io);
75
79
  reader->head = (char*)reader->in_str;
76
80
  reader->tail = reader->head;
77
81
  reader->read_end = reader->head + RSTRING_LEN(io);
78
- } else if (oj_stringio_class == rb_obj_class(io)) {
82
+ } else if (oj_stringio_class == io_class) {
79
83
  VALUE s = rb_funcall2(io, oj_string_id, 0, 0);
80
84
 
81
85
  reader->read_func = read_from_str;
@@ -83,30 +87,19 @@ oj_reader_init(Reader reader, VALUE io, int fd) {
83
87
  reader->head = (char*)reader->in_str;
84
88
  reader->tail = reader->head;
85
89
  reader->read_end = reader->head + RSTRING_LEN(s);
90
+ } else if (rb_cFile == io_class &&
91
+ Qnil != (stat = rb_funcall(io, oj_stat_id, 0)) &&
92
+ Qnil != (ftype = rb_funcall(stat, oj_ftype_id, 0)) &&
93
+ 0 == strcmp("file", StringValuePtr(ftype)) &&
94
+ 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) {
95
+ reader->read_func = read_from_fd;
96
+ reader->fd = FIX2INT(rb_funcall(io, oj_fileno_id, 0));
86
97
  } else if (rb_respond_to(io, oj_readpartial_id)) {
87
- VALUE rfd;
88
-
89
- if (rb_respond_to(io, oj_fileno_id) && Qnil != (rfd = rb_funcall(io, oj_fileno_id, 0)) &&
90
- rb_respond_to(io, oj_pos_id) && 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) {
91
-
92
- reader->read_func = read_from_fd;
93
- reader->fd = FIX2INT(rfd);
94
- } else {
95
- reader->read_func = read_from_io_partial;
96
- reader->io = io;
97
- }
98
+ reader->read_func = read_from_io_partial;
99
+ reader->io = io;
98
100
  } else if (rb_respond_to(io, oj_read_id)) {
99
- VALUE rfd;
100
-
101
- if (rb_respond_to(io, oj_fileno_id) && Qnil != (rfd = rb_funcall(io, oj_fileno_id, 0)) &&
102
- rb_respond_to(io, oj_pos_id) && 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) {
103
-
104
- reader->read_func = read_from_fd;
105
- reader->fd = FIX2INT(rfd);
106
- } else {
107
- reader->read_func = read_from_io;
108
- reader->io = io;
109
- }
101
+ reader->read_func = read_from_io;
102
+ reader->io = io;
110
103
  } else {
111
104
  rb_raise(rb_eException, "parser io argument must respond to readpartial() or read().\n");
112
105
  }
@@ -627,22 +627,6 @@ read_quoted_value(ParseInfo pi) {
627
627
  return value;
628
628
  }
629
629
 
630
- inline static int
631
- respond_to(VALUE obj, ID method) {
632
- #ifdef JRUBY_RUBY
633
- /* There is a bug in JRuby where rb_respond_to() returns true (1) even if
634
- * a method is private. */
635
- {
636
- VALUE args[1];
637
-
638
- *args = ID2SYM(method);
639
- return (Qtrue == rb_funcall2(obj, rb_intern("respond_to?"), 1, args));
640
- }
641
- #else
642
- return rb_respond_to(obj, method);
643
- #endif
644
- }
645
-
646
630
  static void
647
631
  saj_parse(VALUE handler, char *json) {
648
632
  volatile VALUE obj = Qnil;
@@ -675,12 +659,12 @@ saj_parse(VALUE handler, char *json) {
675
659
  }
676
660
  #endif
677
661
  pi.handler = handler;
678
- pi.has_hash_start = respond_to(handler, oj_hash_start_id);
679
- pi.has_hash_end = respond_to(handler, oj_hash_end_id);
680
- pi.has_array_start = respond_to(handler, oj_array_start_id);
681
- pi.has_array_end = respond_to(handler, oj_array_end_id);
682
- pi.has_add_value = respond_to(handler, oj_add_value_id);
683
- pi.has_error = respond_to(handler, oj_error_id);
662
+ pi.has_hash_start = rb_respond_to(handler, oj_hash_start_id);
663
+ pi.has_hash_end = rb_respond_to(handler, oj_hash_end_id);
664
+ pi.has_array_start = rb_respond_to(handler, oj_array_start_id);
665
+ pi.has_array_end = rb_respond_to(handler, oj_array_end_id);
666
+ pi.has_add_value = rb_respond_to(handler, oj_add_value_id);
667
+ pi.has_error = rb_respond_to(handler, oj_error_id);
684
668
  read_next(&pi, 0);
685
669
  next_non_white(&pi);
686
670
  if ('\0' != *pi.s) {
@@ -716,9 +700,6 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
716
700
  } else {
717
701
  VALUE clas = rb_obj_class(input);
718
702
  volatile VALUE s;
719
- #if !IS_WINDOWS
720
- int fd;
721
- #endif
722
703
 
723
704
  if (oj_stringio_class == clas) {
724
705
  s = rb_funcall2(input, oj_string_id, 0, 0);
@@ -726,9 +707,8 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
726
707
  json = ALLOC_N(char, len);
727
708
  strcpy(json, rb_string_value_cstr((VALUE*)&s));
728
709
  #if !IS_WINDOWS
729
- } else if (rb_respond_to(input, oj_fileno_id) &&
730
- Qnil != (s = rb_funcall(input, oj_fileno_id, 0)) &&
731
- 0 != (fd = FIX2INT(s))) {
710
+ } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
711
+ int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
732
712
  ssize_t cnt;
733
713
 
734
714
  len = lseek(fd, 0, SEEK_END);
@@ -39,22 +39,6 @@
39
39
  #include "parse.h"
40
40
  #include "encode.h"
41
41
 
42
- inline static int
43
- respond_to(VALUE obj, ID method) {
44
- #ifdef JRUBY_RUBY
45
- /* There is a bug in JRuby where rb_respond_to() returns true (1) even if
46
- * a method is private. */
47
- {
48
- VALUE args[1];
49
-
50
- *args = ID2SYM(method);
51
- return (Qtrue == rb_funcall2(obj, rb_intern("respond_to?"), 1, args));
52
- }
53
- #else
54
- return rb_respond_to(obj, method);
55
- #endif
56
- }
57
-
58
42
  static VALUE
59
43
  noop_start(ParseInfo pi) {
60
44
  return Qnil;
@@ -102,7 +86,7 @@ noop_array_append_value(ParseInfo pi, VALUE value) {
102
86
 
103
87
  static void
104
88
  add_value(ParseInfo pi, VALUE val) {
105
- rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, val);
89
+ rb_funcall(pi->handler, oj_add_value_id, 1, val);
106
90
  }
107
91
 
108
92
  static void
@@ -110,32 +94,32 @@ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
110
94
  volatile VALUE rstr = rb_str_new(str, len);
111
95
 
112
96
  rstr = oj_encode(rstr);
113
- rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, rstr);
97
+ rb_funcall(pi->handler, oj_add_value_id, 1, rstr);
114
98
  }
115
99
 
116
100
  static void
117
101
  add_num(ParseInfo pi, NumInfo ni) {
118
- rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, oj_num_as_value(ni));
102
+ rb_funcall(pi->handler, oj_add_value_id, 1, oj_num_as_value(ni));
119
103
  }
120
104
 
121
105
  static VALUE
122
106
  start_hash(ParseInfo pi) {
123
- return rb_funcall((VALUE)pi->cbc, oj_hash_start_id, 0);
107
+ return rb_funcall(pi->handler, oj_hash_start_id, 0);
124
108
  }
125
109
 
126
110
  static void
127
111
  end_hash(ParseInfo pi) {
128
- rb_funcall((VALUE)pi->cbc, oj_hash_end_id, 0);
112
+ rb_funcall(pi->handler, oj_hash_end_id, 0);
129
113
  }
130
114
 
131
115
  static VALUE
132
116
  start_array(ParseInfo pi) {
133
- return rb_funcall((VALUE)pi->cbc, oj_array_start_id, 0);
117
+ return rb_funcall(pi->handler, oj_array_start_id, 0);
134
118
  }
135
119
 
136
120
  static void
137
121
  end_array(ParseInfo pi) {
138
- rb_funcall((VALUE)pi->cbc, oj_array_end_id, 0);
122
+ rb_funcall(pi->handler, oj_array_end_id, 0);
139
123
  }
140
124
 
141
125
  static VALUE
@@ -154,17 +138,17 @@ hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_
154
138
  volatile VALUE rstr = rb_str_new(str, len);
155
139
 
156
140
  rstr = oj_encode(rstr);
157
- rb_funcall((VALUE)pi->cbc, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), rstr);
141
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), rstr);
158
142
  }
159
143
 
160
144
  static void
161
145
  hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
162
- 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));
146
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), oj_num_as_value(ni));
163
147
  }
164
148
 
165
149
  static void
166
150
  hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
167
- rb_funcall((VALUE)pi->cbc, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), value);
151
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), value);
168
152
  }
169
153
 
170
154
  static void
@@ -172,41 +156,24 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
172
156
  volatile VALUE rstr = rb_str_new(str, len);
173
157
 
174
158
  rstr = oj_encode(rstr);
175
- rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);
159
+ rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);
176
160
  }
177
161
 
178
162
  static void
179
163
  array_append_num(ParseInfo pi, NumInfo ni) {
180
- rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, oj_num_as_value(ni));
164
+ rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, oj_num_as_value(ni));
181
165
  }
182
166
 
183
167
  static void
184
168
  array_append_value(ParseInfo pi, VALUE value) {
185
- rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, value);
186
- }
187
-
188
- static VALUE
189
- protect_parse(VALUE pip) {
190
- oj_parse2((ParseInfo)pip);
191
-
192
- return Qnil;
169
+ rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, value);
193
170
  }
194
171
 
195
172
  VALUE
196
173
  oj_sc_parse(int argc, VALUE *argv, VALUE self) {
197
174
  struct _ParseInfo pi;
198
- char *buf = 0;
199
- VALUE input;
200
- VALUE handler;
201
- volatile VALUE wrapped_stack;
202
- int line = 0;
203
-
204
- if (argc < 2) {
205
- rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.");
206
- }
207
- handler = *argv;;
208
- input = argv[1];
209
- pi.json = 0;
175
+ VALUE input = argv[1];
176
+
210
177
  pi.options = oj_default_options;
211
178
  if (3 == argc) {
212
179
  oj_parse_options(argv[2], &pi.options);
@@ -216,13 +183,13 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
216
183
  } else {
217
184
  pi.proc = Qundef;
218
185
  }
219
- pi.cbc = (void*)handler;
186
+ pi.handler = *argv;
220
187
 
221
- pi.start_hash = respond_to(handler, oj_hash_start_id) ? start_hash : noop_start;
222
- pi.end_hash = respond_to(handler, oj_hash_end_id) ? end_hash : noop_end;
223
- pi.start_array = respond_to(handler, oj_array_start_id) ? start_array : noop_start;
224
- pi.end_array = respond_to(handler, oj_array_end_id) ? end_array : noop_end;
225
- if (respond_to(handler, oj_hash_set_id)) {
188
+ pi.start_hash = rb_respond_to(pi.handler, oj_hash_start_id) ? start_hash : noop_start;
189
+ pi.end_hash = rb_respond_to(pi.handler, oj_hash_end_id) ? end_hash : noop_end;
190
+ pi.start_array = rb_respond_to(pi.handler, oj_array_start_id) ? start_array : noop_start;
191
+ pi.end_array = rb_respond_to(pi.handler, oj_array_end_id) ? end_array : noop_end;
192
+ if (rb_respond_to(pi.handler, oj_hash_set_id)) {
226
193
  pi.hash_set_value = hash_set_value;
227
194
  pi.hash_set_cstr = hash_set_cstr;
228
195
  pi.hash_set_num = hash_set_num;
@@ -233,7 +200,7 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
233
200
  pi.hash_set_num = noop_hash_set_num;
234
201
  pi.expect_value = 0;
235
202
  }
236
- if (respond_to(handler, oj_array_append_id)) {
203
+ if (rb_respond_to(pi.handler, oj_array_append_id)) {
237
204
  pi.array_append_value = array_append_value;
238
205
  pi.array_append_cstr = array_append_cstr;
239
206
  pi.array_append_num = array_append_num;
@@ -244,7 +211,7 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
244
211
  pi.array_append_num = noop_array_append_num;
245
212
  pi.expect_value = 0;
246
213
  }
247
- if (respond_to(handler, oj_add_value_id)) {
214
+ if (rb_respond_to(pi.handler, oj_add_value_id)) {
248
215
  pi.add_cstr = add_cstr;
249
216
  pi.add_num = add_num;
250
217
  pi.add_value = add_value;
@@ -255,56 +222,10 @@ oj_sc_parse(int argc, VALUE *argv, VALUE self) {
255
222
  pi.add_value = noop_add_value;
256
223
  pi.expect_value = 0;
257
224
  }
258
- if (rb_type(input) == T_STRING) {
259
- oj_pi_set_input_str(&pi, input);
225
+
226
+ if (T_STRING == rb_type(input)) {
227
+ return oj_pi_parse(argc - 1, argv + 1, &pi, 0, 0, 1);
260
228
  } else {
261
- VALUE clas = rb_obj_class(input);
262
- volatile VALUE s;
263
- #if !IS_WINDOWS
264
- int fd;
265
- #endif
266
- if (oj_stringio_class == clas) {
267
- s = rb_funcall2(input, oj_string_id, 0, 0);
268
- oj_pi_set_input_str(&pi, s);
269
- #if !IS_WINDOWS
270
- // JRuby gets confused with what is the real fileno.
271
- } else if (rb_respond_to(input, oj_fileno_id) &&
272
- Qnil != (s = rb_funcall(input, oj_fileno_id, 0)) &&
273
- 0 != (fd = FIX2INT(s))) {
274
- ssize_t cnt;
275
- size_t len = lseek(fd, 0, SEEK_END);
276
-
277
- lseek(fd, 0, SEEK_SET);
278
- buf = ALLOC_N(char, len + 1);
279
- buf[len] = '\0';
280
- pi.json = buf;
281
- pi.end = buf + len;
282
- if (0 >= (cnt = read(fd, (char*)pi.json, len)) || cnt != (ssize_t)len) {
283
- if (0 != buf) {
284
- xfree(buf);
285
- }
286
- rb_raise(rb_eIOError, "failed to read from IO Object.");
287
- }
288
- #endif
289
- } else if (rb_respond_to(input, oj_read_id)) {
290
- s = rb_funcall2(input, oj_read_id, 0, 0);
291
- oj_pi_set_input_str(&pi, s);
292
- } else {
293
- rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
294
- }
295
- }
296
- wrapped_stack = oj_stack_init(&pi.stack);
297
- rb_protect(protect_parse, (VALUE)&pi, &line);
298
- DATA_PTR(wrapped_stack) = NULL;
299
- if (0 != buf) {
300
- xfree(buf);
229
+ return oj_pi_sparse(argc - 1, argv + 1, &pi, 0);
301
230
  }
302
- stack_cleanup(&pi.stack);
303
- if (0 != line) {
304
- rb_jump_tag(line);
305
- }
306
- if (err_has(&pi.err)) {
307
- oj_err_raise(&pi.err);
308
- }
309
- return Qnil;
310
231
  }