iimplement base64 data in-place decoding - ics2txt - convert icalendar .ics file to plain text Err bitreich.org 70 hgit clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt URL:git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt bitreich.org 70 1Log /scm/ics2txt/log.gph bitreich.org 70 1Files /scm/ics2txt/files.gph bitreich.org 70 1Refs /scm/ics2txt/refs.gph bitreich.org 70 1Tags /scm/ics2txt/tag bitreich.org 70 1README /scm/ics2txt/file/README.md.gph bitreich.org 70 i--- Err bitreich.org 70 1commit b72092250747c7443e20fee06bee232b236f441e /scm/ics2txt/commit/b72092250747c7443e20fee06bee232b236f441e.gph bitreich.org 70 1parent 917f5b056d0b1241f0816bfd41276a36b5727fb1 /scm/ics2txt/commit/917f5b056d0b1241f0816bfd41276a36b5727fb1.gph bitreich.org 70 hAuthor: Josuah Demangeon URL:mailto:me@josuah.net bitreich.org 70 iDate: Sun, 13 Jun 2021 13:47:25 +0200 Err bitreich.org 70 i Err bitreich.org 70 iimplement base64 data in-place decoding Err bitreich.org 70 i Err bitreich.org 70 iThis is not done implicitly in case base64 decoding is not needed Err bitreich.org 70 ievery time, but instead available as a ical_get_value() function that Err bitreich.org 70 idecodes the content if it is base64 data. Err bitreich.org 70 i Err bitreich.org 70 iDiffstat: Err bitreich.org 70 i M Makefile | 4 ++-- Err bitreich.org 70 i A base64.c | 107 +++++++++++++++++++++++++++++++ Err bitreich.org 70 i A base64.h | 19 +++++++++++++++++++ Err bitreich.org 70 i M ical.c | 22 +++++++++++++++++++++- Err bitreich.org 70 i M ical.h | 9 +++++---- Err bitreich.org 70 i M ics2tree.c | 5 ++++- Err bitreich.org 70 i D ics2tsv.c | 59 ------------------------------- Err bitreich.org 70 i M util.c | 2 +- Err bitreich.org 70 i Err bitreich.org 70 i8 files changed, 159 insertions(+), 68 deletions(-) Err bitreich.org 70 i--- Err bitreich.org 70 1diff --git a/Makefile b/Makefile /scm/ics2txt/file/Makefile.gph bitreich.org 70 i@@ -7,8 +7,8 @@ CFLAGS = $D $W -g Err bitreich.org 70 i PREFIX = /usr/local Err bitreich.org 70 i MANPREFIX = ${PREFIX}/man Err bitreich.org 70 i Err bitreich.org 70 i-SRC = ical.c util.c Err bitreich.org 70 i-HDR = ical.h util.h Err bitreich.org 70 i+SRC = ical.c base64.c util.c Err bitreich.org 70 i+HDR = ical.h base64.h util.h Err bitreich.org 70 i OBJ = ${SRC:.c=.o} Err bitreich.org 70 i BIN = ics2tree Err bitreich.org 70 i MAN1 = ics2txt.1 Err bitreich.org 70 1diff --git a/base64.c b/base64.c /scm/ics2txt/file/base64.c.gph bitreich.org 70 i@@ -0,0 +1,107 @@ Err bitreich.org 70 i+#include "base64.h" Err bitreich.org 70 i+ Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+#include Err bitreich.org 70 i+ Err bitreich.org 70 i+#include Err bitreich.org 70 i+ Err bitreich.org 70 i+static char encode_map[64] = Err bitreich.org 70 i+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+base64_encode(char const *s, size_t slen, char *d, size_t *dlen) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ char const *sbeg = s, *send = s + slen, *dbeg = d; Err bitreich.org 70 i+ unsigned char x; Err bitreich.org 70 i+ Err bitreich.org 70 i+ while (s < send) { Err bitreich.org 70 i+ switch ((s - sbeg) % 3) { Err bitreich.org 70 i+ case 0: /* AAAAAABB bbbbcccc ccdddddd */ Err bitreich.org 70 i+ assert((size_t)(d - dbeg) + 1 < *dlen); Err bitreich.org 70 i+ *d++ = encode_map[*s >> 2]; Err bitreich.org 70 i+ x = *s << 4 & 0x3f; Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ case 1: /* aaaaaabb BBBBCCCC ccdddddd */ Err bitreich.org 70 i+ assert((size_t)(d - dbeg) + 1 < *dlen); Err bitreich.org 70 i+ *d++ = encode_map[x | (*s >> 4)]; Err bitreich.org 70 i+ x = (*s << 2) & 0x3f; Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ case 2: /* aaaaaabb bbbbcccc CCDDDDDD */ Err bitreich.org 70 i+ assert((size_t)(d - dbeg) + 2 < *dlen); Err bitreich.org 70 i+ *d++ = encode_map[x | (*s >> 6)]; Err bitreich.org 70 i+ *d++ = encode_map[*s & 0x3f]; Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ s++; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* flush extra content in 'x' */ Err bitreich.org 70 i+ assert((size_t)(d - dbeg) + 1 < *dlen); Err bitreich.org 70 i+ if ((s - sbeg) % 3 != 2) Err bitreich.org 70 i+ *d++ = encode_map[x]; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* pad the end with '=' */ Err bitreich.org 70 i+ while ((d - dbeg) % 4 != 0) { Err bitreich.org 70 i+ assert((size_t)(d - dbeg) + 1 < *dlen); Err bitreich.org 70 i+ *d++ = '='; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ *dlen = d - dbeg; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+static int8_t decode_map[256] = { Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, Err bitreich.org 70 i+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, Err bitreich.org 70 i+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, Err bitreich.org 70 i+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, Err bitreich.org 70 i+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Err bitreich.org 70 i+}; Err bitreich.org 70 i+ Err bitreich.org 70 i+int Err bitreich.org 70 i+base64_decode(char const *s, size_t *slen, char *d, size_t *dlen) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ char const *sbeg = s, *send = sbeg + *slen, *dbeg = d; Err bitreich.org 70 i+ Err bitreich.org 70 i+ for (; s + 3 < send; s += 4) { Err bitreich.org 70 i+ int8_t x0 = decode_map[(unsigned)s[0]]; Err bitreich.org 70 i+ int8_t x1 = decode_map[(unsigned)s[1]]; Err bitreich.org 70 i+ int8_t x2 = decode_map[(unsigned)s[2]]; Err bitreich.org 70 i+ int8_t x3 = decode_map[(unsigned)s[3]]; Err bitreich.org 70 i+ uint32_t x = (x0 << 18) | (x1 << 12) | (x2 << 6) | (x3 << 0); Err bitreich.org 70 i+ Err bitreich.org 70 i+ assert((size_t)(d - dbeg) + 3 < *dlen); Err bitreich.org 70 i+ *d++ = x >> 16; Err bitreich.org 70 i+ *d++ = x >> 8 & 0xff; Err bitreich.org 70 i+ *d++ = x & 0xff; Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* only "xxxx" or "xxx=" or "xx==" allowed */ Err bitreich.org 70 i+ if (s[0] == '=' || s[1] == '=' || (s[2] == '=' && s[3] != '=')) Err bitreich.org 70 i+ return -2; Err bitreich.org 70 i+ if (s[2] == '=') Err bitreich.org 70 i+ d--; Err bitreich.org 70 i+ if (s[3] == '=') { Err bitreich.org 70 i+ d--; Err bitreich.org 70 i+ break; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ if (x0 < 0 || x1 < 0 || x2 < 0 || x3 < 0) Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ *slen = s - sbeg; Err bitreich.org 70 i+ *dlen = d - dbeg; Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+} Err bitreich.org 70 1diff --git a/base64.h b/base64.h /scm/ics2txt/file/base64.h.gph bitreich.org 70 i@@ -0,0 +1,19 @@ Err bitreich.org 70 i+#ifndef BASE64_H Err bitreich.org 70 i+#define BASE64_H Err bitreich.org 70 i+ Err bitreich.org 70 i+#include Err bitreich.org 70 i+ Err bitreich.org 70 i+void base64_encode(char const *, size_t, char *, size_t *); Err bitreich.org 70 i+ Err bitreich.org 70 i+/* Err bitreich.org 70 i+ * It is possible to use the same variables for both source and Err bitreich.org 70 i+ * destination. Then the base64 will overwrite the source buffer Err bitreich.org 70 i+ * with the destination data. Err bitreich.org 70 i+ * Err bitreich.org 70 i+ * If the same pointer is passed as both source and destination Err bitreich.org 70 i+ * size, the source size will be inaccurate but the destination Err bitreich.org 70 i+ * will be correct. Err bitreich.org 70 i+ */ Err bitreich.org 70 i+int base64_decode(char const *, size_t *, char *, size_t *); Err bitreich.org 70 i+ Err bitreich.org 70 i+#endif Err bitreich.org 70 1diff --git a/ical.c b/ical.c /scm/ics2txt/file/ical.c.gph bitreich.org 70 i@@ -9,14 +9,31 @@ Err bitreich.org 70 i #include Err bitreich.org 70 i Err bitreich.org 70 i #include "util.h" Err bitreich.org 70 i+#include "base64.h" Err bitreich.org 70 i Err bitreich.org 70 i-static int Err bitreich.org 70 i+int Err bitreich.org 70 i ical_error(IcalParser *p, char const *msg) Err bitreich.org 70 i { Err bitreich.org 70 i p->errmsg = msg; Err bitreich.org 70 i return -1; Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i+int Err bitreich.org 70 i+ical_get_value(IcalParser *p, char *s, size_t *len) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ *len = strlen(s); Err bitreich.org 70 i+ if (p->base64) Err bitreich.org 70 i+ if (base64_decode(s, len, s, len) < 0) Err bitreich.org 70 i+ return ical_error(p, "invalid base64 data"); Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+int Err bitreich.org 70 i+ical_get_time(IcalParser *p, char *s, time_t *t) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i #define CALL(p, fn, ...) ((p)->fn ? (p)->fn((p), __VA_ARGS__) : 0) Err bitreich.org 70 i Err bitreich.org 70 i static int Err bitreich.org 70 i@@ -40,6 +57,8 @@ ical_parse_value(IcalParser *p, char **sp, char *name) Err bitreich.org 70 i c = *s, *s = '\0'; Err bitreich.org 70 i if ((err = CALL(p, fn_param_value, name, val)) != 0) Err bitreich.org 70 i return err; Err bitreich.org 70 i+ if (strcasecmp(name, "ENCODING") == 0) Err bitreich.org 70 i+ p->base64 = (strcasecmp(val, "BASE64") == 0); Err bitreich.org 70 i *s = c; Err bitreich.org 70 i Err bitreich.org 70 i *sp = s; Err bitreich.org 70 i@@ -90,6 +109,7 @@ ical_parse_contentline(IcalParser *p, char *line) Err bitreich.org 70 i *s = c; Err bitreich.org 70 i end = s; Err bitreich.org 70 i Err bitreich.org 70 i+ p->base64 = 0; Err bitreich.org 70 i while (*s == ';') { Err bitreich.org 70 i s++; Err bitreich.org 70 i if ((err = ical_parse_param(p, &s)) != 0) Err bitreich.org 70 1diff --git a/ical.h b/ical.h /scm/ics2txt/file/ical.h.gph bitreich.org 70 i@@ -15,7 +15,7 @@ struct IcalParser { Err bitreich.org 70 i int (*fn_block_end)(IcalParser *, char *); Err bitreich.org 70 i /* if returning non-zero then halt the parser */ Err bitreich.org 70 i Err bitreich.org 70 i- int base64encoded; Err bitreich.org 70 i+ int base64; Err bitreich.org 70 i char const *errmsg; Err bitreich.org 70 i size_t line; Err bitreich.org 70 i Err bitreich.org 70 i@@ -24,8 +24,9 @@ struct IcalParser { Err bitreich.org 70 i char stack[1024]; Err bitreich.org 70 i }; Err bitreich.org 70 i Err bitreich.org 70 i-int ical_parse(IcalParser *, FILE *); Err bitreich.org 70 i-//TODO: char *ical_get_time(char *); Err bitreich.org 70 i-//TODO: char *ical_get_value(IcalCtx *, char *); Err bitreich.org 70 i+int ical_parse(IcalParser *, FILE *); Err bitreich.org 70 i+int ical_get_time(IcalParser *, char *, time_t *); Err bitreich.org 70 i+int ical_get_value(IcalParser *, char *, size_t *); Err bitreich.org 70 i+int ical_error(IcalParser *, char const *); Err bitreich.org 70 i Err bitreich.org 70 i #endif Err bitreich.org 70 1diff --git a/ics2tree.c b/ics2tree.c /scm/ics2txt/file/ics2tree.c.gph bitreich.org 70 i@@ -39,8 +39,11 @@ fn_param_value(IcalParser *p, char *name, char *value) Err bitreich.org 70 i static int Err bitreich.org 70 i fn_entry_value(IcalParser *p, char *name, char *value) Err bitreich.org 70 i { Err bitreich.org 70 i+ size_t len; Err bitreich.org 70 i (void)name; Err bitreich.org 70 i Err bitreich.org 70 i+ if (ical_get_value(p, value, &len) < 0) Err bitreich.org 70 i+ return -1; Err bitreich.org 70 i print_ruler(p->level + 1); Err bitreich.org 70 i printf("value %s\n", value); Err bitreich.org 70 i return 0; Err bitreich.org 70 i@@ -59,7 +62,7 @@ main(int argc, char **argv) Err bitreich.org 70 i Err bitreich.org 70 i if (*argv == NULL) { Err bitreich.org 70 i if (ical_parse(&p, stdin) < 0) Err bitreich.org 70 i- err("parsing stdin:%d %s", p.line, p.errmsg); Err bitreich.org 70 i+ err("parsing stdin:%d: %s", p.line, p.errmsg); Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i for (; *argv != NULL; argv++, argc--) { Err bitreich.org 70 1diff --git a/ics2tsv.c b/ics2tsv.c /scm/ics2txt/file/ics2tsv.c.gph bitreich.org 70 i@@ -1,59 +0,0 @@ Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i-#include Err bitreich.org 70 i- Err bitreich.org 70 i-#include "ical.h" Err bitreich.org 70 i-#include "log.h" Err bitreich.org 70 i-#include "util.h" Err bitreich.org 70 i- Err bitreich.org 70 i-int Err bitreich.org 70 i-print_ical_tsv(FILE *fp) Err bitreich.org 70 i-{ Err bitreich.org 70 i- struct ical_vcalendar vcal; Err bitreich.org 70 i- int e; Err bitreich.org 70 i- Err bitreich.org 70 i- if ((e = ical_read_vcalendar(&vcal, fp)) < 0) Err bitreich.org 70 i- die("reading ical file: %s", ical_strerror(e)); Err bitreich.org 70 i- Err bitreich.org 70 i- ical_free_vcalendar(&vcal); Err bitreich.org 70 i- return 0; Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i-void Err bitreich.org 70 i-print_header(void) Err bitreich.org 70 i-{ Err bitreich.org 70 i- char *fields[] = { "", NULL }; Err bitreich.org 70 i- Err bitreich.org 70 i- printf("%s\t%s", "beg", "end"); Err bitreich.org 70 i- Err bitreich.org 70 i- for (char **f = fields; *f != NULL; f++) { Err bitreich.org 70 i- fprintf(stdout, "\t%s", *f); Err bitreich.org 70 i- } Err bitreich.org 70 i- fprintf(stdout, "\n"); Err bitreich.org 70 i-} Err bitreich.org 70 i- Err bitreich.org 70 i-int Err bitreich.org 70 i-main(int argc, char **argv) Err bitreich.org 70 i-{ Err bitreich.org 70 i- print_header(); Err bitreich.org 70 i- Err bitreich.org 70 i- log_arg0 = *argv++; Err bitreich.org 70 i- Err bitreich.org 70 i- if (*argv == NULL) { Err bitreich.org 70 i- if (print_ical_tsv(stdin) < 0) Err bitreich.org 70 i- die("converting stdin"); Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- for (; *argv != NULL; argv++, argc--) { Err bitreich.org 70 i- FILE *fp; Err bitreich.org 70 i- Err bitreich.org 70 i- info("converting \"%s\"", *argv); Err bitreich.org 70 i- if ((fp = fopen(*argv, "r")) == NULL) Err bitreich.org 70 i- die("opening %s", *argv); Err bitreich.org 70 i- if (print_ical_tsv(fp) < 0) Err bitreich.org 70 i- die("converting %s", *argv); Err bitreich.org 70 i- fclose(fp); Err bitreich.org 70 i- } Err bitreich.org 70 i- Err bitreich.org 70 i- return 0; Err bitreich.org 70 i-} Err bitreich.org 70 1diff --git a/util.c b/util.c /scm/ics2txt/file/util.c.gph bitreich.org 70 i@@ -49,7 +49,7 @@ debug(char const *fmt, ...) Err bitreich.org 70 i va_list va; Err bitreich.org 70 i Err bitreich.org 70 i if (verbose < 0) Err bitreich.org 70 i- verbose = (getenv("DEBUG") == NULL); Err bitreich.org 70 i+ verbose = (getenv("DEBUG") != NULL); Err bitreich.org 70 i if (!verbose) Err bitreich.org 70 i return; Err bitreich.org 70 i va_start(va, fmt); Err bitreich.org 70 .