- error messages when writing TIFF images were always
[imager.git] / iolayer.c
CommitLineData
7ac6a2e9 1#include "imio.h"
02d1d628
AMH
2#include "iolayer.h"
3#include "log.h"
4#include <stdlib.h>
5#include <stdio.h>
6#ifdef _MSC_VER
7#include <io.h>
8#endif
35891892 9#include <string.h>
2691d220 10#include <errno.h>
02d1d628
AMH
11
12#define IOL_DEB(x)
13
14
15char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
16
17
18/*
19=head1 NAME
20
21iolayer.c - encapsulates different source of data into a single framework.
22
23=head1 SYNOPSIS
24
25 io_glue *ig = io_new_fd( fileno(stdin) );
26 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
27 io_glue_commit_types(ig); // always assume IOL_SEEK for now
28 switch (method) {
29 case IOL_NOSEEK:
30 code that uses ig->readcb()
31 to read data goes here.
32 break;
33 case IOL_MMAP:
34 code that uses ig->readcb()
35 to read data goes here.
36 break;
37 }
38
39 io_glue_DESTROY(ig);
40 // and much more
41
42=head1 DESCRIPTION
43
44iolayer.c implements the basic functions to create and destroy io_glue
45objects for Imager. The typical usage pattern for data sources is:
46
47 1. Create the source (io_new_fd)
48 2. Define how you want to get data from it (io_reqmeth)
49 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
50 4. Close the source, which
51 shouldn't really close the underlying source. (io_glue DESTROY)
52
53=head1 FUNCTION REFERENCE
54
55Some of these functions are internal.
56
b8c2033e 57=over
02d1d628
AMH
58
59=cut
60*/
61
10461f9a
TC
62static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
63static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
64static off_t fd_seek(io_glue *ig, off_t offset, int whence);
65static void fd_close(io_glue *ig);
66static ssize_t fd_size(io_glue *ig);
02d1d628
AMH
67
68/*
69 * Callbacks for sources that cannot seek
70 */
71
72/* fakeseek_read: read method for when emulating a seekable source
73static
74ssize_t
75fakeseek_read(io_glue *ig, void *buf, size_t count) {
76 io_ex_fseek *exdata = ig->exdata;
77 return 0;
78}
79*/
80
81
82
83/*
84 * Callbacks for sources that can seek
85 */
86
87/*
88=item realseek_read(ig, buf, count)
89
90Does the reading from a source that can be seeked on
91
92 ig - io_glue object
93 buf - buffer to return data in
94 count - number of bytes to read into buffer max
95
96=cut
97*/
98
99static
100ssize_t
101realseek_read(io_glue *ig, void *buf, size_t count) {
102 io_ex_rseek *ier = ig->exdata;
10461f9a 103 void *p = ig->source.cb.p;
02d1d628
AMH
104 ssize_t rc = 0;
105 size_t bc = 0;
106 char *cbuf = buf;
107
10461f9a
TC
108 IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = %p, "
109 "count = %d\n", fd, (long) ier->cpos, buf, count) );
110 /* Is this a good idea? Would it be better to handle differently?
111 skip handling? */
112 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
113 bc+=rc;
114 }
02d1d628
AMH
115
116 ier->cpos += bc;
117 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
118 return bc;
119}
120
121
122/*
123=item realseek_write(ig, buf, count)
124
125Does the writing to a 'source' that can be seeked on
126
127 ig - io_glue object
128 buf - buffer that contains data
129 count - number of bytes to write
130
131=cut
132*/
133
134static
135ssize_t
136realseek_write(io_glue *ig, const void *buf, size_t count) {
137 io_ex_rseek *ier = ig->exdata;
10461f9a 138 void *p = ig->source.cb.p;
02d1d628
AMH
139 ssize_t rc = 0;
140 size_t bc = 0;
141 char *cbuf = (char*)buf;
142
10461f9a
TC
143 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
144 "count = %d\n", ig, (long) ier->cpos, buf, count) );
02d1d628 145
10461f9a
TC
146 /* Is this a good idea? Would it be better to handle differently?
147 skip handling? */
148 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
149 bc+=rc;
150 }
02d1d628
AMH
151
152 ier->cpos += bc;
153 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
154 return bc;
155}
156
157
158/*
159=item realseek_close(ig)
160
10461f9a
TC
161Closes a source that can be seeked on. Not sure if this should be an
162actual close or not. Does nothing for now. Should be fixed.
02d1d628
AMH
163
164 ig - data source
165
10461f9a 166=cut */
02d1d628
AMH
167
168static
169void
170realseek_close(io_glue *ig) {
171 mm_log((1, "realseek_close(ig %p)\n", ig));
10461f9a
TC
172 if (ig->source.cb.closecb)
173 ig->source.cb.closecb(ig->source.cb.p);
02d1d628
AMH
174}
175
176
177/* realseek_seek(ig, offset, whence)
178
179Implements seeking for a source that is seekable, the purpose of having this is to be able to
180have an offset into a file that is different from what the underlying library thinks.
181
182 ig - data source
183 offset - offset into stream
184 whence - whence argument a la lseek
185
186=cut
187*/
188
189static
190off_t
191realseek_seek(io_glue *ig, off_t offset, int whence) {
192 /* io_ex_rseek *ier = ig->exdata; Needed later */
10461f9a 193 void *p = ig->source.cb.p;
02d1d628 194 int rc;
930c67c8 195 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
10461f9a 196 rc = ig->source.cb.seekcb(p, offset, whence);
02d1d628
AMH
197
198 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
199 return rc;
200 /* FIXME: How about implementing this offset handling stuff? */
201}
202
4dfa5522
AMH
203/*
204 * Callbacks for sources that are a fixed size buffer
205 */
206
207/*
208=item buffer_read(ig, buf, count)
209
210Does the reading from a buffer source
211
212 ig - io_glue object
213 buf - buffer to return data in
214 count - number of bytes to read into buffer max
215
216=cut
217*/
218
219static
220ssize_t
221buffer_read(io_glue *ig, void *buf, size_t count) {
222 io_ex_buffer *ieb = ig->exdata;
4dfa5522
AMH
223
224 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
225
226 if ( ieb->cpos+count > ig->source.buffer.len ) {
227 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
228 count = ig->source.buffer.len - ieb->cpos;
229 }
230
231 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
232 ieb->cpos += count;
233 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
234 return count;
235}
236
237
238/*
239=item buffer_write(ig, buf, count)
240
241Does nothing, returns -1
242
243 ig - io_glue object
244 buf - buffer that contains data
245 count - number of bytes to write
246
247=cut
248*/
249
250static
251ssize_t
252buffer_write(io_glue *ig, const void *buf, size_t count) {
253 mm_log((1, "buffer_write called, this method should never be called.\n"));
254 return -1;
255}
256
257
258/*
259=item buffer_close(ig)
260
261Closes a source that can be seeked on. Not sure if this should be an actual close
262or not. Does nothing for now. Should be fixed.
263
264 ig - data source
265
266=cut
267*/
268
269static
270void
271buffer_close(io_glue *ig) {
272 mm_log((1, "buffer_close(ig %p)\n", ig));
273 /* FIXME: Do stuff here */
274}
275
276
277/* buffer_seek(ig, offset, whence)
278
279Implements seeking for a buffer source.
280
281 ig - data source
282 offset - offset into stream
283 whence - whence argument a la lseek
284
285=cut
286*/
287
288static
289off_t
290buffer_seek(io_glue *ig, off_t offset, int whence) {
291 io_ex_buffer *ieb = ig->exdata;
292 off_t reqpos = offset
293 + (whence == SEEK_CUR)*ieb->cpos
294 + (whence == SEEK_END)*ig->source.buffer.len;
295
296 if (reqpos > ig->source.buffer.len) {
297 mm_log((1, "seeking out of readable range\n"));
298 return (off_t)-1;
299 }
300
301 ieb->cpos = reqpos;
302 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
303
304 return reqpos;
305 /* FIXME: How about implementing this offset handling stuff? */
306}
307
308
309
310
311
02d1d628
AMH
312/*
313 * Callbacks for sources that are a chain of variable sized buffers
314 */
315
316
317
318/* Helper functions for buffer chains */
319
320static
321io_blink*
faa9b3e7 322io_blink_new(void) {
02d1d628
AMH
323 io_blink *ib;
324
325 mm_log((1, "io_blink_new()\n"));
326
327 ib = mymalloc(sizeof(io_blink));
328
329 ib->next = NULL;
330 ib->prev = NULL;
331 ib->len = BBSIZ;
332
333 memset(&ib->buf, 0, ib->len);
334 return ib;
335}
336
337
338
339/*
340=item io_bchain_advance(ieb)
341
342Advances the buffer chain to the next link - extending if
343necessary. Also adjusts the cpos and tfill counters as needed.
344
345 ieb - buffer chain object
346
347=cut
348*/
349
350static
351void
352io_bchain_advance(io_ex_bchain *ieb) {
353 if (ieb->cp->next == NULL) {
354 ieb->tail = io_blink_new();
355 ieb->tail->prev = ieb->cp;
356 ieb->cp->next = ieb->tail;
357
358 ieb->tfill = 0; /* Only set this if we added a new slice */
359 }
360 ieb->cp = ieb->cp->next;
361 ieb->cpos = 0;
362}
363
364
c3cc977e
AMH
365
366/*
367=item io_bchain_destroy()
368
369frees all resources used by a buffer chain.
370
371=cut
372*/
373
374void
375io_destroy_bufchain(io_ex_bchain *ieb) {
4dfa5522
AMH
376 io_blink *cp;
377 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
378 cp = ieb->head;
379
c3cc977e
AMH
380 while(cp) {
381 io_blink *t = cp->next;
4dfa5522 382 myfree(cp);
c3cc977e
AMH
383 cp = t;
384 }
385}
386
387
388
389
02d1d628
AMH
390/*
391
392static
393void
394bufchain_dump(io_ex_bchain *ieb) {
395 mm_log((1, " buf_chain_dump(ieb %p)\n"));
396 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
397 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
398 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
399 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
400 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
401 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
402 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
403 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
404}
405*/
406
407/*
408 * TRUE if lengths are NOT equal
409 */
410
411/*
412static
413void
414chainlencert( io_glue *ig ) {
415 int clen;
416 int cfl = 0;
417 size_t csize = 0;
418 size_t cpos = 0;
419 io_ex_bchain *ieb = ig->exdata;
420 io_blink *cp = ieb->head;
421
422
423 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
424
425 while(cp) {
426 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
427 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
428 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
429
430 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
431 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
432
433 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
434 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
435
436 if (cp == ieb->cp) {
437 cfl = 1;
438 cpos += ieb->cpos;
439 }
440
441 if (!cfl) cpos += clen;
442
443 csize += clen;
444 cp = cp->next;
445 }
446 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
447 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
448}
449
450
451static
452void
453chaincert( io_glue *ig) {
454 size_t csize = 0;
455 io_ex_bchain *ieb = ig->exdata;
456 io_blink *cp = ieb->head;
457
458 mm_log((1, "Chain verification.\n"));
459
460 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
461 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
462 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
463 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
464 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
465 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
466 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
467 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
468
469 while(cp) {
470 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
471 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
472 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
473 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
474
475 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
476 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
477
478 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
479 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
480
481 csize += clen;
482 cp = cp->next;
483 }
484
485 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
486}
487*/
488
489
490
491
492
493
494
495
496
497
498
499/*
500=item bufchain_read(ig, buf, count)
501
502Does the reading from a source that can be seeked on
503
504 ig - io_glue object
505 buf - buffer to return data in
506 count - number of bytes to read into buffer max
507
508=cut
509*/
510
511static
512ssize_t
513bufchain_read(io_glue *ig, void *buf, size_t count) {
514 io_ex_bchain *ieb = ig->exdata;
515 size_t scount = count;
516 char *cbuf = buf;
517 size_t sk;
518
519 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
02d1d628
AMH
520
521 while( scount ) {
522 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
523 if (clen == ieb->cpos) {
524 if (ieb->cp == ieb->tail) break; /* EOF */
525 ieb->cp = ieb->cp->next;
526 ieb->cpos = 0;
527 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
528 }
529
530 sk = clen - ieb->cpos;
531 sk = sk > scount ? scount : sk;
532
533 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
534 scount -= sk;
535 ieb->cpos += sk;
536 ieb->gpos += sk;
537 }
538
539 mm_log((1, "bufchain_read: returning %d\n", count-scount));
540 return count-scount;
541}
542
543
544
545
546
547/*
548=item bufchain_write(ig, buf, count)
549
550Does the writing to a 'source' that can be seeked on
551
552 ig - io_glue object
553 buf - buffer that contains data
554 count - number of bytes to write
555
556=cut
557*/
558
559static
560ssize_t
561bufchain_write(io_glue *ig, const void *buf, size_t count) {
562 char *cbuf = (char *)buf;
563 io_ex_bchain *ieb = ig->exdata;
564 size_t ocount = count;
565 size_t sk;
566
930c67c8 567 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
02d1d628 568
930c67c8 569 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
02d1d628
AMH
570
571 while(count) {
572 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
573 if (ieb->cp->len == ieb->cpos) {
574 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
575 io_bchain_advance(ieb);
576 }
577
578 sk = ieb->cp->len - ieb->cpos;
579 sk = sk > count ? count : sk;
580 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
581
582 if (ieb->cp == ieb->tail) {
583 int extend = ieb->cpos + sk - ieb->tfill;
584 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
585 if (extend > 0) {
586 ieb->length += extend;
587 ieb->tfill += extend;
588 }
589 }
590
591 ieb->cpos += sk;
592 ieb->gpos += sk;
593 count -= sk;
594 }
595 return ocount;
596}
597
598/*
599=item bufchain_close(ig)
600
601Closes a source that can be seeked on. Not sure if this should be an actual close
602or not. Does nothing for now. Should be fixed.
603
604 ig - data source
605
606=cut
607*/
608
609static
610void
611bufchain_close(io_glue *ig) {
612 mm_log((1, "bufchain_close(ig %p)\n",ig));
930c67c8 613 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
02d1d628
AMH
614 /* FIXME: Commit a seek point here */
615
616}
617
618
619/* bufchain_seek(ig, offset, whence)
620
621Implements seeking for a source that is seekable, the purpose of having this is to be able to
622have an offset into a file that is different from what the underlying library thinks.
623
624 ig - data source
625 offset - offset into stream
626 whence - whence argument a la lseek
627
628=cut
629*/
630
631static
632off_t
633bufchain_seek(io_glue *ig, off_t offset, int whence) {
634 io_ex_bchain *ieb = ig->exdata;
635 io_blink *ib = NULL;
636 int wrlen;
637
638 off_t cof = 0;
639 off_t scount = offset;
640 off_t sk;
641
642 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
643
644 switch (whence) {
645 case SEEK_SET: /* SEEK_SET = 0, From the top */
646 ieb->cp = ieb->head;
647 ieb->cpos = 0;
648 ieb->gpos = 0;
649
650 while( scount ) {
651 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
652 if (clen == ieb->cpos) {
653 if (ieb->cp == ieb->tail) break; /* EOF */
654 ieb->cp = ieb->cp->next;
655 ieb->cpos = 0;
656 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
657 }
658
659 sk = clen - ieb->cpos;
660 sk = sk > scount ? scount : sk;
661
662 scount -= sk;
663 ieb->cpos += sk;
664 ieb->gpos += sk;
665 }
666
667 wrlen = scount;
668
669 if (wrlen > 0) {
670 /*
671 * extending file - get ieb into consistent state and then
672 * call write which will get it to the correct position
673 */
674 char TB[BBSIZ];
675 memset(TB, 0, BBSIZ);
676 ieb->gpos = ieb->length;
677 ieb->cpos = ieb->tfill;
678
679 while(wrlen > 0) {
b33c08f8 680 ssize_t rc, wl = i_min(wrlen, BBSIZ);
02d1d628
AMH
681 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
682 rc = bufchain_write( ig, TB, wl );
683 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
684 wrlen -= rc;
685 }
686 }
687
688 break;
689
690 case SEEK_CUR:
691 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
692
693 /*
694 case SEEK_CUR:
695 ib = ieb->cp;
696 if (cof < 0) {
697 cof += ib->cpos;
698 cpos = 0;
699 while(cof < 0 && ib->prev) {
700 ib = ib->prev;
701 cof += ib->len;
702 }
703 */
704
705 case SEEK_END: /* SEEK_END = 2 */
706 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
707
708 ieb->cp = ieb->tail;
709 ieb->cpos = ieb->tfill;
710
711 if (cof<0) {
712 cof += ieb->cpos;
713 ieb->cpos = 0;
714
715 while(cof<0 && ib->prev) {
716 ib = ib->prev;
717 cof += ib->len;
718 }
719
720 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
721 ieb->gpos = ieb->length+offset;
722 ieb->cpos = cof;
723 }
724 break;
725 default:
726 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
727 }
728
729 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
730 return ieb->gpos;
731}
732
733
734
735
736
737
738/*
739 * Methods for setting up data source
740 */
741
742/*
743=item io_obj_setp_buffer(io, p, len)
744
745Sets an io_object for reading from a buffer source
746
747 io - io object that describes a source
748 p - pointer to buffer
749 len - length of buffer
750
751=cut
752*/
753
754void
4dfa5522
AMH
755io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata) {
756 io->buffer.type = BUFFER;
757 io->buffer.data = p;
758 io->buffer.len = len;
759 io->buffer.closecb = closecb;
760 io->buffer.closedata = closedata;
02d1d628
AMH
761}
762
763
764/*
4dfa5522 765=item io_obj_setp_buchain(io)
02d1d628
AMH
766
767Sets an io_object for reading/writing from a buffer source
768
769 io - io object that describes a source
770 p - pointer to buffer
771 len - length of buffer
772
773=cut
774*/
775
776void
777io_obj_setp_bufchain(io_obj *io) {
778 io->type = BUFCHAIN;
779}
780
781
782/*
10461f9a 783=item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
02d1d628
AMH
784
785Sets an io_object for reading from a source that uses callbacks
786
787 io - io object that describes a source
10461f9a
TC
788 p - pointer to data for callbacks
789 readcb - read callback to read from source
790 writecb - write callback to write to source
791 seekcb - seek callback to seek on source
792 closecb - flush any pending data
793 destroycb - release any extra resources
02d1d628
AMH
794
795=cut
796*/
797
798void
10461f9a
TC
799io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
800 io->cb.type = CBSEEK;
801 io->cb.p = p;
802 io->cb.readcb = readcb;
803 io->cb.writecb = writecb;
804 io->cb.seekcb = seekcb;
805 io->cb.closecb = closecb;
806 io->cb.destroycb = destroycb;
807}
808
809void
810io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb,
811 seekl seekcb) {
812 io_obj_setp_cb2(io, p, readcb, writecb, seekcb, NULL, NULL);
02d1d628
AMH
813}
814
815/*
816=item io_glue_commit_types(ig)
817
818Creates buffers and initializes structures to read with the chosen interface.
819
820 ig - io_glue object
821
822=cut
823*/
824
825void
826io_glue_commit_types(io_glue *ig) {
827 io_type inn = ig->source.type;
527c0c3e 828
930c67c8 829 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
02d1d628 830 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
527c0c3e
AMH
831
832 if (ig->flags & 0x01) {
833 mm_log((1, "io_glue_commit_types: type already set up\n"));
834 return;
835 }
836
02d1d628
AMH
837 switch (inn) {
838 case BUFCHAIN:
839 {
840 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
841
842 ieb->offset = 0;
843 ieb->length = 0;
844 ieb->cpos = 0;
845 ieb->gpos = 0;
846 ieb->tfill = 0;
c3cc977e 847
02d1d628
AMH
848 ieb->head = io_blink_new();
849 ieb->cp = ieb->head;
850 ieb->tail = ieb->head;
851
852 ig->exdata = ieb;
853 ig->readcb = bufchain_read;
854 ig->writecb = bufchain_write;
855 ig->seekcb = bufchain_seek;
856 ig->closecb = bufchain_close;
857 }
858 break;
859 case CBSEEK:
02d1d628
AMH
860 {
861 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
862
863 ier->offset = 0;
864 ier->cpos = 0;
865
866 ig->exdata = ier;
867 ig->readcb = realseek_read;
868 ig->writecb = realseek_write;
869 ig->seekcb = realseek_seek;
870 ig->closecb = realseek_close;
871 }
4dfa5522
AMH
872 break;
873 case BUFFER:
874 {
875 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
876 ieb->offset = 0;
877 ieb->cpos = 0;
878
879 ig->exdata = ieb;
880 ig->readcb = buffer_read;
881 ig->writecb = buffer_write;
882 ig->seekcb = buffer_seek;
883 ig->closecb = buffer_close;
884 }
885 break;
10461f9a
TC
886 case FDSEEK:
887 {
888 ig->exdata = NULL;
889 ig->readcb = fd_read;
890 ig->writecb = fd_write;
891 ig->seekcb = fd_seek;
892 ig->closecb = fd_close;
893 break;
894 }
02d1d628 895 }
527c0c3e 896 ig->flags |= 0x01; /* indicate source has been setup already */
02d1d628
AMH
897}
898
899/*
900=item io_glue_gettypes(ig, reqmeth)
901
902Returns a set of compatible interfaces to read data with.
903
904 ig - io_glue object
905 reqmeth - request mask
906
907The request mask is a bit mask (of something that hasn't been implemented yet)
908of interfaces that it would like to read data from the source which the ig
909describes.
910
911=cut
912*/
913
914void
915io_glue_gettypes(io_glue *ig, int reqmeth) {
916
917 ig = NULL;
918 reqmeth = 0;
919
920 /* FIXME: Implement this function! */
921 /* if (ig->source.type =
922 if (reqmeth & IO_BUFF) */
923
924}
925
926
927/*
928=item io_new_bufchain()
929
930returns a new io_glue object that has the 'empty' source and but can
931be written to and read from later (like a pseudo file).
932
933=cut
934*/
935
936io_glue *
937io_new_bufchain() {
4dfa5522
AMH
938 io_glue *ig;
939 mm_log((1, "io_new_bufchain()\n"));
940 ig = mymalloc(sizeof(io_glue));
527c0c3e 941 memset(ig, 0, sizeof(*ig));
02d1d628
AMH
942 io_obj_setp_bufchain(&ig->source);
943 return ig;
944}
945
946
c3cc977e
AMH
947
948
949
4dfa5522
AMH
950/*
951=item io_new_buffer(data, len)
952
953Returns a new io_glue object that has the source defined as reading
954from specified buffer. Note that the buffer is not copied.
955
956 data - buffer to read from
957 len - length of buffer
c3cc977e 958
4dfa5522
AMH
959=cut
960*/
961
962io_glue *
963io_new_buffer(char *data, size_t len, closebufp closecb, void *closedata) {
964 io_glue *ig;
965 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
966 ig = mymalloc(sizeof(io_glue));
967 memset(ig, 0, sizeof(*ig));
968 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
527c0c3e 969 ig->flags = 0;
4dfa5522
AMH
970 return ig;
971}
c3cc977e
AMH
972
973
02d1d628
AMH
974/*
975=item io_new_fd(fd)
976
977returns a new io_glue object that has the source defined as reading
978from specified filedescriptor. Note that the the interface to recieving
979data from the io_glue callbacks hasn't been done yet.
980
981 fd - file descriptor to read/write from
982
983=cut
984*/
985
986io_glue *
987io_new_fd(int fd) {
4dfa5522
AMH
988 io_glue *ig;
989 mm_log((1, "io_new_fd(fd %d)\n", fd));
990 ig = mymalloc(sizeof(io_glue));
261f91c5 991 memset(ig, 0, sizeof(*ig));
10461f9a
TC
992 ig->source.type = FDSEEK;
993 ig->source.fdseek.fd = fd;
527c0c3e 994 ig->flags = 0;
10461f9a 995#if 0
02d1d628
AMH
996#ifdef _MSC_VER
997 io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek);
998#else
999 io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek);
10461f9a 1000#endif
02d1d628 1001#endif
4dfa5522 1002 mm_log((1, "(%p) <- io_new_fd\n", ig));
02d1d628
AMH
1003 return ig;
1004}
1005
10461f9a
TC
1006io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
1007 closel closecb, destroyl destroycb) {
1008 io_glue *ig;
02d1d628 1009
10461f9a
TC
1010 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1011 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1012 ig = mymalloc(sizeof(io_glue));
527c0c3e 1013 memset(ig, 0, sizeof(*ig));
10461f9a
TC
1014 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1015 mm_log((1, "(%p) <- io_new_cb\n", ig));
1016
1017 return ig;
1018}
02d1d628
AMH
1019
1020/*
1021=item io_slurp(ig)
1022
1023Takes the source that the io_glue is bound to and allocates space
1024for a return buffer and returns the entire content in a single buffer.
1025Note: This only works for io_glue objects that contain a bufchain. It
1026is usefull for saving to scalars and such.
1027
1028 ig - io_glue object
1029 c - pointer to a pointer to where data should be copied to
1030
1031=cut
1032*/
1033
1034size_t
1035io_slurp(io_glue *ig, unsigned char **c) {
1036 ssize_t rc;
1037 off_t orgoff;
1038 io_ex_bchain *ieb;
1039 unsigned char *cc;
1040 io_type inn = ig->source.type;
1041
1042 if ( inn != BUFCHAIN ) {
1043 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1044 }
1045
1046 ieb = ig->exdata;
1047 cc = *c = mymalloc( ieb->length );
1048
1049 orgoff = ieb->gpos;
1050
1051 bufchain_seek(ig, 0, SEEK_SET);
1052
1053 rc = bufchain_read(ig, cc, ieb->length);
1054
1055 if (rc != ieb->length)
1056 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1057
1058 return rc;
1059}
1060
10461f9a
TC
1061/*
1062=item fd_read(ig, buf, count)
1063
1064=cut
1065*/
1066static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1067#ifdef _MSC_VER
1068 return _read(ig->source.fdseek.fd, buf, count);
1069#else
1070 return read(ig->source.fdseek.fd, buf, count);
1071#endif
1072}
1073
1074static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
2691d220 1075 ssize_t result;
10461f9a 1076#ifdef _MSC_VER
2691d220 1077 result = _write(ig->source.fdseek.fd, buf, count);
10461f9a 1078#else
2691d220 1079 result = write(ig->source.fdseek.fd, buf, count);
10461f9a 1080#endif
2691d220
TC
1081
1082 if (result <= 0) {
1083 i_push_errorf(errno, "write() failure: %s (%d)", strerror(errno), errno);
1084 }
1085
1086 return result;
10461f9a
TC
1087}
1088
1089static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
2691d220 1090 off_t result;
10461f9a 1091#ifdef _MSC_VER
2691d220 1092 result = _lseek(ig->source.fdseek.fd, offset, whence);
10461f9a 1093#else
2691d220 1094 result = lseek(ig->source.fdseek.fd, offset, whence);
10461f9a 1095#endif
2691d220
TC
1096
1097 if (result == (off_t)-1) {
1098 i_push_errorf(errno, "lseek() failure: %s (%d)", strerror(errno), errno);
1099 }
1100
1101 return result;
10461f9a
TC
1102}
1103
1104static void fd_close(io_glue *ig) {
1105 /* no, we don't close it */
1106}
1107
1108static ssize_t fd_size(io_glue *ig) {
1109 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1110
1111 return -1;
1112}
02d1d628
AMH
1113
1114/*
1115=item io_glue_DESTROY(ig)
1116
1117A destructor method for io_glue objects. Should clean up all related buffers.
1118Might leave us with a dangling pointer issue on some buffers.
1119
1120 ig - io_glue object to destroy.
1121
1122=cut
1123*/
1124
1125void
1126io_glue_DESTROY(io_glue *ig) {
c3cc977e
AMH
1127 io_type inn = ig->source.type;
1128 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1129
1130 switch (inn) {
1131 case BUFCHAIN:
1132 {
1133 io_ex_bchain *ieb = ig->exdata;
1134 io_destroy_bufchain(ieb);
4dfa5522 1135 myfree(ieb);
c3cc977e
AMH
1136 }
1137 break;
1138 case CBSEEK:
c3cc977e
AMH
1139 {
1140 io_ex_rseek *ier = ig->exdata;
10461f9a
TC
1141 if (ig->source.cb.destroycb)
1142 ig->source.cb.destroycb(ig->source.cb.p);
c3cc977e
AMH
1143 myfree(ier);
1144 }
4dfa5522
AMH
1145 break;
1146 case BUFFER:
1147 {
1148 io_ex_buffer *ieb = ig->exdata;
1149 if (ig->source.buffer.closecb) {
1150 mm_log((1,"calling close callback %p for io_buffer\n", ig->source.buffer.closecb));
1151 ig->source.buffer.closecb(ig->source.buffer.closedata);
1152 }
1153 myfree(ieb);
1154 }
1155 break;
10461f9a
TC
1156 default:
1157 break;
c3cc977e
AMH
1158 }
1159 myfree(ig);
02d1d628 1160}
b8c2033e
AMH
1161
1162
1163/*
1164=back
1165
1166=head1 AUTHOR
1167
1168Arnar M. Hrafnkelsson <addi@umich.edu>
1169
1170=head1 SEE ALSO
1171
1172Imager(3)
1173
1174=cut
1175*/