Commit | Line | Data |
---|---|---|
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 | ||
13 | char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" }; | |
14 | ||
15 | ||
16 | /* | |
17 | =head1 NAME | |
18 | ||
19 | iolayer.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 | ||
42 | iolayer.c implements the basic functions to create and destroy io_glue | |
43 | objects 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 | ||
53 | Some of these functions are internal. | |
54 | ||
55 | =over 4 | |
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 | |
68 | static | |
69 | ssize_t | |
70 | fakeseek_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 | ||
85 | Does 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 | ||
94 | static | |
95 | ssize_t | |
96 | realseek_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 | ||
103 | IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = 0x%p, count = %d\n", fd, (long) ier->cpos, buf, count) ); | |
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 | ||
116 | Does 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 | ||
125 | static | |
126 | ssize_t | |
127 | realseek_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 | ||
134 | IOL_DEB( printf("realseek_write: fd = %d, ier->cpos = %ld, buf = 0x%p, count = %d\n", fd, (long) ier->cpos, buf, count) ); | |
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 | ||
148 | Closes a source that can be seeked on. Not sure if this should be an actual close | |
149 | or not. Does nothing for now. Should be fixed. | |
150 | ||
151 | ig - data source | |
152 | ||
153 | =cut | |
154 | */ | |
155 | ||
156 | static | |
157 | void | |
158 | realseek_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 | ||
166 | Implements seeking for a source that is seekable, the purpose of having this is to be able to | |
167 | have 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 | ||
176 | static | |
177 | off_t | |
178 | realseek_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; | |
182 | IOL_DEB( printf("realseek_seek(ig 0x%p, offset %ld, whence %d)\n", ig, (long) offset, whence) ); | |
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 | ||
196 | /* | |
197 | * Callbacks for sources that are a chain of variable sized buffers | |
198 | */ | |
199 | ||
200 | ||
201 | ||
202 | /* Helper functions for buffer chains */ | |
203 | ||
204 | static | |
205 | io_blink* | |
206 | io_blink_new() { | |
207 | io_blink *ib; | |
208 | ||
209 | mm_log((1, "io_blink_new()\n")); | |
210 | ||
211 | ib = mymalloc(sizeof(io_blink)); | |
212 | ||
213 | ib->next = NULL; | |
214 | ib->prev = NULL; | |
215 | ib->len = BBSIZ; | |
216 | ||
217 | memset(&ib->buf, 0, ib->len); | |
218 | return ib; | |
219 | } | |
220 | ||
221 | ||
222 | ||
223 | /* | |
224 | =item io_bchain_advance(ieb) | |
225 | ||
226 | Advances the buffer chain to the next link - extending if | |
227 | necessary. Also adjusts the cpos and tfill counters as needed. | |
228 | ||
229 | ieb - buffer chain object | |
230 | ||
231 | =cut | |
232 | */ | |
233 | ||
234 | static | |
235 | void | |
236 | io_bchain_advance(io_ex_bchain *ieb) { | |
237 | if (ieb->cp->next == NULL) { | |
238 | ieb->tail = io_blink_new(); | |
239 | ieb->tail->prev = ieb->cp; | |
240 | ieb->cp->next = ieb->tail; | |
241 | ||
242 | ieb->tfill = 0; /* Only set this if we added a new slice */ | |
243 | } | |
244 | ieb->cp = ieb->cp->next; | |
245 | ieb->cpos = 0; | |
246 | } | |
247 | ||
248 | ||
249 | /* | |
250 | ||
251 | static | |
252 | void | |
253 | bufchain_dump(io_ex_bchain *ieb) { | |
254 | mm_log((1, " buf_chain_dump(ieb %p)\n")); | |
255 | mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset)); | |
256 | mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length)); | |
257 | mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head )); | |
258 | mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail )); | |
259 | mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill )); | |
260 | mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp )); | |
261 | mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos )); | |
262 | mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos )); | |
263 | } | |
264 | */ | |
265 | ||
266 | /* | |
267 | * TRUE if lengths are NOT equal | |
268 | */ | |
269 | ||
270 | /* | |
271 | static | |
272 | void | |
273 | chainlencert( io_glue *ig ) { | |
274 | int clen; | |
275 | int cfl = 0; | |
276 | size_t csize = 0; | |
277 | size_t cpos = 0; | |
278 | io_ex_bchain *ieb = ig->exdata; | |
279 | io_blink *cp = ieb->head; | |
280 | ||
281 | ||
282 | if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length)); | |
283 | ||
284 | while(cp) { | |
285 | clen = (cp == ieb->tail) ? ieb->tfill : cp->len; | |
286 | if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n")); | |
287 | if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n")); | |
288 | ||
289 | if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n")); | |
290 | if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n")); | |
291 | ||
292 | if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next)); | |
293 | if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev)); | |
294 | ||
295 | if (cp == ieb->cp) { | |
296 | cfl = 1; | |
297 | cpos += ieb->cpos; | |
298 | } | |
299 | ||
300 | if (!cfl) cpos += clen; | |
301 | ||
302 | csize += clen; | |
303 | cp = cp->next; | |
304 | } | |
305 | if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length)); | |
306 | if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos )); | |
307 | } | |
308 | ||
309 | ||
310 | static | |
311 | void | |
312 | chaincert( io_glue *ig) { | |
313 | size_t csize = 0; | |
314 | io_ex_bchain *ieb = ig->exdata; | |
315 | io_blink *cp = ieb->head; | |
316 | ||
317 | mm_log((1, "Chain verification.\n")); | |
318 | ||
319 | mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset)); | |
320 | mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length)); | |
321 | mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head )); | |
322 | mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail )); | |
323 | mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill )); | |
324 | mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp )); | |
325 | mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos )); | |
326 | mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos )); | |
327 | ||
328 | while(cp) { | |
329 | int clen = cp == ieb->tail ? ieb->tfill : cp->len; | |
330 | mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next)); | |
331 | if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n")); | |
332 | if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n")); | |
333 | ||
334 | if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n")); | |
335 | if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n")); | |
336 | ||
337 | if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next)); | |
338 | if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev)); | |
339 | ||
340 | csize += clen; | |
341 | cp = cp->next; | |
342 | } | |
343 | ||
344 | mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length)); | |
345 | } | |
346 | */ | |
347 | ||
348 | ||
349 | ||
350 | ||
351 | ||
352 | ||
353 | ||
354 | ||
355 | ||
356 | ||
357 | ||
358 | /* | |
359 | =item bufchain_read(ig, buf, count) | |
360 | ||
361 | Does the reading from a source that can be seeked on | |
362 | ||
363 | ig - io_glue object | |
364 | buf - buffer to return data in | |
365 | count - number of bytes to read into buffer max | |
366 | ||
367 | =cut | |
368 | */ | |
369 | ||
370 | static | |
371 | ssize_t | |
372 | bufchain_read(io_glue *ig, void *buf, size_t count) { | |
373 | io_ex_bchain *ieb = ig->exdata; | |
374 | size_t scount = count; | |
375 | char *cbuf = buf; | |
376 | size_t sk; | |
377 | ||
378 | mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count)); | |
379 | IOL_DEB( printf("bufchain_read: fd = %d, ier->cpos = %ld, buf = 0x%p, count = %d\n", fd, (long) ier->cpos, buf, count) ); | |
380 | ||
381 | while( scount ) { | |
382 | int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; | |
383 | if (clen == ieb->cpos) { | |
384 | if (ieb->cp == ieb->tail) break; /* EOF */ | |
385 | ieb->cp = ieb->cp->next; | |
386 | ieb->cpos = 0; | |
387 | clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; | |
388 | } | |
389 | ||
390 | sk = clen - ieb->cpos; | |
391 | sk = sk > scount ? scount : sk; | |
392 | ||
393 | memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk); | |
394 | scount -= sk; | |
395 | ieb->cpos += sk; | |
396 | ieb->gpos += sk; | |
397 | } | |
398 | ||
399 | mm_log((1, "bufchain_read: returning %d\n", count-scount)); | |
400 | return count-scount; | |
401 | } | |
402 | ||
403 | ||
404 | ||
405 | ||
406 | ||
407 | /* | |
408 | =item bufchain_write(ig, buf, count) | |
409 | ||
410 | Does the writing to a 'source' that can be seeked on | |
411 | ||
412 | ig - io_glue object | |
413 | buf - buffer that contains data | |
414 | count - number of bytes to write | |
415 | ||
416 | =cut | |
417 | */ | |
418 | ||
419 | static | |
420 | ssize_t | |
421 | bufchain_write(io_glue *ig, const void *buf, size_t count) { | |
422 | char *cbuf = (char *)buf; | |
423 | io_ex_bchain *ieb = ig->exdata; | |
424 | size_t ocount = count; | |
425 | size_t sk; | |
426 | ||
427 | mm_log((1, "bufchain_write: ig = %p, buf = 0x%p, count = %d\n", ig, buf, count)); | |
428 | ||
429 | IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = 0x%p, count = %d\n", ig, (long) ieb->cpos, buf, count) ); | |
430 | ||
431 | while(count) { | |
432 | mm_log((2, "bufchain_write: - looping - count = %d\n", count)); | |
433 | if (ieb->cp->len == ieb->cpos) { | |
434 | mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos)); | |
435 | io_bchain_advance(ieb); | |
436 | } | |
437 | ||
438 | sk = ieb->cp->len - ieb->cpos; | |
439 | sk = sk > count ? count : sk; | |
440 | memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk); | |
441 | ||
442 | if (ieb->cp == ieb->tail) { | |
443 | int extend = ieb->cpos + sk - ieb->tfill; | |
444 | mm_log((2, "bufchain_write: extending tail by %d\n", extend)); | |
445 | if (extend > 0) { | |
446 | ieb->length += extend; | |
447 | ieb->tfill += extend; | |
448 | } | |
449 | } | |
450 | ||
451 | ieb->cpos += sk; | |
452 | ieb->gpos += sk; | |
453 | count -= sk; | |
454 | } | |
455 | return ocount; | |
456 | } | |
457 | ||
458 | /* | |
459 | =item bufchain_close(ig) | |
460 | ||
461 | Closes a source that can be seeked on. Not sure if this should be an actual close | |
462 | or not. Does nothing for now. Should be fixed. | |
463 | ||
464 | ig - data source | |
465 | ||
466 | =cut | |
467 | */ | |
468 | ||
469 | static | |
470 | void | |
471 | bufchain_close(io_glue *ig) { | |
472 | mm_log((1, "bufchain_close(ig %p)\n",ig)); | |
473 | IOL_DEB( printf("bufchain_close(ig 0x%p)\n", ig) ); | |
474 | /* FIXME: Commit a seek point here */ | |
475 | ||
476 | } | |
477 | ||
478 | ||
479 | /* bufchain_seek(ig, offset, whence) | |
480 | ||
481 | Implements seeking for a source that is seekable, the purpose of having this is to be able to | |
482 | have an offset into a file that is different from what the underlying library thinks. | |
483 | ||
484 | ig - data source | |
485 | offset - offset into stream | |
486 | whence - whence argument a la lseek | |
487 | ||
488 | =cut | |
489 | */ | |
490 | ||
491 | static | |
492 | off_t | |
493 | bufchain_seek(io_glue *ig, off_t offset, int whence) { | |
494 | io_ex_bchain *ieb = ig->exdata; | |
495 | io_blink *ib = NULL; | |
496 | int wrlen; | |
497 | ||
498 | off_t cof = 0; | |
499 | off_t scount = offset; | |
500 | off_t sk; | |
501 | ||
502 | mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence)); | |
503 | ||
504 | switch (whence) { | |
505 | case SEEK_SET: /* SEEK_SET = 0, From the top */ | |
506 | ieb->cp = ieb->head; | |
507 | ieb->cpos = 0; | |
508 | ieb->gpos = 0; | |
509 | ||
510 | while( scount ) { | |
511 | int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; | |
512 | if (clen == ieb->cpos) { | |
513 | if (ieb->cp == ieb->tail) break; /* EOF */ | |
514 | ieb->cp = ieb->cp->next; | |
515 | ieb->cpos = 0; | |
516 | clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; | |
517 | } | |
518 | ||
519 | sk = clen - ieb->cpos; | |
520 | sk = sk > scount ? scount : sk; | |
521 | ||
522 | scount -= sk; | |
523 | ieb->cpos += sk; | |
524 | ieb->gpos += sk; | |
525 | } | |
526 | ||
527 | wrlen = scount; | |
528 | ||
529 | if (wrlen > 0) { | |
530 | /* | |
531 | * extending file - get ieb into consistent state and then | |
532 | * call write which will get it to the correct position | |
533 | */ | |
534 | char TB[BBSIZ]; | |
535 | memset(TB, 0, BBSIZ); | |
536 | ieb->gpos = ieb->length; | |
537 | ieb->cpos = ieb->tfill; | |
538 | ||
539 | while(wrlen > 0) { | |
540 | ssize_t rc, wl = min(wrlen, BBSIZ); | |
541 | mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl)); | |
542 | rc = bufchain_write( ig, TB, wl ); | |
543 | if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n"); | |
544 | wrlen -= rc; | |
545 | } | |
546 | } | |
547 | ||
548 | break; | |
549 | ||
550 | case SEEK_CUR: | |
551 | m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n"); | |
552 | ||
553 | /* | |
554 | case SEEK_CUR: | |
555 | ib = ieb->cp; | |
556 | if (cof < 0) { | |
557 | cof += ib->cpos; | |
558 | cpos = 0; | |
559 | while(cof < 0 && ib->prev) { | |
560 | ib = ib->prev; | |
561 | cof += ib->len; | |
562 | } | |
563 | */ | |
564 | ||
565 | case SEEK_END: /* SEEK_END = 2 */ | |
566 | if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof); | |
567 | ||
568 | ieb->cp = ieb->tail; | |
569 | ieb->cpos = ieb->tfill; | |
570 | ||
571 | if (cof<0) { | |
572 | cof += ieb->cpos; | |
573 | ieb->cpos = 0; | |
574 | ||
575 | while(cof<0 && ib->prev) { | |
576 | ib = ib->prev; | |
577 | cof += ib->len; | |
578 | } | |
579 | ||
580 | if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n"); | |
581 | ieb->gpos = ieb->length+offset; | |
582 | ieb->cpos = cof; | |
583 | } | |
584 | break; | |
585 | default: | |
586 | m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence ); | |
587 | } | |
588 | ||
589 | mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos)); | |
590 | return ieb->gpos; | |
591 | } | |
592 | ||
593 | ||
594 | ||
595 | ||
596 | ||
597 | ||
598 | /* | |
599 | * Methods for setting up data source | |
600 | */ | |
601 | ||
602 | /* | |
603 | =item io_obj_setp_buffer(io, p, len) | |
604 | ||
605 | Sets an io_object for reading from a buffer source | |
606 | ||
607 | io - io object that describes a source | |
608 | p - pointer to buffer | |
609 | len - length of buffer | |
610 | ||
611 | =cut | |
612 | */ | |
613 | ||
614 | void | |
615 | io_obj_setp_buffer(io_obj *io, void *p, size_t len) { | |
616 | io->buffer.type = BUFFER; | |
617 | io->buffer.c = (char*) p; | |
618 | io->buffer.len = len; | |
619 | } | |
620 | ||
621 | ||
622 | /* | |
623 | =item io_obj_setp_cbuf(io, p) | |
624 | ||
625 | Sets an io_object for reading/writing from a buffer source | |
626 | ||
627 | io - io object that describes a source | |
628 | p - pointer to buffer | |
629 | len - length of buffer | |
630 | ||
631 | =cut | |
632 | */ | |
633 | ||
634 | void | |
635 | io_obj_setp_bufchain(io_obj *io) { | |
636 | io->type = BUFCHAIN; | |
637 | } | |
638 | ||
639 | ||
640 | /* | |
641 | =item io_obj_setp_cb(io, p, readcb, writecb, seekcb) | |
642 | ||
643 | Sets an io_object for reading from a source that uses callbacks | |
644 | ||
645 | io - io object that describes a source | |
646 | p - pointer to data for callbacks | |
647 | readcb - read callback to read from source | |
648 | writecb - write callback to write to source | |
649 | seekcb - seek callback to seek on source | |
650 | ||
651 | =cut | |
652 | */ | |
653 | ||
654 | void | |
655 | io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb) { | |
656 | io->cb.type = CBSEEK; | |
657 | io->cb.p = p; | |
658 | io->cb.readcb = readcb; | |
659 | io->cb.writecb = writecb; | |
660 | io->cb.seekcb = seekcb; | |
661 | } | |
662 | ||
663 | /* | |
664 | =item io_glue_commit_types(ig) | |
665 | ||
666 | Creates buffers and initializes structures to read with the chosen interface. | |
667 | ||
668 | ig - io_glue object | |
669 | ||
670 | =cut | |
671 | */ | |
672 | ||
673 | void | |
674 | io_glue_commit_types(io_glue *ig) { | |
675 | io_type inn = ig->source.type; | |
676 | ||
677 | mm_log((1, "io_glue_commit_types(ig 0x%p)\n", ig)); | |
678 | mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn])); | |
679 | ||
680 | switch (inn) { | |
681 | case BUFCHAIN: | |
682 | { | |
683 | io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain)); | |
684 | ||
685 | ieb->offset = 0; | |
686 | ieb->length = 0; | |
687 | ieb->cpos = 0; | |
688 | ieb->gpos = 0; | |
689 | ieb->tfill = 0; | |
690 | ||
691 | ieb->head = io_blink_new(); | |
692 | ieb->cp = ieb->head; | |
693 | ieb->tail = ieb->head; | |
694 | ||
695 | ig->exdata = ieb; | |
696 | ig->readcb = bufchain_read; | |
697 | ig->writecb = bufchain_write; | |
698 | ig->seekcb = bufchain_seek; | |
699 | ig->closecb = bufchain_close; | |
700 | } | |
701 | break; | |
702 | case CBSEEK: | |
703 | default: | |
704 | { | |
705 | io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek)); | |
706 | ||
707 | ier->offset = 0; | |
708 | ier->cpos = 0; | |
709 | ||
710 | ig->exdata = ier; | |
711 | ig->readcb = realseek_read; | |
712 | ig->writecb = realseek_write; | |
713 | ig->seekcb = realseek_seek; | |
714 | ig->closecb = realseek_close; | |
715 | } | |
716 | } | |
717 | } | |
718 | ||
719 | /* | |
720 | =item io_glue_gettypes(ig, reqmeth) | |
721 | ||
722 | Returns a set of compatible interfaces to read data with. | |
723 | ||
724 | ig - io_glue object | |
725 | reqmeth - request mask | |
726 | ||
727 | The request mask is a bit mask (of something that hasn't been implemented yet) | |
728 | of interfaces that it would like to read data from the source which the ig | |
729 | describes. | |
730 | ||
731 | =cut | |
732 | */ | |
733 | ||
734 | void | |
735 | io_glue_gettypes(io_glue *ig, int reqmeth) { | |
736 | ||
737 | ig = NULL; | |
738 | reqmeth = 0; | |
739 | ||
740 | /* FIXME: Implement this function! */ | |
741 | /* if (ig->source.type = | |
742 | if (reqmeth & IO_BUFF) */ | |
743 | ||
744 | } | |
745 | ||
746 | ||
747 | /* | |
748 | =item io_new_bufchain() | |
749 | ||
750 | returns a new io_glue object that has the 'empty' source and but can | |
751 | be written to and read from later (like a pseudo file). | |
752 | ||
753 | =cut | |
754 | */ | |
755 | ||
756 | io_glue * | |
757 | io_new_bufchain() { | |
758 | io_glue *ig = mymalloc(sizeof(io_glue)); | |
759 | io_obj_setp_bufchain(&ig->source); | |
760 | return ig; | |
761 | } | |
762 | ||
763 | ||
764 | /* | |
765 | =item io_new_fd(fd) | |
766 | ||
767 | returns a new io_glue object that has the source defined as reading | |
768 | from specified filedescriptor. Note that the the interface to recieving | |
769 | data from the io_glue callbacks hasn't been done yet. | |
770 | ||
771 | fd - file descriptor to read/write from | |
772 | ||
773 | =cut | |
774 | */ | |
775 | ||
776 | io_glue * | |
777 | io_new_fd(int fd) { | |
778 | io_glue *ig = mymalloc(sizeof(io_glue)); | |
779 | #ifdef _MSC_VER | |
780 | io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek); | |
781 | #else | |
782 | io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek); | |
783 | #endif | |
784 | return ig; | |
785 | } | |
786 | ||
787 | ||
788 | ||
789 | /* | |
790 | =item io_slurp(ig) | |
791 | ||
792 | Takes the source that the io_glue is bound to and allocates space | |
793 | for a return buffer and returns the entire content in a single buffer. | |
794 | Note: This only works for io_glue objects that contain a bufchain. It | |
795 | is usefull for saving to scalars and such. | |
796 | ||
797 | ig - io_glue object | |
798 | c - pointer to a pointer to where data should be copied to | |
799 | ||
800 | =cut | |
801 | */ | |
802 | ||
803 | size_t | |
804 | io_slurp(io_glue *ig, unsigned char **c) { | |
805 | ssize_t rc; | |
806 | off_t orgoff; | |
807 | io_ex_bchain *ieb; | |
808 | unsigned char *cc; | |
809 | io_type inn = ig->source.type; | |
810 | ||
811 | if ( inn != BUFCHAIN ) { | |
812 | m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n"); | |
813 | } | |
814 | ||
815 | ieb = ig->exdata; | |
816 | cc = *c = mymalloc( ieb->length ); | |
817 | ||
818 | orgoff = ieb->gpos; | |
819 | ||
820 | bufchain_seek(ig, 0, SEEK_SET); | |
821 | ||
822 | rc = bufchain_read(ig, cc, ieb->length); | |
823 | ||
824 | if (rc != ieb->length) | |
825 | m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length); | |
826 | ||
827 | return rc; | |
828 | } | |
829 | ||
830 | ||
831 | /* | |
832 | =item io_glue_DESTROY(ig) | |
833 | ||
834 | A destructor method for io_glue objects. Should clean up all related buffers. | |
835 | Might leave us with a dangling pointer issue on some buffers. | |
836 | ||
837 | ig - io_glue object to destroy. | |
838 | ||
839 | =cut | |
840 | */ | |
841 | ||
842 | void | |
843 | io_glue_DESTROY(io_glue *ig) { | |
844 | free(ig); | |
845 | /* FIXME: Handle extradata and such */ | |
846 | } |