update I/O layers to accept a context on creation
[imager.git] / iolayer.c
CommitLineData
ed60e785 1#define IMAGER_NO_CONTEXT
e310e5f9 2#include "imager.h"
02d1d628 3#include "iolayer.h"
af070d99 4#include "imerror.h"
02d1d628
AMH
5#include "log.h"
6#include <stdlib.h>
7#include <stdio.h>
8#ifdef _MSC_VER
9#include <io.h>
10#endif
35891892 11#include <string.h>
2691d220 12#include <errno.h>
50c75381 13#include "imageri.h"
02d1d628 14
ed60e785
TC
15#define dIMCTXio(io) dIMCTXctx((io)->context)
16
02d1d628 17#define IOL_DEB(x)
6d5c85a2 18#define IOL_DEBs stderr
02d1d628 19
6d5c85a2 20#define IO_BUF_SIZE 8192
02d1d628
AMH
21
22char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
23
299da279
TC
24typedef 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
299da279 33typedef struct {
6d5c85a2
TC
34 i_io_glue_t base;
35 int fd;
36} io_fdseek;
299da279
TC
37
38typedef struct {
6d5c85a2
TC
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;
299da279 44 off_t cpos;
6d5c85a2 45} io_buffer;
299da279 46
6d5c85a2
TC
47typedef 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;
299da279
TC
56
57typedef 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
eda1622c
TC
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)
02d1d628
AMH
73
74/*
75=head1 NAME
76
77iolayer.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
6d5c85a2 83
02d1d628
AMH
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
d16420e9 95 io_glue_destroy(ig);
02d1d628
AMH
96 // and much more
97
98=head1 DESCRIPTION
99
100iolayer.c implements the basic functions to create and destroy io_glue
101objects 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
111Some of these functions are internal.
112
b8c2033e 113=over
02d1d628
AMH
114
115=cut
116*/
117
6d5c85a2 118static void
ed60e785
TC
119i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb,
120 i_io_writep_t writecb, i_io_seekp_t seekcb);
6d5c85a2 121
10461f9a
TC
122static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
123static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
124static off_t fd_seek(io_glue *ig, off_t offset, int whence);
2b405c9e 125static int fd_close(io_glue *ig);
10461f9a 126static ssize_t fd_size(io_glue *ig);
40d75d5a 127static const char *my_strerror(int err);
6d5c85a2
TC
128static void i_io_setup_buffer(io_glue *ig);
129static void
130i_io_start_write(io_glue *ig);
131static int
132i_io_read_fill(io_glue *ig, ssize_t needed);
133static void
134dump_data(unsigned char *start, unsigned char *end, int bias);
135static ssize_t realseek_read(io_glue *igo, void *buf, size_t count);
136static ssize_t realseek_write(io_glue *igo, const void *buf, size_t count);
137static int realseek_close(io_glue *igo);
138static off_t realseek_seek(io_glue *igo, off_t offset, int whence);
139static void realseek_destroy(io_glue *igo);
140static ssize_t buffer_read(io_glue *igo, void *buf, size_t count);
141static ssize_t buffer_write(io_glue *ig, const void *buf, size_t count);
142static int buffer_close(io_glue *ig);
143static off_t buffer_seek(io_glue *igo, off_t offset, int whence);
144static void buffer_destroy(io_glue *igo);
145static io_blink*io_blink_new(void);
146static void io_bchain_advance(io_ex_bchain *ieb);
147static void io_destroy_bufchain(io_ex_bchain *ieb);
148static ssize_t bufchain_read(io_glue *ig, void *buf, size_t count);
149static ssize_t bufchain_write(io_glue *ig, const void *buf, size_t count);
150static int bufchain_close(io_glue *ig);
151static off_t bufchain_seek(io_glue *ig, off_t offset, int whence);
152static void bufchain_destroy(io_glue *ig);
02d1d628
AMH
153
154/*
6d5c85a2 155 * Methods for setting up data source
02d1d628
AMH
156 */
157
6d5c85a2 158/*
ed60e785 159=item io_new_bufchain(ctx)
6d5c85a2
TC
160=order 10
161=category I/O Layers
162
d03fd5a4 163returns a new io_glue object that has the 'empty' source and but can
6d5c85a2
TC
164be written to and read from later (like a pseudo file).
165
166=cut
167*/
168
169io_glue *
ed60e785 170im_io_new_bufchain(pIMCTX) {
6d5c85a2
TC
171 io_glue *ig;
172 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
173
ed60e785 174 im_log((aIMCTX, 1, "io_new_bufchain()\n"));
6d5c85a2
TC
175
176 ig = mymalloc(sizeof(io_glue));
177 memset(ig, 0, sizeof(*ig));
ed60e785 178 i_io_init(aIMCTX, ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek);
6d5c85a2
TC
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
ed60e785
TC
194 im_context_refinc(aIMCTX, "im_io_new_bufchain");
195
6d5c85a2 196 return ig;
02d1d628 197}
6d5c85a2
TC
198
199/*
d03fd5a4 200=item io_new_buffer(data, length)
6d5c85a2
TC
201=order 10
202=category I/O Layers
203
204Returns a new io_glue object that has the source defined as reading
205from specified buffer. Note that the buffer is not copied.
206
207 data - buffer to read from
208 length - length of buffer
209
210=cut
02d1d628
AMH
211*/
212
6d5c85a2 213io_glue *
ed60e785 214im_io_new_buffer(pIMCTX, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
6d5c85a2
TC
215 io_buffer *ig;
216
ed60e785 217 im_log((aIMCTX, 1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
6d5c85a2
TC
218
219 ig = mymalloc(sizeof(io_buffer));
220 memset(ig, 0, sizeof(*ig));
ed60e785 221 i_io_init(aIMCTX, &ig->base, BUFFER, buffer_read, buffer_write, buffer_seek);
6d5c85a2
TC
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
ed60e785
TC
232 im_context_refinc(aIMCTX, "im_io_new_bufchain");
233
6d5c85a2
TC
234 return (io_glue *)ig;
235}
02d1d628
AMH
236
237
238/*
d03fd5a4 239=item io_new_fd(fd)
6d5c85a2
TC
240=order 10
241=category I/O Layers
242
d03fd5a4 243returns a new io_glue object that has the source defined as reading
6d5c85a2
TC
244from specified file descriptor. Note that the the interface to receiving
245data from the io_glue callbacks hasn't been done yet.
246
d03fd5a4 247 fd - file descriptor to read/write from
6d5c85a2
TC
248
249=cut
250*/
251
252io_glue *
ed60e785 253im_io_new_fd(pIMCTX, int fd) {
6d5c85a2
TC
254 io_fdseek *ig;
255
ed60e785 256 im_log((aIMCTX, 1, "io_new_fd(fd %d)\n", fd));
6d5c85a2
TC
257
258 ig = mymalloc(sizeof(io_fdseek));
259 memset(ig, 0, sizeof(*ig));
ed60e785 260 i_io_init(aIMCTX, &ig->base, FDSEEK, fd_read, fd_write, fd_seek);
6d5c85a2
TC
261 ig->fd = fd;
262
263 ig->base.closecb = fd_close;
264 ig->base.sizecb = fd_size;
265 ig->base.destroycb = NULL;
ed60e785 266 im_context_refinc(aIMCTX, "im_io_new_bufchain");
6d5c85a2 267
ed60e785 268 im_log((aIMCTX, 1, "(%p) <- io_new_fd\n", ig));
6d5c85a2
TC
269 return (io_glue *)ig;
270}
02d1d628
AMH
271
272/*
d03fd5a4 273=item io_new_cb(p, read_cb, write_cb, seek_cb, close_cb, destroy_cb)
6d5c85a2
TC
274=category I/O Layers
275=order 10
02d1d628 276
6d5c85a2 277Create a new I/O layer object that calls your supplied callbacks.
02d1d628 278
6d5c85a2
TC
279In general the callbacks should behave like the corresponding POSIX
280primitives.
281
282=over
283
284=item *
285
286C<read_cb>(p, buffer, length) should read up to C<length> bytes into
287C<buffer> and return the number of bytes read. At end of file, return
2880. On error, return -1.
289
290=item *
291
292C<write_cb>(p, buffer, length) should write up to C<length> bytes from
293C<buffer> and return the number of bytes written. A return value <= 0
294will be treated as an error.
295
296=item *
297
298C<seekcb>(p, offset, whence) should seek and return the new offset.
299
300=item *
301
302C<close_cb>(p) should return 0 on success, -1 on failure.
303
304=item *
305
306C<destroy_cb>(p) should release any memory specific to your callback
307handlers.
308
309=back
02d1d628
AMH
310
311=cut
312*/
313
6d5c85a2 314io_glue *
ed60e785 315im_io_new_cb(pIMCTX, void *p, i_io_readl_t readcb, i_io_writel_t writecb,
6d5c85a2
TC
316 i_io_seekl_t seekcb, i_io_closel_t closecb,
317 i_io_destroyl_t destroycb) {
318 io_cb *ig;
02d1d628 319
ed60e785 320 im_log((aIMCTX, 1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
6d5c85a2
TC
321 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
322 ig = mymalloc(sizeof(io_cb));
323 memset(ig, 0, sizeof(*ig));
ed60e785
TC
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));
6d5c85a2
TC
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;
ed60e785
TC
336
337 im_context_refinc(aIMCTX, "im_io_new_bufchain");
6d5c85a2
TC
338
339 return (io_glue *)ig;
340}
341
342/*
343=item io_slurp(ig, c)
344=category I/O Layers
345
346Takes the source that the io_glue is bound to and allocates space for
347a return buffer and returns the entire content in a single buffer.
348Note: This only works for io_glue objects created by
349io_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
359io_slurp() will abort the program if the supplied I/O layer is not
360from io_new_bufchain().
361
362=cut
363*/
364
365size_t
366io_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 ) {
d03fd5a4 374 i_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
10461f9a 375 }
6d5c85a2
TC
376
377 ieb = ig->exdata;
378 cc = *c = mymalloc( ieb->length );
02d1d628 379
6d5c85a2
TC
380 orgoff = ieb->gpos;
381
382 bufchain_seek(ig, 0, SEEK_SET);
383
384 rc = bufchain_read(ig, cc, ieb->length);
385
d03fd5a4
TC
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);
6d5c85a2
TC
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
398Destroy an io_glue objects. Should clean up all related buffers.
399
400 ig - io_glue object to destroy.
401
402=cut
403*/
404
405void
406io_glue_destroy(io_glue *ig) {
ed60e785
TC
407 dIMCTXio(ig);
408 im_log((aIMCTX, 1, "io_glue_DESTROY(ig %p)\n", ig));
6d5c85a2
TC
409
410 if (ig->destroycb)
411 ig->destroycb(ig);
412
413 if (ig->buffer)
414 myfree(ig->buffer);
415
416 myfree(ig);
ed60e785
TC
417
418 im_context_refdec(aIMCTX, "io_glue_destroy");
6d5c85a2
TC
419}
420
421/*
422=item i_io_getc(ig)
423=category I/O Layers
424
425A macro to read a single byte from a buffered I/O glue object.
426
427Returns EOF on failure, or a byte.
428
429=cut
430*/
431
432int
433i_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
471Read the next character from the stream without advancing the stream.
472
473On error or end of file, return EOF.
474
475For unbuffered streams a single character buffer will be setup.
476
477=cut
478*/
479
480int
481i_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
521Buffer at least C<size> (at most C<< ig->buf_size >> bytes of data
522from the stream and return C<size> bytes of it to the caller in
523C<buffer>.
524
525This ignores the buffered state of the stream, and will always setup
526buffering if needed.
527
528If no C<type> parameter is provided to Imager::read() or
529Imager::read_multi(), Imager will call C<i_io_peekn()> when probing
530for the file format.
531
532Returns -1 on error, 0 if there is no data before EOF, or the number
533of bytes read into C<buffer>.
534
535=cut
536*/
537
538ssize_t
539i_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) {
ed60e785 543 dIMCTXio(ig);
6d5c85a2
TC
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
589Write a single character to the stream.
590
591On success return c, on error returns EOF
592
593=cut
594*/
595
596int
597i_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;
39e938a4 603 int result = c;
6d5c85a2
TC
604
605 if (ig->error)
606 return EOF;
607
608 write_result = i_io_raw_write(ig, &buf, 1);
6d5c85a2
TC
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
644Read up to C<size> bytes from the stream C<io> into C<buffer>.
645
646Returns the number of bytes read. Returns 0 on end of file. Returns
647-1 on error.
648
649=cut
650*/
651
652ssize_t
653i_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
734Write to the given I/O stream.
735
736Returns the number of bytes written.
737
738=cut
739*/
740
741ssize_t
742i_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
834Seek within the stream.
835
836Acts like perl's seek.
837
838=cut
839 */
840
841off_t
842i_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
873Flush any buffered output.
874
875Returns true on success,
876
877=cut
878*/
879
880int
881i_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
918Flush any pending output and perform the close action for the stream.
919
920Returns 0 on success.
921
922=cut
923*/
924
925int
926i_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
950Read up to C<size>-1 bytes from the stream C<ig> into C<buffer>.
951
952If the byte C<end_of_line> is seen then no further bytes will be read.
953
954Returns the number of bytes read.
955
956Always C<NUL> terminates the buffer.
957
958=cut
959*/
960
961ssize_t
962i_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
985Do common initialization for io_glue objects.
986
987=cut
988*/
989
990static void
ed60e785 991i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
6d5c85a2
TC
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;
ed60e785 1001 ig->context = aIMCTX;
6d5c85a2
TC
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
1018Set the buffering mode of the stream.
1019
1020If you switch buffering off on a stream with buffering on:
1021
1022=over
1023
1024=item *
1025
1026any buffered output will be flushed.
1027
1028=item *
1029
1030any existing buffered input will be consumed before reads become
1031unbuffered.
1032
1033=back
1034
1035Returns true on success. This may fail if any buffered output cannot
1036be flushed.
1037
1038=cut
1039*/
1040
1041int
1042i_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
1057Dump the base fields of an io_glue object to stdout.
1058
1059=cut
1060*/
1061void
1062i_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
1107Calls strerror() and ensures we don't return NULL.
1108
1109On some platforms it's possible for strerror() to return NULL, this
1110wrapper ensures we only get non-NULL values.
1111
1112=cut
1113*/
1114
1115static
1116const 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
1125static void
1126i_io_setup_buffer(io_glue *ig) {
1127 ig->buffer = mymalloc(ig->buf_size);
1128}
1129
1130static void
1131i_io_start_write(io_glue *ig) {
1132 ig->write_ptr = ig->buffer;
1133 ig->write_end = ig->buffer + ig->buf_size;
1134}
1135
1136static int
1137i_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
1204Hex dump the data between C<start> and C<end>.
1205
1206If there is more than a pleasing amount of data, either dump the
1207beginning (C<bias == 0>) or dump the end C(<bias != 0>) of the range.
1208
1209=cut
1210*/
1211
1212static void
1213dump_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
1271Does 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
1280static
1281ssize_t
1282realseek_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;
02d1d628
AMH
1294}
1295
1296
1297/*
1298=item realseek_write(ig, buf, count)
1299
1300Does 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
1309static
1310ssize_t
6d5c85a2
TC
1311realseek_write(io_glue *igo, const void *buf, size_t count) {
1312 io_cb *ig = (io_cb *)igo;
1313 void *p = ig->p;
02d1d628
AMH
1314 ssize_t rc = 0;
1315 size_t bc = 0;
1316 char *cbuf = (char*)buf;
1317
6d5c85a2
TC
1318 IOL_DEB( fprintf(IOL_DEBs, "realseek_write: ig = %p, buf = %p, "
1319 "count = %u\n", ig, buf, (unsigned)count) );
02d1d628 1320
10461f9a
TC
1321 /* Is this a good idea? Would it be better to handle differently?
1322 skip handling? */
6d5c85a2 1323 while( count!=bc && (rc = ig->writecb(p,cbuf+bc,count-bc))>0 ) {
10461f9a
TC
1324 bc+=rc;
1325 }
02d1d628 1326
6d5c85a2 1327 IOL_DEB( fprintf(IOL_DEBs, "realseek_write: rc = %d, bc = %u\n", (int)rc, (unsigned)bc) );
1f6c1c10 1328 return rc < 0 ? rc : bc;
02d1d628
AMH
1329}
1330
1331
1332/*
1333=item realseek_close(ig)
1334
10461f9a
TC
1335Closes a source that can be seeked on. Not sure if this should be an
1336actual close or not. Does nothing for now. Should be fixed.
02d1d628
AMH
1337
1338 ig - data source
1339
10461f9a 1340=cut */
02d1d628
AMH
1341
1342static
2b405c9e 1343int
6d5c85a2
TC
1344realseek_close(io_glue *igo) {
1345 io_cb *ig = (io_cb *)igo;
ed60e785 1346 dIMCTXio(igo);
6d5c85a2
TC
1347
1348 IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig));
ed60e785 1349 im_log((aIMCTX,1, "realseek_close(ig %p)\n", ig));
6d5c85a2
TC
1350 if (ig->closecb)
1351 return ig->closecb(ig->p);
2b405c9e
TC
1352 else
1353 return 0;
02d1d628
AMH
1354}
1355
1356
1357/* realseek_seek(ig, offset, whence)
1358
1359Implements seeking for a source that is seekable, the purpose of having this is to be able to
1360have 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
1369static
1370off_t
6d5c85a2
TC
1371realseek_seek(io_glue *igo, off_t offset, int whence) {
1372 io_cb *ig = (io_cb *)igo;
1373 void *p = ig->p;
8d14daab 1374 off_t rc;
6d5c85a2
TC
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);
02d1d628 1377
6d5c85a2 1378 IOL_DEB( fprintf(IOL_DEBs, "realseek_seek: rc %ld\n", (long) rc) );
02d1d628
AMH
1379 return rc;
1380 /* FIXME: How about implementing this offset handling stuff? */
1381}
1382
d16420e9
TC
1383static
1384void
6d5c85a2
TC
1385realseek_destroy(io_glue *igo) {
1386 io_cb *ig = (io_cb *)igo;
d16420e9 1387
6d5c85a2
TC
1388 if (ig->destroycb)
1389 ig->destroycb(ig->p);
d16420e9
TC
1390}
1391
4dfa5522
AMH
1392/*
1393 * Callbacks for sources that are a fixed size buffer
1394 */
1395
1396/*
1397=item buffer_read(ig, buf, count)
1398
1399Does 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
1408static
1409ssize_t
6d5c85a2
TC
1410buffer_read(io_glue *igo, void *buf, size_t count) {
1411 io_buffer *ig = (io_buffer *)igo;
4dfa5522 1412
6d5c85a2 1413 IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) );
4dfa5522 1414
6d5c85a2 1415 if ( ig->cpos+count > ig->len ) {
ed60e785
TC
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));
6d5c85a2 1418 count = ig->len - ig->cpos;
4dfa5522
AMH
1419 }
1420
6d5c85a2
TC
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) );
4dfa5522
AMH
1424 return count;
1425}
1426
1427
1428/*
1429=item buffer_write(ig, buf, count)
1430
1431Does 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
1440static
1441ssize_t
1442buffer_write(io_glue *ig, const void *buf, size_t count) {
ed60e785
TC
1443 dIMCTXio(ig);
1444 im_log((aIMCTX, 1, "buffer_write called, this method should never be called.\n"));
4dfa5522
AMH
1445 return -1;
1446}
1447
1448
1449/*
1450=item buffer_close(ig)
1451
1452Closes a source that can be seeked on. Not sure if this should be an actual close
1453or not. Does nothing for now. Should be fixed.
1454
1455 ig - data source
1456
1457=cut
1458*/
1459
1460static
2b405c9e 1461int
4dfa5522 1462buffer_close(io_glue *ig) {
ed60e785
TC
1463 dIMCTXio(ig);
1464 im_log((aIMCTX, 1, "buffer_close(ig %p)\n", ig));
2b405c9e
TC
1465
1466 return 0;
4dfa5522
AMH
1467}
1468
1469
1470/* buffer_seek(ig, offset, whence)
1471
1472Implements 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
1481static
1482off_t
6d5c85a2
TC
1483buffer_seek(io_glue *igo, off_t offset, int whence) {
1484 io_buffer *ig = (io_buffer *)igo;
eda1622c 1485 off_t reqpos =
6d5c85a2 1486 calc_seek_offset(ig->cpos, ig->len, offset, whence);
4dfa5522 1487
6d5c85a2 1488 if (reqpos > ig->len) {
ed60e785
TC
1489 dIMCTXio(igo);
1490 im_log((aIMCTX, 1, "seeking out of readable range\n"));
4dfa5522
AMH
1491 return (off_t)-1;
1492 }
eda1622c 1493 if (reqpos < 0) {
ed60e785 1494 dIMCTXio(igo);
eda1622c
TC
1495 i_push_error(0, "seek before beginning of file");
1496 return (off_t)-1;
1497 }
4dfa5522 1498
6d5c85a2
TC
1499 ig->cpos = reqpos;
1500 IOL_DEB( fprintf(IOL_DEBs, "buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
4dfa5522
AMH
1501
1502 return reqpos;
1503 /* FIXME: How about implementing this offset handling stuff? */
1504}
1505
d16420e9
TC
1506static
1507void
6d5c85a2
TC
1508buffer_destroy(io_glue *igo) {
1509 io_buffer *ig = (io_buffer *)igo;
4dfa5522 1510
6d5c85a2 1511 if (ig->closecb) {
ed60e785
TC
1512 dIMCTXio(igo);
1513 im_log((aIMCTX, 1,"calling close callback %p for io_buffer\n",
6d5c85a2
TC
1514 ig->closecb));
1515 ig->closecb(ig->closedata);
d16420e9 1516 }
d16420e9 1517}
4dfa5522
AMH
1518
1519
1520
02d1d628
AMH
1521/*
1522 * Callbacks for sources that are a chain of variable sized buffers
1523 */
1524
1525
1526
1527/* Helper functions for buffer chains */
1528
1529static
1530io_blink*
faa9b3e7 1531io_blink_new(void) {
02d1d628
AMH
1532 io_blink *ib;
1533
ed60e785
TC
1534#if 0
1535 im_log((aIMCTX, 1, "io_blink_new()\n"));
1536#endif
02d1d628
AMH
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
1553Advances the buffer chain to the next link - extending if
1554necessary. Also adjusts the cpos and tfill counters as needed.
1555
1556 ieb - buffer chain object
1557
1558=cut
1559*/
1560
1561static
1562void
1563io_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
c3cc977e
AMH
1576
1577/*
1578=item io_bchain_destroy()
1579
1580frees all resources used by a buffer chain.
1581
1582=cut
1583*/
1584
6d5c85a2 1585static void
c3cc977e 1586io_destroy_bufchain(io_ex_bchain *ieb) {
4dfa5522 1587 io_blink *cp;
ed60e785 1588#if 0
4dfa5522 1589 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
ed60e785 1590#endif
4dfa5522
AMH
1591 cp = ieb->head;
1592
c3cc977e
AMH
1593 while(cp) {
1594 io_blink *t = cp->next;
4dfa5522 1595 myfree(cp);
c3cc977e
AMH
1596 cp = t;
1597 }
1598}
1599
1600
1601
1602
02d1d628
AMH
1603/*
1604
1605static
1606void
1607bufchain_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/*
1625static
1626void
1627chainlencert( 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
1664static
1665void
1666chaincert( 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
02d1d628
AMH
1702/*
1703=item bufchain_read(ig, buf, count)
1704
1705Does 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
1714static
1715ssize_t
1716bufchain_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;
ed60e785 1721 dIMCTXio(ig);
02d1d628 1722
ed60e785 1723 im_log((aIMCTX, 1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
02d1d628
AMH
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
ed60e785 1743 im_log((aIMCTX, 1, "bufchain_read: returning %ld\n", (long)(count-scount)));
02d1d628
AMH
1744 return count-scount;
1745}
1746
1747
1748
1749
1750
1751/*
1752=item bufchain_write(ig, buf, count)
1753
1754Does 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
1763static
1764ssize_t
1765bufchain_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;
ed60e785 1770 dIMCTXio(ig);
02d1d628 1771
ed60e785 1772 im_log((aIMCTX, 1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
02d1d628 1773
6d5c85a2 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) );
02d1d628
AMH
1775
1776 while(count) {
ed60e785 1777 im_log((aIMCTX, 2, "bufchain_write: - looping - count = %ld\n", (long)count));
02d1d628 1778 if (ieb->cp->len == ieb->cpos) {
ed60e785 1779 im_log((aIMCTX, 1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
02d1d628
AMH
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;
ed60e785 1789 im_log((aIMCTX, 2, "bufchain_write: extending tail by %d\n", extend));
02d1d628
AMH
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
1806Closes a source that can be seeked on. Not sure if this should be an actual close
1807or not. Does nothing for now. Should be fixed.
1808
1809 ig - data source
1810
1811=cut
1812*/
1813
1814static
2b405c9e 1815int
02d1d628 1816bufchain_close(io_glue *ig) {
ed60e785
TC
1817 dIMCTXio(ig);
1818 im_log((aIMCTX, 1, "bufchain_close(ig %p)\n",ig));
6d5c85a2 1819 IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) );
2b405c9e
TC
1820
1821 return 0;
02d1d628
AMH
1822}
1823
1824
1825/* bufchain_seek(ig, offset, whence)
1826
1827Implements seeking for a source that is seekable, the purpose of having this is to be able to
1828have 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
1837static
1838off_t
1839bufchain_seek(io_glue *ig, off_t offset, int whence) {
1840 io_ex_bchain *ieb = ig->exdata;
02d1d628
AMH
1841 int wrlen;
1842
eda1622c 1843 off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
02d1d628 1844 off_t sk;
ed60e785 1845 dIMCTXio(ig);
02d1d628 1846
ed60e785 1847 im_log((aIMCTX, 1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
02d1d628 1848
eda1622c
TC
1849 if (scount < 0) {
1850 i_push_error(0, "invalid whence supplied or seek before start of file");
1851 return (off_t)-1;
1852 }
02d1d628 1853
eda1622c
TC
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;
02d1d628
AMH
1865 }
1866
eda1622c
TC
1867 sk = clen - ieb->cpos;
1868 sk = sk > scount ? scount : sk;
02d1d628 1869
eda1622c
TC
1870 scount -= sk;
1871 ieb->cpos += sk;
1872 ieb->gpos += sk;
1873 }
1874
1875 wrlen = scount;
02d1d628 1876
eda1622c
TC
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;
02d1d628
AMH
1885 ieb->cpos = ieb->tfill;
1886
eda1622c
TC
1887 while(wrlen > 0) {
1888 ssize_t rc, wl = i_min(wrlen, BBSIZ);
ed60e785 1889 im_log((aIMCTX, 1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
eda1622c 1890 rc = bufchain_write( ig, TB, wl );
d03fd5a4 1891 if (rc != wl) i_fatal(0, "bufchain_seek: Unable to extend file\n");
eda1622c 1892 wrlen -= rc;
02d1d628 1893 }
02d1d628
AMH
1894 }
1895
ed60e785 1896 im_log((aIMCTX, 2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
02d1d628
AMH
1897 return ieb->gpos;
1898}
1899
d16420e9
TC
1900static
1901void
1902bufchain_destroy(io_glue *ig) {
1903 io_ex_bchain *ieb = ig->exdata;
02d1d628 1904
d16420e9 1905 io_destroy_bufchain(ieb);
02d1d628 1906
d16420e9
TC
1907 myfree(ieb);
1908}
02d1d628 1909
10461f9a
TC
1910/*
1911=item fd_read(ig, buf, count)
1912
6d5c85a2
TC
1913Read callback for file descriptor IO objects.
1914
10461f9a
TC
1915=cut
1916*/
6d5c85a2
TC
1917static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
1918 io_fdseek *ig = (io_fdseek *)igo;
5f8f8e17 1919 ssize_t result;
10461f9a 1920#ifdef _MSC_VER
6d5c85a2 1921 result = _read(ig->fd, buf, count);
10461f9a 1922#else
6d5c85a2 1923 result = read(ig->fd, buf, count);
10461f9a 1924#endif
5f8f8e17 1925
6d5c85a2
TC
1926 IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf,
1927 (unsigned)count, (int)result));
1928
5f8f8e17
TC
1929 /* 0 is valid - means EOF */
1930 if (result < 0) {
ed60e785
TC
1931 dIMCTXio(igo);
1932 im_push_errorf(aIMCTX, 0, "read() failure: %s (%d)", my_strerror(errno), errno);
5f8f8e17
TC
1933 }
1934
1935 return result;
10461f9a
TC
1936}
1937
6d5c85a2
TC
1938static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) {
1939 io_fdseek *ig = (io_fdseek *)igo;
2691d220 1940 ssize_t result;
10461f9a 1941#ifdef _MSC_VER
6d5c85a2 1942 result = _write(ig->fd, buf, count);
10461f9a 1943#else
6d5c85a2 1944 result = write(ig->fd, buf, count);
10461f9a 1945#endif
2691d220 1946
6d5c85a2
TC
1947 IOL_DEB(fprintf(IOL_DEBs, "fd_write(%p, %p, %u) => %d\n", ig, buf,
1948 (unsigned)count, (int)result));
1949
2691d220 1950 if (result <= 0) {
ed60e785
TC
1951 dIMCTXio(igo);
1952 im_push_errorf(aIMCTX, errno, "write() failure: %s (%d)", my_strerror(errno), errno);
2691d220
TC
1953 }
1954
1955 return result;
10461f9a
TC
1956}
1957
6d5c85a2
TC
1958static off_t fd_seek(io_glue *igo, off_t offset, int whence) {
1959 io_fdseek *ig = (io_fdseek *)igo;
2691d220 1960 off_t result;
10461f9a 1961#ifdef _MSC_VER
6d5c85a2 1962 result = _lseek(ig->fd, offset, whence);
10461f9a 1963#else
6d5c85a2 1964 result = lseek(ig->fd, offset, whence);
10461f9a 1965#endif
2691d220
TC
1966
1967 if (result == (off_t)-1) {
ed60e785
TC
1968 dIMCTXio(igo);
1969 im_push_errorf(aIMCTX, errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
2691d220
TC
1970 }
1971
1972 return result;
10461f9a
TC
1973}
1974
2b405c9e 1975static int fd_close(io_glue *ig) {
10461f9a 1976 /* no, we don't close it */
2b405c9e 1977 return 0;
10461f9a
TC
1978}
1979
1980static ssize_t fd_size(io_glue *ig) {
ed60e785
TC
1981 dIMCTXio(ig);
1982 im_log((aIMCTX, 1, "fd_size(ig %p) unimplemented\n", ig));
10461f9a
TC
1983
1984 return -1;
1985}
02d1d628 1986
b8c2033e
AMH
1987
1988/*
1989=back
1990
1991=head1 AUTHOR
1992
1993Arnar M. Hrafnkelsson <addi@umich.edu>
1994
1995=head1 SEE ALSO
1996
1997Imager(3)
1998
1999=cut
2000*/