+#define f_oddenc 256u
+
+/*----- Encoding and decoding ---------------------------------------------*/
+
+/* --- Hex encoding --- */
+
+static void puthex(const octet *buf, size_t sz, FILE *fp)
+{
+ while (sz) {
+ fprintf(fp, "%02x", *buf++);
+ sz--;
+ }
+}
+
+static size_t gethex(const char *p, octet *q, size_t sz, char **pp)
+{
+ size_t i = 0;
+ while (sz > 0 &&
+ isxdigit((unsigned char)p[0]) &&
+ isxdigit((unsigned char)p[1])) {
+ char buf[3];
+ buf[0] = p[0];
+ buf[1] = p[1];
+ buf[2] = 0;
+ *q++ = strtoul(buf, 0, 16);
+ sz--;
+ p += 2;
+ i++;
+ }
+ if (pp)
+ *pp = (char *)p;
+ return (i);
+}
+
+/* --- Base64 encoding --- */
+
+static void putb64(const octet *buf, size_t sz, FILE *fp)
+{
+ base64_ctx b;
+ dstr d = DSTR_INIT;
+
+ base64_init(&b);
+ b.indent = "";
+ b.maxline = 0;
+ base64_encode(&b, buf, sz, &d);
+ base64_encode(&b, 0, 0, &d);
+ dstr_write(&d, fp);
+ dstr_destroy(&d);
+}
+
+static size_t getb64(const char *p, octet *q, size_t sz, char **pp)
+{
+ base64_ctx b;
+ dstr d = DSTR_INIT;
+ size_t n = strlen(p);
+
+ base64_init(&b);
+ base64_decode(&b, p, n, &d);
+ if (pp) *pp = (/*unconst*/ char *)p + n;
+ base64_decode(&b, 0, 0, &d);
+ assert(d.len <= sz);
+ memcpy(q, d.buf, sz);
+ n = d.len;
+ dstr_destroy(&d);
+ return (n);
+}
+
+/* --- Base32 encoding --- */
+
+static void putb32(const octet *buf, size_t sz, FILE *fp)
+{
+ base32_ctx b;
+ dstr d = DSTR_INIT;
+
+ base32_init(&b);
+ b.indent = "";
+ b.maxline = 0;
+ base32_encode(&b, buf, sz, &d);
+ base32_encode(&b, 0, 0, &d);
+ dstr_write(&d, fp);
+ dstr_destroy(&d);
+}
+
+static size_t getb32(const char *p, octet *q, size_t sz, char **pp)
+{
+ base32_ctx b;
+ dstr d = DSTR_INIT;
+ size_t n = strlen(p);
+
+ base32_init(&b);
+ base32_decode(&b, p, n, &d);
+ if (pp) *pp = (/*unconst*/ char *)p + n;
+ base32_decode(&b, 0, 0, &d);
+ assert(d.len <= sz);
+ memcpy(q, d.buf, sz);
+ n = d.len;
+ dstr_destroy(&d);
+ return (n);
+}
+
+/* --- Table --- */
+
+typedef struct encodeops {
+ const char *name;
+ void (*put)(const octet *, size_t, FILE *);
+ size_t (*get)(const char *, octet *, size_t, char **);
+} encodeops;
+
+static const encodeops encodingtab[] = {
+ { "hex", puthex, gethex },
+ { "base64", putb64, getb64 },
+ { "base32", putb32, getb32 },
+ { 0, 0, 0 }
+};
+
+static const encodeops *getencoding(const char *ename)
+{
+ const encodeops *e;
+
+ for (e = encodingtab; e->name; e++) {
+ if (strcmp(ename, e->name) == 0)
+ return (e);
+ }
+ return (0);
+}