update limits.c with IMAGER_NO_CONTEXT
[imager.git] / iolayer.c
CommitLineData
e310e5f9 1#include "imager.h"
02d1d628 2#include "iolayer.h"
af070d99 3#include "imerror.h"
02d1d628
AMH
4#include "log.h"
5#include <stdlib.h>
6#include <stdio.h>
7#ifdef _MSC_VER
8#include <io.h>
9#endif
35891892 10#include <string.h>
2691d220 11#include <errno.h>
50c75381 12#include "imageri.h"
02d1d628
AMH
13
14#define IOL_DEB(x)
6d5c85a2 15#define IOL_DEBs stderr
02d1d628 16
6d5c85a2 17#define IO_BUF_SIZE 8192
02d1d628
AMH
18
19char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
20
299da279
TC
21typedef struct io_blink {
22 char buf[BBSIZ];
23 /* size_t cnt; */
24 size_t len; /* How large is this buffer = BBZIS for now */
25 struct io_blink *next;
26 struct io_blink *prev;
27} io_blink;
28
29
299da279 30typedef struct {
6d5c85a2
TC
31 i_io_glue_t base;
32 int fd;
33} io_fdseek;
299da279
TC
34
35typedef struct {
6d5c85a2
TC
36 i_io_glue_t base;
37 const char *data;
38 size_t len;
39 i_io_closebufp_t closecb; /* free memory mapped segment or decrement refcount */
40 void *closedata;
299da279 41 off_t cpos;
6d5c85a2 42} io_buffer;
299da279 43
6d5c85a2
TC
44typedef struct {
45 i_io_glue_t base;
46 void *p; /* Callback data */
47 i_io_readl_t readcb;
48 i_io_writel_t writecb;
49 i_io_seekl_t seekcb;
50 i_io_closel_t closecb;
51 i_io_destroyl_t destroycb;
52} io_cb;
299da279
TC
53
54typedef struct {
55 off_t offset; /* Offset of the source - not used */
56 off_t length; /* Total length of chain in bytes */
57 io_blink *head; /* Start of chain */
58 io_blink *tail; /* End of chain */
59 off_t tfill; /* End of stream in last link */
60 io_blink *cp; /* Current element of list */
61 off_t cpos; /* Offset within the current */
62 off_t gpos; /* Global position in stream */
63} io_ex_bchain;
64
eda1622c
TC
65/* turn current offset, file length, whence and offset into a new offset */
66#define calc_seek_offset(curr_off, length, offset, whence) \
67 (((whence) == SEEK_SET) ? (offset) : \
68 ((whence) == SEEK_CUR) ? (curr_off) + (offset) : \
69 ((whence) == SEEK_END) ? (length) + (offset) : -1)
02d1d628
AMH
70
71/*
72=head1 NAME
73
74iolayer.c - encapsulates different source of data into a single framework.
75
76=head1 SYNOPSIS
77
78 io_glue *ig = io_new_fd( fileno(stdin) );
79 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
6d5c85a2 80
02d1d628
AMH
81 switch (method) {
82 case IOL_NOSEEK:
83 code that uses ig->readcb()
84 to read data goes here.
85 break;
86 case IOL_MMAP:
87 code that uses ig->readcb()
88 to read data goes here.
89 break;
90 }
91
d16420e9 92 io_glue_destroy(ig);
02d1d628
AMH
93 // and much more
94
95=head1 DESCRIPTION
96
97iolayer.c implements the basic functions to create and destroy io_glue
98objects for Imager. The typical usage pattern for data sources is:
99
100 1. Create the source (io_new_fd)
101 2. Define how you want to get data from it (io_reqmeth)
102 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
103 4. Close the source, which
104 shouldn't really close the underlying source. (io_glue DESTROY)
105
106=head1 FUNCTION REFERENCE
107
108Some of these functions are internal.
109
b8c2033e 110=over
02d1d628
AMH
111
112=cut
113*/
114
6d5c85a2 115static void
d03fd5a4
TC
116i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
117 i_io_seekp_t seekcb);
6d5c85a2 118
10461f9a
TC
119static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
120static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
121static off_t fd_seek(io_glue *ig, off_t offset, int whence);
2b405c9e 122static int fd_close(io_glue *ig);
10461f9a 123static ssize_t fd_size(io_glue *ig);
40d75d5a 124static const char *my_strerror(int err);
6d5c85a2
TC
125static void i_io_setup_buffer(io_glue *ig);
126static void
127i_io_start_write(io_glue *ig);
128static int
129i_io_read_fill(io_glue *ig, ssize_t needed);
130static void
131dump_data(unsigned char *start, unsigned char *end, int bias);
132static ssize_t realseek_read(io_glue *igo, void *buf, size_t count);
133static ssize_t realseek_write(io_glue *igo, const void *buf, size_t count);
134static int realseek_close(io_glue *igo);
135static off_t realseek_seek(io_glue *igo, off_t offset, int whence);
136static void realseek_destroy(io_glue *igo);
137static ssize_t buffer_read(io_glue *igo, void *buf, size_t count);
138static ssize_t buffer_write(io_glue *ig, const void *buf, size_t count);
139static int buffer_close(io_glue *ig);
140static off_t buffer_seek(io_glue *igo, off_t offset, int whence);
141static void buffer_destroy(io_glue *igo);
142static io_blink*io_blink_new(void);
143static void io_bchain_advance(io_ex_bchain *ieb);
144static void io_destroy_bufchain(io_ex_bchain *ieb);
145static ssize_t bufchain_read(io_glue *ig, void *buf, size_t count);
146static ssize_t bufchain_write(io_glue *ig, const void *buf, size_t count);
147static int bufchain_close(io_glue *ig);
148static off_t bufchain_seek(io_glue *ig, off_t offset, int whence);
149static void bufchain_destroy(io_glue *ig);
02d1d628
AMH
150
151/*
6d5c85a2 152 * Methods for setting up data source
02d1d628
AMH
153 */
154
6d5c85a2 155/*
d03fd5a4 156=item io_new_bufchain()
6d5c85a2
TC
157=order 10
158=category I/O Layers
159
d03fd5a4 160returns a new io_glue object that has the 'empty' source and but can
6d5c85a2
TC
161be written to and read from later (like a pseudo file).
162
163=cut
164*/
165
166io_glue *
d03fd5a4 167io_new_bufchain() {
6d5c85a2
TC
168 io_glue *ig;
169 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
170
d03fd5a4 171 mm_log((1, "io_new_bufchain()\n"));
6d5c85a2
TC
172
173 ig = mymalloc(sizeof(io_glue));
174 memset(ig, 0, sizeof(*ig));
d03fd5a4 175 i_io_init(ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek);
6d5c85a2
TC
176
177 ieb->offset = 0;
178 ieb->length = 0;
179 ieb->cpos = 0;
180 ieb->gpos = 0;
181 ieb->tfill = 0;
182
183 ieb->head = io_blink_new();
184 ieb->cp = ieb->head;
185 ieb->tail = ieb->head;
186
187 ig->exdata = ieb;
188 ig->closecb = bufchain_close;
189 ig->destroycb = bufchain_destroy;
190
191 return ig;
02d1d628 192}
6d5c85a2
TC
193
194/*
d03fd5a4 195=item io_new_buffer(data, length)
6d5c85a2
TC
196=order 10
197=category I/O Layers
198
199Returns a new io_glue object that has the source defined as reading
200from specified buffer. Note that the buffer is not copied.
201
202 data - buffer to read from
203 length - length of buffer
204
205=cut
02d1d628
AMH
206*/
207
6d5c85a2 208io_glue *
d03fd5a4 209io_new_buffer(const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
6d5c85a2
TC
210 io_buffer *ig;
211
d03fd5a4 212 mm_log((1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
6d5c85a2
TC
213
214 ig = mymalloc(sizeof(io_buffer));
215 memset(ig, 0, sizeof(*ig));
d03fd5a4 216 i_io_init(&ig->base, BUFFER, buffer_read, buffer_write, buffer_seek);
6d5c85a2
TC
217 ig->data = data;
218 ig->len = len;
219 ig->closecb = closecb;
220 ig->closedata = closedata;
221
222 ig->cpos = 0;
223
224 ig->base.closecb = buffer_close;
225 ig->base.destroycb = buffer_destroy;
226
227 return (io_glue *)ig;
228}
02d1d628
AMH
229
230
231/*
d03fd5a4 232=item io_new_fd(fd)
6d5c85a2
TC
233=order 10
234=category I/O Layers
235
d03fd5a4 236returns a new io_glue object that has the source defined as reading
6d5c85a2
TC
237from specified file descriptor. Note that the the interface to receiving
238data from the io_glue callbacks hasn't been done yet.
239
d03fd5a4 240 fd - file descriptor to read/write from
6d5c85a2
TC
241
242=cut
243*/
244
245io_glue *
d03fd5a4 246io_new_fd(int fd) {
6d5c85a2
TC
247 io_fdseek *ig;
248
d03fd5a4 249 mm_log((1, "io_new_fd(fd %d)\n", fd));
6d5c85a2
TC
250
251 ig = mymalloc(sizeof(io_fdseek));
252 memset(ig, 0, sizeof(*ig));
d03fd5a4 253 i_io_init(&ig->base, FDSEEK, fd_read, fd_write, fd_seek);
6d5c85a2
TC
254 ig->fd = fd;
255
256 ig->base.closecb = fd_close;
257 ig->base.sizecb = fd_size;
258 ig->base.destroycb = NULL;
259
d03fd5a4 260 mm_log((1, "(%p) <- io_new_fd\n", ig));
6d5c85a2
TC
261 return (io_glue *)ig;
262}
02d1d628
AMH
263
264/*
d03fd5a4 265=item io_new_cb(p, read_cb, write_cb, seek_cb, close_cb, destroy_cb)
6d5c85a2
TC
266=category I/O Layers
267=order 10
02d1d628 268
6d5c85a2 269Create a new I/O layer object that calls your supplied callbacks.
02d1d628 270
6d5c85a2
TC
271In general the callbacks should behave like the corresponding POSIX
272primitives.
273
274=over
275
276=item *
277
278C<read_cb>(p, buffer, length) should read up to C<length> bytes into
279C<buffer> and return the number of bytes read. At end of file, return
2800. On error, return -1.
281
282=item *
283
284C<write_cb>(p, buffer, length) should write up to C<length> bytes from
285C<buffer> and return the number of bytes written. A return value <= 0
286will be treated as an error.
287
288=item *
289
290C<seekcb>(p, offset, whence) should seek and return the new offset.
291
292=item *
293
294C<close_cb>(p) should return 0 on success, -1 on failure.
295
296=item *
297
298C<destroy_cb>(p) should release any memory specific to your callback
299handlers.
300
301=back
02d1d628
AMH
302
303=cut
304*/
305
6d5c85a2 306io_glue *
d03fd5a4 307io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb,
6d5c85a2
TC
308 i_io_seekl_t seekcb, i_io_closel_t closecb,
309 i_io_destroyl_t destroycb) {
310 io_cb *ig;
02d1d628 311
d03fd5a4 312 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
6d5c85a2
TC
313 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
314 ig = mymalloc(sizeof(io_cb));
315 memset(ig, 0, sizeof(*ig));
d03fd5a4
TC
316 i_io_init(&ig->base, CBSEEK, realseek_read, realseek_write, realseek_seek);
317 mm_log((1, "(%p) <- io_new_cb\n", ig));
6d5c85a2
TC
318
319 ig->base.closecb = realseek_close;
320 ig->base.destroycb = realseek_destroy;
321
322 ig->p = p;
323 ig->readcb = readcb;
324 ig->writecb = writecb;
325 ig->seekcb = seekcb;
326 ig->closecb = closecb;
327 ig->destroycb = destroycb;
328
329 return (io_glue *)ig;
330}
331
332/*
333=item io_slurp(ig, c)
334=category I/O Layers
335
336Takes the source that the io_glue is bound to and allocates space for
337a return buffer and returns the entire content in a single buffer.
338Note: This only works for io_glue objects created by
339io_new_bufchain(). It is useful for saving to scalars and such.
340
341 ig - io_glue object
342 c - pointer to a pointer to where data should be copied to
343
344 char *data;
345 size_t size = io_slurp(ig, &data);
346 ... do something with the data ...
347 myfree(data);
348
349io_slurp() will abort the program if the supplied I/O layer is not
350from io_new_bufchain().
351
352=cut
353*/
354
355size_t
356io_slurp(io_glue *ig, unsigned char **c) {
357 ssize_t rc;
358 off_t orgoff;
359 io_ex_bchain *ieb;
360 unsigned char *cc;
361 io_type inn = ig->type;
362
363 if ( inn != BUFCHAIN ) {
d03fd5a4 364 i_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
10461f9a 365 }
6d5c85a2
TC
366
367 ieb = ig->exdata;
368 cc = *c = mymalloc( ieb->length );
02d1d628 369
6d5c85a2
TC
370 orgoff = ieb->gpos;
371
372 bufchain_seek(ig, 0, SEEK_SET);
373
374 rc = bufchain_read(ig, cc, ieb->length);
375
d03fd5a4
TC
376 if (rc != ieb->length)
377 i_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
6d5c85a2
TC
378
379 return rc;
380}
381
382/*
383=item io_glue_destroy(ig)
384=category I/O Layers
385=order 90
386=synopsis io_glue_destroy(ig);
387
388Destroy an io_glue objects. Should clean up all related buffers.
389
390 ig - io_glue object to destroy.
391
392=cut
393*/
394
395void
396io_glue_destroy(io_glue *ig) {
d03fd5a4 397 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
6d5c85a2
TC
398
399 if (ig->destroycb)
400 ig->destroycb(ig);
401
402 if (ig->buffer)
403 myfree(ig->buffer);
404
405 myfree(ig);
406}
407
408/*
409=item i_io_getc(ig)
410=category I/O Layers
411
412A macro to read a single byte from a buffered I/O glue object.
413
414Returns EOF on failure, or a byte.
415
416=cut
417*/
418
419int
420i_io_getc_imp(io_glue *ig) {
421 if (ig->write_ptr)
422 return EOF;
423
424 if (ig->error || ig->buf_eof)
425 return EOF;
426
427 if (!ig->buffered) {
428 unsigned char buf;
429 ssize_t rc = i_io_raw_read(ig, &buf, 1);
430 if (rc > 0) {
431 return buf;
432 }
433 else if (rc == 0) {
434 ig->buf_eof = 1;
435 return EOF;
436 }
437 else {
438 ig->error = 1;
439 return EOF;
440 }
441 }
442
443 if (!ig->buffer)
444 i_io_setup_buffer(ig);
445
446 if (!ig->read_ptr || ig->read_ptr == ig->read_end) {
447 if (!i_io_read_fill(ig, 1))
448 return EOF;
449 }
450
451 return *(ig->read_ptr++);
452}
453
454/*
455=item i_io_peekc(ig)
456=category I/O Layers
457
458Read the next character from the stream without advancing the stream.
459
460On error or end of file, return EOF.
461
462For unbuffered streams a single character buffer will be setup.
463
464=cut
465*/
466
467int
468i_io_peekc_imp(io_glue *ig) {
469 if (ig->write_ptr)
470 return EOF;
471
472 if (!ig->buffer)
473 i_io_setup_buffer(ig);
474
475 if (!ig->buffered) {
476 ssize_t rc = i_io_raw_read(ig, ig->buffer, 1);
477 if (rc > 0) {
478 ig->read_ptr = ig->buffer;
479 ig->read_end = ig->buffer + 1;
480 return *(ig->buffer);
481 }
482 else if (rc == 0) {
483 ig->buf_eof = 1;
484 return EOF;
485 }
486 else {
487 ig->error = 1;
488 return EOF;
489 }
490 }
491
492 if (!ig->read_ptr || ig->read_ptr == ig->read_end) {
493 if (ig->error || ig->buf_eof)
494 return EOF;
495
496 if (!i_io_read_fill(ig, 1))
497 return EOF;
498 }
499
500 return *(ig->read_ptr);
501}
502
503/*
504=item i_io_peekn(ig, buffer, size)
505=category I/O Layers
506=synopsis ssize_t count = i_io_peekn(ig, buffer, sizeof(buffer));
507
508Buffer at least C<size> (at most C<< ig->buf_size >> bytes of data
509from the stream and return C<size> bytes of it to the caller in
510C<buffer>.
511
512This ignores the buffered state of the stream, and will always setup
513buffering if needed.
514
515If no C<type> parameter is provided to Imager::read() or
516Imager::read_multi(), Imager will call C<i_io_peekn()> when probing
517for the file format.
518
519Returns -1 on error, 0 if there is no data before EOF, or the number
520of bytes read into C<buffer>.
521
522=cut
523*/
524
525ssize_t
526i_io_peekn(io_glue *ig, void *buf, size_t size) {
527 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn(%p, %p, %d)\n", ig, buf, (int)size));
528
529 if (size == 0) {
530 i_push_error(0, "peekn size must be positive");
531 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (zero size)\n"));
532 return -1;
533 }
534
535 if (ig->write_ptr) {
536 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (write_ptr set)\n"));
537 return -1;
538 }
539
540 if (!ig->buffer)
541 i_io_setup_buffer(ig);
542
543 if ((!ig->read_ptr || size > ig->read_end - ig->read_ptr)
544 && !(ig->buf_eof || ig->error)) {
545 i_io_read_fill(ig, size);
546 }
547
548 if (size > ig->read_end - ig->read_ptr)
549 size = ig->read_end - ig->read_ptr;
550
551 if (size)
552 memcpy(buf, ig->read_ptr, size);
553 else if (ig->buf_eof) {
554 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => 0 (eof)\n"));
555 return 0;
556 }
557 else if (ig->error) {
558 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (error)\n"));
559 return -1;
560 }
561 else {
562 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() - size 0 but not eof or error!\n"));
563 return -1;
564 }
565
566 IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => %d\n", (int)size));
567
568 return size;
569}
570
571/*
572=item i_io_putc(ig, c)
573=category I/O Layers
574
575Write a single character to the stream.
576
577On success return c, on error returns EOF
578
579=cut
580*/
581
582int
583i_io_putc_imp(io_glue *ig, int c) {
584 IOL_DEB(fprintf(IOL_DEBs, "i_io_putc_imp(%p, %d)\n", ig, c));
585
586 if (!ig->buffered) {
587 char buf = c;
588 ssize_t write_result;
39e938a4 589 int result = c;
6d5c85a2
TC
590
591 if (ig->error)
592 return EOF;
593
594 write_result = i_io_raw_write(ig, &buf, 1);
6d5c85a2
TC
595 if (write_result != 1) {
596 ig->error = 1;
597 result = EOF;
598 IOL_DEB(fprintf(IOL_DEBs, " unbuffered putc() failed, setting error mode\n"));
599 }
600 IOL_DEB(fprintf(IOL_DEBs, " unbuffered: result %d\n", result));
601
602 return result;
603 }
604
605 if (ig->read_ptr)
606 return EOF;
607
608 if (ig->error)
609 return EOF;
610
611 if (!ig->buffer)
612 i_io_setup_buffer(ig);
613
614 if (ig->write_ptr && ig->write_ptr == ig->write_end) {
615 if (!i_io_flush(ig))
616 return EOF;
617 }
618
619 i_io_start_write(ig);
620
621 *(ig->write_ptr)++ = c;
622
623 return (unsigned char)c;
624}
625
626/*
627=item i_io_read(io, buffer, size)
628=category I/O Layers
629
630Read up to C<size> bytes from the stream C<io> into C<buffer>.
631
632Returns the number of bytes read. Returns 0 on end of file. Returns
633-1 on error.
634
635=cut
636*/
637
638ssize_t
639i_io_read(io_glue *ig, void *buf, size_t size) {
640 unsigned char *pbuf = buf;
641 ssize_t read_total = 0;
642
643 IOL_DEB(fprintf(IOL_DEBs, "i_io_read(%p, %p, %u)\n", ig, buf, (unsigned)size));
644
645 if (ig->write_ptr) {
646 IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => -1 (write_ptr set)\n"));
647 return -1;
648 }
649
650 if (!ig->buffer && ig->buffered)
651 i_io_setup_buffer(ig);
652
653 if (ig->read_ptr && ig->read_ptr < ig->read_end) {
654 size_t alloc = ig->read_end - ig->read_ptr;
655
656 if (alloc > size)
657 alloc = size;
658
659 memcpy(pbuf, ig->read_ptr, alloc);
660 ig->read_ptr += alloc;
661 pbuf += alloc;
662 size -= alloc;
663 read_total += alloc;
664 }
665
666 if (size > 0 && !(ig->error || ig->buf_eof)) {
667 if (!ig->buffered || size > ig->buf_size) {
668 ssize_t rc;
669
670 while (size > 0 && (rc = i_io_raw_read(ig, pbuf, size)) > 0) {
671 size -= rc;
672 pbuf += rc;
673 read_total += rc;
674 }
675
676 IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => %d (raw read)\n", (int)read_total));
677
678 if (rc < 0)
679 ig->error = 1;
680 else if (rc == 0)
681 ig->buf_eof = 1;
682
683 if (!read_total)
684 return rc;
685 }
686 else {
687 if (i_io_read_fill(ig, size)) {
688 size_t alloc = ig->read_end - ig->read_ptr;
689 if (alloc > size)
690 alloc = size;
691
692 memcpy(pbuf, ig->read_ptr, alloc);
693 ig->read_ptr += alloc;
694 pbuf += alloc;
695 size -= alloc;
696 read_total += alloc;
697 }
698 else {
699 if (!read_total && ig->error) {
700 IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => -1 (fill failure)\n"));
701 return -1;
702 }
703 }
704 }
705 }
706
707 if (!read_total && ig->error)
708 read_total = -1;
709
710 IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => %d\n", (int)read_total));
711
712 return read_total;
713}
714
715/*
716=item i_io_write(io, buffer, size)
717=category I/O Layers
718=synopsis ssize_t result = i_io_write(io, buffer, size)
719
720Write to the given I/O stream.
721
722Returns the number of bytes written.
723
724=cut
725*/
726
727ssize_t
728i_io_write(io_glue *ig, const void *buf, size_t size) {
729 const unsigned char *pbuf = buf;
730 size_t write_count = 0;
731
732 IOL_DEB(fprintf(IOL_DEBs, "i_io_write(%p, %p, %u)\n", ig, buf, (unsigned)size));
733
734 if (!ig->buffered) {
735 ssize_t result;
736
737 if (ig->error) {
738 IOL_DEB(fprintf(IOL_DEBs, " unbuffered, error state\n"));
739 return -1;
740 }
741
742 result = i_io_raw_write(ig, buf, size);
743
744 if (result != size) {
745 ig->error = 1;
746 IOL_DEB(fprintf(IOL_DEBs, " unbuffered, setting error flag\n"));
747 }
748
749 IOL_DEB(fprintf(IOL_DEBs, " unbuffered, result: %d\n", (int)result));
750
751 return result;
752 }
753
754 if (ig->read_ptr) {
755 IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (read_ptr set)\n"));
756 return -1;
757 }
758
759 if (ig->error) {
760 IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (error)\n"));
761 return -1;
762 }
763
764 if (!ig->buffer)
765 i_io_setup_buffer(ig);
766
767 if (!ig->write_ptr)
768 i_io_start_write(ig);
769
770 if (ig->write_ptr && ig->write_ptr + size <= ig->write_end) {
771 size_t alloc = ig->write_end - ig->write_ptr;
772 if (alloc > size)
773 alloc = size;
774 memcpy(ig->write_ptr, pbuf, alloc);
775 write_count += alloc;
776 size -= alloc;
777 pbuf += alloc;
778 ig->write_ptr += alloc;
779 }
780
781 if (size) {
782 if (!i_io_flush(ig)) {
783 IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => %d (i_io_flush failure)\n", (int)write_count));
784 return write_count ? write_count : -1;
785 }
786
787 i_io_start_write(ig);
788
789 if (size > ig->buf_size) {
790 ssize_t rc;
791 while (size > 0 && (rc = i_io_raw_write(ig, pbuf, size)) > 0) {
792 write_count += rc;
793 pbuf += rc;
794 size -= rc;
795 }
796 if (rc <= 0) {
797 ig->error = 1;
798 if (!write_count) {
799 IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (direct write failure)\n"));
800 return -1;
801 }
802 }
803 }
804 else {
805 memcpy(ig->write_ptr, pbuf, size);
806 write_count += size;
807 ig->write_ptr += size;
808 }
809 }
810
811 IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => %d\n", (int)write_count));
812
813 return write_count;
814}
815
816/*
817=item i_io_seek(io, offset, whence)
818=category I/O Layers
819
820Seek within the stream.
821
822Acts like perl's seek.
823
824=cut
825 */
826
827off_t
828i_io_seek(io_glue *ig, off_t offset, int whence) {
829 off_t new_off;
830
831 IOL_DEB(fprintf(IOL_DEBs, "i_io_seek(%p, %ld, %d)\n", ig, (long)offset, whence));
832
833 if (ig->write_ptr && ig->write_ptr != ig->write_end) {
834 if (!i_io_flush(ig))
835 return (off_t)(-1);
836 }
837
838 if (whence == SEEK_CUR && ig->read_ptr && ig->read_ptr != ig->read_end)
839 offset -= ig->read_end - ig->read_ptr;
840
841 ig->read_ptr = ig->read_end = NULL;
842 ig->write_ptr = ig->write_end = NULL;
843 ig->error = 0;
844 ig->buf_eof = 0;
845
846 new_off = i_io_raw_seek(ig, offset, whence);
847 if (new_off < 0)
848 ig->error = 1;
849
850 IOL_DEB(fprintf(IOL_DEBs, "i_io_seek() => %ld\n", (long)new_off));
851
852 return new_off;
853}
854
855/*
856=item i_io_flush(io)
857=category I/O Layers
858
859Flush any buffered output.
860
861Returns true on success,
862
863=cut
864*/
865
866int
867i_io_flush(io_glue *ig) {
868 unsigned char *bufp;
869
870 IOL_DEB(fprintf(IOL_DEBs, "i_io_flush(%p)\n", ig));
871
872 if (ig->error) {
873 IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 0 (error set)\n", ig));
874 return 0;
875 }
876
877 /* nothing to do */
878 if (!ig->write_ptr)
879 return 1;
880
881 bufp = ig->buffer;
882 while (bufp < ig->write_ptr) {
883 ssize_t rc = i_io_raw_write(ig, bufp, ig->write_ptr - bufp);
884 if (rc <= 0) {
885 IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 0 (write error)\n", ig));
886 ig->error = 1;
887 return 0;
888 }
889
890 bufp += rc;
891 }
892
893 ig->write_ptr = ig->write_end = NULL;
894
895 IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 1\n", ig));
896
897 return 1;
898}
899
900/*
901=item i_io_close(io)
902=category I/O Layers
903
904Flush any pending output and perform the close action for the stream.
905
906Returns 0 on success.
907
908=cut
909*/
910
911int
912i_io_close(io_glue *ig) {
913 int result = 0;
914
915 IOL_DEB(fprintf(IOL_DEBs, "i_io_close(%p)\n", ig));
916 if (ig->error)
917 result = -1;
918
919 if (ig->write_ptr && !i_io_flush(ig))
920 result = -1;
921
922 if (i_io_raw_close(ig))
923 result = -1;
924
925 IOL_DEB(fprintf(IOL_DEBs, "i_io_close() => %d\n", result));
926
927 return result;
928}
929
930/*
931=item i_io_gets(ig, buffer, size, end_of_line)
932=category I/O Layers
933=synopsis char buffer[BUFSIZ]
934=synopsis ssize_t len = i_io_gets(buffer, sizeof(buffer), '\n');
935
936Read up to C<size>-1 bytes from the stream C<ig> into C<buffer>.
937
938If the byte C<end_of_line> is seen then no further bytes will be read.
939
940Returns the number of bytes read.
941
942Always C<NUL> terminates the buffer.
943
944=cut
945*/
946
947ssize_t
948i_io_gets(io_glue *ig, char *buffer, size_t size, int eol) {
949 ssize_t read_count = 0;
950 if (size < 2)
951 return 0;
952 --size; /* room for nul */
953 while (size > 0) {
954 int byte = i_io_getc(ig);
955 if (byte == EOF)
956 break;
957 *buffer++ = byte;
958 ++read_count;
959 if (byte == eol)
960 break;
961 --size;
962 }
963 *buffer++ = '\0';
964
965 return read_count;
966}
967
968/*
969=item i_io_init(ig, readcb, writecb, seekcb)
970
971Do common initialization for io_glue objects.
972
973=cut
974*/
975
976static void
d03fd5a4 977i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
6d5c85a2
TC
978 i_io_seekp_t seekcb) {
979 ig->type = type;
980 ig->exdata = NULL;
981 ig->readcb = readcb;
982 ig->writecb = writecb;
983 ig->seekcb = seekcb;
984 ig->closecb = NULL;
985 ig->sizecb = NULL;
986 ig->destroycb = NULL;
987
988 ig->buffer = NULL;
989 ig->read_ptr = NULL;
990 ig->read_end = NULL;
991 ig->write_ptr = NULL;
992 ig->write_end = NULL;
993 ig->buf_size = IO_BUF_SIZE;
994 ig->buf_eof = 0;
995 ig->error = 0;
996 ig->buffered = 1;
997}
998
999/*
1000=item i_io_set_buffered(io, buffered)
1001=category I/O Layers
1002
1003Set the buffering mode of the stream.
1004
1005If you switch buffering off on a stream with buffering on:
1006
1007=over
1008
1009=item *
1010
1011any buffered output will be flushed.
1012
1013=item *
1014
1015any existing buffered input will be consumed before reads become
1016unbuffered.
1017
1018=back
1019
1020Returns true on success. This may fail if any buffered output cannot
1021be flushed.
1022
1023=cut
1024*/
1025
1026int
1027i_io_set_buffered(io_glue *ig, int buffered) {
1028 if (!buffered && ig->write_ptr) {
1029 if (!i_io_flush(ig)) {
1030 ig->error = 1;
1031 return 0;
1032 }
1033 }
1034 ig->buffered = buffered;
1035
1036 return 1;
1037}
1038
1039/*
1040=item i_io_dump(ig)
1041
1042Dump the base fields of an io_glue object to stdout.
1043
1044=cut
1045*/
1046void
1047i_io_dump(io_glue *ig, int flags) {
1048 fprintf(IOL_DEBs, "ig %p:\n", ig);
1049 fprintf(IOL_DEBs, " type: %d\n", ig->type);
1050 fprintf(IOL_DEBs, " exdata: %p\n", ig->exdata);
1051 if (flags & I_IO_DUMP_CALLBACKS) {
1052 fprintf(IOL_DEBs, " readcb: %p\n", ig->readcb);
1053 fprintf(IOL_DEBs, " writecb: %p\n", ig->writecb);
1054 fprintf(IOL_DEBs, " seekcb: %p\n", ig->seekcb);
1055 fprintf(IOL_DEBs, " closecb: %p\n", ig->closecb);
1056 fprintf(IOL_DEBs, " sizecb: %p\n", ig->sizecb);
1057 }
1058 if (flags & I_IO_DUMP_BUFFER) {
1059 fprintf(IOL_DEBs, " buffer: %p\n", ig->buffer);
1060 fprintf(IOL_DEBs, " read_ptr: %p\n", ig->read_ptr);
1061 if (ig->read_ptr) {
1062 fprintf(IOL_DEBs, " ");
1063 dump_data(ig->read_ptr, ig->read_end, 0);
1064 putc('\n', IOL_DEBs);
1065 }
1066 fprintf(IOL_DEBs, " read_end: %p\n", ig->read_end);
1067 fprintf(IOL_DEBs, " write_ptr: %p\n", ig->write_ptr);
1068 if (ig->write_ptr) {
1069 fprintf(IOL_DEBs, " ");
1070 dump_data(ig->buffer, ig->write_ptr, 1);
1071 putc('\n', IOL_DEBs);
1072 }
1073 fprintf(IOL_DEBs, " write_end: %p\n", ig->write_end);
1074 fprintf(IOL_DEBs, " buf_size: %u\n", (unsigned)(ig->buf_size));
1075 }
1076 if (flags & I_IO_DUMP_STATUS) {
1077 fprintf(IOL_DEBs, " buf_eof: %d\n", ig->buf_eof);
1078 fprintf(IOL_DEBs, " error: %d\n", ig->error);
1079 fprintf(IOL_DEBs, " buffered: %d\n", ig->buffered);
1080 }
1081}
1082
1083/*
1084=back
1085
1086=head1 INTERNAL FUNCTIONS
1087
1088=over
1089
1090=item my_strerror
1091
1092Calls strerror() and ensures we don't return NULL.
1093
1094On some platforms it's possible for strerror() to return NULL, this
1095wrapper ensures we only get non-NULL values.
1096
1097=cut
1098*/
1099
1100static
1101const char *my_strerror(int err) {
1102 const char *result = strerror(err);
1103
1104 if (!result)
1105 result = "Unknown error";
1106
1107 return result;
1108}
1109
1110static void
1111i_io_setup_buffer(io_glue *ig) {
1112 ig->buffer = mymalloc(ig->buf_size);
1113}
1114
1115static void
1116i_io_start_write(io_glue *ig) {
1117 ig->write_ptr = ig->buffer;
1118 ig->write_end = ig->buffer + ig->buf_size;
1119}
1120
1121static int
1122i_io_read_fill(io_glue *ig, ssize_t needed) {
1123 unsigned char *buf_end = ig->buffer + ig->buf_size;
1124 unsigned char *buf_start = ig->buffer;
1125 unsigned char *work = ig->buffer;
1126 ssize_t rc;
1127 int good = 0;
1128
1129 IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%p, %d)\n", ig, (int)needed));
1130
1131 /* these conditions may be unused, callers should also be checking them */
1132 if (ig->error || ig->buf_eof)
1133 return 0;
1134
1135 if (needed > ig->buf_size)
1136 needed = ig->buf_size;
1137
1138 if (ig->read_ptr && ig->read_ptr < ig->read_end) {
1139 size_t kept = ig->read_end - ig->read_ptr;
1140
1141 if (needed < kept) {
1142 IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%u) -> 1 (already have enough)\n", (unsigned)needed));
1143 return 1;
1144 }
1145
1146 if (ig->read_ptr != ig->buffer)
1147 memmove(ig->buffer, ig->read_ptr, kept);
1148
1149 good = 1; /* we have *something* available to read */
1150 work = buf_start + kept;
1151 needed -= kept;
1152 }
1153 else {
1154 work = ig->buffer;
1155 }
1156
1157 while (work < buf_end && (rc = i_io_raw_read(ig, work, buf_end - work)) > 0) {
1158 work += rc;
1159 good = 1;
1160 if (needed < rc)
1161 break;
1162
1163 needed -= rc;
1164 }
1165
1166 if (rc < 0) {
1167 ig->error = 1;
1168 IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc %d, setting error\n",
1169 (int)rc));
1170 }
1171 else if (rc == 0) {
1172 ig->buf_eof = 1;
1173 IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc 0, setting eof\n"));
1174 }
1175
1176 if (good) {
1177 ig->read_ptr = buf_start;
1178 ig->read_end = work;
1179 }
1180
1181 IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill => %d, %u buffered\n", good,
1182 (unsigned)(ig->read_end - ig->read_ptr)));
1183 return good;
1184}
1185
1186/*
1187=item dump_data(start, end, bias)
1188
1189Hex dump the data between C<start> and C<end>.
1190
1191If there is more than a pleasing amount of data, either dump the
1192beginning (C<bias == 0>) or dump the end C(<bias != 0>) of the range.
1193
1194=cut
1195*/
1196
1197static void
1198dump_data(unsigned char *start, unsigned char *end, int bias) {
1199 unsigned char *p;
1200 size_t count = end - start;
1201
1202 if (start == end) {
1203 fprintf(IOL_DEBs, "(empty)");
1204 return;
1205 }
1206
1207 if (count > 15) {
1208 if (bias) {
1209 fprintf(IOL_DEBs, "... ");
1210 start = end - 14;
1211 }
1212 else {
1213 end = start + 14;
1214 }
1215
1216 for (p = start; p < end; ++p) {
1217 fprintf(IOL_DEBs, " %02x", *p);
1218 }
1219 putc(' ', IOL_DEBs);
1220 putc('<', IOL_DEBs);
1221 for (p = start; p < end; ++p) {
1222 if (*p < ' ' || *p > '~')
1223 putc('.', IOL_DEBs);
1224 else
1225 putc(*p, IOL_DEBs);
1226 }
1227 putc('>', IOL_DEBs);
1228 if (!bias)
1229 fprintf(IOL_DEBs, " ...");
1230 }
1231 else {
1232 for (p = start; p < end; ++p) {
1233 fprintf(IOL_DEBs, " %02x", *p);
1234 }
1235 putc(' ', IOL_DEBs);
1236 for (p = start; p < end; ++p) {
1237 if (*p < ' ' || *p > '~')
1238 putc('.', IOL_DEBs);
1239 else
1240 putc(*p, IOL_DEBs);
1241 }
1242 }
1243}
1244
1245/*
1246 * Callbacks for sources that cannot seek
1247 */
1248
1249/*
1250 * Callbacks for sources that can seek
1251 */
1252
1253/*
1254=item realseek_read(ig, buf, count)
1255
1256Does the reading from a source that can be seeked on
1257
1258 ig - io_glue object
1259 buf - buffer to return data in
1260 count - number of bytes to read into buffer max
1261
1262=cut
1263*/
1264
1265static
1266ssize_t
1267realseek_read(io_glue *igo, void *buf, size_t count) {
1268 io_cb *ig = (io_cb *)igo;
1269 void *p = ig->p;
1270 ssize_t rc = 0;
1271
1272 IOL_DEB( fprintf(IOL_DEBs, "realseek_read: buf = %p, count = %u\n",
1273 buf, (unsigned)count) );
1274 rc = ig->readcb(p,buf,count);
1275
1276 IOL_DEB( fprintf(IOL_DEBs, "realseek_read: rc = %d\n", (int)rc) );
1277
1278 return rc;
02d1d628
AMH
1279}
1280
1281
1282/*
1283=item realseek_write(ig, buf, count)
1284
1285Does the writing to a 'source' that can be seeked on
1286
1287 ig - io_glue object
1288 buf - buffer that contains data
1289 count - number of bytes to write
1290
1291=cut
1292*/
1293
1294static
1295ssize_t
6d5c85a2
TC
1296realseek_write(io_glue *igo, const void *buf, size_t count) {
1297 io_cb *ig = (io_cb *)igo;
1298 void *p = ig->p;
02d1d628
AMH
1299 ssize_t rc = 0;
1300 size_t bc = 0;
1301 char *cbuf = (char*)buf;
1302
6d5c85a2
TC
1303 IOL_DEB( fprintf(IOL_DEBs, "realseek_write: ig = %p, buf = %p, "
1304 "count = %u\n", ig, buf, (unsigned)count) );
02d1d628 1305
10461f9a
TC
1306 /* Is this a good idea? Would it be better to handle differently?
1307 skip handling? */
6d5c85a2 1308 while( count!=bc && (rc = ig->writecb(p,cbuf+bc,count-bc))>0 ) {
10461f9a
TC
1309 bc+=rc;
1310 }
02d1d628 1311
6d5c85a2 1312 IOL_DEB( fprintf(IOL_DEBs, "realseek_write: rc = %d, bc = %u\n", (int)rc, (unsigned)bc) );
1f6c1c10 1313 return rc < 0 ? rc : bc;
02d1d628
AMH
1314}
1315
1316
1317/*
1318=item realseek_close(ig)
1319
10461f9a
TC
1320Closes a source that can be seeked on. Not sure if this should be an
1321actual close or not. Does nothing for now. Should be fixed.
02d1d628
AMH
1322
1323 ig - data source
1324
10461f9a 1325=cut */
02d1d628
AMH
1326
1327static
2b405c9e 1328int
6d5c85a2
TC
1329realseek_close(io_glue *igo) {
1330 io_cb *ig = (io_cb *)igo;
1331
1332 IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig));
d03fd5a4 1333 mm_log((1, "realseek_close(ig %p)\n", ig));
6d5c85a2
TC
1334 if (ig->closecb)
1335 return ig->closecb(ig->p);
2b405c9e
TC
1336 else
1337 return 0;
02d1d628
AMH
1338}
1339
1340
1341/* realseek_seek(ig, offset, whence)
1342
1343Implements seeking for a source that is seekable, the purpose of having this is to be able to
1344have an offset into a file that is different from what the underlying library thinks.
1345
1346 ig - data source
1347 offset - offset into stream
1348 whence - whence argument a la lseek
1349
1350=cut
1351*/
1352
1353static
1354off_t
6d5c85a2
TC
1355realseek_seek(io_glue *igo, off_t offset, int whence) {
1356 io_cb *ig = (io_cb *)igo;
1357 void *p = ig->p;
8d14daab 1358 off_t rc;
6d5c85a2
TC
1359 IOL_DEB( fprintf(IOL_DEBs, "realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
1360 rc = ig->seekcb(p, offset, whence);
02d1d628 1361
6d5c85a2 1362 IOL_DEB( fprintf(IOL_DEBs, "realseek_seek: rc %ld\n", (long) rc) );
02d1d628
AMH
1363 return rc;
1364 /* FIXME: How about implementing this offset handling stuff? */
1365}
1366
d16420e9
TC
1367static
1368void
6d5c85a2
TC
1369realseek_destroy(io_glue *igo) {
1370 io_cb *ig = (io_cb *)igo;
d16420e9 1371
6d5c85a2
TC
1372 if (ig->destroycb)
1373 ig->destroycb(ig->p);
d16420e9
TC
1374}
1375
4dfa5522
AMH
1376/*
1377 * Callbacks for sources that are a fixed size buffer
1378 */
1379
1380/*
1381=item buffer_read(ig, buf, count)
1382
1383Does the reading from a buffer source
1384
1385 ig - io_glue object
1386 buf - buffer to return data in
1387 count - number of bytes to read into buffer max
1388
1389=cut
1390*/
1391
1392static
1393ssize_t
6d5c85a2
TC
1394buffer_read(io_glue *igo, void *buf, size_t count) {
1395 io_buffer *ig = (io_buffer *)igo;
4dfa5522 1396
6d5c85a2 1397 IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) );
4dfa5522 1398
6d5c85a2 1399 if ( ig->cpos+count > ig->len ) {
d03fd5a4 1400 mm_log((1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count));
6d5c85a2 1401 count = ig->len - ig->cpos;
4dfa5522
AMH
1402 }
1403
6d5c85a2
TC
1404 memcpy(buf, ig->data+ig->cpos, count);
1405 ig->cpos += count;
1406 IOL_DEB( fprintf(IOL_DEBs, "buffer_read: count = %ld\n", (long)count) );
4dfa5522
AMH
1407 return count;
1408}
1409
1410
1411/*
1412=item buffer_write(ig, buf, count)
1413
1414Does nothing, returns -1
1415
1416 ig - io_glue object
1417 buf - buffer that contains data
1418 count - number of bytes to write
1419
1420=cut
1421*/
1422
1423static
1424ssize_t
1425buffer_write(io_glue *ig, const void *buf, size_t count) {
d03fd5a4 1426 mm_log((1, "buffer_write called, this method should never be called.\n"));
4dfa5522
AMH
1427 return -1;
1428}
1429
1430
1431/*
1432=item buffer_close(ig)
1433
1434Closes a source that can be seeked on. Not sure if this should be an actual close
1435or not. Does nothing for now. Should be fixed.
1436
1437 ig - data source
1438
1439=cut
1440*/
1441
1442static
2b405c9e 1443int
4dfa5522 1444buffer_close(io_glue *ig) {
d03fd5a4 1445 mm_log((1, "buffer_close(ig %p)\n", ig));
2b405c9e
TC
1446
1447 return 0;
4dfa5522
AMH
1448}
1449
1450
1451/* buffer_seek(ig, offset, whence)
1452
1453Implements seeking for a buffer source.
1454
1455 ig - data source
1456 offset - offset into stream
1457 whence - whence argument a la lseek
1458
1459=cut
1460*/
1461
1462static
1463off_t
6d5c85a2
TC
1464buffer_seek(io_glue *igo, off_t offset, int whence) {
1465 io_buffer *ig = (io_buffer *)igo;
eda1622c 1466 off_t reqpos =
6d5c85a2 1467 calc_seek_offset(ig->cpos, ig->len, offset, whence);
4dfa5522 1468
6d5c85a2 1469 if (reqpos > ig->len) {
d03fd5a4 1470 mm_log((1, "seeking out of readable range\n"));
4dfa5522
AMH
1471 return (off_t)-1;
1472 }
eda1622c
TC
1473 if (reqpos < 0) {
1474 i_push_error(0, "seek before beginning of file");
1475 return (off_t)-1;
1476 }
4dfa5522 1477
6d5c85a2
TC
1478 ig->cpos = reqpos;
1479 IOL_DEB( fprintf(IOL_DEBs, "buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
4dfa5522
AMH
1480
1481 return reqpos;
1482 /* FIXME: How about implementing this offset handling stuff? */
1483}
1484
d16420e9
TC
1485static
1486void
6d5c85a2
TC
1487buffer_destroy(io_glue *igo) {
1488 io_buffer *ig = (io_buffer *)igo;
4dfa5522 1489
6d5c85a2 1490 if (ig->closecb) {
d03fd5a4 1491 mm_log((1,"calling close callback %p for io_buffer\n",
6d5c85a2
TC
1492 ig->closecb));
1493 ig->closecb(ig->closedata);
d16420e9 1494 }
d16420e9 1495}
4dfa5522
AMH
1496
1497
1498
02d1d628
AMH
1499/*
1500 * Callbacks for sources that are a chain of variable sized buffers
1501 */
1502
1503
1504
1505/* Helper functions for buffer chains */
1506
1507static
1508io_blink*
faa9b3e7 1509io_blink_new(void) {
02d1d628
AMH
1510 io_blink *ib;
1511
d03fd5a4 1512 mm_log((1, "io_blink_new()\n"));
02d1d628
AMH
1513
1514 ib = mymalloc(sizeof(io_blink));
1515
1516 ib->next = NULL;
1517 ib->prev = NULL;
1518 ib->len = BBSIZ;
1519
1520 memset(&ib->buf, 0, ib->len);
1521 return ib;
1522}
1523
1524
1525
1526/*
1527=item io_bchain_advance(ieb)
1528
1529Advances the buffer chain to the next link - extending if
1530necessary. Also adjusts the cpos and tfill counters as needed.
1531
1532 ieb - buffer chain object
1533
1534=cut
1535*/
1536
1537static
1538void
1539io_bchain_advance(io_ex_bchain *ieb) {
1540 if (ieb->cp->next == NULL) {
1541 ieb->tail = io_blink_new();
1542 ieb->tail->prev = ieb->cp;
1543 ieb->cp->next = ieb->tail;
1544
1545 ieb->tfill = 0; /* Only set this if we added a new slice */
1546 }
1547 ieb->cp = ieb->cp->next;
1548 ieb->cpos = 0;
1549}
1550
1551
c3cc977e
AMH
1552
1553/*
1554=item io_bchain_destroy()
1555
1556frees all resources used by a buffer chain.
1557
1558=cut
1559*/
1560
6d5c85a2 1561static void
c3cc977e 1562io_destroy_bufchain(io_ex_bchain *ieb) {
4dfa5522
AMH
1563 io_blink *cp;
1564 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
1565 cp = ieb->head;
1566
c3cc977e
AMH
1567 while(cp) {
1568 io_blink *t = cp->next;
4dfa5522 1569 myfree(cp);
c3cc977e
AMH
1570 cp = t;
1571 }
1572}
1573
1574
1575
1576
02d1d628
AMH
1577/*
1578
1579static
1580void
1581bufchain_dump(io_ex_bchain *ieb) {
1582 mm_log((1, " buf_chain_dump(ieb %p)\n"));
1583 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
1584 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
1585 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
1586 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
1587 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
1588 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
1589 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
1590 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
1591}
1592*/
1593
1594/*
1595 * TRUE if lengths are NOT equal
1596 */
1597
1598/*
1599static
1600void
1601chainlencert( io_glue *ig ) {
1602 int clen;
1603 int cfl = 0;
1604 size_t csize = 0;
1605 size_t cpos = 0;
1606 io_ex_bchain *ieb = ig->exdata;
1607 io_blink *cp = ieb->head;
1608
1609
1610 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
1611
1612 while(cp) {
1613 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
1614 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
1615 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
1616
1617 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
1618 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
1619
1620 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
1621 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
1622
1623 if (cp == ieb->cp) {
1624 cfl = 1;
1625 cpos += ieb->cpos;
1626 }
1627
1628 if (!cfl) cpos += clen;
1629
1630 csize += clen;
1631 cp = cp->next;
1632 }
1633 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
1634 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
1635}
1636
1637
1638static
1639void
1640chaincert( io_glue *ig) {
1641 size_t csize = 0;
1642 io_ex_bchain *ieb = ig->exdata;
1643 io_blink *cp = ieb->head;
1644
1645 mm_log((1, "Chain verification.\n"));
1646
1647 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
1648 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
1649 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
1650 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
1651 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
1652 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
1653 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
1654 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
1655
1656 while(cp) {
1657 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
1658 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
1659 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
1660 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
1661
1662 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
1663 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
1664
1665 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
1666 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
1667
1668 csize += clen;
1669 cp = cp->next;
1670 }
1671
1672 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
1673}
1674*/
1675
02d1d628
AMH
1676/*
1677=item bufchain_read(ig, buf, count)
1678
1679Does the reading from a source that can be seeked on
1680
1681 ig - io_glue object
1682 buf - buffer to return data in
1683 count - number of bytes to read into buffer max
1684
1685=cut
1686*/
1687
1688static
1689ssize_t
1690bufchain_read(io_glue *ig, void *buf, size_t count) {
1691 io_ex_bchain *ieb = ig->exdata;
1692 size_t scount = count;
1693 char *cbuf = buf;
1694 size_t sk;
1695
d03fd5a4 1696 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
02d1d628
AMH
1697
1698 while( scount ) {
1699 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1700 if (clen == ieb->cpos) {
1701 if (ieb->cp == ieb->tail) break; /* EOF */
1702 ieb->cp = ieb->cp->next;
1703 ieb->cpos = 0;
1704 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1705 }
1706
1707 sk = clen - ieb->cpos;
1708 sk = sk > scount ? scount : sk;
1709
1710 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
1711 scount -= sk;
1712 ieb->cpos += sk;
1713 ieb->gpos += sk;
1714 }
1715
d03fd5a4 1716 mm_log((1, "bufchain_read: returning %ld\n", (long)(count-scount)));
02d1d628
AMH
1717 return count-scount;
1718}
1719
1720
1721
1722
1723
1724/*
1725=item bufchain_write(ig, buf, count)
1726
1727Does the writing to a 'source' that can be seeked on
1728
1729 ig - io_glue object
1730 buf - buffer that contains data
1731 count - number of bytes to write
1732
1733=cut
1734*/
1735
1736static
1737ssize_t
1738bufchain_write(io_glue *ig, const void *buf, size_t count) {
1739 char *cbuf = (char *)buf;
1740 io_ex_bchain *ieb = ig->exdata;
1741 size_t ocount = count;
1742 size_t sk;
1743
d03fd5a4 1744 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
02d1d628 1745
6d5c85a2 1746 IOL_DEB( fprintf(IOL_DEBs, "bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %ld\n", ig, (long) ieb->cpos, buf, (long)count) );
02d1d628
AMH
1747
1748 while(count) {
d03fd5a4 1749 mm_log((2, "bufchain_write: - looping - count = %ld\n", (long)count));
02d1d628 1750 if (ieb->cp->len == ieb->cpos) {
d03fd5a4 1751 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
02d1d628
AMH
1752 io_bchain_advance(ieb);
1753 }
1754
1755 sk = ieb->cp->len - ieb->cpos;
1756 sk = sk > count ? count : sk;
1757 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
1758
1759 if (ieb->cp == ieb->tail) {
1760 int extend = ieb->cpos + sk - ieb->tfill;
d03fd5a4 1761 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
02d1d628
AMH
1762 if (extend > 0) {
1763 ieb->length += extend;
1764 ieb->tfill += extend;
1765 }
1766 }
1767
1768 ieb->cpos += sk;
1769 ieb->gpos += sk;
1770 count -= sk;
1771 }
1772 return ocount;
1773}
1774
1775/*
1776=item bufchain_close(ig)
1777
1778Closes a source that can be seeked on. Not sure if this should be an actual close
1779or not. Does nothing for now. Should be fixed.
1780
1781 ig - data source
1782
1783=cut
1784*/
1785
1786static
2b405c9e 1787int
02d1d628 1788bufchain_close(io_glue *ig) {
d03fd5a4 1789 mm_log((1, "bufchain_close(ig %p)\n",ig));
6d5c85a2 1790 IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) );
2b405c9e
TC
1791
1792 return 0;
02d1d628
AMH
1793}
1794
1795
1796/* bufchain_seek(ig, offset, whence)
1797
1798Implements seeking for a source that is seekable, the purpose of having this is to be able to
1799have an offset into a file that is different from what the underlying library thinks.
1800
1801 ig - data source
1802 offset - offset into stream
1803 whence - whence argument a la lseek
1804
1805=cut
1806*/
1807
1808static
1809off_t
1810bufchain_seek(io_glue *ig, off_t offset, int whence) {
1811 io_ex_bchain *ieb = ig->exdata;
02d1d628
AMH
1812 int wrlen;
1813
eda1622c 1814 off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
02d1d628
AMH
1815 off_t sk;
1816
d03fd5a4 1817 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
02d1d628 1818
eda1622c
TC
1819 if (scount < 0) {
1820 i_push_error(0, "invalid whence supplied or seek before start of file");
1821 return (off_t)-1;
1822 }
02d1d628 1823
eda1622c
TC
1824 ieb->cp = ieb->head;
1825 ieb->cpos = 0;
1826 ieb->gpos = 0;
1827
1828 while( scount ) {
1829 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1830 if (clen == ieb->cpos) {
1831 if (ieb->cp == ieb->tail) break; /* EOF */
1832 ieb->cp = ieb->cp->next;
1833 ieb->cpos = 0;
1834 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
02d1d628
AMH
1835 }
1836
eda1622c
TC
1837 sk = clen - ieb->cpos;
1838 sk = sk > scount ? scount : sk;
02d1d628 1839
eda1622c
TC
1840 scount -= sk;
1841 ieb->cpos += sk;
1842 ieb->gpos += sk;
1843 }
1844
1845 wrlen = scount;
02d1d628 1846
eda1622c
TC
1847 if (wrlen > 0) {
1848 /*
1849 * extending file - get ieb into consistent state and then
1850 * call write which will get it to the correct position
1851 */
1852 char TB[BBSIZ];
1853 memset(TB, 0, BBSIZ);
1854 ieb->gpos = ieb->length;
02d1d628
AMH
1855 ieb->cpos = ieb->tfill;
1856
eda1622c
TC
1857 while(wrlen > 0) {
1858 ssize_t rc, wl = i_min(wrlen, BBSIZ);
d03fd5a4 1859 mm_log((1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
eda1622c 1860 rc = bufchain_write( ig, TB, wl );
d03fd5a4 1861 if (rc != wl) i_fatal(0, "bufchain_seek: Unable to extend file\n");
eda1622c 1862 wrlen -= rc;
02d1d628 1863 }
02d1d628
AMH
1864 }
1865
d03fd5a4 1866 mm_log((2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
02d1d628
AMH
1867 return ieb->gpos;
1868}
1869
d16420e9
TC
1870static
1871void
1872bufchain_destroy(io_glue *ig) {
1873 io_ex_bchain *ieb = ig->exdata;
02d1d628 1874
d16420e9 1875 io_destroy_bufchain(ieb);
02d1d628 1876
d16420e9
TC
1877 myfree(ieb);
1878}
02d1d628 1879
10461f9a
TC
1880/*
1881=item fd_read(ig, buf, count)
1882
6d5c85a2
TC
1883Read callback for file descriptor IO objects.
1884
10461f9a
TC
1885=cut
1886*/
6d5c85a2
TC
1887static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
1888 io_fdseek *ig = (io_fdseek *)igo;
5f8f8e17 1889 ssize_t result;
10461f9a 1890#ifdef _MSC_VER
6d5c85a2 1891 result = _read(ig->fd, buf, count);
10461f9a 1892#else
6d5c85a2 1893 result = read(ig->fd, buf, count);
10461f9a 1894#endif
5f8f8e17 1895
6d5c85a2
TC
1896 IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf,
1897 (unsigned)count, (int)result));
1898
5f8f8e17
TC
1899 /* 0 is valid - means EOF */
1900 if (result < 0) {
d03fd5a4 1901 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
5f8f8e17
TC
1902 }
1903
1904 return result;
10461f9a
TC
1905}
1906
6d5c85a2
TC
1907static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) {
1908 io_fdseek *ig = (io_fdseek *)igo;
2691d220 1909 ssize_t result;
10461f9a 1910#ifdef _MSC_VER
6d5c85a2 1911 result = _write(ig->fd, buf, count);
10461f9a 1912#else
6d5c85a2 1913 result = write(ig->fd, buf, count);
10461f9a 1914#endif
2691d220 1915
6d5c85a2
TC
1916 IOL_DEB(fprintf(IOL_DEBs, "fd_write(%p, %p, %u) => %d\n", ig, buf,
1917 (unsigned)count, (int)result));
1918
2691d220 1919 if (result <= 0) {
d03fd5a4 1920 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
2691d220
TC
1921 }
1922
1923 return result;
10461f9a
TC
1924}
1925
6d5c85a2
TC
1926static off_t fd_seek(io_glue *igo, off_t offset, int whence) {
1927 io_fdseek *ig = (io_fdseek *)igo;
2691d220 1928 off_t result;
10461f9a 1929#ifdef _MSC_VER
6d5c85a2 1930 result = _lseek(ig->fd, offset, whence);
10461f9a 1931#else
6d5c85a2 1932 result = lseek(ig->fd, offset, whence);
10461f9a 1933#endif
2691d220
TC
1934
1935 if (result == (off_t)-1) {
d03fd5a4 1936 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
2691d220
TC
1937 }
1938
1939 return result;
10461f9a
TC
1940}
1941
2b405c9e 1942static int fd_close(io_glue *ig) {
10461f9a 1943 /* no, we don't close it */
2b405c9e 1944 return 0;
10461f9a
TC
1945}
1946
1947static ssize_t fd_size(io_glue *ig) {
d03fd5a4 1948 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
10461f9a
TC
1949
1950 return -1;
1951}
02d1d628 1952
b8c2033e
AMH
1953
1954/*
1955=back
1956
1957=head1 AUTHOR
1958
1959Arnar M. Hrafnkelsson <addi@umich.edu>
1960
1961=head1 SEE ALSO
1962
1963Imager(3)
1964
1965=cut
1966*/