File Coverage

src/xh_reader.c
Criterion Covered Total %
statement 213 324 65.7
branch 75 166 45.1
condition n/a
subroutine n/a
pod n/a
total 288 490 58.7


line stmt bran cond sub pod time code
1             #include "xh_config.h"
2             #include "xh_core.h"
3              
4             static void
5 72           xh_common_reader_init(xh_reader_t *reader, SV *XH_UNUSED(input), xh_char_t *encoding, size_t buf_size)
6             {
7 72           reader->buf_size = buf_size;
8              
9 72 100         if (encoding[0] != '\0')
10 4           reader->switch_encoding(reader, encoding, NULL, NULL);
11 72           }
12              
13             static void
14 72           xh_common_reader_destroy(xh_reader_t *reader)
15             {
16             #ifdef XH_HAVE_ENCODER
17 72           xh_buffer_destroy(&reader->enc_buf);
18 72 100         if (reader->encoder != NULL)
19 5           xh_encoder_destroy(reader->encoder);
20             #endif
21 72           }
22              
23             static void
24 30           xh_common_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
25             {
26             xh_log_debug1("switch encoding to '%s'", encoding);
27              
28 30 100         if (xh_strcasecmp(encoding, XH_INTERNAL_ENCODING) == 0) {
29             #ifdef XH_HAVE_ENCODER
30 25 50         if (reader->encoder != NULL) {
31 0           croak("Can't to switch encoding from %s to %s", reader->encoder->fromcode, encoding);
32             }
33             #endif
34             }
35             else {
36             #ifdef XH_HAVE_ENCODER
37 5 50         if (reader->encoder == NULL) {
38             /* create encoder */
39             xh_log_debug1("create a new encoder: %s", encoding);
40              
41 5           reader->encoder = xh_encoder_create(XH_CHAR_CAST XH_INTERNAL_ENCODING, encoding);
42 5 50         if (reader->encoder == NULL) {
43 0           croak("Can't create encoder for '%s'", encoding);
44             }
45              
46 5           xh_buffer_init(&reader->enc_buf, reader->buf_size);
47              
48 5 100         if (len != NULL && *len > 0) {
    50          
49 2           reader->fake_read_pos = *buf;
50 2           reader->fake_read_len = *len;
51 2           *len = 0;
52             }
53             }
54 0 0         else if (xh_strcasecmp(encoding, reader->encoder->fromcode) != 0) {
55 0           croak("Can't to switch encoding from %s to %s", reader->encoder->fromcode, encoding);
56             }
57             #else
58             croak("Can't create encoder for '%s'", encoding);
59             #endif
60             }
61 30           }
62              
63             static void
64 59           xh_string_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
65             {
66             STRLEN len;
67             xh_char_t *str;
68              
69 59           str = XH_CHAR_CAST SvPV(input, len);
70 59           reader->str = str;
71 59           reader->len = (size_t) len;
72              
73 59           reader->main_buf.start = reader->main_buf.cur = str;
74 59           reader->main_buf.end = str + len;
75              
76 59           xh_common_reader_init(reader, input, encoding, buf_size);
77 59           }
78              
79             static size_t
80 122           xh_string_reader_read(xh_reader_t *reader, xh_char_t **buf, xh_char_t *XH_UNUSED(preserve), size_t *off)
81             {
82             size_t len;
83             xh_buffer_t *main_buf;
84              
85 122           *off = 0;
86 122           main_buf = &reader->main_buf;
87              
88 122           *buf = xh_buffer_pos(main_buf);
89 122           len = xh_buffer_avail(main_buf);
90              
91 122           xh_buffer_seek_eof(main_buf);
92              
93 122           return len;
94             }
95              
96             #ifdef XH_HAVE_ENCODER
97             static size_t
98 10           xh_string_reader_read_with_encoding(xh_reader_t *reader, xh_char_t **buf, xh_char_t *preserve, size_t *off)
99             {
100             xh_char_t *old_buf_addr;
101             size_t src_left, dst_left;
102             xh_buffer_t *main_buf, *enc_buf;
103              
104 10           *off = 0;
105 10           main_buf = &reader->main_buf;
106 10           enc_buf = &reader->enc_buf;
107              
108             xh_log_debug4("enc_buf: %p[%.*s] len: %lu", enc_buf->start, enc_buf->cur - enc_buf->start, enc_buf->cur, enc_buf->cur - enc_buf->start);
109              
110             xh_log_debug1("preserve data: %p", preserve);
111 10 100         if (preserve == NULL) {
112 5           xh_buffer_seek_top(enc_buf);
113             }
114             else {
115 5           *off = preserve - enc_buf->start;
116             xh_log_debug1("off: %lu", *off);
117 5 50         if (*off) {
118             xh_log_debug3("memmove dest: %p src %p size: %lu", enc_buf->start, preserve, enc_buf->end - preserve);
119 5           xh_memmove(enc_buf->start, preserve, enc_buf->end - preserve);
120             }
121 5           enc_buf->cur -= *off;
122             }
123              
124 10           old_buf_addr = xh_buffer_start(enc_buf);
125 10           xh_buffer_grow50(enc_buf);
126              
127 10 100         if (preserve != NULL && xh_buffer_start(enc_buf) != old_buf_addr) {
    50          
128 0           *off += old_buf_addr - xh_buffer_start(enc_buf);
129             }
130              
131 10           *buf = xh_buffer_pos(enc_buf);
132              
133 10 50         while (enc_buf->cur < enc_buf->end) {
134 10 100         if (reader->fake_read_pos != NULL) {
135 2           main_buf->cur = reader->fake_read_pos;
136 2           reader->fake_read_pos = NULL;
137 2           reader->fake_read_len = 0;
138             }
139              
140             xh_log_debug2("main buf cur: %p end: %p", main_buf->cur, main_buf->end);
141 10           src_left = xh_buffer_avail(main_buf);
142 10 100         if (src_left == 0 && reader->encoder->state == XH_ENC_OK) {
    50          
143 5 50         if (main_buf->cur == main_buf->end)
144 5           break;
145 0           croak("Truncate char found");
146             }
147              
148 5           dst_left = xh_buffer_avail(enc_buf);
149              
150             xh_log_debug4("main_buf: %.*s src_left: %lu dst_left: %lu", src_left, main_buf->cur, src_left, dst_left);
151              
152 5           xh_encoder_encode_string(reader->encoder, &main_buf->cur, &src_left, &enc_buf->cur, &dst_left);
153              
154             xh_log_debug3("enc_buf: %.*s len: %lu", enc_buf->cur - enc_buf->start, enc_buf->start, enc_buf->cur - enc_buf->start);
155              
156 5 50         switch (reader->encoder->state) {
157 0           case XH_ENC_TRUNCATED_CHAR_FOUND:
158 0 0         if (src_left == 0)
159 0           croak("Truncated char found but buffer is empty");
160 0           break;
161 5           case XH_ENC_BUFFER_OVERFLOW:
162             default:
163 5           goto DONE;
164             }
165             }
166              
167 0           DONE:
168 10           dst_left = enc_buf->cur - *buf;
169             xh_log_debug4("enc_buf: %p[%.*s] len: %lu", enc_buf->start, dst_left, enc_buf->cur, dst_left);
170              
171 10           return dst_left;
172             }
173             #endif /* XH_HAVE_ENCODER */
174              
175             static void
176 28           xh_string_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
177             {
178              
179 28           xh_common_reader_switch_encoding(reader, encoding, buf, len);
180              
181             #ifdef XH_HAVE_ENCODER
182 56           reader->read = reader->encoder == NULL
183             ? xh_string_reader_read
184 28 100         : xh_string_reader_read_with_encoding;
185             #endif
186 28           }
187              
188             static void
189 59           xh_string_reader_destroy(xh_reader_t *reader)
190             {
191 59           xh_common_reader_destroy(reader);
192 59           }
193              
194             #ifdef XH_HAVE_MMAP
195             static void
196 11           xh_mmaped_file_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
197             {
198             struct stat sb;
199              
200 11           reader->file = XH_CHAR_CAST SvPV_nolen(input);
201              
202             xh_log_debug1("open file: %s", reader->file);
203              
204 11           reader->fd = open((const char *) reader->file, O_RDONLY);
205 11 50         if (reader->fd == -1) {
206 0           croak("Can't open file '%s': %s", reader->file, strerror(errno));
207             }
208              
209 11 50         if (fstat(reader->fd, &sb) == -1) {
210 0           croak("Can't get stat of file '%s': %s", reader->file, strerror(errno));
211             }
212              
213             xh_log_debug1("file size: %lu", sb.st_size);
214              
215 11 50         if (sb.st_size == 0) {
216 0           croak("File '%s' is empty", reader->file);
217             }
218 11           reader->len = sb.st_size;
219              
220             #ifdef WIN32
221             reader->fh = (HANDLE) _get_osfhandle(reader->fd);
222             if (reader->fh == INVALID_HANDLE_VALUE) {
223             croak("Can't get file handle of file '%s'", reader->file);
224             }
225              
226             xh_log_debug1("create mapping for file %s", reader->file);
227             reader->fm = CreateFileMapping(reader->fh, NULL, PAGE_READONLY, 0, 0, NULL);
228             if (reader->fm == NULL) {
229             croak("Can't create file mapping of file '%s'", reader->file);
230             }
231              
232             xh_log_debug1("create map view for file %s", reader->file);
233             reader->str = XH_CHAR_CAST MapViewOfFile(reader->fm, FILE_MAP_READ, 0, 0, reader->len);
234             if (reader->str == NULL) {
235             croak("Can't create map view of file '%s'", reader->file);
236             }
237             #else
238             xh_log_debug1("mmap file %s", reader->file);
239 11           reader->str = XH_CHAR_CAST mmap((caddr_t) 0, reader->len, PROT_READ, MAP_PRIVATE, reader->fd, 0);
240 11 50         if ((caddr_t) reader->str == (caddr_t) (-1)) {
241 0           croak("Can't create map of file '%s': %s", reader->file, strerror(errno));
242             }
243             #endif
244              
245 11           reader->main_buf.start = reader->main_buf.cur = reader->str;
246 11           reader->main_buf.end = reader->str + reader->len;
247              
248 11           xh_common_reader_init(reader, input, encoding, buf_size);
249 11           }
250              
251             static void
252 11           xh_mmaped_file_reader_destroy(xh_reader_t *reader)
253             {
254 11           xh_common_reader_destroy(reader);
255              
256 11 50         if (reader->fd == -1) return;
257              
258             #ifdef WIN32
259             xh_log_debug1("unmap view of file %s", reader->file);
260             UnmapViewOfFile(reader->str);
261             xh_log_debug1("close handle of file %s", reader->file);
262             CloseHandle(reader->fm);
263             #else
264             xh_log_debug1("munmap file %s", reader->file);
265 11 50         if (munmap(reader->str, reader->len) == -1) {
266 0           croak("Can't munmap file '%s': %s", reader->file, strerror(errno));
267             }
268             #endif
269              
270             xh_log_debug1("close file %s", reader->file);
271 11 50         if (close(reader->fd) == -1) {
272 0           croak("Can't close file '%s': %s", reader->file, strerror(errno));
273             }
274             }
275             #else
276             static void
277             xh_file_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
278             {
279             reader->file = XH_CHAR_CAST SvPV_nolen(input);
280              
281             xh_log_debug1("open file: %s", reader->file);
282              
283             reader->fd = open((char *) reader->file, O_RDONLY);
284             if (reader->fd == -1) {
285             croak("Can't open file '%s': %s", reader->file, strerror(errno));
286             }
287              
288             xh_buffer_init(&reader->main_buf, buf_size);
289              
290             xh_common_reader_init(reader, input, encoding, buf_size);
291             }
292              
293             static void
294             xh_file_reader_destroy(xh_reader_t *reader)
295             {
296             xh_common_reader_destroy(reader);
297              
298             if (reader->main_buf.start != NULL)
299             free(reader->main_buf.start);
300              
301             if (close(reader->fd) == -1) {
302             croak("Can't close file '%s': %s", reader->file, strerror(errno));
303             }
304             }
305             #endif /* XH_HAVE_MMAP */
306              
307             static size_t
308 2           xh_file_reader_read(xh_reader_t *reader, xh_char_t **buf, xh_char_t *preserve, size_t *off)
309             {
310             xh_char_t *old_buf_addr;
311             size_t len;
312             xh_buffer_t *main_buf;
313              
314 2           main_buf = &reader->main_buf;
315 2           *off = 0;
316              
317             xh_log_debug1("read preserve: %p", preserve);
318 2 100         if (preserve == NULL) {
319 1           main_buf->cur = main_buf->start;
320             }
321             else {
322 1           *off = preserve - main_buf->start;
323             xh_log_debug1("off: %lu", *off);
324 1 50         if (*off) {
325             xh_log_debug3("memmove dest: %p src %p size: %lu", main_buf->start, preserve, main_buf->end - preserve);
326 1           xh_memmove(main_buf->start, preserve, main_buf->end - preserve);
327             }
328 1           main_buf->cur -= *off;
329             xh_log_debug1("read cur: %p", main_buf->cur);
330             }
331              
332 2           old_buf_addr = main_buf->start;
333              
334 2           xh_buffer_grow50(main_buf);
335              
336 2 100         if (preserve != NULL && main_buf->start != old_buf_addr) {
    50          
337 0           *off += old_buf_addr - main_buf->start;
338             }
339              
340 2           len = read(reader->fd, main_buf->cur, xh_buffer_avail(main_buf));
341 2           *buf = main_buf->cur;
342 2 50         if (len == (size_t) (-1)) {
343 0           croak("Failed to read file");
344             }
345 2           main_buf->cur += len;
346              
347 2           return len;
348             }
349              
350             #ifdef XH_HAVE_ENCODER
351             static size_t
352 0           xh_file_reader_read_with_encoding(xh_reader_t *reader, xh_char_t **buf, xh_char_t *preserve, size_t *off)
353             {
354             xh_char_t *old_buf_addr;
355             size_t src_left, dst_left;
356             xh_buffer_t *main_buf, *enc_buf;
357              
358 0           *off = 0;
359 0           main_buf = &reader->main_buf;
360 0           enc_buf = &reader->enc_buf;
361              
362             xh_log_debug4("enc_buf: %p[%.*s] len: %lu", enc_buf->start, enc_buf->cur - enc_buf->start, enc_buf->cur, enc_buf->cur - enc_buf->start);
363              
364             xh_log_debug1("preserve data: %p", preserve);
365 0 0         if (preserve == NULL) {
366 0           xh_buffer_seek_top(enc_buf);
367             }
368             else {
369 0           *off = preserve - enc_buf->start;
370             xh_log_debug1("off: %lu", *off);
371 0 0         if (*off) {
372             xh_log_debug3("memmove dest: %p src %p size: %lu", enc_buf->start, preserve, enc_buf->end - preserve);
373 0           xh_memmove(enc_buf->start, preserve, enc_buf->end - preserve);
374             }
375 0           enc_buf->cur -= *off;
376             }
377              
378 0           old_buf_addr = enc_buf->start;
379 0           xh_buffer_grow50(enc_buf);
380              
381 0 0         if (preserve != NULL && enc_buf->start != old_buf_addr) {
    0          
382 0           *off += old_buf_addr - enc_buf->start;
383             }
384              
385 0           *buf = xh_buffer_pos(enc_buf);
386              
387 0 0         while (enc_buf->cur < enc_buf->end) {
388 0           xh_buffer_grow50(main_buf);
389              
390 0 0         if (reader->fake_read_pos == NULL) {
391 0           src_left = read(reader->fd, xh_buffer_pos(main_buf), xh_buffer_avail(main_buf));
392             }
393             else {
394 0           main_buf->cur = reader->fake_read_pos;
395 0           src_left = reader->fake_read_len;
396 0           reader->fake_read_pos = NULL;
397 0           reader->fake_read_len = 0;
398             }
399 0 0         if (src_left == 0) {
400 0 0         if (main_buf->cur == main_buf->end)
401 0           break;
402 0           croak("Truncate char found");
403             }
404 0 0         if (src_left == (size_t) (-1))
405 0           croak("Failed to read file");
406              
407 0           dst_left = xh_buffer_avail(enc_buf);
408              
409             xh_log_debug4("main_buf: %.*s src_left: %lu dst_left: %lu", src_left, main_buf->cur, src_left, dst_left);
410              
411 0           xh_encoder_encode_string(reader->encoder, &main_buf->cur, &src_left, &enc_buf->cur, &dst_left);
412              
413             xh_log_debug3("enc_buf: %.*s len: %lu", enc_buf->cur - enc_buf->start, enc_buf->start, enc_buf->cur - enc_buf->start);
414              
415 0 0         switch (reader->encoder->state) {
416 0           case XH_ENC_TRUNCATED_CHAR_FOUND:
417 0 0         if (src_left == 0)
418 0           croak("Truncated char found but buffer is empty");
419 0           xh_memmove(main_buf->start, main_buf->cur, src_left);
420 0           main_buf->cur = main_buf->start + src_left;
421 0           break;
422 0           case XH_ENC_BUFFER_OVERFLOW:
423             default:
424 0           xh_buffer_seek_top(main_buf);
425 0           goto DONE;
426             }
427             }
428              
429 0           DONE:
430 0           dst_left = enc_buf->cur - *buf;
431             xh_log_debug4("enc_buf: %p[%.*s] len: %lu", enc_buf->start, dst_left, enc_buf->cur, dst_left);
432              
433 0           return dst_left;
434             }
435             #endif /* XH_HAVE_ENCODER */
436              
437             static void
438 1           xh_file_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
439             {
440 1           xh_common_reader_switch_encoding(reader, encoding, buf, len);
441              
442             #ifdef XH_HAVE_ENCODER
443 2           reader->read = reader->encoder == NULL
444             ? xh_file_reader_read
445 1 50         : xh_file_reader_read_with_encoding;
446             #endif
447 1           }
448              
449             static void
450 1           xh_perl_io_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
451             {
452 1           reader->fd = PerlIO_fileno(reader->perl_io);
453              
454 1           xh_buffer_init(&reader->main_buf, buf_size);
455              
456 1           xh_common_reader_init(reader, input, encoding, buf_size);
457 1           }
458              
459             static void
460 1           xh_perl_io_reader_destroy(xh_reader_t *reader)
461             {
462 1           xh_common_reader_destroy(reader);
463              
464 1 50         if (reader->main_buf.start != NULL)
465 1           free(reader->main_buf.start);
466 1           }
467              
468             static size_t
469 6           xh_perl_obj_read(SV *obj, SV *buf, size_t count, size_t offset)
470             {
471             int nparam;
472 6           size_t len = 0;
473              
474 6           dSP;
475              
476 6           ENTER;
477 6           SAVETMPS;
478              
479 6 50         PUSHMARK(SP);
480 6 50         XPUSHs(obj);
481 6 50         XPUSHs(buf);
482 6 50         XPUSHs(sv_2mortal(newSViv(count)));
483 6 50         XPUSHs(sv_2mortal(newSViv(offset)));
484 6           PUTBACK;
485              
486 6           nparam = call_method("READ", G_SCALAR);
487              
488 6           SPAGAIN;
489              
490 6 50         if (nparam) {
491 6           len = POPi;
492             }
493             else {
494 0           len = 0;
495             }
496              
497 6 50         FREETMPS;
498 6           LEAVE;
499              
500 6           return len;
501             }
502              
503             static void
504 1           xh_perl_obj_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
505             {
506 1           xh_perl_buffer_init(&reader->perl_buf, buf_size);
507              
508 1           xh_common_reader_init(reader, input, encoding, buf_size);
509 1           }
510              
511             static void
512 1           xh_perl_obj_reader_destroy(xh_reader_t *reader)
513             {
514 1           xh_common_reader_destroy(reader);
515              
516 1 50         if (reader->perl_buf.scalar != NULL)
517 1           SvREFCNT_dec(reader->perl_buf.scalar);
518 1           }
519              
520             static size_t
521 6           xh_perl_obj_reader_read(xh_reader_t *reader, xh_char_t **buf, xh_char_t *preserve, size_t *off)
522             {
523             xh_char_t *old_buf_addr;
524             size_t len;
525             xh_perl_buffer_t *main_buf;
526              
527 6           main_buf = &reader->perl_buf;
528 6           *off = 0;
529              
530             xh_log_debug1("read preserve: %p", preserve);
531 6 100         if (preserve == NULL) {
532 4           main_buf->cur = main_buf->start;
533             }
534             else {
535 2           *off = preserve - main_buf->start;
536             xh_log_debug1("off: %lu", *off);
537 2 50         if (*off) {
538             xh_log_debug3("memmove dest: %p src %p size: %lu", main_buf->start, preserve, main_buf->end - preserve);
539 2           xh_memmove(main_buf->start, preserve, main_buf->end - preserve);
540             }
541 2           main_buf->cur -= *off;
542             xh_log_debug1("read cur: %p", main_buf->cur);
543             }
544              
545             {
546 6           old_buf_addr = main_buf->start;
547              
548 6           xh_perl_buffer_grow50(main_buf);
549              
550 6           len = xh_perl_obj_read(reader->perl_obj, main_buf->scalar, xh_perl_buffer_avail(main_buf), main_buf->cur - main_buf->start);
551              
552 6           xh_perl_buffer_sync(main_buf);
553              
554 6 100         if (preserve != NULL && main_buf->start != old_buf_addr) {
    50          
555 2           *off += old_buf_addr - main_buf->start;
556             }
557             }
558              
559 6           *buf = main_buf->cur;
560 6 50         if (len == (size_t) (-1)) {
561 0           croak("Failed to read file");
562             }
563 6           main_buf->cur += len;
564              
565 6           return len;
566             }
567              
568             #ifdef XH_HAVE_ENCODER
569             static size_t
570 0           xh_perl_obj_reader_read_with_encoding(xh_reader_t *reader, xh_char_t **buf, xh_char_t *preserve, size_t *off)
571             {
572             xh_char_t *old_buf_addr;
573             size_t src_left, dst_left;
574             xh_perl_buffer_t *main_buf;
575             xh_buffer_t *enc_buf;
576              
577 0           *off = 0;
578 0           main_buf = &reader->perl_buf;
579 0           enc_buf = &reader->enc_buf;
580              
581             xh_log_debug4("enc_buf: %p[%.*s] len: %lu", enc_buf->start, enc_buf->cur - enc_buf->start, enc_buf->cur, enc_buf->cur - enc_buf->start);
582              
583             xh_log_debug1("preserve data: %p", preserve);
584 0 0         if (preserve == NULL) {
585 0           xh_buffer_seek_top(enc_buf);
586             }
587             else {
588 0           *off = preserve - enc_buf->start;
589             xh_log_debug1("off: %lu", *off);
590 0 0         if (*off) {
591             xh_log_debug3("memmove dest: %p src %p size: %lu", enc_buf->start, preserve, enc_buf->end - preserve);
592 0           xh_memmove(enc_buf->start, preserve, enc_buf->end - preserve);
593             }
594 0           enc_buf->cur -= *off;
595             }
596              
597 0           old_buf_addr = enc_buf->start;
598 0           xh_buffer_grow50(enc_buf);
599              
600 0 0         if (preserve != NULL && enc_buf->start != old_buf_addr) {
    0          
601 0           *off += old_buf_addr - enc_buf->start;
602             }
603              
604 0           *buf = xh_buffer_pos(enc_buf);
605              
606 0 0         while (enc_buf->cur < enc_buf->end) {
607 0           xh_perl_buffer_grow50(main_buf);
608              
609 0 0         if (reader->fake_read_pos == NULL) {
610 0           src_left = xh_perl_obj_read(reader->perl_obj, main_buf->scalar, xh_perl_buffer_avail(main_buf), main_buf->cur - main_buf->start);
611             }
612             else {
613 0           main_buf->cur = reader->fake_read_pos;
614 0           src_left = reader->fake_read_len;
615 0           reader->fake_read_pos = NULL;
616 0           reader->fake_read_len = 0;
617             }
618 0 0         if (src_left == 0) {
619 0 0         if (main_buf->cur == main_buf->end)
620 0           break;
621 0           croak("Truncate char found");
622             }
623 0 0         if (src_left == (size_t) (-1))
624 0           croak("Failed to read file");
625              
626 0           dst_left = xh_buffer_avail(enc_buf);
627              
628             xh_log_debug4("main_buf: %.*s src_left: %lu dst_left: %lu", src_left, main_buf->cur, src_left, dst_left);
629              
630 0           xh_encoder_encode_string(reader->encoder, &main_buf->cur, &src_left, &enc_buf->cur, &dst_left);
631              
632             xh_log_debug3("enc_buf: %.*s len: %lu", enc_buf->cur - enc_buf->start, enc_buf->start, enc_buf->cur - enc_buf->start);
633              
634 0 0         switch (reader->encoder->state) {
635 0           case XH_ENC_TRUNCATED_CHAR_FOUND:
636 0 0         if (src_left == 0)
637 0           croak("Truncated char found but buffer is empty");
638 0           xh_memmove(main_buf->start, main_buf->cur, src_left);
639 0           main_buf->cur = main_buf->start + src_left;
640 0           break;
641 0           case XH_ENC_BUFFER_OVERFLOW:
642             default:
643 0           xh_buffer_seek_top(main_buf);
644 0           goto DONE;
645             }
646             }
647              
648 0           DONE:
649 0           dst_left = enc_buf->cur - *buf;
650             xh_log_debug4("enc_buf: %p[%.*s] len: %lu", enc_buf->start, dst_left, enc_buf->cur, dst_left);
651              
652 0           return dst_left;
653             }
654             #endif /* XH_HAVE_ENCODER */
655              
656             static void
657 1           xh_perl_obj_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
658             {
659 1           xh_common_reader_switch_encoding(reader, encoding, buf, len);
660              
661             #ifdef XH_HAVE_ENCODER
662 2           reader->read = reader->encoder == NULL
663             ? xh_perl_obj_reader_read
664 1 50         : xh_perl_obj_reader_read_with_encoding;
665             #endif
666 1           }
667              
668             void
669 72           xh_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
670             {
671             STRLEN len;
672             xh_char_t *str;
673             MAGIC *mg;
674             GV *gv;
675             IO *io;
676              
677 72 100         if (SvTYPE(input) != SVt_PVGV) {
678 70           str = XH_CHAR_CAST SvPV(input, len);
679 70 50         if (len == 0)
680 0           croak("String is empty");
681              
682             /* Parsing string */
683 70 100         if (xh_str_is_xml(str)) {
684 59           reader->type = XH_READER_STRING_TYPE;
685 59           reader->init = xh_string_reader_init;
686 59           reader->read = xh_string_reader_read;
687 59           reader->switch_encoding = xh_string_reader_switch_encoding;
688 59           reader->destroy = xh_string_reader_destroy;
689             }
690             /* Parsing file */
691             else {
692             #ifdef XH_HAVE_MMAP
693 11           reader->type = XH_READER_MMAPED_FILE_TYPE;
694 11           reader->init = xh_mmaped_file_reader_init;
695 11           reader->read = xh_string_reader_read;
696 11           reader->switch_encoding = xh_string_reader_switch_encoding;
697 11           reader->destroy = xh_mmaped_file_reader_destroy;
698             #else
699             reader->type = XH_READER_FILE_TYPE;
700             reader->init = xh_file_reader_init;
701             reader->read = xh_file_reader_read;
702             reader->switch_encoding = xh_file_reader_switch_encoding;
703             reader->destroy = xh_file_reader_destroy;
704             #endif
705             }
706             }
707             else {
708 2           gv = (GV *) input;
709 2 50         io = GvIO(gv);
    50          
    0          
    50          
710              
711 2 50         if (!io)
712 0           croak("Can't use file handle as a PerlIO handle");
713              
714 2 100         if ((mg = SvTIED_mg(MUTABLE_SV(io), PERL_MAGIC_tiedscalar))) {
    100          
715             /* Tied handle */
716             xh_log_debug0("Tied handle detected");
717 1 50         reader->perl_obj = SvTIED_obj(MUTABLE_SV(io), mg);
718 1           reader->type = XH_READER_FILE_TYPE;
719 1           reader->init = xh_perl_obj_reader_init;
720 1           reader->read = xh_perl_obj_reader_read;
721 1           reader->switch_encoding = xh_perl_obj_reader_switch_encoding;
722 1           reader->destroy = xh_perl_obj_reader_destroy;
723             }
724             else {
725             /* PerlIO handle */
726             xh_log_debug0("PerlIO handle detected");
727 1           reader->perl_io = IoIFP(io);
728 1           reader->type = XH_READER_FILE_TYPE;
729 1           reader->init = xh_perl_io_reader_init;
730 1           reader->read = xh_file_reader_read;
731 1           reader->switch_encoding = xh_file_reader_switch_encoding;
732 1           reader->destroy = xh_perl_io_reader_destroy;
733             }
734             }
735              
736 72           reader->init(reader, input, encoding, buf_size);
737 72           }
738              
739             void
740 72           xh_reader_destroy(xh_reader_t *reader)
741             {
742 72 50         if (reader->destroy != NULL)
743 72           reader->destroy(reader);
744 72           }