diff options
Diffstat (limited to 'Source/WTF/wtf/text/Base64.cpp')
-rw-r--r-- | Source/WTF/wtf/text/Base64.cpp | 76 |
1 files changed, 50 insertions, 26 deletions
diff --git a/Source/WTF/wtf/text/Base64.cpp b/Source/WTF/wtf/text/Base64.cpp index 2323f3fa3..714a7ead4 100644 --- a/Source/WTF/wtf/text/Base64.cpp +++ b/Source/WTF/wtf/text/Base64.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2000-2001 Dawit Alemayehu <adawit@kde.org> Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> - Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved. + Copyright (C) 2007, 2008, 2013, 2016 Apple Inc. All rights reserved. Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> This program is free software; you can redistribute it and/or modify @@ -92,7 +92,7 @@ static const char base64URLDecMap[128] = { 0x31, 0x32, 0x33, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet }; -static inline void base64EncodeInternal(const char* data, unsigned len, Vector<char>& out, Base64EncodePolicy policy, const char (&encodeMap)[64]) +static inline void base64EncodeInternal(const unsigned char* data, unsigned len, Vector<char>& out, Base64EncodePolicy policy, const char (&encodeMap)[64]) { out.clear(); if (!len) @@ -160,29 +160,29 @@ static inline void base64EncodeInternal(const char* data, unsigned len, Vector<c String base64Encode(const void* data, unsigned length, Base64EncodePolicy policy) { Vector<char> result; - base64EncodeInternal(static_cast<const char*>(data), length, result, policy, base64EncMap); + base64EncodeInternal(static_cast<const unsigned char*>(data), length, result, policy, base64EncMap); return String(result.data(), result.size()); } void base64Encode(const void* data, unsigned len, Vector<char>& out, Base64EncodePolicy policy) { - base64EncodeInternal(static_cast<const char*>(data), len, out, policy, base64EncMap); + base64EncodeInternal(static_cast<const unsigned char*>(data), len, out, policy, base64EncMap); } String base64URLEncode(const void* data, unsigned length) { Vector<char> result; - base64EncodeInternal(static_cast<const char*>(data), length, result, Base64URLPolicy, base64URLEncMap); + base64EncodeInternal(static_cast<const unsigned char*>(data), length, result, Base64URLPolicy, base64URLEncMap); return String(result.data(), result.size()); } void base64URLEncode(const void* data, unsigned len, Vector<char>& out) { - base64EncodeInternal(static_cast<const char*>(data), len, out, Base64URLPolicy, base64URLEncMap); + base64EncodeInternal(static_cast<const unsigned char*>(data), len, out, Base64URLPolicy, base64URLEncMap); } template<typename T> -static inline bool base64DecodeInternal(const T* data, unsigned length, Vector<char>& out, Base64DecodePolicy policy, const char (&decodeMap)[128]) +static inline bool base64DecodeInternal(const T* data, unsigned length, SignedOrUnsignedCharVectorAdapter& out, unsigned options, const char (&decodeMap)[128]) { out.clear(); if (!length) @@ -192,29 +192,47 @@ static inline bool base64DecodeInternal(const T* data, unsigned length, Vector<c unsigned equalsSignCount = 0; unsigned outLength = 0; + bool hadError = false; for (unsigned idx = 0; idx < length; ++idx) { unsigned ch = data[idx]; if (ch == '=') { ++equalsSignCount; - // There should be no padding if length is a multiple of 4, and there - // should never be more than 2 padding characters. - if (policy == Base64FailOnInvalidCharacterOrExcessPadding && (length % 4 || equalsSignCount > 2)) - return false; + // There should never be more than 2 padding characters. + if (options & Base64ValidatePadding && equalsSignCount > 2) { + hadError = true; + break; + } } else { char decodedCharacter = ch < WTF_ARRAY_LENGTH(decodeMap) ? decodeMap[ch] : nonAlphabet; if (decodedCharacter != nonAlphabet) { - if (equalsSignCount) - return false; - out[outLength] = decodedCharacter; - ++outLength; - } else if (policy == Base64FailOnInvalidCharacterOrExcessPadding || policy == Base64FailOnInvalidCharacter || (policy == Base64IgnoreWhitespace && !isSpaceOrNewline(ch))) - return false; + if (equalsSignCount) { + hadError = true; + break; + } + out[outLength++] = decodedCharacter; + } else if (!(options & Base64IgnoreSpacesAndNewLines) || !isSpaceOrNewline(ch)) { + hadError = true; + break; + } } } + // Make sure we shrink back the Vector before returning. outLength may be shorter than expected + // in case of error or in case of ignored spaces. + if (outLength < out.size()) + out.shrink(outLength); + + if (hadError) + return false; + if (!outLength) return !equalsSignCount; + // The should be no padding if length is a multiple of 4. + // We use (outLength + equalsSignCount) instead of length because we don't want to account for ignored characters (i.e. spaces). + if (options & Base64ValidatePadding && equalsSignCount && (outLength + equalsSignCount) % 4) + return false; + // Valid data is (n * 4 + [0,2,3]) characters long. if ((outLength % 4) == 1) return false; @@ -248,12 +266,15 @@ static inline bool base64DecodeInternal(const T* data, unsigned length, Vector<c return true; } -bool base64Decode(const String& in, SignedOrUnsignedCharVectorAdapter out, Base64DecodePolicy policy) +bool base64Decode(const String& in, SignedOrUnsignedCharVectorAdapter out, unsigned options) { - return base64DecodeInternal<UChar>(in.deprecatedCharacters(), in.length(), out, policy, base64DecMap); + unsigned length = in.length(); + if (!length || in.is8Bit()) + return base64DecodeInternal(in.characters8(), length, out, options, base64DecMap); + return base64DecodeInternal(in.characters16(), length, out, options, base64DecMap); } -bool base64Decode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter out, Base64DecodePolicy policy) +bool base64Decode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter out, unsigned options) { out.clear(); @@ -261,17 +282,20 @@ bool base64Decode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter out, if (in.size() > UINT_MAX) return false; - return base64DecodeInternal<char>(in.data(), in.size(), out, policy, base64DecMap); + return base64DecodeInternal(reinterpret_cast<const LChar*>(in.data()), in.size(), out, options, base64DecMap); } -bool base64Decode(const char* data, unsigned len, SignedOrUnsignedCharVectorAdapter out, Base64DecodePolicy policy) +bool base64Decode(const char* data, unsigned len, SignedOrUnsignedCharVectorAdapter out, unsigned options) { - return base64DecodeInternal<char>(data, len, out, policy, base64DecMap); + return base64DecodeInternal(reinterpret_cast<const LChar*>(data), len, out, options, base64DecMap); } bool base64URLDecode(const String& in, SignedOrUnsignedCharVectorAdapter out) { - return base64DecodeInternal<UChar>(in.deprecatedCharacters(), in.length(), out, Base64FailOnInvalidCharacter, base64URLDecMap); + unsigned length = in.length(); + if (!length || in.is8Bit()) + return base64DecodeInternal(in.characters8(), length, out, Base64Default, base64URLDecMap); + return base64DecodeInternal(in.characters16(), length, out, Base64Default, base64URLDecMap); } bool base64URLDecode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter out) @@ -282,12 +306,12 @@ bool base64URLDecode(const Vector<char>& in, SignedOrUnsignedCharVectorAdapter o if (in.size() > UINT_MAX) return false; - return base64DecodeInternal<char>(in.data(), in.size(), out, Base64FailOnInvalidCharacter, base64URLDecMap); + return base64DecodeInternal(reinterpret_cast<const LChar*>(in.data()), in.size(), out, Base64Default, base64URLDecMap); } bool base64URLDecode(const char* data, unsigned len, SignedOrUnsignedCharVectorAdapter out) { - return base64DecodeInternal<char>(data, len, out, Base64FailOnInvalidCharacter, base64URLDecMap); + return base64DecodeInternal(reinterpret_cast<const LChar*>(data), len, out, Base64Default, base64URLDecMap); } } // namespace WTF |