/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace folly { // // base64 encoding/decoding // // There are a few variations of base64 encoding. // // We have 2: base64 and base64URL. // // base64 uses '+' '/' for encoding 62 and 63 and uses '=' padding symbol. // (padding symbols are required on decoding) // // base64URL uses '-' '_' for encoding 62 and 63 and has no padding. // Decoding with base64URL will accept both base64 and base64URL encoded data + // padding is always optional. // // SIMD implementation is based on 0x80 blog. // See details explained in folly/detail/base64_detail/README.md // // // High level API. // Encoding never fails, except for allocation. // Decoding will throw base64_decode_error if it fails. // // NOTE: the expection does not contain detailed information // about the error because keeping track of that is overhead. // We can potentially improve error reporting by doing a second // pass if we decide that it's benefitial. struct base64_decode_error; inline auto base64Encode(std::string_view s) -> std::string; inline auto base64Decode(std::string_view s) -> std::string; inline auto base64URLEncode(std::string_view s) -> std::string; inline auto base64URLDecode(std::string_view s) -> std::string; // Low level API. // // This API does not throw and is constexpr enabled. // // Encode returns a pointer past the last the byte written // Decode returns a struct with `is_success` flag and the pointer `o` // past the last char written. // // NOTE: decode will not stop writing when encountering a failure // and can always write up to size. // // NOTE: since on C++17 we cannot always adequately determine if // the function is running in compile time or not, // we provide explicit runime versions too. constexpr std::size_t base64EncodedSize(std::size_t inSize) noexcept; constexpr std::size_t base64URLEncodedSize(std::size_t inSize) noexcept; inline constexpr char* base64Encode( const char* f, const char* l, char* o) noexcept; inline constexpr char* base64URLEncode( const char* f, const char* l, char* o) noexcept; inline char* base64EncodeRuntime( const char* f, const char* l, char* o) noexcept; inline char* base64URLEncodeRuntime( const char* f, const char* l, char* o) noexcept; constexpr std::size_t base64DecodedSize(const char* f, const char* l) noexcept; constexpr std::size_t base64DecodedSize(std::string_view s) noexcept; constexpr std::size_t base64URLDecodedSize( const char* f, const char* l) noexcept; constexpr std::size_t base64URLDecodedSize(std::string_view s) noexcept; struct base64_decode_result { bool is_success; char* o; }; inline constexpr base64_decode_result base64Decode( const char* f, const char* l, char* o) noexcept; inline constexpr base64_decode_result base64Decode( std::string_view s, char* o) noexcept; inline constexpr base64_decode_result base64URLDecode( const char* f, const char* l, char* o) noexcept; inline constexpr base64_decode_result base64URLDecode( std::string_view s, char* o) noexcept; inline base64_decode_result base64DecodeRuntime( const char* f, const char* l, char* o) noexcept; inline base64_decode_result base64DecodeRuntime( std::string_view s, char* o) noexcept; inline base64_decode_result base64URLDecodeRuntime( const char* f, const char* l, char* o) noexcept; inline base64_decode_result base64URLDecodeRuntime( std::string_view s, char* o) noexcept; // ----------------------------------------------------------------- // implementation struct base64_decode_error : std::runtime_error { using std::runtime_error::runtime_error; }; constexpr std::size_t base64EncodedSize(std::size_t inSize) noexcept { return detail::base64_detail::base64EncodedSize(inSize); } constexpr std::size_t base64URLEncodedSize(std::size_t inSize) noexcept { return detail::base64_detail::base64URLEncodedSize(inSize); } inline constexpr char* base64Encode( const char* f, const char* l, char* o) noexcept { return detail::base64_detail::base64Encode(f, l, o); } inline constexpr char* base64URLEncode( const char* f, const char* l, char* o) noexcept { return detail::base64_detail::base64URLEncode(f, l, o); } inline char* base64EncodeRuntime( const char* f, const char* l, char* o) noexcept { return detail::base64_detail::base64EncodeRuntime(f, l, o); } inline char* base64URLEncodeRuntime( const char* f, const char* l, char* o) noexcept { return detail::base64_detail::base64URLEncodeRuntime(f, l, o); } inline std::string base64Encode(std::string_view s) { std::string res; std::size_t resSize = folly::base64EncodedSize(s.size()); folly::resizeWithoutInitialization(res, resSize); folly::base64EncodeRuntime(s.data(), s.data() + s.size(), res.data()); return res; } inline std::string base64URLEncode(std::string_view s) { std::string res; std::size_t resSize = folly::base64URLEncodedSize(s.size()); folly::resizeWithoutInitialization(res, resSize); folly::base64URLEncodeRuntime(s.data(), s.data() + s.size(), res.data()); return res; } constexpr std::size_t base64DecodedSize(const char* f, const char* l) noexcept { return detail::base64_detail::base64DecodedSize(f, l); } constexpr std::size_t base64DecodedSize(std::string_view s) noexcept { return folly::base64DecodedSize(s.data(), s.data() + s.size()); } constexpr std::size_t base64URLDecodedSize( const char* f, const char* l) noexcept { return detail::base64_detail::base64URLDecodedSize(f, l); } constexpr std::size_t base64URLDecodedSize(std::string_view s) noexcept { return folly::base64URLDecodedSize(s.data(), s.data() + s.size()); } inline constexpr base64_decode_result base64Decode( const char* f, const char* l, char* o) noexcept { auto detailResult = detail::base64_detail::base64Decode(f, l, o); return {detailResult.isSuccess, detailResult.o}; } inline constexpr base64_decode_result base64Decode( std::string_view s, char* o) noexcept { return folly::base64Decode(s.data(), s.data() + s.size(), o); } inline constexpr base64_decode_result base64URLDecode( const char* f, const char* l, char* o) noexcept { auto detailResult = detail::base64_detail::base64URLDecode(f, l, o); return {detailResult.isSuccess, detailResult.o}; } inline constexpr base64_decode_result base64URLDecode( std::string_view s, char* o) noexcept { return folly::base64URLDecode(s.data(), s.data() + s.size(), o); } inline base64_decode_result base64DecodeRuntime( const char* f, const char* l, char* o) noexcept { auto detailResult = detail::base64_detail::base64DecodeRuntime(f, l, o); return {detailResult.isSuccess, detailResult.o}; } inline base64_decode_result base64DecodeRuntime( std::string_view s, char* o) noexcept { return folly::base64DecodeRuntime(s.data(), s.data() + s.size(), o); } inline base64_decode_result base64URLDecodeRuntime( const char* f, const char* l, char* o) noexcept { auto detailResult = detail::base64_detail::base64URLDecodeRuntime(f, l, o); return {detailResult.isSuccess, detailResult.o}; } inline base64_decode_result base64URLDecodeRuntime( std::string_view s, char* o) noexcept { return folly::base64URLDecodeRuntime(s.data(), s.data() + s.size(), o); } // NOTE: for resizeWithoutInitialization we don't need to declare the macros, // since we are using char which is already included by default. inline std::string base64Decode(std::string_view s) { std::string res; std::size_t resSize = folly::base64DecodedSize(s); folly::resizeWithoutInitialization(res, resSize); if (!folly::base64DecodeRuntime(s, res.data()).is_success) { folly::throw_exception("Base64 Decoding failed"); } return res; } inline std::string base64URLDecode(std::string_view s) { std::string res; std::size_t resSize = folly::base64URLDecodedSize(s); folly::resizeWithoutInitialization(res, resSize); if (!folly::base64URLDecodeRuntime(s, res.data()).is_success) { folly::throw_exception("Base64URL Decoding failed"); } return res; } inline bool isBase64URL(std::string_view s) { std::string res; std::size_t resSize = folly::base64URLDecodedSize(s); folly::resizeWithoutInitialization(res, resSize); if (!folly::base64URLDecodeRuntime(s, res.data()).is_success) { return false; } return true; } } // namespace folly