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