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