diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/intl/nsUTF7ToUnicode.cpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/comm/mailnews/intl/nsUTF7ToUnicode.cpp b/comm/mailnews/intl/nsUTF7ToUnicode.cpp new file mode 100644 index 0000000000..2257affa51 --- /dev/null +++ b/comm/mailnews/intl/nsUTF7ToUnicode.cpp @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsUTF7ToUnicode.h" + +#define ENC_DIRECT 0 +#define ENC_BASE64 1 + +//---------------------------------------------------------------------- +// Class nsBasicUTF7Decoder [implementation] + +nsBasicUTF7Decoder::nsBasicUTF7Decoder(char aLastChar, char aEscChar) { + mLastChar = aLastChar; + mEscChar = aEscChar; + mFreshBase64 = false; + Reset(); +} + +nsresult nsBasicUTF7Decoder::DecodeDirect(const char* aSrc, int32_t* aSrcLength, + char16_t* aDest, + int32_t* aDestLength) { + const char* srcEnd = aSrc + *aSrcLength; + const char* src = aSrc; + char16_t* destEnd = aDest + *aDestLength; + char16_t* dest = aDest; + nsresult res = NS_OK; + char ch; + + while (src < srcEnd) { + ch = *src; + + // stop when we meet other chars or end of direct encoded seq. + // if (!(DirectEncodable(ch)) || (ch == mEscChar)) { + // but we are decoding; so we should be lax; pass everything until escchar + if (ch == mEscChar) { + res = NS_ERROR_UDEC_ILLEGALINPUT; + break; + } + + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } else { + *dest++ = ch; + src++; + } + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +nsresult nsBasicUTF7Decoder::DecodeBase64(const char* aSrc, int32_t* aSrcLength, + char16_t* aDest, + int32_t* aDestLength) { + const char* srcEnd = aSrc + *aSrcLength; + const char* src = aSrc; + char16_t* destEnd = aDest + *aDestLength; + char16_t* dest = aDest; + nsresult res = NS_OK; + char ch; + uint32_t value; + + while (src < srcEnd) { + ch = *src; + + // stop when we meet other chars or end of direct encoded seq. + value = CharToValue(ch); + if (value > 0xff) { + res = NS_ERROR_UDEC_ILLEGALINPUT; + break; + } + + switch (mEncStep) { + case 0: + mEncBits = value << 10; + break; + case 1: + mEncBits += value << 4; + break; + case 2: + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + mEncBits += value >> 2; + *(dest++) = (char16_t)mEncBits; + mEncBits = (value & 0x03) << 14; + break; + case 3: + mEncBits += value << 8; + break; + case 4: + mEncBits += value << 2; + break; + case 5: + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + mEncBits += value >> 4; + *(dest++) = (char16_t)mEncBits; + mEncBits = (value & 0x0f) << 12; + break; + case 6: + mEncBits += value << 6; + break; + case 7: + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + mEncBits += value; + *(dest++) = (char16_t)mEncBits; + mEncBits = 0; + break; + } + + if (res != NS_OK) break; + + src++; + (++mEncStep) %= 8; + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +uint32_t nsBasicUTF7Decoder::CharToValue(char aChar) { + if ((aChar >= 'A') && (aChar <= 'Z')) + return (uint8_t)(aChar - 'A'); + else if ((aChar >= 'a') && (aChar <= 'z')) + return (uint8_t)(26 + aChar - 'a'); + else if ((aChar >= '0') && (aChar <= '9')) + return (uint8_t)(26 + 26 + aChar - '0'); + else if (aChar == '+') + return (uint8_t)(26 + 26 + 10); + else if (aChar == mLastChar) + return (uint8_t)(26 + 26 + 10 + 1); + else + return 0xffff; +} + +//---------------------------------------------------------------------- +// Subclassing of nsBufferDecoderSupport class [implementation] + +NS_IMETHODIMP nsBasicUTF7Decoder::ConvertNoBuff(const char* aSrc, + int32_t* aSrcLength, + char16_t* aDest, + int32_t* aDestLength) { + const char* srcEnd = aSrc + *aSrcLength; + const char* src = aSrc; + char16_t* destEnd = aDest + *aDestLength; + char16_t* dest = aDest; + int32_t bcr, bcw; + nsresult res = NS_OK; + + while (src < srcEnd) { + // first, attempt to decode in the current mode + bcr = srcEnd - src; + bcw = destEnd - dest; + if (mEncoding == ENC_DIRECT) + res = DecodeDirect(src, &bcr, dest, &bcw); + else if ((mFreshBase64) && (*src == '-')) { + *dest = mEscChar; + bcr = 0; + bcw = 1; + res = NS_ERROR_UDEC_ILLEGALINPUT; + } else { + mFreshBase64 = false; + res = DecodeBase64(src, &bcr, dest, &bcw); + } + src += bcr; + dest += bcw; + + // if an illegal char was encountered, test if it is an escape seq. + if (res == NS_ERROR_UDEC_ILLEGALINPUT) { + if (mEncoding == ENC_DIRECT) { + if (*src == mEscChar) { + mEncoding = ENC_BASE64; + mFreshBase64 = true; + mEncBits = 0; + mEncStep = 0; + src++; + res = NS_OK; + } else + break; + } else { + mEncoding = ENC_DIRECT; + res = NS_OK; + // absorbe end of escape sequence + if (*src == '-') src++; + } + } else if (res != NS_OK) + break; + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +NS_IMETHODIMP nsBasicUTF7Decoder::Reset() { + mEncoding = ENC_DIRECT; + mEncBits = 0; + mEncStep = 0; + return NS_OK; +} + +//---------------------------------------------------------------------- +// Class nsUTF7ToUnicode [implementation] + +nsUTF7ToUnicode::nsUTF7ToUnicode() : nsBasicUTF7Decoder('/', '+') {} |