/* -*- 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 "nsUnicodeToUTF7.h" #include //---------------------------------------------------------------------- // Global functions and data [declaration] #define ENC_DIRECT 0 #define ENC_BASE64 1 //---------------------------------------------------------------------- // Class nsBasicUTF7Encoder [implementation] nsBasicUTF7Encoder::nsBasicUTF7Encoder(char aLastChar, char aEscChar) { mLastChar = aLastChar; mEscChar = aEscChar; Reset(); } nsresult nsBasicUTF7Encoder::ShiftEncoding(int32_t aEncoding, char* aDest, int32_t* aDestLength) { if (aEncoding == mEncoding) { *aDestLength = 0; return NS_OK; } nsresult res = NS_OK; char* dest = aDest; char* destEnd = aDest + *aDestLength; if (mEncStep != 0) { if (dest >= destEnd) return NS_OK_UENC_MOREOUTPUT; *(dest++) = ValueToChar(mEncBits); mEncStep = 0; mEncBits = 0; } if (dest >= destEnd) { res = NS_OK_UENC_MOREOUTPUT; } else { switch (aEncoding) { case 0: *(dest++) = '-'; mEncStep = 0; mEncBits = 0; break; case 1: *(dest++) = mEscChar; break; } mEncoding = aEncoding; } *aDestLength = dest - aDest; return res; } nsresult nsBasicUTF7Encoder::EncodeDirect(const char16_t* aSrc, int32_t* aSrcLength, char* aDest, int32_t* aDestLength) { nsresult res = NS_OK; const char16_t* src = aSrc; const char16_t* srcEnd = aSrc + *aSrcLength; char* dest = aDest; char* destEnd = aDest + *aDestLength; char16_t ch; while (src < srcEnd) { ch = *src; // stop when we reach Unicode chars if (!DirectEncodable(ch)) break; if (ch == mEscChar) { // special case for the escape char if (destEnd - dest < 1) { res = NS_OK_UENC_MOREOUTPUT; break; } else { *dest++ = (char)ch; *dest++ = (char)'-'; src++; } } else { // classic direct encoding if (dest >= destEnd) { res = NS_OK_UENC_MOREOUTPUT; break; } else { *dest++ = (char)ch; src++; } } } *aSrcLength = src - aSrc; *aDestLength = dest - aDest; return res; } nsresult nsBasicUTF7Encoder::EncodeBase64(const char16_t* aSrc, int32_t* aSrcLength, char* aDest, int32_t* aDestLength) { nsresult res = NS_OK; const char16_t* src = aSrc; const char16_t* srcEnd = aSrc + *aSrcLength; char* dest = aDest; char* destEnd = aDest + *aDestLength; char16_t ch; uint32_t value; while (src < srcEnd) { ch = *src; // stop when we reach printable US-ASCII chars if (DirectEncodable(ch)) break; switch (mEncStep) { case 0: if (destEnd - dest < 2) { res = NS_OK_UENC_MOREOUTPUT; break; } value = ch >> 10; *(dest++) = ValueToChar(value); value = (ch >> 4) & 0x3f; *(dest++) = ValueToChar(value); mEncBits = (ch & 0x0f) << 2; break; case 1: if (destEnd - dest < 3) { res = NS_OK_UENC_MOREOUTPUT; break; } value = mEncBits + (ch >> 14); *(dest++) = ValueToChar(value); value = (ch >> 8) & 0x3f; *(dest++) = ValueToChar(value); value = (ch >> 2) & 0x3f; *(dest++) = ValueToChar(value); mEncBits = (ch & 0x03) << 4; break; case 2: if (destEnd - dest < 3) { res = NS_OK_UENC_MOREOUTPUT; break; } value = mEncBits + (ch >> 12); *(dest++) = ValueToChar(value); value = (ch >> 6) & 0x3f; *(dest++) = ValueToChar(value); value = ch & 0x3f; *(dest++) = ValueToChar(value); mEncBits = 0; break; } if (res != NS_OK) break; src++; (++mEncStep) %= 3; } *aSrcLength = src - aSrc; *aDestLength = dest - aDest; return res; } char nsBasicUTF7Encoder::ValueToChar(uint32_t aValue) { if (aValue < 26) return (char)('A' + aValue); else if (aValue < 26 + 26) return (char)('a' + aValue - 26); else if (aValue < 26 + 26 + 10) return (char)('0' + aValue - 26 - 26); else if (aValue == 26 + 26 + 10) return '+'; else if (aValue == 26 + 26 + 10 + 1) return mLastChar; else return -1; } bool nsBasicUTF7Encoder::DirectEncodable(char16_t aChar) { // spec says: printable US-ASCII chars if ((aChar >= 0x20) && (aChar <= 0x7e)) return true; else return false; } //---------------------------------------------------------------------- // Subclassing of nsEncoderSupport class [implementation] NS_IMETHODIMP nsBasicUTF7Encoder::ConvertNoBuffNoErr(const char16_t* aSrc, int32_t* aSrcLength, char* aDest, int32_t* aDestLength) { nsresult res = NS_OK; const char16_t* src = aSrc; const char16_t* srcEnd = aSrc + *aSrcLength; char* dest = aDest; char* destEnd = aDest + *aDestLength; int32_t bcr, bcw; char16_t ch; int32_t enc; while (src < srcEnd) { // find the encoding for the next char ch = *src; if (DirectEncodable(ch)) enc = ENC_DIRECT; else enc = ENC_BASE64; // if necessary, shift into the required encoding bcw = destEnd - dest; res = ShiftEncoding(enc, dest, &bcw); dest += bcw; if (res != NS_OK) break; // now encode (as much as you can) bcr = srcEnd - src; bcw = destEnd - dest; if (enc == ENC_DIRECT) res = EncodeDirect(src, &bcr, dest, &bcw); else res = EncodeBase64(src, &bcr, dest, &bcw); src += bcr; dest += bcw; if (res != NS_OK) break; } *aSrcLength = src - aSrc; *aDestLength = dest - aDest; return res; } NS_IMETHODIMP nsBasicUTF7Encoder::FinishNoBuff(char* aDest, int32_t* aDestLength) { return ShiftEncoding(ENC_DIRECT, aDest, aDestLength); } NS_IMETHODIMP nsBasicUTF7Encoder::Reset() { mEncoding = ENC_DIRECT; mEncBits = 0; mEncStep = 0; return NS_OK; } //---------------------------------------------------------------------- // Class nsUnicodeToUTF7 [implementation] nsUnicodeToUTF7::nsUnicodeToUTF7() : nsBasicUTF7Encoder('/', '+') {} bool nsUnicodeToUTF7::DirectEncodable(char16_t aChar) { if ((aChar >= 'A') && (aChar <= 'Z')) return true; else if ((aChar >= 'a') && (aChar <= 'z')) return true; else if ((aChar >= '0') && (aChar <= '9')) return true; else if ((aChar >= 39) && (aChar <= 41)) return true; else if ((aChar >= 44) && (aChar <= 47)) return true; else if (aChar == 58) return true; else if (aChar == 63) return true; else if (aChar == ' ') return true; else if (aChar == 9) return true; else if (aChar == 13) return true; else if (aChar == 10) return true; else if (aChar == 60) return true; // '<' else if (aChar == 33) return true; // '!' else if (aChar == 34) return true; // '"' else if (aChar == 62) return true; // '>' else if (aChar == 61) return true; // '=' else if (aChar == 59) return true; // ';' else if (aChar == 91) return true; // '[' else if (aChar == 93) return true; // ']' else return false; }