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, U_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 = U_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 = U_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 = U_MIN(io->rcount, size);
00594 memcpy(out, io->rbuf + io->roff, wr);
00595 io->rcount -= wr;
00596 io->roff += wr;
00597 io->rtot += wr;
00598 out += wr;
00599 size -= wr;
00600 }
00601
00602 return out - buf;
00603 err:
00604 return -1;
00605 }
00606
00621 ssize_t io_vprintf(io_t *io, const char *fmt, va_list ap)
00622 {
00623 enum { BUFSZ = 2048 };
00624 char *bbuf = NULL;
00625 int sz;
00626 char buf[BUFSZ];
00627 va_list apcpy;
00628
00629 dbg_err_if (io == NULL);
00630 dbg_err_if (fmt == NULL);
00631
00632 #ifdef VA_COPY_UNAVAIL
00633 u_unused_args(apcpy);
00634 #elif defined(VA_LIST_BY_VALUE)
00635
00636
00637 apcpy = ap;
00638 #else
00639
00640 kl_va_copy(apcpy, ap);
00641 #endif
00642
00643
00644 sz = vsnprintf(buf, BUFSZ, fmt, ap);
00645
00646 if(sz >= BUFSZ)
00647 {
00648 #ifndef VA_COPY_UNAVAIL
00649
00650 bbuf = (char*)u_malloc(++sz);
00651 dbg_err_if(bbuf == NULL);
00652
00653
00654 if((sz = vsnprintf(bbuf, sz, fmt, apcpy)) > 0)
00655 dbg_err_if(io_write(io, bbuf, sz) < 0);
00656
00657 U_FREE(bbuf);
00658 #else
00659
00660 warn("last %d byte(s) could not be written out", sz - BUFSZ + 1);
00661 dbg_err_if(io_write(io, buf, BUFSZ) < 0);
00662 #endif
00663 } else if(sz > 0) {
00664 dbg_err_if(io_write(io, buf, sz) < 0);
00665 }
00666
00667 #if !defined(VA_LIST_BY_VALUE) && !defined(VA_COPY_UNAVAIL)
00668 va_end(apcpy);
00669 #endif
00670 return 0;
00671 err:
00672 #if !defined(VA_LIST_BY_VALUE) && !defined(VA_COPY_UNAVAIL)
00673 va_end(apcpy);
00674 #endif
00675 return -1;
00676 }
00677
00692 ssize_t io_printf(io_t *io, const char *fmt, ...)
00693 {
00694 va_list ap;
00695 ssize_t ret;
00696
00697 dbg_err_if (io == NULL);
00698 dbg_err_if (fmt == NULL);
00699
00700
00701 va_start(ap, fmt);
00702
00703 ret = io_vprintf(io, fmt, ap);
00704
00705 va_end(ap);
00706
00707 return ret;
00708 err:
00709 return -1;
00710 }
00711
00722 ssize_t io_flush(io_t *io)
00723 {
00724 ssize_t c;
00725 size_t off = 0;
00726
00727 dbg_err_if (io == NULL);
00728
00729 while(io->wcount)
00730 {
00731 c = io->write(io, io->wbuf + off, io->wcount);
00732 dbg_err_if(c < 0);
00733 if(c == 0)
00734 break;
00735
00736 io->wcount -= c;
00737 off += c;
00738 }
00739
00740 return 0;
00741 err:
00742 return -1;
00743 }
00744
00757 ssize_t io_write(io_t *io, const char *buf, size_t size)
00758 {
00759 size_t sz = 0, rem = size;
00760 ssize_t c = 0;
00761
00762 dbg_err_if (io == NULL);
00763 dbg_err_if (buf == NULL);
00764
00765 if(io->wbuf == NULL)
00766 dbg_err_if(io_wbuf_alloc(io));
00767
00768 while(rem)
00769 {
00770 if(IO_WBUF_FULL(io))
00771 dbg_err_if(io_flush(io));
00772
00773 sz = IO_WBUF_AVAIL(io);
00774 c = io_transfer(io, io->wbuf + io->wcount, &sz, buf, rem);
00775 dbg_err_if(c < 0);
00776 dbg_err_if(c == 0 && sz == 0);
00777
00778 io->wcount += sz;
00779 buf += c;
00780 rem -= c;
00781 }
00782
00783 return size;
00784 err:
00785 return -1;
00786 }
00787
00799 inline ssize_t io_putc(io_t *io, char c)
00800 {
00801 return io_write(io, &c, 1);
00802 }
00803
00815 inline ssize_t io_getc(io_t *io, char *pc)
00816 {
00817 return io_read(io, pc, 1);
00818 }
00819
00820 static inline char *io_strnchr(char *buf, size_t sz, char c)
00821 {
00822 register char *p;
00823
00824 dbg_goto_if (buf == NULL, end);
00825
00826 p = buf;
00827
00828 while(sz--)
00829 {
00830 if(*p == c)
00831 return p;
00832 ++p;
00833 }
00834 end:
00835 return NULL;
00836 }
00837
00853 ssize_t io_get_until(io_t *io, char stop_at, char *buf, size_t size)
00854 {
00855 ssize_t wr, c, len = 0;
00856 char *p, *base = buf;
00857
00858 dbg_err_if (io == NULL);
00859 dbg_err_if (buf == NULL);
00860
00861 if(size < 2)
00862 return -1;
00863
00864 --size;
00865
00866 if(io->rcount == 0)
00867 dbg_err_if(io_underflow(io) < 0);
00868
00869 if(io->rcount == 0)
00870 return 0;
00871
00872 for(;;)
00873 {
00874 if((p = io_strnchr(io->rbuf + io->roff, io->rcount, stop_at)) != NULL)
00875 {
00876 p++;
00877 wr = U_MIN(p - (io->rbuf + io->roff), size);
00878 memcpy(buf, io->rbuf + io->roff, wr);
00879 buf[wr] = 0;
00880 io->rcount -= wr;
00881 io->roff += wr;
00882 io->rtot += wr;
00883 len += wr;
00884 break;
00885 } else {
00886 if(size >= io->rcount)
00887 {
00888 memcpy(buf, io->rbuf + io->roff, io->rcount);
00889 len += io->rcount;
00890 buf += io->rcount;
00891 size -= io->rcount;
00892 io->rtot += io->rcount;
00893 io->rcount = 0;
00894 io->roff = 0;
00895 dbg_err_if((c = io_underflow(io)) < 0);
00896 if(c == 0)
00897 break;
00898 } else {
00899
00900 memcpy(buf, io->rbuf + io->roff, size);
00901 len += size;
00902 io->rcount -= size;
00903 io->roff += size;
00904 io->rtot += size;
00905 break;
00906 }
00907 }
00908 }
00909
00910 base[len] = 0;
00911 return len;
00912 err:
00913 return -1;
00914 }
00915
00929 ssize_t io_gets(io_t *io, char *buf, size_t size)
00930 {
00931 return io_get_until(io, '\n', buf, size);
00932 }
00933
00943 int io_codec_add_head(io_t *io, codec_t* c)
00944 {
00945 dbg_return_if (io == NULL, ~0);
00946 dbg_return_if (c == NULL, ~0);
00947
00948
00949 TAILQ_INSERT_HEAD(&io->codec_chain, c, np);
00950
00951 return 0;
00952 }
00953
00963 int io_codec_add_tail(io_t *io, codec_t* c)
00964 {
00965 dbg_return_if (io == NULL, ~0);
00966 dbg_return_if (c == NULL, ~0);
00967
00968
00969 TAILQ_INSERT_TAIL(&io->codec_chain, c, np);
00970
00971 return 0;
00972 }
00973
00982 int io_codecs_remove(io_t *io)
00983 {
00984 codec_t *codec;
00985 int rc = 0;
00986
00987 dbg_return_if (io == NULL, ~0);
00988
00989 if(!TAILQ_EMPTY(&io->codec_chain))
00990 {
00991 if(io->wbuf)
00992 dbg_ifb(io_chain_flush(io))
00993 rc++;
00994
00995 while((codec = TAILQ_FIRST(&io->codec_chain)) != NULL)
00996 {
00997 TAILQ_REMOVE(&io->codec_chain, codec, np);
00998 codec_free(codec);
00999 }
01000 }
01001
01002 return rc;
01003 }
01004
01017 int io_name_set(io_t *io, const char *name)
01018 {
01019 char *n;
01020
01021 dbg_err_if (io == NULL);
01022 dbg_err_if (name == NULL);
01023
01024 n = u_strdup(name);
01025 dbg_err_if(n == NULL);
01026
01027 U_FREE(io->name);
01028
01029 io->name = n;
01030
01031 return 0;
01032 err:
01033 return ~0;
01034 }
01035
01048 int io_name_get(io_t *io, char *name, size_t sz)
01049 {
01050 size_t min = 0;
01051
01052 dbg_err_if (io == NULL);
01053 dbg_err_if (io->name == NULL);
01054 dbg_err_if (name == NULL);
01055 dbg_err_if (sz < 2);
01056
01057 min = U_MIN(sz-1, strlen(io->name));
01058
01059 memcpy(name, io->name, min);
01060 name[min] = 0;
01061
01062 return 0;
01063 err:
01064 return ~0;
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078 int io_is_secure(io_t *io)
01079 {
01080 dbg_err_if(io == NULL);
01081
01082 return io->is_secure;
01083 err:
01084 return 0;
01085 }
01086
01087
01088
01089
01090 int io_prv_create(size_t dev_sz, io_t **pio)
01091 {
01092 io_t *io = NULL;
01093
01094 dbg_err_if (pio == NULL);
01095
01096 io = u_zalloc(dev_sz);
01097 dbg_err_if(io == NULL);
01098
01099 TAILQ_INIT(&io->codec_chain);
01100
01101
01102 io->refcnt++;
01103
01104
01105 io->size = dev_sz;
01106
01107 *pio = io;
01108
01109 return 0;
01110 err:
01111 U_FREE(io);
01112 return -1;
01113 }