]> git.imager.perl.org - imager.git/blob - iolayer.c
Merge branch 'png'
[imager.git] / iolayer.c
1 #include "imager.h"
2 #include "iolayer.h"
3 #include "imerror.h"
4 #include "log.h"
5 #include <stdlib.h>
6 #include <stdio.h>
7 #ifdef _MSC_VER
8 #include <io.h>
9 #endif
10 #include <string.h>
11 #include <errno.h>
12 #include "imageri.h"
13
14 #define IOL_DEB(x)
15 #define IOL_DEBs stderr
16
17 #define IO_BUF_SIZE 8192
18
19 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
20
21 typedef 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
30 typedef struct {
31   i_io_glue_t   base;
32   int           fd;
33 } io_fdseek;
34
35 typedef struct {
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;
41   off_t cpos;
42 } io_buffer;
43
44 typedef 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;
53
54 typedef 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
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)
70
71 /*
72 =head1 NAME
73
74 iolayer.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
80
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
92   io_glue_destroy(ig);
93   // and much more
94
95 =head1 DESCRIPTION
96
97 iolayer.c implements the basic functions to create and destroy io_glue
98 objects 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
108 Some of these functions are internal.
109
110 =over
111
112 =cut
113 */
114
115 static void
116 i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
117           i_io_seekp_t seekcb);
118
119 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
120 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
121 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
122 static int fd_close(io_glue *ig);
123 static ssize_t fd_size(io_glue *ig);
124 static const char *my_strerror(int err);
125 static void i_io_setup_buffer(io_glue *ig);
126 static void
127 i_io_start_write(io_glue *ig);
128 static int
129 i_io_read_fill(io_glue *ig, ssize_t needed);
130 static void
131 dump_data(unsigned char *start, unsigned char *end, int bias);
132 static ssize_t realseek_read(io_glue *igo, void *buf, size_t count);
133 static ssize_t realseek_write(io_glue *igo, const void *buf, size_t count);
134 static int realseek_close(io_glue *igo);
135 static off_t realseek_seek(io_glue *igo, off_t offset, int whence);
136 static void realseek_destroy(io_glue *igo);
137 static ssize_t buffer_read(io_glue *igo, void *buf, size_t count);
138 static ssize_t buffer_write(io_glue *ig, const void *buf, size_t count);
139 static int buffer_close(io_glue *ig);
140 static off_t buffer_seek(io_glue *igo, off_t offset, int whence);
141 static void buffer_destroy(io_glue *igo);
142 static io_blink*io_blink_new(void);
143 static void io_bchain_advance(io_ex_bchain *ieb);
144 static void io_destroy_bufchain(io_ex_bchain *ieb);
145 static ssize_t bufchain_read(io_glue *ig, void *buf, size_t count);
146 static ssize_t bufchain_write(io_glue *ig, const void *buf, size_t count);
147 static int bufchain_close(io_glue *ig);
148 static off_t bufchain_seek(io_glue *ig, off_t offset, int whence);
149 static void bufchain_destroy(io_glue *ig);
150
151 /*
152  * Methods for setting up data source
153  */
154
155 /*
156 =item io_new_bufchain()
157 =order 10
158 =category I/O Layers
159
160 returns a new io_glue object that has the 'empty' source and but can
161 be written to and read from later (like a pseudo file).
162
163 =cut
164 */
165
166 io_glue *
167 io_new_bufchain() {
168   io_glue *ig;
169   io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
170
171   mm_log((1, "io_new_bufchain()\n"));
172
173   ig = mymalloc(sizeof(io_glue));
174   memset(ig, 0, sizeof(*ig));
175   i_io_init(ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek);
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;
192 }
193
194 /*
195 =item io_new_buffer(data, length)
196 =order 10
197 =category I/O Layers
198
199 Returns a new io_glue object that has the source defined as reading
200 from specified buffer.  Note that the buffer is not copied.
201
202    data - buffer to read from
203    length - length of buffer
204
205 =cut
206 */
207
208 io_glue *
209 io_new_buffer(const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
210   io_buffer *ig;
211   
212   mm_log((1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
213
214   ig = mymalloc(sizeof(io_buffer));
215   memset(ig, 0, sizeof(*ig));
216   i_io_init(&ig->base, BUFFER, buffer_read, buffer_write, buffer_seek);
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 }
229
230
231 /*
232 =item io_new_fd(fd)
233 =order 10
234 =category I/O Layers
235
236 returns a new io_glue object that has the source defined as reading
237 from specified file descriptor.  Note that the the interface to receiving
238 data from the io_glue callbacks hasn't been done yet.
239
240    fd - file descriptor to read/write from
241
242 =cut
243 */
244
245 io_glue *
246 io_new_fd(int fd) {
247   io_fdseek *ig;
248
249   mm_log((1, "io_new_fd(fd %d)\n", fd));
250
251   ig = mymalloc(sizeof(io_fdseek));
252   memset(ig, 0, sizeof(*ig));
253   i_io_init(&ig->base, FDSEEK, fd_read, fd_write, fd_seek);
254   ig->fd = fd;
255
256   ig->base.closecb   = fd_close;
257   ig->base.sizecb    = fd_size;
258   ig->base.destroycb = NULL;
259
260   mm_log((1, "(%p) <- io_new_fd\n", ig));
261   return (io_glue *)ig;
262 }
263
264 /*
265 =item io_new_cb(p, read_cb, write_cb, seek_cb, close_cb, destroy_cb)
266 =category I/O Layers
267 =order 10
268
269 Create a new I/O layer object that calls your supplied callbacks.
270
271 In general the callbacks should behave like the corresponding POSIX
272 primitives.
273
274 =over
275
276 =item *
277
278 C<read_cb>(p, buffer, length) should read up to C<length> bytes into
279 C<buffer> and return the number of bytes read.  At end of file, return
280 0.  On error, return -1.
281
282 =item *
283
284 C<write_cb>(p, buffer, length) should write up to C<length> bytes from
285 C<buffer> and return the number of bytes written.  A return value <= 0
286 will be treated as an error.
287
288 =item *
289
290 C<seekcb>(p, offset, whence) should seek and return the new offset.
291
292 =item *
293
294 C<close_cb>(p) should return 0 on success, -1 on failure.
295
296 =item *
297
298 C<destroy_cb>(p) should release any memory specific to your callback
299 handlers.
300
301 =back
302
303 =cut
304 */
305
306 io_glue *
307 io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb, 
308           i_io_seekl_t seekcb, i_io_closel_t closecb, 
309           i_io_destroyl_t destroycb) {
310   io_cb *ig;
311
312   mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
313           "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
314   ig = mymalloc(sizeof(io_cb));
315   memset(ig, 0, sizeof(*ig));
316   i_io_init(&ig->base, CBSEEK, realseek_read, realseek_write, realseek_seek);
317   mm_log((1, "(%p) <- io_new_cb\n", ig));
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
336 Takes the source that the io_glue is bound to and allocates space for
337 a return buffer and returns the entire content in a single buffer.
338 Note: This only works for io_glue objects created by
339 io_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
349 io_slurp() will abort the program if the supplied I/O layer is not
350 from io_new_bufchain().
351
352 =cut
353 */
354
355 size_t
356 io_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 ) {
364     i_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
365   }
366
367   ieb = ig->exdata;
368   cc = *c = mymalloc( ieb->length );
369   
370   orgoff = ieb->gpos;
371   
372   bufchain_seek(ig, 0, SEEK_SET);
373   
374   rc = bufchain_read(ig, cc, ieb->length);
375
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);
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
388 Destroy an io_glue objects.  Should clean up all related buffers.
389
390    ig - io_glue object to destroy.
391
392 =cut
393 */
394
395 void
396 io_glue_destroy(io_glue *ig) {
397   mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
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
412 A macro to read a single byte from a buffered I/O glue object.
413
414 Returns EOF on failure, or a byte.
415
416 =cut
417 */
418
419 int
420 i_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
458 Read the next character from the stream without advancing the stream.
459
460 On error or end of file, return EOF.
461
462 For unbuffered streams a single character buffer will be setup.
463
464 =cut
465 */
466
467 int
468 i_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
508 Buffer at least C<size> (at most C<< ig->buf_size >> bytes of data
509 from the stream and return C<size> bytes of it to the caller in
510 C<buffer>.
511
512 This ignores the buffered state of the stream, and will always setup
513 buffering if needed.
514
515 If no C<type> parameter is provided to Imager::read() or
516 Imager::read_multi(), Imager will call C<i_io_peekn()> when probing
517 for the file format.
518
519 Returns -1 on error, 0 if there is no data before EOF, or the number
520 of bytes read into C<buffer>.
521
522 =cut
523 */
524
525 ssize_t
526 i_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
575 Write a single character to the stream.
576
577 On success return c, on error returns EOF
578
579 =cut
580 */
581
582 int
583 i_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;
589     int result = c;
590
591     if (ig->error)
592       return EOF;
593
594     write_result = i_io_raw_write(ig, &buf, 1);
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
630 Read up to C<size> bytes from the stream C<io> into C<buffer>.
631
632 Returns the number of bytes read.  Returns 0 on end of file.  Returns
633 -1 on error.
634
635 =cut
636 */
637
638 ssize_t
639 i_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
720 Write to the given I/O stream.
721
722 Returns the number of bytes written.
723
724 =cut
725 */
726
727 ssize_t
728 i_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
820 Seek within the stream.
821
822 Acts like perl's seek.
823
824 =cut
825  */
826
827 off_t
828 i_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
859 Flush any buffered output.
860
861 Returns true on success,
862
863 =cut
864 */
865
866 int
867 i_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
904 Flush any pending output and perform the close action for the stream.
905
906 Returns 0 on success.
907
908 =cut
909 */
910
911 int
912 i_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
936 Read up to C<size>-1 bytes from the stream C<ig> into C<buffer>.
937
938 If the byte C<end_of_line> is seen then no further bytes will be read.
939
940 Returns the number of bytes read.
941
942 Always C<NUL> terminates the buffer.
943
944 =cut
945 */
946
947 ssize_t
948 i_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
971 Do common initialization for io_glue objects.
972
973 =cut
974 */
975
976 static void
977 i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
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
1003 Set the buffering mode of the stream.
1004
1005 If you switch buffering off on a stream with buffering on:
1006
1007 =over
1008
1009 =item *
1010
1011 any buffered output will be flushed.
1012
1013 =item *
1014
1015 any existing buffered input will be consumed before reads become
1016 unbuffered.
1017
1018 =back
1019
1020 Returns true on success.  This may fail if any buffered output cannot
1021 be flushed.
1022
1023 =cut
1024 */
1025
1026 int
1027 i_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
1042 Dump the base fields of an io_glue object to stdout.
1043
1044 =cut
1045 */
1046 void
1047 i_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
1092 Calls strerror() and ensures we don't return NULL.
1093
1094 On some platforms it's possible for strerror() to return NULL, this
1095 wrapper ensures we only get non-NULL values.
1096
1097 =cut
1098 */
1099
1100 static
1101 const 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
1110 static void
1111 i_io_setup_buffer(io_glue *ig) {
1112   ig->buffer = mymalloc(ig->buf_size);
1113 }
1114
1115 static void
1116 i_io_start_write(io_glue *ig) {
1117   ig->write_ptr = ig->buffer;
1118   ig->write_end = ig->buffer + ig->buf_size;
1119 }
1120
1121 static int
1122 i_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
1189 Hex dump the data between C<start> and C<end>.
1190
1191 If there is more than a pleasing amount of data, either dump the
1192 beginning (C<bias == 0>) or dump the end C(<bias != 0>) of the range.
1193
1194 =cut
1195 */
1196
1197 static void
1198 dump_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
1256 Does 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
1265 static
1266 ssize_t 
1267 realseek_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;
1279 }
1280
1281
1282 /*
1283 =item realseek_write(ig, buf, count)
1284
1285 Does 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
1294 static
1295 ssize_t 
1296 realseek_write(io_glue *igo, const void *buf, size_t count) {
1297   io_cb        *ig = (io_cb *)igo;
1298   void          *p = ig->p;
1299   ssize_t       rc = 0;
1300   size_t        bc = 0;
1301   char       *cbuf = (char*)buf; 
1302   
1303   IOL_DEB( fprintf(IOL_DEBs, "realseek_write: ig = %p, buf = %p, "
1304                    "count = %u\n", ig, buf, (unsigned)count) );
1305
1306   /* Is this a good idea? Would it be better to handle differently? 
1307      skip handling? */
1308   while( count!=bc && (rc = ig->writecb(p,cbuf+bc,count-bc))>0 ) {
1309     bc+=rc;
1310   }
1311
1312   IOL_DEB( fprintf(IOL_DEBs, "realseek_write: rc = %d, bc = %u\n", (int)rc, (unsigned)bc) );
1313   return rc < 0 ? rc : bc;
1314 }
1315
1316
1317 /*
1318 =item realseek_close(ig)
1319
1320 Closes a source that can be seeked on.  Not sure if this should be an
1321 actual close or not.  Does nothing for now.  Should be fixed.
1322
1323    ig - data source
1324
1325 =cut */
1326
1327 static
1328 int
1329 realseek_close(io_glue *igo) {
1330   io_cb *ig = (io_cb *)igo;
1331
1332   IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig));
1333   mm_log((1, "realseek_close(ig %p)\n", ig));
1334   if (ig->closecb)
1335     return ig->closecb(ig->p);
1336   else
1337     return 0;
1338 }
1339
1340
1341 /* realseek_seek(ig, offset, whence)
1342
1343 Implements seeking for a source that is seekable, the purpose of having this is to be able to
1344 have 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
1353 static
1354 off_t
1355 realseek_seek(io_glue *igo, off_t offset, int whence) {
1356   io_cb *ig = (io_cb *)igo;
1357   void *p = ig->p;
1358   off_t rc;
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);
1361
1362   IOL_DEB( fprintf(IOL_DEBs, "realseek_seek: rc %ld\n", (long) rc) );
1363   return rc;
1364   /* FIXME: How about implementing this offset handling stuff? */
1365 }
1366
1367 static
1368 void
1369 realseek_destroy(io_glue *igo) {
1370   io_cb *ig = (io_cb *)igo;
1371
1372   if (ig->destroycb)
1373     ig->destroycb(ig->p);
1374 }
1375
1376 /*
1377  * Callbacks for sources that are a fixed size buffer
1378  */
1379
1380 /*
1381 =item buffer_read(ig, buf, count)
1382
1383 Does 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
1392 static
1393 ssize_t 
1394 buffer_read(io_glue *igo, void *buf, size_t count) {
1395   io_buffer *ig = (io_buffer *)igo;
1396
1397   IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) );
1398
1399   if ( ig->cpos+count > ig->len ) {
1400     mm_log((1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count));
1401     count = ig->len - ig->cpos;
1402   }
1403   
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) );
1407   return count;
1408 }
1409
1410
1411 /*
1412 =item buffer_write(ig, buf, count)
1413
1414 Does 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
1423 static
1424 ssize_t 
1425 buffer_write(io_glue *ig, const void *buf, size_t count) {
1426   mm_log((1, "buffer_write called, this method should never be called.\n"));
1427   return -1;
1428 }
1429
1430
1431 /*
1432 =item buffer_close(ig)
1433
1434 Closes a source that can be seeked on.  Not sure if this should be an actual close
1435 or not.  Does nothing for now.  Should be fixed.
1436
1437    ig - data source
1438
1439 =cut
1440 */
1441
1442 static
1443 int
1444 buffer_close(io_glue *ig) {
1445   mm_log((1, "buffer_close(ig %p)\n", ig));
1446
1447   return 0;
1448 }
1449
1450
1451 /* buffer_seek(ig, offset, whence)
1452
1453 Implements 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
1462 static
1463 off_t
1464 buffer_seek(io_glue *igo, off_t offset, int whence) {
1465   io_buffer *ig = (io_buffer *)igo;
1466   off_t reqpos = 
1467     calc_seek_offset(ig->cpos, ig->len, offset, whence);
1468   
1469   if (reqpos > ig->len) {
1470     mm_log((1, "seeking out of readable range\n"));
1471     return (off_t)-1;
1472   }
1473   if (reqpos < 0) {
1474     i_push_error(0, "seek before beginning of file");
1475     return (off_t)-1;
1476   }
1477   
1478   ig->cpos = reqpos;
1479   IOL_DEB( fprintf(IOL_DEBs, "buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
1480
1481   return reqpos;
1482   /* FIXME: How about implementing this offset handling stuff? */
1483 }
1484
1485 static
1486 void
1487 buffer_destroy(io_glue *igo) {
1488   io_buffer *ig = (io_buffer *)igo;
1489
1490   if (ig->closecb) {
1491     mm_log((1,"calling close callback %p for io_buffer\n", 
1492             ig->closecb));
1493     ig->closecb(ig->closedata);
1494   }
1495 }
1496
1497
1498
1499 /*
1500  * Callbacks for sources that are a chain of variable sized buffers
1501  */
1502
1503
1504
1505 /* Helper functions for buffer chains */
1506
1507 static
1508 io_blink*
1509 io_blink_new(void) {
1510   io_blink *ib;
1511
1512   mm_log((1, "io_blink_new()\n"));
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
1529 Advances the buffer chain to the next link - extending if
1530 necessary.  Also adjusts the cpos and tfill counters as needed.
1531
1532    ieb   - buffer chain object
1533
1534 =cut
1535 */
1536
1537 static
1538 void
1539 io_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
1552
1553 /*
1554 =item io_bchain_destroy()
1555
1556 frees all resources used by a buffer chain.
1557
1558 =cut
1559 */
1560
1561 static void
1562 io_destroy_bufchain(io_ex_bchain *ieb) {
1563   io_blink *cp;
1564   mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
1565   cp = ieb->head;
1566   
1567   while(cp) {
1568     io_blink *t = cp->next;
1569     myfree(cp);
1570     cp = t;
1571   }
1572 }
1573
1574
1575
1576
1577 /*
1578
1579 static
1580 void
1581 bufchain_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 /*
1599 static
1600 void
1601 chainlencert( 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
1638 static
1639 void
1640 chaincert( 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
1676 /*
1677 =item bufchain_read(ig, buf, count)
1678
1679 Does 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
1688 static
1689 ssize_t 
1690 bufchain_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
1696   mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
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
1716   mm_log((1, "bufchain_read: returning %ld\n", (long)(count-scount)));
1717   return count-scount;
1718 }
1719
1720
1721
1722
1723
1724 /*
1725 =item bufchain_write(ig, buf, count)
1726
1727 Does 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
1736 static
1737 ssize_t
1738 bufchain_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
1744   mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
1745
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) );
1747   
1748   while(count) {
1749     mm_log((2, "bufchain_write: - looping - count = %ld\n", (long)count));
1750     if (ieb->cp->len == ieb->cpos) {
1751       mm_log((1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
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;
1761       mm_log((2, "bufchain_write: extending tail by %d\n", extend));
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
1778 Closes a source that can be seeked on.  Not sure if this should be an actual close
1779 or not.  Does nothing for now.  Should be fixed.
1780
1781    ig - data source
1782
1783 =cut
1784 */
1785
1786 static
1787 int
1788 bufchain_close(io_glue *ig) {
1789   mm_log((1, "bufchain_close(ig %p)\n",ig));
1790   IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) );
1791
1792   return 0;  
1793 }
1794
1795
1796 /* bufchain_seek(ig, offset, whence)
1797
1798 Implements seeking for a source that is seekable, the purpose of having this is to be able to
1799 have 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
1808 static
1809 off_t
1810 bufchain_seek(io_glue *ig, off_t offset, int whence) {
1811   io_ex_bchain *ieb = ig->exdata;
1812   int wrlen;
1813
1814   off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
1815   off_t sk;
1816
1817   mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
1818
1819   if (scount < 0) {
1820     i_push_error(0, "invalid whence supplied or seek before start of file");
1821     return (off_t)-1;
1822   }
1823
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;
1835     }
1836     
1837     sk = clen - ieb->cpos;
1838     sk = sk > scount ? scount : sk;
1839     
1840     scount    -= sk;
1841     ieb->cpos += sk;
1842     ieb->gpos += sk;
1843   }
1844   
1845   wrlen = scount;
1846
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;
1855     ieb->cpos = ieb->tfill;
1856     
1857     while(wrlen > 0) {
1858       ssize_t rc, wl = i_min(wrlen, BBSIZ);
1859       mm_log((1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
1860       rc = bufchain_write( ig, TB, wl );
1861       if (rc != wl) i_fatal(0, "bufchain_seek: Unable to extend file\n");
1862       wrlen -= rc;
1863     }
1864   }
1865
1866   mm_log((2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
1867   return ieb->gpos;
1868 }
1869
1870 static
1871 void
1872 bufchain_destroy(io_glue *ig) {
1873   io_ex_bchain *ieb = ig->exdata;
1874
1875   io_destroy_bufchain(ieb);
1876
1877   myfree(ieb);
1878 }
1879
1880 /*
1881 =item fd_read(ig, buf, count)
1882
1883 Read callback for file descriptor IO objects.
1884
1885 =cut
1886 */
1887 static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
1888   io_fdseek *ig = (io_fdseek *)igo;
1889   ssize_t result;
1890 #ifdef _MSC_VER
1891   result = _read(ig->fd, buf, count);
1892 #else
1893   result = read(ig->fd, buf, count);
1894 #endif
1895
1896   IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf,
1897                   (unsigned)count, (int)result));
1898
1899   /* 0 is valid - means EOF */
1900   if (result < 0) {
1901     i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1902   }
1903
1904   return result;
1905 }
1906
1907 static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) {
1908   io_fdseek *ig = (io_fdseek *)igo;
1909   ssize_t result;
1910 #ifdef _MSC_VER
1911   result = _write(ig->fd, buf, count);
1912 #else
1913   result = write(ig->fd, buf, count);
1914 #endif
1915
1916   IOL_DEB(fprintf(IOL_DEBs, "fd_write(%p, %p, %u) => %d\n", ig, buf,
1917                   (unsigned)count, (int)result));
1918
1919   if (result <= 0) {
1920     i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1921   }
1922
1923   return result;
1924 }
1925
1926 static off_t fd_seek(io_glue *igo, off_t offset, int whence) {
1927   io_fdseek *ig = (io_fdseek *)igo;
1928   off_t result;
1929 #ifdef _MSC_VER
1930   result = _lseek(ig->fd, offset, whence);
1931 #else
1932   result = lseek(ig->fd, offset, whence);
1933 #endif
1934
1935   if (result == (off_t)-1) {
1936     i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1937   }
1938
1939   return result;
1940 }
1941
1942 static int fd_close(io_glue *ig) {
1943   /* no, we don't close it */
1944   return 0;
1945 }
1946
1947 static ssize_t fd_size(io_glue *ig) {
1948   mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1949   
1950   return -1;
1951 }
1952
1953
1954 /*
1955 =back
1956
1957 =head1 AUTHOR
1958
1959 Arnar M. Hrafnkelsson <addi@umich.edu>
1960
1961 =head1 SEE ALSO
1962
1963 Imager(3)
1964
1965 =cut
1966 */