X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/c65df27983057ec76ed0e72bb370f9a5ae7dad28..cd6eca4375f46a35b93e2fea4b0428a23b451aa3:/cc-enc.c diff --git a/cc-enc.c b/cc-enc.c index c3da95b..2b8b0fd 100644 --- a/cc-enc.c +++ b/cc-enc.c @@ -7,7 +7,7 @@ * (c) 2004 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,12 +15,12 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * Catacomb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with Catacomb; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -29,27 +29,35 @@ /*----- Header files ------------------------------------------------------*/ +#define _FILE_OFFSET_BITS 64 + +#include #include #include #include #include +#include #include #include #include "cc.h" +typedef int encbdryp(const char *, void *); + /*----- Main code ---------------------------------------------------------*/ /* --- Binary --- */ -static enc *bin_init(FILE *fp, const char *msg) +static enc *bin_encinit(FILE *fp, const char *msg) + { enc *e = CREATE(enc); return (e); } +static enc *bin_decinit(FILE *fp, encbdryp *func, void *p) { enc *e = CREATE(enc); return (e); } static int bin_read(enc *e, void *p, size_t sz) { size_t n; - + if (!sz) return (0); n = fread(p, 1, sz, e->fp); if (!n || ferror(e->fp)) return (-1); @@ -88,7 +96,9 @@ static enc *pem_encinit(FILE *fp, const char *msg) return (&pe->e); } -static enc *pem_decinit(FILE *fp, const char *msg) +int checkbdry(const char *b, void *p) { return (!p || strcmp(b, p) == 0); } + +static enc *pem_decinit(FILE *fp, encbdryp *func, void *p) { char buf[128]; int i, d; @@ -125,8 +135,7 @@ banner: /* --- Check we have the right framing --- */ if (d != 5) goto top; - if (strncmp(buf, "BEGIN ", 6) != 0 || - (msg && strcmp(buf + 6, msg) != 0)) + if (strncmp(buf, "BEGIN ", 6) != 0 || (func && !func(buf + 6, p))) goto top; /* --- Ready --- */ @@ -261,18 +270,18 @@ static void pem_destroy(enc *e) /* --- Encoder table --- */ const encops enctab[] = { - { "binary", "rb", "wb", - bin_init, bin_init, + { "binary", "rb", "wb", 1, 1, + bin_encinit, bin_decinit, bin_read, bin_write, bin_done, bin_done, bin_destroy }, - { "pem", "r", "w", + { "pem", "r", "w", 3, 4, pem_encinit, pem_decinit, pem_read, pem_write, pem_encdone, pem_decdone, pem_destroy }, { 0 } -}; +}; /* --- @getenc@ --- * * @@ -301,19 +310,39 @@ e_found: * Arguments: @const encops *eo@ = operations (from @getenc@) * @FILE *fp@ = file handle to attach * @const char *msg@ = banner message - * @int wantenc@ = nonzero if we want to encode * * Returns: The encoder object. * * Use: Initializes an encoder. */ -enc *initenc(const encops *eo, FILE *fp, const char *msg, int wantenc) +enc *initenc(const encops *eo, FILE *fp, const char *msg) +{ + enc *e = eo->initenc(fp, msg); + e->ops = eo; + e->fp = fp; + return (e); +} + +/* --- @initdec@ --- * + * + * Arguments: @const encops *eo@ = operations (from @getenc@) + * @FILE *fp@ = file handle to attach + * @int (*func)(const char *, void *)@ = banner check function + * @void *p@ = argument for @func@ + * + * Returns: The encoder object. + * + * Use: Initializes an encoder. + */ + +enc *initdec(const encops *eo, FILE *fp, + int (*func)(const char *, void *), void *p) { - enc *e = (wantenc ? eo->initenc : eo->initdec)(fp, msg); + enc *e = eo->initdec(fp, func, p); e->ops = eo; e->fp = fp; - return (e); + return (e); } /* --- @freeenc@ --- * @@ -327,4 +356,175 @@ enc *initenc(const encops *eo, FILE *fp, const char *msg, int wantenc) void freeenc(enc *e) { e->ops->destroy(e); } +/*----- Encoding and decoding commands ------------------------------------*/ + +int cmd_encode(int argc, char *argv[]) +{ + const char *fn, *of = 0; + FILE *ofp = 0; + FILE *fp = 0; + const char *ef = "binary"; + const char *bd = "MESSAGE"; + fprogress ff; + int i; + size_t n; + char buf[4096]; + unsigned f = 0; + const encops *eo; + enc *e; + +#define f_bogus 1u +#define f_progress 2u + + for (;;) { + static const struct option opt[] = { + { "format", OPTF_ARGREQ, 0, 'f' }, + { "boundary", OPTF_ARGREQ, 0, 'b' }, + { "output", OPTF_ARGREQ, 0, 'o' }, + { "progress", 0, 0, 'p' }, + { 0, 0, 0, 0 } + }; + i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0); + if (i < 0) break; + switch (i) { + case 'f': ef = optarg; break; + case 'b': bd = optarg; break; + case 'o': of = optarg; break; + case 'p': f |= f_progress; break; + default: f |= f_bogus; break; + } + } + if (argc - optind > 1 || (f & f_bogus)) + die(EXIT_FAILURE, "Usage: encode [-OPTIONS] [FILE]"); + + if ((eo = getenc(ef)) == 0) + die(EXIT_FAILURE, "encoding `%s' not found", ef); + + fn = optind < argc ? argv[optind++] : "-"; + if (strcmp(fn, "-") == 0) + fp = stdin; + else if ((fp = fopen(fn, "rb")) == 0) { + die(EXIT_FAILURE, "couldn't open file `%s': %s", + fn, strerror(errno)); + } + + if (!of || strcmp(of, "-") == 0) + ofp = stdout; + else if ((ofp = fopen(of, eo->wmode)) == 0) { + die(EXIT_FAILURE, "couldn't open file `%s' for output: %s", + ofp, strerror(errno)); + } + + e = initenc(eo, ofp, bd); + + if (f & f_progress) { + if (fprogress_init(&ff, fn, fp)) { + die(EXIT_FAILURE, "failed to initialize progress display: %s", + strerror(errno)); + } + } + + do { + n = fread(buf, 1, sizeof(buf), fp); + if (f & f_progress) fprogress_update(&ff, n); + if (e->ops->write(e, buf, n)) { + if (f & f_progress) fprogress_done(&ff); + die(EXIT_FAILURE, "error writing output: %s", strerror(errno)); + } + } while (n == sizeof(buf)); + if (f & f_progress) fprogress_done(&ff); + e->ops->encdone(e); + freeenc(e); + return (0); + +#undef f_bogus +#undef f_progress +} + +int cmd_decode(int argc, char *argv[]) +{ + const char *fn, *of = 0; + FILE *ofp = 0; + FILE *fp = 0; + const char *ef = "binary"; + const char *bd = 0; + fprogress ff; + int i; + char buf[4096]; + unsigned f = 0; + const encops *eo; + enc *e; + +#define f_bogus 1u +#define f_progress 2u + + for (;;) { + static const struct option opt[] = { + { "format", OPTF_ARGREQ, 0, 'f' }, + { "boundary", OPTF_ARGREQ, 0, 'b' }, + { "output", OPTF_ARGREQ, 0, 'o' }, + { "progress", 0, 0, 'p' }, + { 0, 0, 0, 0 } + }; + i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0); + if (i < 0) break; + switch (i) { + case 'f': ef = optarg; break; + case 'b': bd = optarg; break; + case 'o': of = optarg; break; + case 'p': f |= f_progress; break; + default: f |= f_bogus; break; + } + } + if (argc - optind > 1 || (f & f_bogus)) + die(EXIT_FAILURE, "Usage: decode [-OPTIONS] [FILE]"); + + if ((eo = getenc(ef)) == 0) + die(EXIT_FAILURE, "encoding `%s' not found", ef); + + fn = optind < argc ? argv[optind++] : "-"; + if (strcmp(fn, "-") == 0) + fp = stdin; + else if ((fp = fopen(fn, eo->rmode)) == 0) { + die(EXIT_FAILURE, "couldn't open file `%s': %s", + fn, strerror(errno)); + } + + if (!of || strcmp(of, "-") == 0) + ofp = stdout; + else if ((ofp = fopen(of, "wb")) == 0) { + die(EXIT_FAILURE, "couldn't open file `%s' for output: %s", + ofp, strerror(errno)); + } + + e = initdec(eo, fp, checkbdry, (/*unconst*/ void *)bd); + + if (f & f_progress) { + if (fprogress_init(&ff, fn, fp)) { + die(EXIT_FAILURE, "failed to initialize progress display: %s", + strerror(errno)); + } + } + + do { + if ((i = e->ops->read(e, buf, sizeof(buf))) < 0) { + if (f & f_progress) fprogress_done(&ff); + die(EXIT_FAILURE, "error reading input: %s", strerror(errno)); + } + if (f & f_progress) + fprogress_update(&ff, i*e->ops->ncook/e->ops->nraw); + if (fwrite(buf, 1, i, ofp) < i) { + if (f & f_progress) fprogress_done(&ff); + die(EXIT_FAILURE, "error writing output: %s", strerror(errno)); + } + } while (i == sizeof(buf)); + e->ops->decdone(e); + if (f & f_progress) fprogress_done(&ff); + freeenc(e); + return (0); + +#undef f_bogus +#undef f_progress +} + /*----- That's all, folks -------------------------------------------------*/