From: Rusty Russell Date: Thu, 5 Apr 2018 02:31:51 +0000 (+0930) Subject: base32: add ability to substitute character set. X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=a8f32342d90676f9904b632706caab44313533dd base32: add ability to substitute character set. Signed-off-by: Rusty Russell --- diff --git a/ccan/str/base32/base32.c b/ccan/str/base32/base32.c index 5cdd461b..71ca87d5 100644 --- a/ccan/str/base32/base32.c +++ b/ccan/str/base32/base32.c @@ -4,6 +4,8 @@ #include #include /* for memcpy, memset */ +const char *base32_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="; + /* RFC 4648: * * (1) The final quantum of encoding input is an integral multiple of 40 @@ -56,7 +58,7 @@ size_t base32_data_size(const char *str, size_t strlen) size_t max = (strlen + 7) / 8 * 5, padding = 0; /* Count trailing padding bytes. */ - while (strlen && str[strlen-1] == '=' && padding < 6) { + while (strlen && str[strlen-1] == base32_chars[32] && padding < 6) { strlen--; padding++; } @@ -69,23 +71,21 @@ static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes) uint64_t acc = 0; size_t num_pad = 0; for (int i = 0; i < 8; i++) { - uint8_t val; + const char *p; + acc <<= 5; - if (c[i] >= 'a' && c[i] <= 'z') - val = c[i] - 'a'; - else if (c[i] >= 'A' && c[i] <= 'Z') - val = c[i] - 'A'; - else if (c[i] >= '2' && c[i] <= '7') - val = c[i] - '2' + 26; - else if (c[i] == '=') { - num_pad++; - continue; - } else + p = memchr(base32_chars, c[i], 32); + if (!p) { + if (c[i] == base32_chars[32]) { + num_pad++; + continue; + } return false; + } /* Can't have padding then non-pad */ if (num_pad) return false; - acc |= val; + acc |= (p - base32_chars); } *res = cpu_to_be64(acc); @@ -120,21 +120,20 @@ static void encode_8_chars(char *dest, const uint8_t *buf, int bytes) beint64_t val = 0; uint64_t res; int bits = bytes * 8; - static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; assert(bytes > 0 && bytes <= 5); memcpy((char *)&val + 3, buf, bytes); res = be64_to_cpu(val); while (bits > 0) { - *dest = enc[(res >> 35) & 0x1F]; + *dest = base32_chars[(res >> 35) & 0x1F]; dest++; res <<= 5; bits -= 5; } if (bytes != 5) - memset(dest, '=', padlen(bytes)); + memset(dest, base32_chars[32], padlen(bytes)); } bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize) diff --git a/ccan/str/base32/base32.h b/ccan/str/base32/base32.h index 6960fe82..177aad7e 100644 --- a/ccan/str/base32/base32.h +++ b/ccan/str/base32/base32.h @@ -65,4 +65,13 @@ size_t base32_str_size(size_t bytes); * base32_decode(str, strlen(str), buf, sizeof(buf)); */ size_t base32_data_size(const char *str, size_t strlen); + +/** + * base32_chars - the encoding/decoding array to use. + * + * It must be at least 33 characters long, representing 32 values and + * the pad value. The default array is "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=". + */ +extern const char *base32_chars; + #endif /* CCAN_STR_BASE32_H */ diff --git a/ccan/str/base32/test/run-lower.c b/ccan/str/base32/test/run-lower.c new file mode 100644 index 00000000..5f64d64e --- /dev/null +++ b/ccan/str/base32/test/run-lower.c @@ -0,0 +1,38 @@ +#include +/* Include the C files directly. */ +#include +#include + +static void test(const char *data, const char *b32) +{ + char test[1000]; + + ok1(base32_str_size(strlen(data)) == strlen(b32) + 1); + ok1(base32_data_size(b32, strlen(b32)) == strlen(data)); + ok1(base32_encode(data, strlen(data), test, strlen(b32)+1)); + ok1(strcmp(test, b32) == 0); + test[strlen(data)] = '\0'; + ok1(base32_decode(b32, strlen(b32), test, strlen(data))); + ok1(strcmp(test, data) == 0); +} + +int main(void) +{ + /* This is how many tests you plan to run */ + plan_tests(8 * 6); + + base32_chars = "abcdefghijklmnopqrstuvwxyz234567="; + + /* Test vectors from RFC, but lower-case */ + test("", ""); + test("f", "my======"); + test("fo", "mzxq===="); + test("foo", "mzxw6==="); + test("foob", "mzxw6yq="); + test("fooba", "mzxw6ytb"); + test("r", "oi======"); + test("foobar", "mzxw6ytboi======"); + + /* This exits depending on whether all tests passed */ + return exit_status(); +}