Catcrypt tools: Roll out progress indicator stuff from hashsum.
[u/mdw/catacomb] / cc-enc.c
index c3da95b..2b8b0fd 100644 (file)
--- 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.
  *
  * 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,
 
 /*----- Header files ------------------------------------------------------*/
 
+#define _FILE_OFFSET_BITS 64
+
+#include <errno.h>
 #include <stdio.h>
 
 #include <mLib/alloc.h>
 #include <mLib/base64.h>
 #include <mLib/dstr.h>
+#include <mLib/mdwopt.h>
 #include <mLib/report.h>
 #include <mLib/sub.h>
 
 #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 -------------------------------------------------*/