// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. // See LICENSE.md for license information. // SPDX-License-Identifier: MIT // // toolBase64.c - base64 decoding for the JoeyLib host tools // (toolBase64.h). #include #include "toolBase64.h" #define BASE64_PAD '=' #define BASE64_NONE 64u #define QUAD 4u #define LOW2_MASK 0x03u #define LOW4_MASK 0x0Fu #define SHIFT2 2u #define SHIFT4 4u #define SHIFT6 6u // Where each run of the alphabet starts: A-Z, a-z, 0-9, then + and /. #define AT_UPPER 0u #define AT_LOWER 26u #define AT_DIGIT 52u #define AT_PLUS 62u #define AT_SLASH 63u static uint32_t sextet(char c); // A base64 character's six bits, or BASE64_NONE for any other character. static uint32_t sextet(char c) { if (c >= 'A' && c <= 'Z') { return (uint32_t)(c - 'A') + AT_UPPER; } if (c >= 'a' && c <= 'z') { return (uint32_t)(c - 'a') + AT_LOWER; } if (c >= '0' && c <= '9') { return (uint32_t)(c - '0') + AT_DIGIT; } if (c == '+') { return AT_PLUS; } if (c == '/') { return AT_SLASH; } return BASE64_NONE; } bool toolBase64Decode(const char *text, size_t len, uint8_t **out, size_t *outLen) { uint8_t *data; size_t n; size_t i; uint32_t quadPos; uint32_t pads; uint32_t left; uint32_t v; data = (uint8_t *)malloc(len / QUAD * 3u + 3u); if (data == NULL) { return false; } n = 0u; quadPos = 0u; pads = 0u; left = 0u; for (i = 0; i < len; i++) { if (text[i] == BASE64_PAD) { // Padding that fills a group of two or three characters out to // four ends it, and the data; any other is skipped. if (quadPos >= 2u) { pads++; if (quadPos + pads >= QUAD) { quadPos = 0u; break; } } continue; } v = sextet(text[i]); if (v == BASE64_NONE) { continue; } pads = 0u; switch (quadPos) { case 0: quadPos = 1u; left = v; break; case 1: quadPos = 2u; data[n++] = (uint8_t)((left << SHIFT2) | (v >> SHIFT4)); left = v & LOW4_MASK; break; case 2: quadPos = 3u; data[n++] = (uint8_t)((left << SHIFT4) | (v >> SHIFT2)); left = v & LOW2_MASK; break; default: quadPos = 0u; data[n++] = (uint8_t)((left << SHIFT6) | v); left = 0u; break; } } if (quadPos != 0u) { free(data); return false; } *out = data; *outLen = n; return true; }