00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <unistd.h>
00013 #include <u/libu.h>
00014 #include <klone/va.h>
00015 #include <klone/io.h>
00016 #include <klone/ioprv.h>
00017 #include <klone/codec.h>
00018
00019 enum io_type_e io_type(io_t *io);
00020
00021 enum {
00022 IO_RD_BUFSZ = 4096,
00023 IO_WR_BUFSZ = 4096
00024 };
00025
00026 #define IO_WBUF_AVAIL(io) (io->wbsz - io->wcount)
00027 #define IO_WBUF_FULL(io) (io->wbsz == io->wcount)
00028
00029 static inline int io_transform_codec_buffer(io_t *, codec_t *, char *,
00030 size_t *);
00031
00043 enum io_type_e io_type(io_t *io)
00044 {
00045 return io->type;
00046 }
00047
00061 ssize_t io_pipe(io_t *out, io_t *in)
00062 {
00063 enum { BUFSZ = 4096 };
00064 char buf[BUFSZ];
00065 size_t count = 0;
00066 ssize_t c;
00067
00068 dbg_err_if (out == NULL);
00069 dbg_err_if (in == NULL);
00070
00071 for(;;)
00072 {
00073 c = io_read(in, buf, BUFSZ);
00074 dbg_err_if(c < 0);
00075 if(c == 0)
00076 break;
00077
00078
00079 dbg_err_if(io_write(out, buf, c) < 0);
00080
00081 count += c;
00082 }
00083
00084 return count;
00085 err:
00086 return -1;
00087 }
00088
00106 int io_dup(io_t *io, io_t **pio)
00107 {
00108 dbg_return_if (io == NULL, ~0);
00109 dbg_return_if (pio == NULL, ~0);
00110
00111 io->refcnt++;
00112
00113 *pio = io;
00114
00115 return 0;
00116 }
00117
00132 ssize_t io_copy(io_t *out, io_t *in, size_t size)
00133 {
00134 enum { BUFSZ = 4096 };
00135 char buf[BUFSZ];
00136 size_t rem = size;
00137 ssize_t c;
00138
00139 dbg_err_if (in == NULL);
00140 dbg_err_if (out == NULL);
00141
00142 while(rem)
00143 {
00144 c = io_read(in, buf, MIN(BUFSZ, rem));
00145 dbg_err_if(c < 0);
00146 if(c == 0)
00147 break;
00148
00149
00150 dbg_err_if(io_write(out, buf, c) < 0);
00151
00152 rem -= c;
00153 }
00154
00155 return size - rem;
00156 err:
00157 return -1;
00158 }
00159
00160
00175 ssize_t io_seek(io_t *io, size_t off)
00176 {
00177 dbg_err_if (io == NULL);
00178 dbg_err_if (io_flush(io));
00179
00180 if(io->seek)
00181 return io->seek(io, off);
00182 err:
00183 return -1;
00184 }
00185
00197 ssize_t io_tell(io_t *io)
00198 {
00199 dbg_err_if (io == NULL);
00200 dbg_err_if (io_flush(io));
00201
00202 if(io->tell)
00203 return io->tell(io);
00204 err:
00205 return -1;
00206 }
00207
00208
00209 static int io_rbuf_alloc(io_t *io)
00210 {
00211 dbg_err_if (io == NULL);
00212
00213 io->rbsz = IO_RD_BUFSZ;
00214
00215
00216 io->rbuf = (char*)u_malloc(io->rbsz);
00217 dbg_err_if(io->rbuf == NULL);
00218 io->roff = 0;
00219
00220 io->ubuf = (char*)u_malloc(io->rbsz);
00221 dbg_err_if(io->ubuf == NULL);
00222
00223 return 0;
00224 err:
00225 return ~0;
00226 }
00227
00228
00229 static int io_wbuf_alloc(io_t *io)
00230 {
00231 dbg_err_if (io == NULL);
00232
00233 io->wbsz = IO_WR_BUFSZ;
00234
00235
00236 io->wbuf = (char*)u_malloc(io->wbsz);
00237 dbg_err_if(io->wbuf == NULL);
00238
00239 return 0;
00240 err:
00241 return ~0;
00242 }
00243
00244 static ssize_t io_transform(io_t *io, codec_t *codec,
00245 char *dst, size_t *dcount, const char *src, size_t sz)
00246 {
00247 ssize_t c;
00248 size_t cavail, sdcount = *dcount;
00249
00250 dbg_err_if (io == NULL);
00251 dbg_err_if (codec == NULL);
00252 dbg_err_if (src == NULL);
00253 dbg_err_if (dst == NULL);
00254 dbg_err_if (dcount == NULL);
00255
00256 if(codec == TAILQ_LAST(&io->codec_chain, codec_chain_s))
00257 {
00258
00259 c = codec->transform(codec, dst, dcount, src, sz);
00260 dbg_err_if(c == 0 && *dcount == 0);
00261 return c;
00262 } else {
00263 c = 0;
00264 do
00265 {
00266 *dcount = sdcount;
00267 if(codec->ccount)
00268 dbg_err_if(io_transform_codec_buffer(io, codec, dst, dcount));
00269 else
00270 *dcount = 0;
00271
00272 c = 0;
00273 cavail = CODEC_BUFSZ - codec->ccount - codec->coff;
00274 if(sz && cavail)
00275 {
00276 dbg_err_if((c = codec->transform(codec,
00277 codec->cbuf + codec->coff + codec->ccount,
00278 &cavail, src, sz)) < 0);
00279
00280 codec->ccount += cavail;
00281 dbg_err_if(c == 0 && cavail == 0);
00282 }
00283 } while(c == 0 && *dcount == 0 && (codec->ccount || sz));
00284
00285 return c;
00286 }
00287
00288 err:
00289 return -1;
00290 }
00291
00292 static inline int io_transform_codec_buffer(io_t *io, codec_t *codec,
00293 char *dst, size_t *dcount)
00294 {
00295 ssize_t ct;
00296
00297 dbg_err_if (io == NULL);
00298 dbg_err_if (codec == NULL);
00299 dbg_err_if (dst == NULL);
00300 dbg_err_if (dcount == NULL);
00301
00302 if(codec->ccount)
00303 {
00304 dbg_err_if((ct = io_transform(io, TAILQ_NEXT(codec, np),
00305 dst, dcount, codec->cbuf + codec->coff,codec->ccount)) < 0);
00306
00307 codec->ccount -= ct;
00308
00309 if(codec->ccount > 0)
00310 codec->coff += ct;
00311 else
00312 codec->coff = 0;
00313 }
00314
00315 return 0;
00316 err:
00317 return ~0;
00318 }
00319
00320 static inline ssize_t io_transfer(io_t *io, char *dst, size_t *dcount,
00321 const char *src, size_t sz)
00322 {
00323 dbg_err_if (io == NULL);
00324 dbg_err_if (src == NULL);
00325 dbg_err_if (dst == NULL);
00326 dbg_err_if (dcount == NULL);
00327
00328 if(!TAILQ_EMPTY(&io->codec_chain))
00329 {
00330 return io_transform(io, TAILQ_FIRST(&io->codec_chain),
00331 dst, dcount, src, sz);
00332 } else {
00333 ssize_t wr = MIN(sz, *dcount);
00334 memcpy(dst, src, wr);
00335 *dcount = wr;
00336 return wr;
00337 }
00338 err:
00339 return -1;
00340 }
00341
00342 static int io_chain_flush_chunk(io_t *io, char *dst, size_t *dcount)
00343 {
00344 int er;
00345 codec_t *codec;
00346 size_t sz, sdcount;
00347
00348 dbg_err_if (io == NULL);
00349 dbg_err_if (dst == NULL);
00350 dbg_err_if (dcount == NULL);
00351
00352 sdcount = *dcount;
00353
00354 TAILQ_FOREACH(codec, &io->codec_chain, np)
00355 {
00356 *dcount = sdcount;
00357 if(codec == TAILQ_LAST(&io->codec_chain, codec_chain_s))
00358 {
00359 return codec->flush(codec, dst, dcount);
00360 } else {
00361 for(;;)
00362 {
00363 *dcount = sdcount;
00364 if(codec->ccount)
00365 {
00366 int rc = io_transform_codec_buffer(io, codec, dst, dcount);
00367 dbg_err_if (rc);
00368
00369 if(*dcount)
00370 return CODEC_FLUSH_CHUNK;
00371 } else
00372 *dcount = 0;
00373
00374 sz = CODEC_BUFSZ - codec->ccount - codec->coff;
00375 dbg_err_if((er = codec->flush(codec,
00376 codec->cbuf + codec->coff + codec->ccount, &sz)) < 0);
00377
00378 codec->ccount += sz;
00379
00380 if(er == CODEC_FLUSH_COMPLETE && codec->ccount == 0)
00381 break;
00382 }
00383 }
00384 }
00385
00386 return CODEC_FLUSH_COMPLETE;
00387 err:
00388 return -1;
00389 }
00390
00391 static int io_chain_flush(io_t *io)
00392 {
00393 enum { BUFSZ = 4096 };
00394 int er;
00395 size_t sz, count;
00396 char buf[BUFSZ], *ptr;
00397
00398 dbg_err_if (io == NULL);
00399
00400 for(;;)
00401 {
00402
00403
00404
00405 count = BUFSZ;
00406 if((er = io_chain_flush_chunk(io, buf, &count)) == CODEC_FLUSH_COMPLETE)
00407 break;
00408
00409 dbg_err_if(er < 0);
00410
00411 for(ptr = buf; count; )
00412 {
00413 if(IO_WBUF_FULL(io))
00414 dbg_err_if(io_flush(io));
00415
00416 sz = MIN(count, IO_WBUF_AVAIL(io));
00417 memcpy(io->wbuf + io->wcount, ptr, sz);
00418
00419 count -= sz;
00420 io->wcount += sz;
00421 ptr += sz;
00422 }
00423 }
00424
00425 return 0;
00426 err:
00427 return ~0;
00428 }
00429
00442 int io_close(io_t *io)
00443 {
00444 dbg_err_if (io == NULL);
00445
00446 if(io->close)
00447 dbg_err_if(io->close(io));
00448
00449 return 0;
00450 err:
00451 return ~0;
00452 }
00453
00469 int io_free(io_t *io)
00470 {
00471 dbg_err_if (io == NULL);
00472 dbg_err_if (io->refcnt == 0);
00473
00474
00475
00476 if(--io->refcnt)
00477 return 0;
00478
00479
00480 dbg_if(io_codecs_remove(io));
00481
00482 dbg_if(io_flush(io));
00483
00484
00485 dbg_if(io_close(io));
00486
00487
00488 if(io->free)
00489 dbg_if(io->free(io));
00490
00491 U_FREE(io->rbuf);
00492 U_FREE(io->ubuf);
00493 U_FREE(io->wbuf);
00494 U_FREE(io->name);
00495 U_FREE(io);
00496
00497 return 0;
00498 err:
00499 return ~0;
00500 }
00501
00502
00503 static ssize_t io_underflow(io_t *io)
00504 {
00505 ssize_t c;
00506 size_t sz;
00507
00508 dbg_err_if (io == NULL);
00509
00510 if(io->rbuf == NULL)
00511 dbg_err_if(io_rbuf_alloc(io));
00512
00513 while(io->rcount == 0)
00514 {
00515 if(io->ucount == 0)
00516 {
00517 dbg_err_if((c = io->read(io, io->ubuf, io->rbsz)) < 0);
00518 if(c == 0)
00519 {
00520
00521 if(!TAILQ_EMPTY(&io->codec_chain))
00522 {
00523 sz = io->rbsz;
00524 c = io_chain_flush_chunk(io, io->rbuf, &sz);
00525 dbg_err_if(c < 0);
00526 io->rcount += sz;
00527 io->roff = 0;
00528 if(c == 0)
00529 io->eof++;
00530 }
00531 break;
00532 }
00533 io->ucount += c;
00534 }
00535
00536
00537 sz = io->rbsz - io->rcount;
00538 dbg_err_if((c = io_transfer(io, io->rbuf, &sz,
00539 io->ubuf + io->uoff, io->ucount)) < 0);
00540 dbg_err_if(c < 0);
00541 dbg_err_if(c == 0 && sz == 0);
00542 io->ucount -= c;
00543 if(io->ucount == 0)
00544 io->uoff = 0;
00545 else
00546 io->uoff += c;
00547
00548 io->rcount = sz;
00549 io->roff = 0;
00550 }
00551
00552 return io->rcount;
00553 err:
00554 return -1;
00555 }
00556
00572 ssize_t io_read(io_t *io, char *buf, size_t size)
00573 {
00574 char *out = buf;
00575 size_t wr;
00576 ssize_t c;
00577
00578 dbg_err_if (io == NULL);
00579 dbg_err_if (buf == NULL);
00580
00581 if(io->eof)
00582 return 0;
00583
00584 while(size)
00585 {
00586 if(io->rcount == 0)
00587 {
00588 dbg_err_if((c = io_underflow(io)) < 0);
00589 if(c == 0)
00590 break;
00591 }
00592
00593 wr = MIN(io->rcount, size);
00594 memcpy(out, io->rbuf + io->roff, wr);
00595 io->rcount -= wr;
00596 io->roff += wr;
00597 out += wr;
00598 size -= wr;
00599 }
00600
00601 return out - buf;
00602 err:
00603 return -1;
00604 }
00605
00620 ssize_t io_vprintf(io_t *io, const char *fmt, va_list ap)
00621 {
00622 enum { BUFSZ = 2048 };
00623 char *bbuf = NULL;
00624 int sz;
00625 char buf[BUFSZ];
00626 va_list apcpy;
00627
00628 dbg_err_if (io == NULL);
00629 dbg_err_if (fmt == NULL);
00630
00631 #ifdef VA_COPY_UNAVAIL
00632 u_unused_args(apcpy);
00633 #elif defined(VA_LIST_BY_VALUE)
00634
00635
00636 apcpy = ap;
00637 #else
00638
00639 kl_va_copy(apcpy, ap);
00640 #endif
00641
00642
00643 sz = vsnprintf(buf, BUFSZ, fmt, ap);
00644
00645 if(sz >= BUFSZ)
00646 {
00647 #ifndef VA_COPY_UNAVAIL
00648
00649 bbuf = (char*)u_malloc(++sz);
00650 dbg_err_if(bbuf == NULL);
00651
00652
00653 if((sz = vsnprintf(bbuf, sz, fmt, apcpy)) > 0)
00654 dbg_err_if(io_write(io, bbuf, sz) < 0);
00655
00656 U_FREE(bbuf);
00657 #else
00658
00659 warn("last %d byte(s) could not be written out", sz - BUFSZ + 1);
00660 dbg_err_if(io_write(io, buf, BUFSZ) < 0);
00661 #endif
00662 } else if(sz > 0) {
00663 dbg_err_if(io_write(io, buf, sz) < 0);
00664 }
00665
00666 #if !defined(VA_LIST_BY_VALUE) && !defined(VA_COPY_UNAVAIL)
00667 va_end(apcpy);
00668 #endif
00669 return 0;
00670 err:
00671 #if !defined(VA_LIST_BY_VALUE) && !defined(VA_COPY_UNAVAIL)
00672 va_end(apcpy);
00673 #endif
00674 return -1;
00675 }
00676
00691 ssize_t io_printf(io_t *io, const char *fmt, ...)
00692 {
00693 va_list ap;
00694 ssize_t ret;
00695
00696 dbg_err_if (io == NULL);
00697 dbg_err_if (fmt == NULL);
00698
00699
00700 va_start(ap, fmt);
00701
00702 ret = io_vprintf(io, fmt, ap);
00703
00704 va_end(ap);
00705
00706 return ret;
00707 err:
00708 return -1;
00709 }
00710
00721 ssize_t io_flush(io_t *io)
00722 {
00723 ssize_t c;
00724 size_t off = 0;
00725
00726 dbg_err_if (io == NULL);
00727
00728 while(io->wcount)
00729 {
00730 c = io->write(io, io->wbuf + off, io->wcount);
00731 dbg_err_if(c < 0);
00732 if(c == 0)
00733 break;
00734
00735 io->wcount -= c;
00736 off += c;
00737 }
00738
00739 return 0;
00740 err:
00741 return -1;
00742 }
00743
00756 ssize_t io_write(io_t *io, const char *buf, size_t size)
00757 {
00758 size_t sz = 0, rem = size;
00759 ssize_t c = 0;
00760
00761 dbg_err_if (io == NULL);
00762 dbg_err_if (buf == NULL);
00763
00764 if(io->wbuf == NULL)
00765 dbg_err_if(io_wbuf_alloc(io));
00766
00767 while(rem)
00768 {
00769 if(IO_WBUF_FULL(io))
00770 dbg_err_if(io_flush(io));
00771
00772 sz = IO_WBUF_AVAIL(io);
00773 c = io_transfer(io, io->wbuf + io->wcount, &sz, buf, rem);
00774 dbg_err_if(c < 0);
00775 dbg_err_if(c == 0 && sz == 0);
00776
00777 io->wcount += sz;
00778 buf += c;
00779 rem -= c;
00780 }
00781
00782 return size;
00783 err:
00784 return -1;
00785 }
00786
00798 inline ssize_t io_putc(io_t *io, char c)
00799 {
00800 return io_write(io, &c, 1);
00801 }
00802
00814 inline ssize_t io_getc(io_t *io, char *pc)
00815 {
00816 return io_read(io, pc, 1);
00817 }
00818
00819 static inline char *io_strnchr(char *buf, size_t sz, char c)
00820 {
00821 register char *p;
00822
00823 dbg_goto_if (buf == NULL, end);
00824
00825 p = buf;
00826
00827 while(sz--)
00828 {
00829 if(*p == c)
00830 return p;
00831 ++p;
00832 }
00833 end:
00834 return NULL;
00835 }
00836
00852 ssize_t io_get_until(io_t *io, char stop_at, char *buf, size_t size)
00853 {
00854 ssize_t wr, c, len = 0;
00855 char *p, *base = buf;
00856
00857 dbg_err_if (io == NULL);
00858 dbg_err_if (buf == NULL);
00859
00860 if(size < 2)
00861 return -1;
00862
00863 --size;
00864
00865 if(io->rcount == 0)
00866 dbg_err_if(io_underflow(io) < 0);
00867
00868 if(io->rcount == 0)
00869 return 0;
00870
00871 for(;;)
00872 {
00873 if((p = io_strnchr(io->rbuf + io->roff, io->rcount, stop_at)) != NULL)
00874 {
00875 p++;
00876 wr = MIN(p - (io->rbuf + io->roff), size);
00877 memcpy(buf, io->rbuf + io->roff, wr);
00878 buf[wr] = 0;
00879 io->rcount -= wr;
00880 io->roff += wr;
00881 len += wr;
00882 break;
00883 } else {
00884 if(size >= io->rcount)
00885 {
00886 memcpy(buf, io->rbuf + io->roff, io->rcount);
00887 len += io->rcount;
00888 buf += io->rcount;
00889 size -= io->rcount;
00890 io->rcount = 0;
00891 io->roff = 0;
00892 dbg_err_if((c = io_underflow(io)) < 0);
00893 if(c == 0)
00894 break;
00895 } else {
00896
00897 memcpy(buf, io->rbuf + io->roff, size);
00898 len += size;
00899 io->rcount -= size;
00900 io->roff += size;
00901 break;
00902 }
00903 }
00904 }
00905
00906 base[len] = 0;
00907 return len;
00908 err:
00909 return -1;
00910 }
00911
00925 ssize_t io_gets(io_t *io, char *buf, size_t size)
00926 {
00927 return io_get_until(io, '\n', buf, size);
00928 }
00929
00939 int io_codec_add_head(io_t *io, codec_t* c)
00940 {
00941 dbg_return_if (io == NULL, ~0);
00942 dbg_return_if (c == NULL, ~0);
00943
00944
00945 TAILQ_INSERT_HEAD(&io->codec_chain, c, np);
00946
00947 return 0;
00948 }
00949
00959 int io_codec_add_tail(io_t *io, codec_t* c)
00960 {
00961 dbg_return_if (io == NULL, ~0);
00962 dbg_return_if (c == NULL, ~0);
00963
00964
00965 TAILQ_INSERT_TAIL(&io->codec_chain, c, np);
00966
00967 return 0;
00968 }
00969
00978 int io_codecs_remove(io_t *io)
00979 {
00980 codec_t *codec;
00981 int rc = 0;
00982
00983 dbg_return_if (io == NULL, ~0);
00984
00985 if(!TAILQ_EMPTY(&io->codec_chain))
00986 {
00987 if(io->wbuf)
00988 dbg_ifb(io_chain_flush(io))
00989 rc++;
00990
00991 while((codec = TAILQ_FIRST(&io->codec_chain)) != NULL)
00992 {
00993 TAILQ_REMOVE(&io->codec_chain, codec, np);
00994 codec_free(codec);
00995 }
00996 }
00997
00998 return rc;
00999 }
01000
01013 int io_name_set(io_t *io, const char *name)
01014 {
01015 char *n;
01016
01017 dbg_err_if (io == NULL);
01018 dbg_err_if (name == NULL);
01019
01020 n = u_strdup(name);
01021 dbg_err_if(n == NULL);
01022
01023 U_FREE(io->name);
01024
01025 io->name = n;
01026
01027 return 0;
01028 err:
01029 return ~0;
01030 }
01031
01044 int io_name_get(io_t *io, char *name, size_t sz)
01045 {
01046 size_t min = 0;
01047
01048 dbg_err_if (io == NULL);
01049 dbg_err_if (io->name == NULL);
01050 dbg_err_if (name == NULL);
01051 dbg_err_if (sz < 2);
01052
01053 min = MIN(sz-1, strlen(io->name));
01054
01055 memcpy(name, io->name, min);
01056 name[min] = 0;
01057
01058 return 0;
01059 err:
01060 return ~0;
01061 }
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074 int io_is_secure(io_t *io)
01075 {
01076 dbg_err_if(io == NULL);
01077
01078 return io->is_secure;
01079 err:
01080 return 0;
01081 }
01082
01083
01084
01085
01086 int io_prv_create(size_t dev_sz, io_t **pio)
01087 {
01088 io_t *io = NULL;
01089
01090 dbg_err_if (pio == NULL);
01091
01092 io = u_zalloc(dev_sz);
01093 dbg_err_if(io == NULL);
01094
01095 TAILQ_INIT(&io->codec_chain);
01096
01097
01098 io->refcnt++;
01099
01100
01101 io->size = dev_sz;
01102
01103 *pio = io;
01104
01105 return 0;
01106 err:
01107 U_FREE(io);
01108 return -1;
01109 }