380 lines
15 KiB
C++
380 lines
15 KiB
C++
/*
|
|
* Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
|
|
* Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
|
|
* Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <wtf/Forward.h>
|
|
#include <wtf/OptionSet.h>
|
|
#include <wtf/Span.h>
|
|
#include <wtf/text/StringConcatenate.h>
|
|
#include <wtf/text/WTFString.h>
|
|
|
|
namespace WTF {
|
|
|
|
enum class Base64EncodePolicy {
|
|
DoNotInsertLFs,
|
|
InsertLFs,
|
|
URL // No padding, no LFs.
|
|
};
|
|
|
|
enum class Base64EncodeMap { Default, URL };
|
|
|
|
enum class Base64DecodeOptions : uint8_t {
|
|
ValidatePadding = 1 << 0,
|
|
IgnoreSpacesAndNewLines = 1 << 1,
|
|
DiscardVerticalTab = 1 << 2,
|
|
};
|
|
|
|
enum class Base64DecodeMap { Default, URL };
|
|
|
|
struct Base64Specification {
|
|
Span<const std::byte> input;
|
|
Base64EncodePolicy policy;
|
|
Base64EncodeMap map;
|
|
};
|
|
|
|
static constexpr unsigned maximumBase64LineLengthWhenInsertingLFs = 76;
|
|
|
|
// If the input string is pathologically large, just return nothing.
|
|
// Rather than being perfectly precise, this is a bit conservative.
|
|
static constexpr unsigned maximumBase64EncoderInputBufferSize = std::numeric_limits<unsigned>::max() / 77 * 76 / 4 * 3 - 2;
|
|
|
|
unsigned calculateBase64EncodedSize(unsigned inputLength, Base64EncodePolicy);
|
|
|
|
template<typename CharacterType> bool isBase64OrBase64URLCharacter(CharacterType);
|
|
|
|
WTF_EXPORT_PRIVATE void base64Encode(Span<const std::byte>, Span<UChar>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
WTF_EXPORT_PRIVATE void base64Encode(Span<const std::byte>, Span<LChar>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
|
|
WTF_EXPORT_PRIVATE Vector<uint8_t> base64EncodeToVector(Span<const std::byte>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Vector<uint8_t> base64EncodeToVector(Span<const uint8_t>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Vector<uint8_t> base64EncodeToVector(Span<const char>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Vector<uint8_t> base64EncodeToVector(const CString&, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Vector<uint8_t> base64EncodeToVector(const void*, unsigned, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
|
|
WTF_EXPORT_PRIVATE String base64EncodeToString(Span<const std::byte>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
String base64EncodeToString(Span<const uint8_t>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
String base64EncodeToString(Span<const char>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
String base64EncodeToString(const CString&, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
String base64EncodeToString(const void*, unsigned, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
|
|
WTF_EXPORT_PRIVATE std::optional<Vector<uint8_t>> base64Decode(Span<const std::byte>, OptionSet<Base64DecodeOptions> = { }, Base64DecodeMap = Base64DecodeMap::Default);
|
|
WTF_EXPORT_PRIVATE std::optional<Vector<uint8_t>> base64Decode(StringView, OptionSet<Base64DecodeOptions> = { }, Base64DecodeMap = Base64DecodeMap::Default);
|
|
std::optional<Vector<uint8_t>> base64Decode(Span<const uint8_t>, OptionSet<Base64DecodeOptions> = { }, Base64DecodeMap = Base64DecodeMap::Default);
|
|
std::optional<Vector<uint8_t>> base64Decode(Span<const char>, OptionSet<Base64DecodeOptions> = { }, Base64DecodeMap = Base64DecodeMap::Default);
|
|
std::optional<Vector<uint8_t>> base64Decode(const String&, OptionSet<Base64DecodeOptions> = { }, Base64DecodeMap = Base64DecodeMap::Default);
|
|
std::optional<Vector<uint8_t>> base64Decode(const void*, unsigned, OptionSet<Base64DecodeOptions> = { }, Base64DecodeMap = Base64DecodeMap::Default);
|
|
|
|
// All the same functions modified for base64url, as defined in RFC 4648.
|
|
// This format uses '-' and '_' instead of '+' and '/' respectively.
|
|
|
|
Vector<uint8_t> base64URLEncodeToVector(Span<const std::byte>);
|
|
Vector<uint8_t> base64URLEncodeToVector(Span<const uint8_t>);
|
|
Vector<uint8_t> base64URLEncodeToVector(Span<const char>);
|
|
Vector<uint8_t> base64URLEncodeToVector(const CString&);
|
|
Vector<uint8_t> base64URLEncodeToVector(const void*, unsigned);
|
|
|
|
String base64URLEncodeToString(Span<const std::byte>);
|
|
String base64URLEncodeToString(Span<const uint8_t>);
|
|
String base64URLEncodeToString(Span<const char>);
|
|
String base64URLEncodeToString(const CString&);
|
|
String base64URLEncodeToString(const void*, unsigned);
|
|
|
|
std::optional<Vector<uint8_t>> base64URLDecode(StringView);
|
|
std::optional<Vector<uint8_t>> base64URLDecode(const String&);
|
|
std::optional<Vector<uint8_t>> base64URLDecode(Span<const std::byte>);
|
|
std::optional<Vector<uint8_t>> base64URLDecode(Span<const uint8_t>);
|
|
std::optional<Vector<uint8_t>> base64URLDecode(Span<const char>);
|
|
std::optional<Vector<uint8_t>> base64URLDecode(const void*, unsigned);
|
|
|
|
// Versions for use with StringBuilder / makeString.
|
|
|
|
Base64Specification base64Encoded(Span<const std::byte>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Base64Specification base64Encoded(Span<const uint8_t>, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Base64Specification base64Encoded(const CString&, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
Base64Specification base64Encoded(const void*, unsigned, Base64EncodePolicy = Base64EncodePolicy::DoNotInsertLFs, Base64EncodeMap = Base64EncodeMap::Default);
|
|
|
|
Base64Specification base64URLEncoded(Span<const std::byte>);
|
|
Base64Specification base64URLEncoded(Span<const uint8_t>);
|
|
Base64Specification base64URLEncoded(const CString&);
|
|
Base64Specification base64URLEncoded(const void*, unsigned);
|
|
|
|
|
|
inline Vector<uint8_t> base64EncodeToVector(Span<const uint8_t> input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToVector(asBytes(input), policy, map);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64EncodeToVector(Span<const char> input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToVector(asBytes(input), policy, map);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64EncodeToVector(const CString& input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToVector(input.bytes(), policy, map);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64EncodeToVector(const void* input, unsigned length, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToVector({ static_cast<const std::byte*>(input), length }, policy, map);
|
|
}
|
|
|
|
inline String base64EncodeToString(Span<const uint8_t> input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToString(asBytes(input), policy, map);
|
|
}
|
|
|
|
inline String base64EncodeToString(Span<const char> input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToString(asBytes(input), policy, map);
|
|
}
|
|
|
|
inline String base64EncodeToString(const CString& input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToString(input.bytes(), policy, map);
|
|
}
|
|
|
|
inline String base64EncodeToString(const void* input, unsigned length, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64EncodeToString({ static_cast<const std::byte*>(input), length }, policy, map);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64Decode(Span<const uint8_t> input, OptionSet<Base64DecodeOptions> options, Base64DecodeMap map)
|
|
{
|
|
return base64Decode(asBytes(input), options, map);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64Decode(Span<const char> input, OptionSet<Base64DecodeOptions> options, Base64DecodeMap map)
|
|
{
|
|
return base64Decode(asBytes(input), options, map);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64Decode(const String& input, OptionSet<Base64DecodeOptions> options, Base64DecodeMap map)
|
|
{
|
|
return base64Decode(StringView { input }, options, map);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64Decode(const void* input, unsigned length, OptionSet<Base64DecodeOptions> options, Base64DecodeMap map)
|
|
{
|
|
return base64Decode({ static_cast<const std::byte*>(input), length }, options, map);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64URLEncodeToVector(Span<const std::byte> input)
|
|
{
|
|
return base64EncodeToVector(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64URLEncodeToVector(Span<const uint8_t> input)
|
|
{
|
|
return base64EncodeToVector(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64URLEncodeToVector(Span<const char> input)
|
|
{
|
|
return base64EncodeToVector(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64URLEncodeToVector(const CString& input)
|
|
{
|
|
return base64EncodeToVector(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Vector<uint8_t> base64URLEncodeToVector(const void* input, unsigned length)
|
|
{
|
|
return base64EncodeToVector(input, length, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline String base64URLEncodeToString(Span<const std::byte> input)
|
|
{
|
|
return base64EncodeToString(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline String base64URLEncodeToString(Span<const uint8_t> input)
|
|
{
|
|
return base64EncodeToString(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline String base64URLEncodeToString(Span<const char> input)
|
|
{
|
|
return base64EncodeToString(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline String base64URLEncodeToString(const CString& input)
|
|
{
|
|
return base64EncodeToString(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline String base64URLEncodeToString(const void* input, unsigned length)
|
|
{
|
|
return base64EncodeToString(input, length, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64URLDecode(StringView input)
|
|
{
|
|
return base64Decode(input, { }, Base64DecodeMap::URL);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64URLDecode(const String& input)
|
|
{
|
|
return base64Decode(input, { }, Base64DecodeMap::URL);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64URLDecode(Span<const std::byte> input)
|
|
{
|
|
return base64Decode(input, { }, Base64DecodeMap::URL);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64URLDecode(Span<const uint8_t> input)
|
|
{
|
|
return base64Decode(input, { }, Base64DecodeMap::URL);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64URLDecode(Span<const char> input)
|
|
{
|
|
return base64Decode(input, { }, Base64DecodeMap::URL);
|
|
}
|
|
|
|
inline std::optional<Vector<uint8_t>> base64URLDecode(const void* input, unsigned length)
|
|
{
|
|
return base64Decode(input, length, { }, Base64DecodeMap::URL);
|
|
}
|
|
|
|
template<typename CharacterType> bool isBase64OrBase64URLCharacter(CharacterType c)
|
|
{
|
|
return isASCIIAlphanumeric(c) || c == '+' || c == '/' || c == '-' || c == '_';
|
|
}
|
|
|
|
inline unsigned calculateBase64EncodedSize(unsigned inputLength, Base64EncodePolicy policy)
|
|
{
|
|
if (!inputLength)
|
|
return 0;
|
|
|
|
if (inputLength > maximumBase64EncoderInputBufferSize)
|
|
return 0;
|
|
|
|
auto basePaddedEncodedSize = [&] {
|
|
return ((inputLength + 2) / 3) * 4;
|
|
};
|
|
|
|
auto baseUnpaddedEncodedSize = [&] {
|
|
return ((inputLength * 4) + 2) / 3;
|
|
};
|
|
|
|
switch (policy) {
|
|
case Base64EncodePolicy::DoNotInsertLFs:
|
|
return basePaddedEncodedSize();
|
|
|
|
case Base64EncodePolicy::InsertLFs: {
|
|
auto result = basePaddedEncodedSize();
|
|
return result + ((result - 1) / maximumBase64LineLengthWhenInsertingLFs);
|
|
}
|
|
|
|
case Base64EncodePolicy::URL:
|
|
return baseUnpaddedEncodedSize();
|
|
}
|
|
|
|
ASSERT_NOT_REACHED();
|
|
return 0;
|
|
}
|
|
|
|
inline Base64Specification base64Encoded(Span<const std::byte> input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return { input, policy, map };
|
|
}
|
|
|
|
inline Base64Specification base64Encoded(Span<const uint8_t> input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64Encoded(asBytes(input), policy, map);
|
|
}
|
|
|
|
inline Base64Specification base64Encoded(const CString& input, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64Encoded(input.bytes(), policy, map);
|
|
}
|
|
|
|
inline Base64Specification base64Encoded(const void* input, unsigned length, Base64EncodePolicy policy, Base64EncodeMap map)
|
|
{
|
|
return base64Encoded({ static_cast<const std::byte*>(input), length }, policy, map);
|
|
}
|
|
|
|
inline Base64Specification base64URLEncoded(Span<const std::byte> input)
|
|
{
|
|
return base64Encoded(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Base64Specification base64URLEncoded(Span<const uint8_t> input)
|
|
{
|
|
return base64Encoded(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Base64Specification base64URLEncoded(const CString& input)
|
|
{
|
|
return base64Encoded(input, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
inline Base64Specification base64URLEncoded(const void* input, unsigned length)
|
|
{
|
|
return base64Encoded(input, length, Base64EncodePolicy::URL, Base64EncodeMap::URL);
|
|
}
|
|
|
|
template<> class StringTypeAdapter<Base64Specification> {
|
|
public:
|
|
StringTypeAdapter(const Base64Specification& base64)
|
|
: m_base64 { base64 }
|
|
, m_encodedLength { calculateBase64EncodedSize(base64.input.size(), base64.policy) }
|
|
{
|
|
}
|
|
|
|
unsigned length() const { return m_encodedLength; }
|
|
bool is8Bit() const { return true; }
|
|
|
|
template<typename CharacterType> void writeTo(CharacterType* destination) const
|
|
{
|
|
base64Encode(m_base64.input, Span { destination, m_encodedLength }, m_base64.policy, m_base64.map);
|
|
}
|
|
|
|
private:
|
|
Base64Specification m_base64;
|
|
unsigned m_encodedLength;
|
|
};
|
|
|
|
} // namespace WTF
|
|
|
|
using WTF::Base64DecodeOptions;
|
|
using WTF::Base64EncodePolicy;
|
|
using WTF::base64Decode;
|
|
using WTF::base64EncodeToString;
|
|
using WTF::base64EncodeToVector;
|
|
using WTF::base64Encoded;
|
|
using WTF::base64URLDecode;
|
|
using WTF::base64URLDecode;
|
|
using WTF::base64URLEncodeToString;
|
|
using WTF::base64URLEncodeToVector;
|
|
using WTF::base64URLEncoded;
|
|
using WTF::isBase64OrBase64URLCharacter;
|