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