From d06ae2f5c345741192a0e3f9086765382690e37b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 1 May 2022 11:19:10 +0100 Subject: [PATCH] New utility function base64_valid(). For when you want to tell the difference between a base64-encoded string and some other kind of string that might replace it. --- misc.h | 1 + utils/CMakeLists.txt | 1 + utils/base64_valid.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 utils/base64_valid.c diff --git a/misc.h b/misc.h index eeed80c1..fe8eb06a 100644 --- a/misc.h +++ b/misc.h @@ -114,6 +114,7 @@ strbuf *base64_decode_sb(ptrlen data); void base64_encode_bs(BinarySink *bs, ptrlen data, int cpl); void base64_encode_fp(FILE *fp, ptrlen data, int cpl); strbuf *base64_encode_sb(ptrlen data, int cpl); +bool base64_valid(ptrlen data); struct bufchain_granule; struct bufchain_tag { diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 949166f5..9d079ecb 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -5,6 +5,7 @@ add_sources_from_current_dir(utils base64_decode.c base64_encode_atom.c base64_encode.c + base64_valid.c bufchain.c buildinfo.c burnstr.c diff --git a/utils/base64_valid.c b/utils/base64_valid.c new file mode 100644 index 00000000..8eb1f3a0 --- /dev/null +++ b/utils/base64_valid.c @@ -0,0 +1,54 @@ +/* + * Determine whether a string looks like valid base64-encoded data. + */ + +#include "misc.h" + +static inline bool valid_char_main(char c) +{ + return ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '+' || c == '/'); +} + +bool base64_valid(ptrlen data) +{ + size_t blocklen = 0, nequals = 0; + + for (size_t i = 0; i < data.len; i++) { + char c = ((const char *)data.ptr)[i]; + + if (c == '\n' || c == '\r') + continue; + + if (valid_char_main(c)) { + if (nequals) /* can't go back to data after = */ + return false; + blocklen++; + if (blocklen == 4) + blocklen = 0; + continue; + } + + if (c == '=') { + if (blocklen == 0 && nequals) /* started a fresh block */ + return false; + + nequals++; + blocklen++; + if (blocklen == 4) { + if (nequals > 2) + return false; /* nonsensical final block */ + blocklen = 0; + } + continue; + } + + return false; /* bad character */ + } + + if (blocklen == 0 || blocklen == 2 || blocklen == 3) + return true; /* permit eliding the trailing = */ + return false; +}