File Coverage

src/xh_reader.c
Criterion Covered Total %
statement 52 315 16.5
branch 11 174 6.3
condition n/a
subroutine n/a
pod n/a
total 63 489 12.8


line stmt bran cond sub pod time code
1             #include "xh_config.h"
2             #include "xh_core.h"
3              
4             static void
5 16           xh_common_reader_init(xh_reader_t *reader, SV *XH_UNUSED(input), xh_char_t *encoding, size_t buf_size)
6             {
7 16           reader->buf_size = buf_size;
8              
9 16 50         if (encoding[0] != '\0')
10 0           reader->switch_encoding(reader, encoding, NULL, NULL);
11 16           }
12              
13             static void
14 16           xh_common_reader_destroy(xh_reader_t *reader)
15             {
16             #ifdef XH_HAVE_ENCODER
17 16           xh_buffer_destroy(&reader->enc_buf);
18 16 50         if (reader->encoder != NULL)
19 0           xh_encoder_destroy(reader->encoder);
20             #endif
21 16           }
22              
23             static void
24 8           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 8 50         if (xh_strcasecmp(encoding, XH_INTERNAL_ENCODING) == 0) {
29             #ifdef XH_HAVE_ENCODER
30 8 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 0 0         if (reader->encoder == NULL) {
38             /* create encoder */
39             xh_log_debug1("create a new encoder: %s", encoding);
40              
41 0           reader->encoder = xh_encoder_create(XH_CHAR_CAST XH_INTERNAL_ENCODING, encoding);
42 0 0         if (reader->encoder == NULL) {
43 0           croak("Can't create encoder for '%s'", encoding);
44             }
45              
46 0           xh_buffer_init(&reader->enc_buf, reader->buf_size);
47              
48 0 0         if (len != NULL && *len > 0) {
    0          
49 0           reader->fake_read_pos = *buf;
50 0           reader->fake_read_len = *len;
51 0           *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 8           }
62              
63             static void
64 16           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 16 50         str = XH_CHAR_CAST SvPV(input, len);
70 16           reader->str = str;
71 16           reader->len = (size_t) len;
72              
73 16           reader->main_buf.start = reader->main_buf.cur = str;
74 16           reader->main_buf.end = str + len;
75              
76 16           xh_common_reader_init(reader, input, encoding, buf_size);
77 16           }
78              
79             static size_t
80 29           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 29           *off = 0;
86 29           main_buf = &reader->main_buf;
87              
88 29           *buf = xh_buffer_pos(main_buf);
89 29           len = xh_buffer_avail(main_buf);
90              
91 29           xh_buffer_seek_eof(main_buf);
92              
93 29           return len;
94             }
95              
96             #ifdef XH_HAVE_ENCODER
97             static size_t
98 0           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 0           *off = 0;
105 0           main_buf = &reader->main_buf;
106 0           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 0 0         if (preserve == NULL) {
112 0           xh_buffer_seek_top(enc_buf);
113             }
114             else {
115 0           *off = preserve - enc_buf->start;
116             xh_log_debug1("off: %lu", *off);
117 0 0         if (*off) {
118             xh_log_debug3("memmove dest: %p src %p size: %lu", enc_buf->start, preserve, enc_buf->end - preserve);
119 0           xh_memmove(enc_buf->start, preserve, enc_buf->end - preserve);
120             }
121 0           enc_buf->cur -= *off;
122             }
123              
124 0           old_buf_addr = xh_buffer_start(enc_buf);
125 0           xh_buffer_grow50(enc_buf);
126              
127 0 0         if (preserve != NULL && xh_buffer_start(enc_buf) != old_buf_addr) {
    0          
128 0           *off += old_buf_addr - xh_buffer_start(enc_buf);
129             }
130              
131 0           *buf = xh_buffer_pos(enc_buf);
132              
133 0 0         while (enc_buf->cur < enc_buf->end) {
134 0 0         if (reader->fake_read_pos != NULL) {
135 0           main_buf->cur = reader->fake_read_pos;
136 0           reader->fake_read_pos = NULL;
137 0           reader->fake_read_len = 0;
138             }
139              
140             xh_log_debug2("main buf cur: %p end: %p", main_buf->cur, main_buf->end);
141 0           src_left = xh_buffer_avail(main_buf);
142 0 0         if (src_left == 0 && reader->encoder->state == XH_ENC_OK) {
    0          
143 0 0         if (main_buf->cur == main_buf->end)
144 0           break;
145 0           croak("Truncate char found");
146             }
147              
148 0           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 0           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 0 0         switch (reader->encoder->state) {
157             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             case XH_ENC_BUFFER_OVERFLOW:
162             default:
163 0           goto DONE;
164             }
165             }
166              
167             DONE:
168 0           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 0           return dst_left;
172             }
173             #endif /* XH_HAVE_ENCODER */
174              
175             static void
176 8           xh_string_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
177             {
178              
179 8           xh_common_reader_switch_encoding(reader, encoding, buf, len);
180              
181             #ifdef XH_HAVE_ENCODER
182 16           reader->read = reader->encoder == NULL
183             ? xh_string_reader_read
184 8 50         : xh_string_reader_read_with_encoding;
185             #endif
186 8           }
187              
188             static void
189 16           xh_string_reader_destroy(xh_reader_t *reader)
190             {
191 16           xh_common_reader_destroy(reader);
192 16           }
193              
194             #ifdef XH_HAVE_MMAP
195             static void
196 0           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 0 0         reader->file = XH_CHAR_CAST SvPV_nolen(input);
201              
202             xh_log_debug1("open file: %s", reader->file);
203              
204 0           reader->fd = open((const char *) reader->file, O_RDONLY);
205 0 0         if (reader->fd == -1) {
206 0           croak("Can't open file '%s': %s", reader->file, strerror(errno));
207             }
208              
209 0 0         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 0 0         if (sb.st_size == 0) {
216 0           croak("File '%s' is empty", reader->file);
217             }
218 0           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 0           reader->str = XH_CHAR_CAST mmap((caddr_t) 0, reader->len, PROT_READ, MAP_PRIVATE, reader->fd, 0);
240 0 0         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 0           reader->main_buf.start = reader->main_buf.cur = reader->str;
246 0           reader->main_buf.end = reader->str + reader->len;
247              
248 0           xh_common_reader_init(reader, input, encoding, buf_size);
249 0           }
250              
251             static void
252 0           xh_mmaped_file_reader_destroy(xh_reader_t *reader)
253             {
254 0           xh_common_reader_destroy(reader);
255              
256 0 0         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 0 0         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 0 0         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 0           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 0           main_buf = &reader->main_buf;
315 0           *off = 0;
316              
317             xh_log_debug1("read preserve: %p", preserve);
318 0 0         if (preserve == NULL) {
319 0           main_buf->cur = main_buf->start;
320             }
321             else {
322 0           *off = preserve - main_buf->start;
323             xh_log_debug1("off: %lu", *off);
324 0 0         if (*off) {
325             xh_log_debug3("memmove dest: %p src %p size: %lu", main_buf->start, preserve, main_buf->end - preserve);
326 0           xh_memmove(main_buf->start, preserve, main_buf->end - preserve);
327             }
328 0           main_buf->cur -= *off;
329             xh_log_debug1("read cur: %p", main_buf->cur);
330             }
331              
332 0           old_buf_addr = main_buf->start;
333              
334 0           xh_buffer_grow50(main_buf);
335              
336 0 0         if (preserve != NULL && main_buf->start != old_buf_addr) {
    0          
337 0           *off += old_buf_addr - main_buf->start;
338             }
339              
340 0           len = read(reader->fd, main_buf->cur, xh_buffer_avail(main_buf));
341 0           *buf = main_buf->cur;
342 0 0         if (len == (size_t) (-1)) {
343 0           croak("Failed to read file");
344             }
345 0           main_buf->cur += len;
346              
347 0           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             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             case XH_ENC_BUFFER_OVERFLOW:
423             default:
424 0           xh_buffer_seek_top(main_buf);
425 0           goto DONE;
426             }
427             }
428              
429             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 0           xh_file_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
439             {
440 0           xh_common_reader_switch_encoding(reader, encoding, buf, len);
441              
442             #ifdef XH_HAVE_ENCODER
443 0           reader->read = reader->encoder == NULL
444             ? xh_file_reader_read
445 0 0         : xh_file_reader_read_with_encoding;
446             #endif
447 0           }
448              
449             static void
450 0           xh_perl_io_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
451             {
452 0           reader->fd = PerlIO_fileno(reader->perl_io);
453              
454 0           xh_buffer_init(&reader->main_buf, buf_size);
455              
456 0           xh_common_reader_init(reader, input, encoding, buf_size);
457 0           }
458              
459             static void
460 0           xh_perl_io_reader_destroy(xh_reader_t *reader)
461             {
462 0           xh_common_reader_destroy(reader);
463              
464 0 0         if (reader->main_buf.start != NULL)
465 0           free(reader->main_buf.start);
466 0           }
467              
468             static size_t
469 0           xh_perl_obj_read(SV *obj, SV *buf, size_t count, size_t offset)
470             {
471             int nparam;
472 0           size_t len = 0;
473              
474 0           dSP;
475              
476 0           ENTER;
477 0           SAVETMPS;
478              
479 0 0         PUSHMARK(SP);
480 0 0         XPUSHs(obj);
481 0 0         XPUSHs(buf);
482 0 0         XPUSHs(sv_2mortal(newSViv(count)));
483 0 0         XPUSHs(sv_2mortal(newSViv(offset)));
484 0           PUTBACK;
485              
486 0           nparam = call_method("READ", G_SCALAR);
487              
488 0           SPAGAIN;
489              
490 0 0         if (nparam) {
491 0 0         len = POPi;
492             }
493             else {
494 0           len = 0;
495             }
496              
497 0 0         FREETMPS;
498 0           LEAVE;
499              
500 0           return len;
501             }
502              
503             static void
504 0           xh_perl_obj_reader_init(xh_reader_t *reader, SV *input, xh_char_t *encoding, size_t buf_size)
505             {
506 0           xh_perl_buffer_init(&reader->perl_buf, buf_size);
507              
508 0           xh_common_reader_init(reader, input, encoding, buf_size);
509 0           }
510              
511             static void
512 0           xh_perl_obj_reader_destroy(xh_reader_t *reader)
513             {
514 0           xh_common_reader_destroy(reader);
515              
516 0 0         if (reader->perl_buf.scalar != NULL)
517 0           SvREFCNT_dec(reader->perl_buf.scalar);
518 0           }
519              
520             static size_t
521 0           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 0           main_buf = &reader->perl_buf;
528 0           *off = 0;
529              
530             xh_log_debug1("read preserve: %p", preserve);
531 0 0         if (preserve == NULL) {
532 0           main_buf->cur = main_buf->start;
533             }
534             else {
535 0           *off = preserve - main_buf->start;
536             xh_log_debug1("off: %lu", *off);
537 0 0         if (*off) {
538             xh_log_debug3("memmove dest: %p src %p size: %lu", main_buf->start, preserve, main_buf->end - preserve);
539 0           xh_memmove(main_buf->start, preserve, main_buf->end - preserve);
540             }
541 0           main_buf->cur -= *off;
542             xh_log_debug1("read cur: %p", main_buf->cur);
543             }
544              
545             {
546 0           old_buf_addr = main_buf->start;
547              
548 0           xh_perl_buffer_grow50(main_buf);
549              
550 0           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 0           xh_perl_buffer_sync(main_buf);
553              
554 0 0         if (preserve != NULL && main_buf->start != old_buf_addr) {
    0          
555 0           *off += old_buf_addr - main_buf->start;
556             }
557             }
558              
559 0           *buf = main_buf->cur;
560 0 0         if (len == (size_t) (-1)) {
561 0           croak("Failed to read file");
562             }
563 0           main_buf->cur += len;
564              
565 0           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             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             case XH_ENC_BUFFER_OVERFLOW:
642             default:
643 0           xh_buffer_seek_top(main_buf);
644 0           goto DONE;
645             }
646             }
647              
648             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 0           xh_perl_obj_reader_switch_encoding(xh_reader_t *reader, xh_char_t *encoding, xh_char_t **buf, size_t *len)
658             {
659 0           xh_common_reader_switch_encoding(reader, encoding, buf, len);
660              
661             #ifdef XH_HAVE_ENCODER
662 0           reader->read = reader->encoder == NULL
663             ? xh_perl_obj_reader_read
664 0 0         : xh_perl_obj_reader_read_with_encoding;
665             #endif
666 0           }
667              
668             void
669 16           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 16 50         if (SvTYPE(input) != SVt_PVGV) {
678 16 50         str = XH_CHAR_CAST SvPV(input, len);
679 16 50         if (len == 0)
680 0           croak("String is empty");
681              
682             /* Parsing string */
683 16 50         if (xh_str_is_xml(str)) {
684 16           reader->type = XH_READER_STRING_TYPE;
685 16           reader->init = xh_string_reader_init;
686 16           reader->read = xh_string_reader_read;
687 16           reader->switch_encoding = xh_string_reader_switch_encoding;
688 16           reader->destroy = xh_string_reader_destroy;
689             }
690             /* Parsing file */
691             else {
692             #ifdef XH_HAVE_MMAP
693 0           reader->type = XH_READER_MMAPED_FILE_TYPE;
694 0           reader->init = xh_mmaped_file_reader_init;
695 0           reader->read = xh_string_reader_read;
696 0           reader->switch_encoding = xh_string_reader_switch_encoding;
697 16           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 0           gv = (GV *) input;
709 0 0         io = GvIO(gv);
    0          
    0          
    0          
710              
711 0 0         if (!io)
712 0           croak("Can't use file handle as a PerlIO handle");
713              
714 0 0         if ((mg = SvTIED_mg(MUTABLE_SV(io), PERL_MAGIC_tiedscalar))) {
    0          
715             /* Tied handle */
716             xh_log_debug0("Tied handle detected");
717 0 0         reader->perl_obj = SvTIED_obj(MUTABLE_SV(io), mg);
718 0           reader->type = XH_READER_FILE_TYPE;
719 0           reader->init = xh_perl_obj_reader_init;
720 0           reader->read = xh_perl_obj_reader_read;
721 0           reader->switch_encoding = xh_perl_obj_reader_switch_encoding;
722 0           reader->destroy = xh_perl_obj_reader_destroy;
723             }
724             else {
725             /* PerlIO handle */
726             xh_log_debug0("PerlIO handle detected");
727 0           reader->perl_io = IoIFP(io);
728 0           reader->type = XH_READER_FILE_TYPE;
729 0           reader->init = xh_perl_io_reader_init;
730 0           reader->read = xh_file_reader_read;
731 0           reader->switch_encoding = xh_file_reader_switch_encoding;
732 0           reader->destroy = xh_perl_io_reader_destroy;
733             }
734             }
735              
736 16           reader->init(reader, input, encoding, buf_size);
737 16           }
738              
739             void
740 16           xh_reader_destroy(xh_reader_t *reader)
741             {
742 16 50         if (reader->destroy != NULL)
743 16           reader->destroy(reader);
744 16           }