ox 1.9.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ox might be problematic. Click here for more details.

@@ -0,0 +1,116 @@
1
+ /* sax.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 __OX_SAX_H__
32
+ #define __OX_SAX_H__
33
+
34
+ #include "sax_buf.h"
35
+ #include "sax_has.h"
36
+ #include "sax_stack.h"
37
+ #include "sax_hint.h"
38
+
39
+ typedef struct _SaxOptions {
40
+ int symbolize;
41
+ int convert_special;
42
+ int smart;
43
+ } *SaxOptions;
44
+
45
+ typedef struct _SaxDrive {
46
+ struct _Buf buf;
47
+ struct _NStack stack; /* element name stack */
48
+ VALUE handler;
49
+ VALUE value_obj;
50
+ struct _SaxOptions options;
51
+ int err;
52
+ struct _Has has;
53
+ Hints hints;
54
+ #if HAS_ENCODING_SUPPORT
55
+ rb_encoding *encoding;
56
+ #elif HAS_PRIVATE_ENCODING
57
+ VALUE encoding;
58
+ #endif
59
+ } *SaxDrive;
60
+
61
+ extern void ox_sax_parse(VALUE handler, VALUE io, SaxOptions options);
62
+ extern void ox_sax_drive_cleanup(SaxDrive dr);
63
+ extern void ox_sax_drive_error(SaxDrive dr, const char *msg);
64
+ extern int ox_sax_collapse_special(SaxDrive dr, char *str, int line, int col);
65
+
66
+ extern VALUE ox_sax_value_class;
67
+
68
+ inline static VALUE
69
+ str2sym(SaxDrive dr, const char *str, char **strp) {
70
+ VALUE *slot;
71
+ VALUE sym;
72
+
73
+ if (dr->options.symbolize) {
74
+ if (Qundef == (sym = ox_cache_get(ox_symbol_cache, str, &slot, strp))) {
75
+ #if HAS_ENCODING_SUPPORT
76
+ if (0 != dr->encoding) {
77
+ VALUE rstr = rb_str_new2(str);
78
+
79
+ rb_enc_associate(rstr, dr->encoding);
80
+ sym = rb_funcall(rstr, ox_to_sym_id, 0);
81
+ } else {
82
+ sym = ID2SYM(rb_intern(str));
83
+ }
84
+ #elif HAS_PRIVATE_ENCODING
85
+ if (Qnil != dr->encoding) {
86
+ VALUE rstr = rb_str_new2(str);
87
+
88
+ rb_funcall(rstr, ox_force_encoding_id, 1, dr->encoding);
89
+ sym = rb_funcall(rstr, ox_to_sym_id, 0);
90
+ } else {
91
+ sym = ID2SYM(rb_intern(str));
92
+ }
93
+ #else
94
+ sym = ID2SYM(rb_intern(str));
95
+ #endif
96
+ *slot = sym;
97
+ }
98
+ } else {
99
+ sym = rb_str_new2(str);
100
+ #if HAS_ENCODING_SUPPORT
101
+ if (0 != dr->encoding) {
102
+ rb_enc_associate(sym, dr->encoding);
103
+ }
104
+ #elif HAS_PRIVATE_ENCODING
105
+ if (Qnil != dr->encoding) {
106
+ rb_funcall(sym, ox_force_encoding_id, 1, dr->encoding);
107
+ }
108
+ #endif
109
+ if (0 != strp) {
110
+ *strp = StringValuePtr(sym);
111
+ }
112
+ }
113
+ return sym;
114
+ }
115
+
116
+ #endif /* __OX_SAX_H__ */
@@ -0,0 +1,254 @@
1
+ /* sax_as.c
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
+ #include <stdlib.h>
32
+ #include <errno.h>
33
+ #include <stdio.h>
34
+ #include <strings.h>
35
+ #include <sys/types.h>
36
+ #if NEEDS_UIO
37
+ #include <sys/uio.h>
38
+ #endif
39
+ #include <unistd.h>
40
+ #include <time.h>
41
+
42
+ #include "ruby.h"
43
+ #include "ox.h"
44
+ #include "sax.h"
45
+
46
+ static VALUE
47
+ parse_double_time(const char *text) {
48
+ long v = 0;
49
+ long v2 = 0;
50
+ const char *dot = 0;
51
+ char c;
52
+
53
+ for (; '.' != *text; text++) {
54
+ c = *text;
55
+ if (c < '0' || '9' < c) {
56
+ return Qnil;
57
+ }
58
+ v = 10 * v + (long)(c - '0');
59
+ }
60
+ dot = text++;
61
+ for (; '\0' != *text && text - dot <= 6; text++) {
62
+ c = *text;
63
+ if (c < '0' || '9' < c) {
64
+ return Qnil;
65
+ }
66
+ v2 = 10 * v2 + (long)(c - '0');
67
+ }
68
+ for (; text - dot <= 9; text++) {
69
+ v2 *= 10;
70
+ }
71
+ #if HAS_NANO_TIME
72
+ return rb_time_nano_new(v, v2);
73
+ #else
74
+ return rb_time_new(v, v2 / 1000);
75
+ #endif
76
+ }
77
+
78
+ typedef struct _Tp {
79
+ int cnt;
80
+ char end;
81
+ char alt;
82
+ } *Tp;
83
+
84
+ static VALUE
85
+ parse_xsd_time(const char *text) {
86
+ long cargs[10];
87
+ long *cp = cargs;
88
+ long v;
89
+ int i;
90
+ char c = '\0';
91
+ struct _Tp tpa[10] = { { 4, '-', '-' },
92
+ { 2, '-', '-' },
93
+ { 2, 'T', ' ' },
94
+ { 2, ':', ':' },
95
+ { 2, ':', ':' },
96
+ { 2, '.', '.' },
97
+ { 9, '+', '-' },
98
+ { 2, ':', ':' },
99
+ { 2, '\0', '\0' },
100
+ { 0, '\0', '\0' } };
101
+ Tp tp = tpa;
102
+ struct tm tm;
103
+
104
+ memset(cargs, 0, sizeof(cargs));
105
+ for (; 0 != tp->cnt; tp++) {
106
+ for (i = tp->cnt, v = 0; 0 < i ; text++, i--) {
107
+ c = *text;
108
+ if (c < '0' || '9' < c) {
109
+ if ('\0' == c || tp->end == c || tp->alt == c) {
110
+ break;
111
+ }
112
+ return Qnil;
113
+ }
114
+ v = 10 * v + (long)(c - '0');
115
+ }
116
+ if ('\0' == c) {
117
+ break;
118
+ }
119
+ c = *text++;
120
+ if (tp->end != c && tp->alt != c) {
121
+ return Qnil;
122
+ }
123
+ *cp++ = v;
124
+ }
125
+ tm.tm_year = (int)cargs[0] - 1900;
126
+ tm.tm_mon = (int)cargs[1] - 1;
127
+ tm.tm_mday = (int)cargs[2];
128
+ tm.tm_hour = (int)cargs[3];
129
+ tm.tm_min = (int)cargs[4];
130
+ tm.tm_sec = (int)cargs[5];
131
+ #if HAS_NANO_TIME
132
+ return rb_time_nano_new(mktime(&tm), cargs[6]);
133
+ #else
134
+ return rb_time_new(mktime(&tm), cargs[6] / 1000);
135
+ #endif
136
+ }
137
+
138
+ static VALUE
139
+ sax_value_as_s(VALUE self) {
140
+ SaxDrive dr = DATA_PTR(self);
141
+ VALUE rs;
142
+
143
+ if ('\0' == *dr->buf.str) {
144
+ return Qnil;
145
+ }
146
+ if (dr->options.convert_special) {
147
+ ox_sax_collapse_special(dr, dr->buf.str, dr->buf.line, dr->buf.col);
148
+ }
149
+ rs = rb_str_new2(dr->buf.str);
150
+ #if HAS_ENCODING_SUPPORT
151
+ if (0 != dr->encoding) {
152
+ rb_enc_associate(rs, dr->encoding);
153
+ }
154
+ #elif HAS_PRIVATE_ENCODING
155
+ if (Qnil != dr->encoding) {
156
+ rb_funcall(rs, ox_force_encoding_id, 1, dr->encoding);
157
+ }
158
+ #endif
159
+ return rs;
160
+ }
161
+
162
+ static VALUE
163
+ sax_value_as_sym(VALUE self) {
164
+ SaxDrive dr = DATA_PTR(self);
165
+
166
+ if ('\0' == *dr->buf.str) {
167
+ return Qnil;
168
+ }
169
+ return str2sym(dr, dr->buf.str, 0);
170
+ }
171
+
172
+ static VALUE
173
+ sax_value_as_f(VALUE self) {
174
+ SaxDrive dr = DATA_PTR(self);
175
+
176
+ if ('\0' == *dr->buf.str) {
177
+ return Qnil;
178
+ }
179
+ return rb_float_new(strtod(dr->buf.str, 0));
180
+ }
181
+
182
+ static VALUE
183
+ sax_value_as_i(VALUE self) {
184
+ SaxDrive dr = DATA_PTR(self);
185
+ const char *s = dr->buf.str;
186
+ long n = 0;
187
+ int neg = 0;
188
+
189
+ if ('\0' == *s) {
190
+ return Qnil;
191
+ }
192
+ if ('-' == *s) {
193
+ neg = 1;
194
+ s++;
195
+ } else if ('+' == *s) {
196
+ s++;
197
+ }
198
+ for (; '\0' != *s; s++) {
199
+ if ('0' <= *s && *s <= '9') {
200
+ n = n * 10 + (*s - '0');
201
+ } else {
202
+ rb_raise(ox_arg_error_class, "Not a valid Fixnum.\n");
203
+ }
204
+ }
205
+ if (neg) {
206
+ n = -n;
207
+ }
208
+ return LONG2NUM(n);
209
+ }
210
+
211
+ static VALUE
212
+ sax_value_as_time(VALUE self) {
213
+ SaxDrive dr = DATA_PTR(self);
214
+ const char *str = dr->buf.str;
215
+ VALUE t;
216
+
217
+ if ('\0' == *str) {
218
+ return Qnil;
219
+ }
220
+ if (Qnil == (t = parse_double_time(str)) &&
221
+ Qnil == (t = parse_xsd_time(str))) {
222
+ VALUE args[1];
223
+
224
+ /*printf("**** time parse\n"); */
225
+ *args = rb_str_new2(str);
226
+ t = rb_funcall2(ox_time_class, ox_parse_id, 1, args);
227
+ }
228
+ return t;
229
+ }
230
+
231
+ static VALUE
232
+ sax_value_as_bool(VALUE self) {
233
+ return (0 == strcasecmp("true", ((SaxDrive)DATA_PTR(self))->buf.str)) ? Qtrue : Qfalse;
234
+ }
235
+
236
+ static VALUE
237
+ sax_value_empty(VALUE self) {
238
+ return ('\0' == *((SaxDrive)DATA_PTR(self))->buf.str) ? Qtrue : Qfalse;
239
+ }
240
+
241
+ void
242
+ ox_sax_define() {
243
+ VALUE sax_module = rb_const_get_at(Ox, rb_intern("Sax"));
244
+
245
+ ox_sax_value_class = rb_define_class_under(sax_module, "Value", rb_cObject);
246
+
247
+ rb_define_method(ox_sax_value_class, "as_s", sax_value_as_s, 0);
248
+ rb_define_method(ox_sax_value_class, "as_sym", sax_value_as_sym, 0);
249
+ rb_define_method(ox_sax_value_class, "as_i", sax_value_as_i, 0);
250
+ rb_define_method(ox_sax_value_class, "as_f", sax_value_as_f, 0);
251
+ rb_define_method(ox_sax_value_class, "as_time", sax_value_as_time, 0);
252
+ rb_define_method(ox_sax_value_class, "as_bool", sax_value_as_bool, 0);
253
+ rb_define_method(ox_sax_value_class, "empty?", sax_value_empty, 0);
254
+ }
@@ -0,0 +1,262 @@
1
+ /* sax_buf.c
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
+ #include <stdlib.h>
32
+ #include <errno.h>
33
+ #include <stdio.h>
34
+ #include <strings.h>
35
+ #include <sys/types.h>
36
+ #if NEEDS_UIO
37
+ #include <sys/uio.h>
38
+ #endif
39
+ #include <unistd.h>
40
+ #include <time.h>
41
+
42
+ #include "ruby.h"
43
+ #include "ox.h"
44
+ #include "sax.h"
45
+
46
+ static VALUE rescue_cb(VALUE rdr, VALUE err);
47
+ static VALUE io_cb(VALUE rdr);
48
+ static VALUE partial_io_cb(VALUE rdr);
49
+ static int read_from_io(Buf buf);
50
+ #ifndef JRUBY_RUBY
51
+ static int read_from_fd(Buf buf);
52
+ #endif
53
+ static int read_from_io_partial(Buf buf);
54
+ static int read_from_str(Buf buf);
55
+
56
+ void
57
+ ox_sax_buf_init(Buf buf, VALUE io) {
58
+ if (ox_stringio_class == rb_obj_class(io)) {
59
+ VALUE s = rb_funcall2(io, ox_string_id, 0, 0);
60
+
61
+ buf->read_func = read_from_str;
62
+ buf->in_str = StringValuePtr(s);
63
+ } else if (rb_respond_to(io, ox_readpartial_id)) {
64
+ #ifdef JRUBY_RUBY
65
+ buf->read_func = read_from_io_partial;
66
+ buf->io = io;
67
+ #else
68
+ VALUE rfd;
69
+
70
+ if (rb_respond_to(io, ox_fileno_id) && Qnil != (rfd = rb_funcall(io, ox_fileno_id, 0))) {
71
+ buf->read_func = read_from_fd;
72
+ buf->fd = FIX2INT(rfd);
73
+ } else {
74
+ buf->read_func = read_from_io_partial;
75
+ buf->io = io;
76
+ }
77
+ #endif
78
+ } else if (rb_respond_to(io, ox_read_id)) {
79
+ #ifdef JRUBY_RUBY
80
+ buf->read_func = read_from_io;
81
+ buf->io = io;
82
+ #else
83
+ VALUE rfd;
84
+
85
+ if (rb_respond_to(io, ox_fileno_id) && Qnil != (rfd = rb_funcall(io, ox_fileno_id, 0))) {
86
+ buf->read_func = read_from_fd;
87
+ buf->fd = FIX2INT(rfd);
88
+ } else {
89
+ buf->read_func = read_from_io;
90
+ buf->io = io;
91
+ }
92
+ #endif
93
+ } else {
94
+ rb_raise(ox_arg_error_class, "sax_parser io argument must respond to readpartial() or read().\n");
95
+ }
96
+ buf->head = buf->base;
97
+ *buf->head = '\0';
98
+ buf->end = buf->head + sizeof(buf->base) - 1; /* 1 less to make debugging easier */
99
+ buf->tail = buf->head;
100
+ buf->read_end = buf->head;
101
+ buf->pro = 0;
102
+ buf->str = 0;
103
+ buf->line = 1;
104
+ buf->col = 0;
105
+ buf->pro_line = 1;
106
+ buf->pro_col = 0;
107
+ buf->dr = 0;
108
+ }
109
+
110
+ int
111
+ ox_sax_buf_read(Buf buf) {
112
+ int err;
113
+ size_t shift = 0;
114
+
115
+ if (buf->head < buf->tail) {
116
+ if (0 == buf->pro) {
117
+ shift = buf->tail - buf->head;
118
+ } else {
119
+ shift = buf->pro - buf->head;
120
+ }
121
+ /*printf("\n*** shift: %lu\n", shift); */
122
+ if (0 == shift) { /* no space left so allocate more */
123
+ char *old = buf->head;
124
+ size_t size = buf->end - buf->head;
125
+
126
+ if (buf->head == buf->base) {
127
+ buf->head = ALLOC_N(char, size * 2);
128
+ memcpy(buf->head, old, size);
129
+ } else {
130
+ REALLOC_N(buf->head, char, size * 2);
131
+ }
132
+ buf->end = buf->head + size * 2;
133
+ buf->tail = buf->head + (buf->tail - old);
134
+ buf->read_end = buf->head + (buf->read_end - old);
135
+ if (0 != buf->pro) {
136
+ buf->pro = buf->head + (buf->pro - old);
137
+ }
138
+ if (0 != buf->str) {
139
+ buf->str = buf->head + (buf->str - old);
140
+ }
141
+ } else {
142
+ memmove(buf->head, buf->head + shift, buf->read_end - (buf->head + shift));
143
+ buf->tail -= shift;
144
+ buf->read_end -= shift;
145
+ if (0 != buf->pro) {
146
+ buf->pro -= shift;
147
+ }
148
+ if (0 != buf->str) {
149
+ buf->str -= shift;
150
+ }
151
+ }
152
+ }
153
+ err = buf->read_func(buf);
154
+ *buf->read_end = '\0';
155
+
156
+ return err;
157
+ }
158
+
159
+ static VALUE
160
+ rescue_cb(VALUE rbuf, VALUE err) {
161
+ #ifndef JRUBY_RUBY
162
+ /* JRuby seems to play by a different set if rules. It passes in an Fixnum
163
+ * instead of an error like other Rubies. For now assume all errors are
164
+ * EOF and deal with the results further down the line. */
165
+ #if (defined(RUBINIUS_RUBY) || (1 == RUBY_VERSION_MAJOR && 8 == RUBY_VERSION_MINOR))
166
+ if (rb_obj_class(err) != rb_eTypeError) {
167
+ #else
168
+ if (rb_obj_class(err) != rb_eEOFError) {
169
+ #endif
170
+ Buf buf = (Buf)rbuf;
171
+
172
+ ox_sax_drive_cleanup(buf->dr);
173
+ rb_raise(err, "at line %d, column %d\n", buf->line, buf->col);
174
+ }
175
+ #endif
176
+ return Qfalse;
177
+ }
178
+
179
+ static VALUE
180
+ partial_io_cb(VALUE rbuf) {
181
+ Buf buf = (Buf)rbuf;
182
+ VALUE args[1];
183
+ VALUE rstr;
184
+ char *str;
185
+ size_t cnt;
186
+
187
+ args[0] = ULONG2NUM(buf->end - buf->tail);
188
+ rstr = rb_funcall2(buf->io, ox_readpartial_id, 1, args);
189
+ str = StringValuePtr(rstr);
190
+ cnt = strlen(str);
191
+ /*printf("*** read %lu bytes, str: '%s'\n", cnt, str); */
192
+ strcpy(buf->tail, str);
193
+ buf->read_end = buf->tail + cnt;
194
+
195
+ return Qtrue;
196
+ }
197
+
198
+ static VALUE
199
+ io_cb(VALUE rbuf) {
200
+ Buf buf = (Buf)rbuf;
201
+ VALUE args[1];
202
+ VALUE rstr;
203
+ char *str;
204
+ size_t cnt;
205
+
206
+ args[0] = ULONG2NUM(buf->end - buf->tail);
207
+ rstr = rb_funcall2(buf->io, ox_read_id, 1, args);
208
+ str = StringValuePtr(rstr);
209
+ cnt = strlen(str);
210
+ /*printf("*** read %lu bytes, str: '%s'\n", cnt, str); */
211
+ strcpy(buf->tail, str);
212
+ buf->read_end = buf->tail + cnt;
213
+
214
+ return Qtrue;
215
+ }
216
+
217
+ static int
218
+ read_from_io_partial(Buf buf) {
219
+ return (Qfalse == rb_rescue(partial_io_cb, (VALUE)buf, rescue_cb, (VALUE)buf));
220
+ }
221
+
222
+ static int
223
+ read_from_io(Buf buf) {
224
+ return (Qfalse == rb_rescue(io_cb, (VALUE)buf, rescue_cb, (VALUE)buf));
225
+ }
226
+
227
+ #ifndef JRUBY_RUBY
228
+ static int
229
+ read_from_fd(Buf buf) {
230
+ ssize_t cnt;
231
+ size_t max = buf->end - buf->tail;
232
+
233
+ cnt = read(buf->fd, buf->tail, max);
234
+ if (cnt < 0) {
235
+ ox_sax_drive_error(buf->dr, "failed to read from file");
236
+ return -1;
237
+ } else if (0 != cnt) {
238
+ buf->read_end = buf->tail + cnt;
239
+ }
240
+ return 0;
241
+ }
242
+ #endif
243
+
244
+ static int
245
+ read_from_str(Buf buf) {
246
+ size_t max = buf->end - buf->tail - 1;
247
+ char *s;
248
+ long cnt;
249
+
250
+ if ('\0' == *buf->in_str) {
251
+ /* done */
252
+ return -1;
253
+ }
254
+ s = stpncpy(buf->tail, buf->in_str, max);
255
+ *s = '\0';
256
+ cnt = s - buf->tail;
257
+ buf->in_str += cnt;
258
+ buf->read_end = buf->tail + cnt;
259
+
260
+ return 0;
261
+ }
262
+