diff --git a/velox/common/encode/Base64.cpp b/velox/common/encode/Base64.cpp index 4135935189baf..3bfb933e85a2c 100644 --- a/velox/common/encode/Base64.cpp +++ b/velox/common/encode/Base64.cpp @@ -22,6 +22,55 @@ namespace facebook::velox::encoding { +namespace { + +class IOBufWrapper { + private: + class Iterator { + public: + /// Constructs an iterator from the provided IOBuf data. + /// @param data The IOBuf data to iterate over. + explicit Iterator(const folly::IOBuf* data) : cs_(data) {} + + /// Advances the iterator to the next position. + /// @return A reference to the updated iterator. + Iterator& operator++(int32_t) { + return *this; + } + + /// Dereferences the iterator to access the current value. + /// @return The current value. + uint8_t operator*() { + return cs_.read(); + } + + private: + folly::io::Cursor cs_; + }; + + public: + /// Constructs an IOBufWrapper from the provided IOBuf data. + /// @param data The IOBuf data to wrap. + explicit IOBufWrapper(const folly::IOBuf* data) : data_(data) {} + + /// Returns the size of the IOBuf chain data. + /// @return The size of the IOBuf chain data. + size_t size() const { + return data_->computeChainDataLength(); + } + + /// Returns an iterator to the beginning of the IOBuf data. + /// @return An iterator to the beginning of the IOBuf data. + Iterator begin() const { + return Iterator(data_); + } + + private: + const folly::IOBuf* data_; +}; + +} // namespace + // Constants defining the size in bytes of binary and encoded blocks for Base64 // encoding. // Size of a binary block in bytes (3 bytes = 24 bits) @@ -29,20 +78,25 @@ constexpr static int kBinaryBlockByteSize = 3; // Size of an encoded block in bytes (4 bytes = 24 bits) constexpr static int kEncodedBlockByteSize = 4; -constexpr const Base64::Charset kBase64Charset = { +constexpr static int kBase = 64; // Encoding base + +// Character sets for Base64 and Base64 URL encoding +constexpr const Charset kBase64Charset = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; -constexpr const Base64::Charset kBase64UrlCharset = { + +constexpr const Charset kBase64UrlCharset = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}; -constexpr const Base64::ReverseIndex kBase64ReverseIndexTable = { +// Reverse lookup tables for decoding +constexpr const ReverseIndex kBase64ReverseIndexTable = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, @@ -61,7 +115,8 @@ constexpr const Base64::ReverseIndex kBase64ReverseIndexTable = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; -constexpr const Base64::ReverseIndex kBase64UrlReverseIndexTable = { + +constexpr const ReverseIndex kBase64UrlReverseIndexTable = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, @@ -81,13 +136,19 @@ constexpr const Base64::ReverseIndex kBase64UrlReverseIndexTable = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; +// Validate the character in charset with ReverseIndex table constexpr bool checkForwardIndex( uint8_t idx, - const Base64::Charset& charset, - const Base64::ReverseIndex& table) { - return (table[static_cast(charset[idx])] == idx) && - (idx > 0 ? checkForwardIndex(idx - 1, charset, table) : true); + const Charset& charset, + const ReverseIndex& reverseIndex) { + for (uint8_t i = 0; i <= idx; ++i) { + if (!(reverseIndex[static_cast(charset[i])] == i)) { + return false; + } + } + return true; } + // Verify that for every entry in kBase64Charset, the corresponding entry // in kBase64ReverseIndexTable is correct. static_assert( @@ -96,6 +157,7 @@ static_assert( kBase64Charset, kBase64ReverseIndexTable), "kBase64Charset has incorrect entries"); + // Verify that for every entry in kBase64UrlCharset, the corresponding entry // in kBase64UrlReverseIndexTable is correct. static_assert( @@ -104,53 +166,97 @@ static_assert( kBase64UrlCharset, kBase64UrlReverseIndexTable), "kBase64UrlCharset has incorrect entries"); -// Similar to strchr(), but for null-terminated const strings. -// Another difference is that we do not consider "\0" to be present in the -// string. -// Returns true if "str" contains the character c. -constexpr bool constCharsetContains( - const Base64::Charset& charset, + +/// Searches for a character within a charset up to a certain index. +/// @param charset The character set to search within. +/// @param base The upper limit index for searching. +/// @param idx The starting index for the search. +/// @param c The character to find within the charset. +/// @return True if the character is found within the charset up to the +/// specified index, otherwise false. +const bool findCharacterInCharSet( + const Charset& charset, + int base, uint8_t idx, const char c) { - return idx < charset.size() && - ((charset[idx] == c) || constCharsetContains(charset, idx + 1, c)); + for (; idx < base; ++idx) { + if (charset[idx] == c) { + return true; + } + } + return false; } + +/// Checks the consistency of a reverse index mapping for a given character set. +/// @param idx Starting index for the reverse index check. +/// @param charset The character set being checked. +/// @param base The base index used for character lookups in the character set. +/// @param reverseIndex The reverse index mapping to validate. +/// @return `true` if all character mappings are consistent, `false` otherwise. constexpr bool checkReverseIndex( uint8_t idx, - const Base64::Charset& charset, - const Base64::ReverseIndex& table) { - return (table[idx] == 255 - ? !constCharsetContains(charset, 0, static_cast(idx)) - : (charset[table[idx]] == idx)) && - (idx > 0 ? checkReverseIndex(idx - 1, charset, table) : true); + const Charset& charset, + int base, + const ReverseIndex& reverseIndex) { + for (uint8_t currentIdx = idx; currentIdx != static_cast(-1); + --currentIdx) { + if (reverseIndex[currentIdx] == 255) { + if (findCharacterInCharSet( + charset, base, 0, static_cast(currentIdx))) { + return false; + } + } else { + if (!(charset[reverseIndex[currentIdx]] == currentIdx)) { + return false; + } + } + } + return true; } + // Verify that for every entry in kBase64ReverseIndexTable, the corresponding // entry in kBase64Charset is correct. static_assert( checkReverseIndex( sizeof(kBase64ReverseIndexTable) - 1, kBase64Charset, + kBase, kBase64ReverseIndexTable), "kBase64ReverseIndexTable has incorrect entries."); + // Verify that for every entry in kBase64ReverseIndexTable, the corresponding // entry in kBase64Charset is correct. -// We can't run this check as the URL version has two duplicate entries so that -// the url decoder can handle url encodings and default encodings -// static_assert( -// checkReverseIndex( -// sizeof(kBase64UrlReverseIndexTable) - 1, -// kBase64UrlCharset, -// kBase64UrlReverseIndexTable), -// "kBase64UrlReverseIndexTable has incorrect entries."); +static_assert( + checkReverseIndex( + sizeof(kBase64UrlReverseIndexTable) - 1, + kBase64UrlCharset, + kBase, + kBase64UrlReverseIndexTable), + "kBase64UrlReverseIndexTable has incorrect entries."); + +/// Performs a reverse lookup in the reverse index to retrieve the original +/// index of a character in the base. +/// @param base The base of the encoding. +/// @param p The character for which the reverse lookup is performed. +/// @param reverseIndex The reverse index mapping characters to their original +/// indices. +/// @return The original index of the character within the base. +inline uint8_t +baseReverseLookup(int base, char p, const ReverseIndex& reverseIndex) { + auto curr = reverseIndex[(uint8_t)p]; + if (curr >= base) { + VELOX_USER_FAIL("decode() - invalid input string: invalid characters"); + } + return curr; +} +// Implementation of Base64 encoding and decoding functions. template -/* static */ std::string +/* static */ std::string Base64::encodeImpl(const T& data, const Charset& charset, bool include_pad) { size_t outlen = calculateEncodedSize(data.size(), include_pad); - std::string out; out.resize(outlen); - encodeImpl(data, charset, include_pad, out.data()); return out; } @@ -160,26 +266,13 @@ size_t Base64::calculateEncodedSize(size_t size, bool withPadding) { if (size == 0) { return 0; } - - // Calculate the output size assuming that we are including padding. size_t encodedSize = ((size + 2) / 3) * 4; if (!withPadding) { - // If the padding was not requested, subtract the padding bytes. encodedSize -= (3 - (size % 3)) % 3; } return encodedSize; } -// static -void Base64::encode(const char* data, size_t len, char* output) { - encodeImpl(folly::StringPiece(data, len), kBase64Charset, true, output); -} - -// static -void Base64::encodeUrl(const char* data, size_t len, char* output) { - encodeImpl(folly::StringPiece(data, len), kBase64UrlCharset, true, output); -} - template /* static */ void Base64::encodeImpl( const T& data, @@ -194,8 +287,6 @@ template auto wp = out; auto it = data.begin(); - // For each group of 3 bytes (24 bits) in the input, split that into - // 4 groups of 6 bits and encode that using the supplied charset lookup for (; len > 2; len -= 3) { uint32_t curr = uint8_t(*it++) << 16; curr |= uint8_t(*it++) << 8; @@ -208,9 +299,6 @@ template } if (len > 0) { - // We have either 1 or 2 input bytes left. Encode this similar to the - // above (assuming 0 for all other bytes). Optionally append the '=' - // character if it is requested. uint32_t curr = uint8_t(*it++) << 16; *wp++ = charset[(curr >> 18) & 0x3f]; if (len > 1) { @@ -218,90 +306,46 @@ template *wp++ = charset[(curr >> 12) & 0x3f]; *wp++ = charset[(curr >> 6) & 0x3f]; if (include_pad) { - *wp = kBase64Pad; + *wp = kPadding; } } else { *wp++ = charset[(curr >> 12) & 0x3f]; if (include_pad) { - *wp++ = kBase64Pad; - *wp = kBase64Pad; + *wp++ = kPadding; + *wp = kPadding; } } } } +// static +void Base64::encode(const char* data, size_t len, char* output) { + encodeImpl(folly::StringPiece(data, len), kBase64Charset, true, output); +} + +// static std::string Base64::encode(folly::StringPiece text) { return encodeImpl(text, kBase64Charset, true); } +// static std::string Base64::encode(const char* data, size_t len) { return encode(folly::StringPiece(data, len)); } -namespace { - -/** - * this is a quick and dirty iterator implementation for an IOBuf so that the - * template that uses iterators can work on IOBuf chains. It only implements - * postfix increment because that is all the algorithm needs, and it is a noop - * since the read<>() function already incremented the cursor. - */ -class IOBufWrapper { - private: - class Iterator { - public: - explicit Iterator(const folly::IOBuf* data) : cs_(data) {} - - Iterator& operator++(int32_t) { - // This is a noop since reading from the Cursor has already moved the - // position - return *this; - } - - uint8_t operator*() { - // This will read _and_ increment - return cs_.read(); - } - - private: - folly::io::Cursor cs_; - }; - - public: - explicit IOBufWrapper(const folly::IOBuf* data) : data_(data) {} - - size_t size() const { - return data_->computeChainDataLength(); - } - - Iterator begin() const { - return Iterator(data_); - } - - private: - const folly::IOBuf* data_; -}; - -} // namespace - +// static std::string Base64::encode(const folly::IOBuf* data) { return encodeImpl(IOBufWrapper(data), kBase64Charset, true); } -void Base64::encodeAppend(folly::StringPiece text, std::string& out) { - size_t outlen = calculateEncodedSize(text.size(), true); - - size_t initialLen = out.size(); - out.resize(initialLen + outlen); - encodeImpl(text, kBase64Charset, true, out.data() + initialLen); -} - +// static std::string Base64::decode(folly::StringPiece encoded) { std::string output; Base64::decode(std::make_pair(encoded.data(), encoded.size()), output); return output; } +// static void Base64::decode( const std::pair& payload, std::string& output) { @@ -316,18 +360,7 @@ void Base64::decode(const char* data, size_t size, char* output) { Base64::decode(data, size, output, out_len); } -uint8_t Base64::Base64ReverseLookup( - char p, - const Base64::ReverseIndex& reverse_lookup) { - auto curr = reverse_lookup[(uint8_t)p]; - if (curr >= 0x40) { - throw Base64Exception( - "Base64::decode() - invalid input string: invalid characters"); - } - - return curr; -} - +// static size_t Base64::decode(const char* src, size_t src_len, char* dst, size_t dst_len) { return decodeImpl(src, src_len, dst, dst_len, kBase64ReverseIndexTable); @@ -339,34 +372,28 @@ size_t Base64::calculateDecodedSize(const char* data, size_t& size) { return 0; } - // Check if the input data is padded if (isPadded(data, size)) { - // If padded, ensure that the string length is a multiple of the encoded - // block size if (size % kEncodedBlockByteSize != 0) { - throw Base64Exception( + VELOX_USER_FAIL( "Base64::decode() - invalid input string: " "string length is not a multiple of 4."); } auto needed = (size * kBinaryBlockByteSize) / kEncodedBlockByteSize; - auto padding = countPadding(data, size); + auto padding = numPadding(data, size); size -= padding; - // Adjust the needed size by deducting the bytes corresponding to the - // padding from the calculated size. return needed - ((padding * kBinaryBlockByteSize) + (kEncodedBlockByteSize - 1)) / kEncodedBlockByteSize; } - // If not padded, Calculate extra bytes, if any + auto extra = size % kEncodedBlockByteSize; auto needed = (size / kEncodedBlockByteSize) * kBinaryBlockByteSize; - // Adjust the needed size for extra bytes, if present if (extra) { if (extra == 1) { - throw Base64Exception( + VELOX_USER_FAIL( "Base64::decode() - invalid input string: " "string length cannot be 1 more than a multiple of 4."); } @@ -376,6 +403,7 @@ size_t Base64::calculateDecodedSize(const char* data, size_t& size) { return needed; } +// static size_t Base64::decodeImpl( const char* src, size_t src_len, @@ -388,36 +416,30 @@ size_t Base64::decodeImpl( auto needed = calculateDecodedSize(src, src_len); if (dst_len < needed) { - throw Base64Exception( + VELOX_USER_FAIL( "Base64::decode() - invalid output string: " "output string is too small."); } - // Handle full groups of 4 characters for (; src_len > 4; src_len -= 4, src += 4, dst += 3) { - // Each character of the 4 encode 6 bits of the original, grab each with - // the appropriate shifts to rebuild the original and then split that back - // into the original 8 bit bytes. - uint32_t last = (Base64ReverseLookup(src[0], reverse_lookup) << 18) | - (Base64ReverseLookup(src[1], reverse_lookup) << 12) | - (Base64ReverseLookup(src[2], reverse_lookup) << 6) | - Base64ReverseLookup(src[3], reverse_lookup); + uint32_t last = (baseReverseLookup(kBase, src[0], reverse_lookup) << 18) | + (baseReverseLookup(kBase, src[1], reverse_lookup) << 12) | + (baseReverseLookup(kBase, src[2], reverse_lookup) << 6) | + baseReverseLookup(kBase, src[3], reverse_lookup); dst[0] = (last >> 16) & 0xff; dst[1] = (last >> 8) & 0xff; dst[2] = last & 0xff; } - // Handle the last 2-4 characters. This is similar to the above, but the - // last 2 characters may or may not exist. DCHECK(src_len >= 2); - uint32_t last = (Base64ReverseLookup(src[0], reverse_lookup) << 18) | - (Base64ReverseLookup(src[1], reverse_lookup) << 12); + uint32_t last = (baseReverseLookup(kBase, src[0], reverse_lookup) << 18) | + (baseReverseLookup(kBase, src[1], reverse_lookup) << 12); dst[0] = (last >> 16) & 0xff; if (src_len > 2) { - last |= Base64ReverseLookup(src[2], reverse_lookup) << 6; + last |= baseReverseLookup(kBase, src[2], reverse_lookup) << 6; dst[1] = (last >> 8) & 0xff; if (src_len > 3) { - last |= Base64ReverseLookup(src[3], reverse_lookup); + last |= baseReverseLookup(kBase, src[3], reverse_lookup); dst[2] = last & 0xff; } } @@ -425,18 +447,27 @@ size_t Base64::decodeImpl( return needed; } +// static std::string Base64::encodeUrl(folly::StringPiece text) { return encodeImpl(text, kBase64UrlCharset, false); } +// static std::string Base64::encodeUrl(const char* data, size_t len) { return encodeUrl(folly::StringPiece(data, len)); } +// static std::string Base64::encodeUrl(const folly::IOBuf* data) { return encodeImpl(IOBufWrapper(data), kBase64UrlCharset, false); } +// static +void Base64::encodeUrl(const char* data, size_t len, char* output) { + encodeImpl(folly::StringPiece(data, len), kBase64UrlCharset, true, output); +} + +// static void Base64::decodeUrl( const char* src, size_t src_len, @@ -445,12 +476,14 @@ void Base64::decodeUrl( decodeImpl(src, src_len, dst, dst_len, kBase64UrlReverseIndexTable); } +// static std::string Base64::decodeUrl(folly::StringPiece encoded) { std::string output; Base64::decodeUrl(std::make_pair(encoded.data(), encoded.size()), output); return output; } +// static void Base64::decodeUrl( const std::pair& payload, std::string& output) { @@ -464,4 +497,5 @@ void Base64::decodeUrl( kBase64UrlReverseIndexTable); output.resize(out_len); } + } // namespace facebook::velox::encoding diff --git a/velox/common/encode/Base64.h b/velox/common/encode/Base64.h index 2c7de463ea6fa..6c7506438f1e0 100644 --- a/velox/common/encode/Base64.h +++ b/velox/common/encode/Base64.h @@ -22,98 +22,176 @@ #include #include -namespace facebook::velox::encoding { +#include "velox/common/base/Exceptions.h" -class Base64Exception : public std::exception { - public: - explicit Base64Exception(const char* msg) : msg_(msg) {} - const char* what() const noexcept override { - return msg_; - } +namespace facebook::velox::encoding { +const size_t kCharsetSize = 64; +const size_t kReverseIndexSize = 256; - protected: - const char* msg_; -}; +/// Character set used for encoding purposes. +/// Contains specific characters that form the encoding scheme. +using Charset = std::array; +/// Reverse lookup table for decoding purposes. +/// Maps each possible encoded character to its corresponding numeric value +/// within the encoding base. +using ReverseIndex = std::array; class Base64 { public: - using Charset = std::array; - using ReverseIndex = std::array; - - static std::string encode(const char* data, size_t len); - static std::string encode(folly::StringPiece text); - static std::string encode(const folly::IOBuf* text); + /// Padding character used in encoding. + const static char kPadding = '='; /// Returns encoded size for the input of the specified size. + /// @param size The size of the input data. + /// @param withPadding Whether padding is included. + /// @return The encoded size. static size_t calculateEncodedSize(size_t size, bool withPadding = true); /// Encodes the specified number of characters from the 'data' and writes the /// result to the 'output'. The output must have enough space, e.g. as /// returned by the calculateEncodedSize(). + /// @param data The input data to encode. + /// @param size The size of the input data. + /// @param output The output buffer to store the encoded data. static void encode(const char* data, size_t size, char* output); - // Appends the encoded text to out. - static void encodeAppend(folly::StringPiece text, std::string& out); + /// Encodes the specified number of characters from the 'data'. + /// @param data The input data to encode. + /// @param len The length of the input data. + /// @return The encoded string. + static std::string encode(const char* data, size_t len); - static std::string decode(folly::StringPiece encoded); + /// Encodes the specified text. + /// @param text The input text to encode. + /// @return The encoded string. + static std::string encode(folly::StringPiece text); + + /// Encodes the specified IOBuf data. + /// @param text The input IOBuf data to encode. + /// @return The encoded string. + static std::string encode(const folly::IOBuf* text); /// Returns the actual size of the decoded data. Will also remove the padding /// length from the input data 'size'. + /// @param data The input encoded data. + /// @param size The size of the input data, updated to remove padding. + /// @return The decoded size. static size_t calculateDecodedSize(const char* data, size_t& size); /// Decodes the specified number of characters from the 'data' and writes the /// result to the 'output'. The output must have enough space, e.g. as /// returned by the calculateDecodedSize(). + /// @param data The input encoded data. + /// @param size The size of the input data. + /// @param output The output buffer to store the decoded data. static void decode(const char* data, size_t size, char* output); + /// Decodes the specified payload and writes the result to the 'output'. + /// @param payload The input encoded payload. + /// @param output The output string to store the decoded data. static void decode( const std::pair& payload, std::string& output); + /// Decodes the specified encoded text. + /// @param encoded The input encoded text. + /// @return The decoded string. + static std::string decode(folly::StringPiece encoded); + + /// Decodes the specified number of characters from the 'src' and writes the + /// result to the 'dst'. + /// @param src The input encoded data. + /// @param src_len The length of the input data. + /// @param dst The output buffer to store the decoded data. + /// @param dst_len The length of the output buffer. + /// @return The number of decoded bytes. + static size_t + decode(const char* src, size_t src_len, char* dst, size_t dst_len); + /// Encodes the specified number of characters from the 'data' and writes the - /// result to the 'output'. The output must have enough space, e.g. as - /// returned by the calculateEncodedSize(). + /// result to the 'output' using URL encoding. The output must have enough + /// space, e.g. as returned by the calculateEncodedSize(). + /// @param data The input data to encode. + /// @param size The size of the input data. + /// @param output The output buffer to store the encoded data. static void encodeUrl(const char* data, size_t size, char* output); - // compatible with www's Base64URL::encode/decode - // TODO rename encode_url/decode_url to encodeUrl/encodeUrl. + /// Encodes the specified number of characters from the 'data' using URL + /// encoding. + /// @param data The input data to encode. + /// @param len The length of the input data. + /// @return The encoded string. static std::string encodeUrl(const char* data, size_t len); + + /// Encodes the specified IOBuf data using URL encoding. + /// @param data The input IOBuf data to encode. + /// @return The encoded string. static std::string encodeUrl(const folly::IOBuf* data); + + /// Encodes the specified text using URL encoding. + /// @param text The input text to encode. + /// @return The encoded string. static std::string encodeUrl(folly::StringPiece text); + + /// Decodes the specified URL encoded payload and writes the result to the + /// 'output'. + /// @param payload The input encoded payload. + /// @param output The output string to store the decoded data. static void decodeUrl( const std::pair& payload, std::string& output); - static std::string decodeUrl(folly::StringPiece text); - static size_t - decode(const char* src, size_t src_len, char* dst, size_t dst_len); + /// Decodes the specified URL encoded text. + /// @param text The input encoded text. + /// @return The decoded string. + static std::string decodeUrl(folly::StringPiece text); + /// Decodes the specified number of characters from the 'src' using URL + /// encoding and writes the result to the 'dst'. + /// @param src The input encoded data. + /// @param src_len The length of the input data. + /// @param dst The output buffer to store the decoded data. + /// @param dst_len The length of the output buffer. static void decodeUrl(const char* src, size_t src_len, char* dst, size_t dst_len); - constexpr static char kBase64Pad = '='; - private: + /// Checks if there is padding in encoded data. + /// @param data The data to check for padding. + /// @param len The length of the data. + /// @return True if there is padding, otherwise false. static inline bool isPadded(const char* data, size_t len) { - return (len > 0 && data[len - 1] == kBase64Pad); + return (len > 0 && data[len - 1] == kPadding) ? true : false; } - static inline size_t countPadding(const char* src, size_t len) { + /// Counts the number of padding characters in encoded data. + /// @param src The source data to check for padding. + /// @param len The length of the source data. + /// @return The number of padding characters. + static inline size_t numPadding(const char* src, size_t len) { size_t numPadding{0}; - while (len > 0 && src[len - 1] == kBase64Pad) { + while (len > 0 && src[len - 1] == kPadding) { numPadding++; len--; } - return numPadding; } - - static uint8_t Base64ReverseLookup(char p, const ReverseIndex& table); - + /// Encodes the specified data using the provided charset. + /// @tparam T The type of the input data. + /// @param data The input data to encode. + /// @param charset The charset used for encoding. + /// @param include_pad Whether to include padding. + /// @return The encoded string. template static std::string encodeImpl(const T& data, const Charset& charset, bool include_pad); + /// Encodes the specified data using the provided charset. + /// @tparam T The type of the input data. + /// @param data The input data to encode. + /// @param charset The charset used for encoding. + /// @param include_pad Whether to include padding. + /// @param out The output buffer to store the encoded data. template static void encodeImpl( const T& data, @@ -121,6 +199,13 @@ class Base64 { bool include_pad, char* out); + /// Decodes the specified data using the provided reverse lookup table. + /// @param src The input encoded data. + /// @param src_len The length of the input data. + /// @param dst The output buffer to store the decoded data. + /// @param dst_len The length of the output buffer. + /// @param table The reverse lookup table used for decoding. + /// @return The number of decoded bytes. static size_t decodeImpl( const char* src, size_t src_len, diff --git a/velox/common/encode/tests/Base64Test.cpp b/velox/common/encode/tests/Base64Test.cpp index 15556583c7519..e1bce6aa50a54 100644 --- a/velox/common/encode/tests/Base64Test.cpp +++ b/velox/common/encode/tests/Base64Test.cpp @@ -61,7 +61,7 @@ TEST_F(Base64Test, calculateDecodedSizeProperSize) { encoded_size = 21; EXPECT_THROW( Base64::calculateDecodedSize("SGVsbG8sIFdvcmxkIQ==", encoded_size), - facebook::velox::encoding::Base64Exception); + std::exception); encoded_size = 32; EXPECT_EQ(