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