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