/* * Carla base64 utils imported from qemu source code * Copyright (C) 2009 Michael Brown * Copyright (C) 2013 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the GPL.txt file */ #ifndef __CARLA_BASE64_UTILS_HPP__ #define __CARLA_BASE64_UTILS_HPP__ #include "CarlaUtils.hpp" #include #include static const char kBase64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * Calculate length of base64-encoded data * * @v rawLen Raw data length * @ret encodedLen Encoded string length (excluding NUL) */ static inline size_t carla_base64_encoded_len(const size_t rawLen) { return (((rawLen + 3 - 1) / 3) * 4); } /** * Calculate maximum length of base64-decoded string * * @v encoded Encoded string * @v maxRawLen Maximum length of raw data * * Note that the exact length of the raw data cannot be known until * the string is decoded. */ static inline size_t carla_base64_decoded_max_len(const char* const encoded) { return (((std::strlen(encoded) + 4 - 1) / 4) * 3); } /** * Base64-encode data * * @v raw Raw data * @v len Length of raw data * @v encoded Buffer for encoded string * * The buffer must be the correct length for the encoded string. * Use something like * * char buf[carla_base64_encoded_len(len) + 1]; * * (the +1 is for the terminating NUL) to provide a buffer of the correct size. */ static inline void carla_base64_encode(const uint8_t* const raw, const size_t len, char* const encoded) { const uint8_t* rawBytes = raw; uint8_t* encodedBytes = (uint8_t*)encoded; size_t rawBitLen = 8*len; size_t bit, tmp; for (bit = 0; bit < rawBitLen; bit += 6) { tmp = static_cast((rawBytes[bit/8] << (bit % 8)) | (rawBytes[bit/8 + 1] >> (8 - (bit % 8)))); tmp = static_cast((tmp >> 2) & 0x3f); CARLA_ASSERT(tmp < 64); *(encodedBytes++) = static_cast(kBase64[tmp]); } for (; (bit % 8) != 0; bit += 6) *(encodedBytes++) = '='; *(encodedBytes++) = '\0'; carla_debug("Base64-encoded to \"%s\"\n", encoded); CARLA_ASSERT(std::strlen(encoded) == carla_base64_encoded_len(len)); } /** * Base64-decode string * * @v encoded Encoded string * @v raw Raw data * @ret len Length of raw data, or 0 * * The buffer must be large enough to contain the decoded data. * Use something like * * char buf[carla_base64_decoded_max_len(encoded)]; * * to provide a buffer of the correct size. */ static inline unsigned int carla_base64_decode(const char* const encoded, uint8_t* const raw) { const uint8_t* encodedBytes = (const uint8_t*)encoded; uint8_t* rawBytes = raw; uint8_t encodedByte; unsigned int bit = 0; unsigned int padCount = 0; /* Zero the raw data */ carla_zeroMem(raw, carla_base64_decoded_max_len(encoded)); /* Decode string */ while ((encodedByte = *(encodedBytes++)) > 0) { /* Ignore whitespace characters */ if (std::isspace(encodedByte)) continue; /* Process pad characters */ if (encodedByte == '=') { if (padCount >= 2) { carla_debug("Base64-encoded string \"%s\" has too many pad characters", encoded); return 0; } padCount++; bit -= 2; /* unused_bits = ( 2 * padCount ) */ continue; } if (padCount > 0) { carla_debug("Base64-encoded string \"%s\" has invalid pad sequence", encoded); return 0; } /* Process normal characters */ const char* const match = std::strchr(kBase64, encodedByte); if (match == nullptr) { carla_debug("Base64-encoded string \"%s\" contains invalid character '%c'", encoded, encodedByte); return 0; } uint8_t decoded = static_cast(match - kBase64); /* Add to raw data */ decoded <<= 2; rawBytes[bit / 8] |= (decoded >> (bit % 8)); rawBytes[bit / 8 + 1] |= (decoded << (8 - (bit % 8))); bit += 6; } /* Check that we decoded a whole number of bytes */ if ((bit % 8) != 0) { carla_debug("Base64-encoded string \"%s\" has invalid bit length %d", encoded, bit); return 0; } unsigned int len = bit/8; carla_debug("Base64-decoded from \"%s\"", encoded); CARLA_ASSERT(len <= carla_base64_decoded_max_len(encoded)); /* Return length in bytes */ return len; } #endif // __CARLA_BASE64_UTILS_HPP__