| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_tools.hxx" |
| |
| #include <cstddef> |
| #include <limits> |
| |
| #include "rtl/tencinfo.h" |
| #include <tools/datetime.hxx> |
| #include <tools/inetmime.hxx> |
| |
| namespace unnamed_tools_inetmime {} using namespace unnamed_tools_inetmime; |
| // unnamed namespaces don't work well yet |
| |
| //============================================================================ |
| namespace unnamed_tools_inetmime { |
| |
| class Charset |
| { |
| rtl_TextEncoding m_eEncoding; |
| const sal_uInt32 * m_pRanges; |
| |
| public: |
| inline Charset(rtl_TextEncoding eTheEncoding, |
| const sal_uInt32 * pTheRanges); |
| |
| rtl_TextEncoding getEncoding() const { return m_eEncoding; } |
| |
| bool contains(sal_uInt32 nChar) const; |
| }; |
| |
| inline Charset::Charset(rtl_TextEncoding eTheEncoding, |
| const sal_uInt32 * pTheRanges): |
| m_eEncoding(eTheEncoding), |
| m_pRanges(pTheRanges) |
| { |
| DBG_ASSERT(m_pRanges, "Charset::Charset(): Bad ranges"); |
| } |
| |
| //============================================================================ |
| void appendISO88591(UniString & rText, sal_Char const * pBegin, |
| sal_Char const * pEnd); |
| |
| } |
| |
| //============================================================================ |
| class INetMIMECharsetList_Impl |
| { |
| struct Node |
| { |
| Charset m_aCharset; |
| bool m_bDisabled; |
| Node * m_pNext; |
| |
| inline Node(const Charset & rTheCharset, bool bTheDisabled, |
| Node * pTheNext); |
| }; |
| |
| Node * m_pFirst; |
| |
| public: |
| INetMIMECharsetList_Impl(): m_pFirst(0) {} |
| |
| ~INetMIMECharsetList_Impl(); |
| |
| void prepend(const Charset & rCharset) |
| { m_pFirst = new Node(rCharset, false, m_pFirst); } |
| |
| void includes(sal_uInt32 nChar); |
| |
| rtl_TextEncoding getPreferredEncoding(rtl_TextEncoding eDefault |
| = RTL_TEXTENCODING_DONTKNOW) |
| const; |
| |
| void reset(); |
| }; |
| |
| inline INetMIMECharsetList_Impl::Node::Node(const Charset & rTheCharset, |
| bool bTheDisabled, |
| Node * pTheNext): |
| m_aCharset(rTheCharset), |
| m_bDisabled(bTheDisabled), |
| m_pNext(pTheNext) |
| {} |
| |
| //============================================================================ |
| namespace unnamed_tools_inetmime { |
| |
| struct Parameter |
| { |
| Parameter * m_pNext; |
| ByteString m_aAttribute; |
| ByteString m_aCharset; |
| ByteString m_aLanguage; |
| ByteString m_aValue; |
| sal_uInt32 m_nSection; |
| bool m_bExtended; |
| |
| inline Parameter(Parameter * pTheNext, ByteString const & rTheAttribute, |
| ByteString const & rTheCharset, |
| ByteString const & rTheLanguage, |
| ByteString const & rTheValue, sal_uInt32 nTheSection, |
| bool bTheExtended); |
| }; |
| |
| inline Parameter::Parameter(Parameter * pTheNext, |
| ByteString const & rTheAttribute, |
| ByteString const & rTheCharset, |
| ByteString const & rTheLanguage, |
| ByteString const & rTheValue, |
| sal_uInt32 nTheSection, bool bTheExtended): |
| m_pNext(pTheNext), |
| m_aAttribute(rTheAttribute), |
| m_aCharset(rTheCharset), |
| m_aLanguage(rTheLanguage), |
| m_aValue(rTheValue), |
| m_nSection(nTheSection), |
| m_bExtended(bTheExtended) |
| {} |
| |
| //============================================================================ |
| struct ParameterList |
| { |
| Parameter * m_pList; |
| |
| ParameterList(): m_pList(0) {} |
| |
| inline ~ParameterList(); |
| |
| Parameter ** find(ByteString const & rAttribute, sal_uInt32 nSection, |
| bool & rPresent); |
| }; |
| |
| inline ParameterList::~ParameterList() |
| { |
| while (m_pList) |
| { |
| Parameter * pNext = m_pList->m_pNext; |
| delete m_pList; |
| m_pList = pNext; |
| } |
| } |
| |
| //============================================================================ |
| bool parseParameters(ParameterList const & rInput, |
| INetContentTypeParameterList * pOutput); |
| |
| } |
| |
| //============================================================================ |
| // |
| // Charset |
| // |
| //============================================================================ |
| |
| bool Charset::contains(sal_uInt32 nChar) const |
| { |
| for (const sal_uInt32 * p = m_pRanges;;) |
| { |
| if (nChar < *p++) |
| return false; |
| if (nChar <= *p++) |
| return true; |
| } |
| } |
| |
| //============================================================================ |
| // |
| // appendISO88591 |
| // |
| //============================================================================ |
| |
| namespace unnamed_tools_inetmime { |
| |
| void appendISO88591(UniString & rText, sal_Char const * pBegin, |
| sal_Char const * pEnd) |
| { |
| xub_StrLen nLength = static_cast< xub_StrLen >(pEnd - pBegin); |
| sal_Unicode * pBuffer = new sal_Unicode[nLength]; |
| for (sal_Unicode * p = pBuffer; pBegin != pEnd;) |
| *p++ = sal_uChar(*pBegin++); |
| rText.Append(pBuffer, nLength); |
| delete[] pBuffer; |
| } |
| |
| } |
| |
| //============================================================================ |
| // |
| // INetMIMECharsetList_Impl |
| // |
| //============================================================================ |
| |
| INetMIMECharsetList_Impl::~INetMIMECharsetList_Impl() |
| { |
| while (m_pFirst) |
| { |
| Node * pRemove = m_pFirst; |
| m_pFirst = m_pFirst->m_pNext; |
| delete pRemove; |
| } |
| } |
| |
| //============================================================================ |
| void INetMIMECharsetList_Impl::includes(sal_uInt32 nChar) |
| { |
| for (Node * p = m_pFirst; p; p = p->m_pNext) |
| if (!(p->m_bDisabled || p->m_aCharset.contains(nChar))) |
| p->m_bDisabled = true; |
| } |
| |
| //============================================================================ |
| rtl_TextEncoding |
| INetMIMECharsetList_Impl::getPreferredEncoding(rtl_TextEncoding eDefault) |
| const |
| { |
| for (Node * p = m_pFirst; p; p = p->m_pNext) |
| if (!p->m_bDisabled) |
| return p->m_aCharset.getEncoding(); |
| return eDefault; |
| } |
| |
| //============================================================================ |
| void INetMIMECharsetList_Impl::reset() |
| { |
| for (Node * p = m_pFirst; p; p = p->m_pNext) |
| p->m_bDisabled = false; |
| } |
| |
| //============================================================================ |
| // |
| // ParameterList |
| // |
| //============================================================================ |
| |
| Parameter ** ParameterList::find(ByteString const & rAttribute, |
| sal_uInt32 nSection, bool & rPresent) |
| { |
| Parameter ** p = &m_pList; |
| for (; *p; p = &(*p)->m_pNext) |
| { |
| StringCompare eCompare = rAttribute.CompareTo((*p)->m_aAttribute); |
| if (eCompare == COMPARE_GREATER) |
| break; |
| else if (eCompare == COMPARE_EQUAL) |
| { |
| if (nSection > (*p)->m_nSection) |
| break; |
| else if (nSection == (*p)->m_nSection) |
| { |
| rPresent = true; |
| return p; |
| } |
| } |
| } |
| rPresent = false; |
| return p; |
| } |
| |
| //============================================================================ |
| // |
| // parseParameters |
| // |
| //============================================================================ |
| |
| namespace unnamed_tools_inetmime { |
| |
| bool parseParameters(ParameterList const & rInput, |
| INetContentTypeParameterList * pOutput) |
| { |
| if (pOutput) |
| pOutput->Clear(); |
| |
| Parameter * pPrev = 0; |
| for (Parameter * p = rInput.m_pList; p; p = p->m_pNext) |
| { |
| if (p->m_nSection > 0 |
| && (!pPrev |
| || pPrev->m_nSection != p->m_nSection - 1 |
| || pPrev->m_aAttribute != p->m_aAttribute)) |
| return false; |
| pPrev = p; |
| } |
| |
| if (pOutput) |
| for (Parameter * p = rInput.m_pList; p;) |
| { |
| bool bCharset = p->m_aCharset.Len() != 0; |
| rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; |
| if (bCharset) |
| eEncoding |
| = INetMIME::getCharsetEncoding(p->m_aCharset.GetBuffer(), |
| p->m_aCharset.GetBuffer() |
| + rInput.m_pList-> |
| m_aCharset. |
| Len()); |
| UniString aValue; |
| bool bBadEncoding = false; |
| Parameter * pNext = p; |
| do |
| { |
| sal_Size nSize; |
| sal_Unicode * pUnicode |
| = INetMIME::convertToUnicode(pNext->m_aValue.GetBuffer(), |
| pNext->m_aValue.GetBuffer() |
| + pNext->m_aValue.Len(), |
| bCharset && p->m_bExtended ? |
| eEncoding : |
| RTL_TEXTENCODING_UTF8, |
| nSize); |
| if (!pUnicode && !(bCharset && p->m_bExtended)) |
| pUnicode = INetMIME::convertToUnicode( |
| pNext->m_aValue.GetBuffer(), |
| pNext->m_aValue.GetBuffer() |
| + pNext->m_aValue.Len(), |
| RTL_TEXTENCODING_ISO_8859_1, nSize); |
| if (!pUnicode) |
| { |
| bBadEncoding = true; |
| break; |
| } |
| aValue += UniString(pUnicode, static_cast< xub_StrLen >(nSize)); |
| delete[] pUnicode; |
| pNext = pNext->m_pNext; |
| } |
| while (pNext && pNext->m_nSection > 0); |
| if (bBadEncoding) |
| { |
| aValue.Erase(); |
| for (pNext = p;;) |
| { |
| if (pNext->m_bExtended) |
| for (xub_StrLen i = 0; i < pNext->m_aValue.Len(); ++i) |
| aValue += sal_Unicode( |
| sal_Unicode( |
| sal_uChar(pNext->m_aValue.GetChar(i))) |
| | 0xF800); |
| else |
| for (xub_StrLen i = 0; i < pNext->m_aValue.Len(); ++i) |
| aValue |
| += sal_Unicode(sal_uChar |
| (pNext-> |
| m_aValue.GetChar(i))); |
| pNext = pNext->m_pNext; |
| if (!pNext || pNext->m_nSection == 0) |
| break; |
| }; |
| } |
| pOutput->Insert(new INetContentTypeParameter(p->m_aAttribute, |
| p->m_aCharset, |
| p->m_aLanguage, |
| aValue, |
| !bBadEncoding), |
| LIST_APPEND); |
| p = pNext; |
| } |
| return true; |
| } |
| |
| } |
| |
| //============================================================================ |
| // |
| // INetMIME |
| // |
| //============================================================================ |
| |
| // static |
| bool INetMIME::isAtomChar(sal_uInt32 nChar) |
| { |
| static const bool aMap[128] |
| = { false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, true, false, true, true, true, true, true, // !"#$%&' |
| false, false, true, true, false, true, false, true, //()*+,-./ |
| true, true, true, true, true, true, true, true, //01234567 |
| true, true, false, false, false, true, false, true, //89:;<=>? |
| false, true, true, true, true, true, true, true, //@ABCDEFG |
| true, true, true, true, true, true, true, true, //HIJKLMNO |
| true, true, true, true, true, true, true, true, //PQRSTUVW |
| true, true, true, false, false, false, true, true, //XYZ[\]^_ |
| true, true, true, true, true, true, true, true, //`abcdefg |
| true, true, true, true, true, true, true, true, //hijklmno |
| true, true, true, true, true, true, true, true, //pqrstuvw |
| true, true, true, true, true, true, true, false //xyz{|}~ |
| }; |
| return isUSASCII(nChar) && aMap[nChar]; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::isTokenChar(sal_uInt32 nChar) |
| { |
| static const sal_Char aMap[128] |
| = { false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, true, false, true, true, true, true, true, // !"#$%&' |
| false, false, true, true, false, true, true, false, //()*+,-./ |
| true, true, true, true, true, true, true, true, //01234567 |
| true, true, false, false, false, false, false, false, //89:;<=>? |
| false, true, true, true, true, true, true, true, //@ABCDEFG |
| true, true, true, true, true, true, true, true, //HIJKLMNO |
| true, true, true, true, true, true, true, true, //PQRSTUVW |
| true, true, true, false, false, false, true, true, //XYZ[\]^_ |
| true, true, true, true, true, true, true, true, //`abcdefg |
| true, true, true, true, true, true, true, true, //hijklmno |
| true, true, true, true, true, true, true, true, //pqrstuvw |
| true, true, true, true, true, true, true, false //xyz{|}~ |
| }; |
| return isUSASCII(nChar) && aMap[nChar]; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::isEncodedWordTokenChar(sal_uInt32 nChar) |
| { |
| static const sal_Char aMap[128] |
| = { false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, true, false, true, true, true, true, true, // !"#$%&' |
| false, false, true, true, false, true, false, false, //()*+,-./ |
| true, true, true, true, true, true, true, true, //01234567 |
| true, true, false, false, false, false, false, false, //89:;<=>? |
| false, true, true, true, true, true, true, true, //@ABCDEFG |
| true, true, true, true, true, true, true, true, //HIJKLMNO |
| true, true, true, true, true, true, true, true, //PQRSTUVW |
| true, true, true, false, false, false, true, true, //XYZ[\]^_ |
| true, true, true, true, true, true, true, true, //`abcdefg |
| true, true, true, true, true, true, true, true, //hijklmno |
| true, true, true, true, true, true, true, true, //pqrstuvw |
| true, true, true, true, true, true, true, false //xyz{|}~ |
| }; |
| return isUSASCII(nChar) && aMap[nChar]; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::isIMAPAtomChar(sal_uInt32 nChar) |
| { |
| static const sal_Char aMap[128] |
| = { false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, false, false, false, false, false, false, false, |
| false, true, false, true, true, false, true, true, // !"#$%&' |
| false, false, false, true, true, true, true, true, //()*+,-./ |
| true, true, true, true, true, true, true, true, //01234567 |
| true, true, true, true, true, true, true, true, //89:;<=>? |
| true, true, true, true, true, true, true, true, //@ABCDEFG |
| true, true, true, true, true, true, true, true, //HIJKLMNO |
| true, true, true, true, true, true, true, true, //PQRSTUVW |
| true, true, true, true, false, true, true, true, //XYZ[\]^_ |
| true, true, true, true, true, true, true, true, //`abcdefg |
| true, true, true, true, true, true, true, true, //hijklmno |
| true, true, true, true, true, true, true, true, //pqrstuvw |
| true, true, true, false, true, true, true, false //xyz{|}~ |
| }; |
| return isUSASCII(nChar) && aMap[nChar]; |
| } |
| |
| //============================================================================ |
| // static |
| sal_uInt32 INetMIME::getDigit(int nWeight) |
| { |
| DBG_ASSERT(nWeight >= 0 && nWeight < 10, |
| "INetMIME::getDigit(): Bad weight"); |
| |
| static const sal_Char aDigits[16] |
| = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; |
| return aDigits[nWeight]; |
| } |
| |
| //============================================================================ |
| // static |
| sal_uInt32 INetMIME::getHexDigit(int nWeight) |
| { |
| DBG_ASSERT(nWeight >= 0 && nWeight < 16, |
| "INetMIME::getHexDigit(): Bad weight"); |
| |
| static const sal_Char aDigits[16] |
| = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', |
| 'D', 'E', 'F' }; |
| return aDigits[nWeight]; |
| } |
| |
| //============================================================================ |
| // static |
| sal_uInt32 INetMIME::getBase64Digit(int nWeight) |
| { |
| DBG_ASSERT(nWeight >= 0 && nWeight < 64, |
| "INetMIME::getBase64Digit(): Bad weight"); |
| |
| static const sal_Char aDigits[64] |
| = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
| 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
| 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
| 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
| '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; |
| return aDigits[nWeight]; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1, |
| const sal_Char * pEnd1, |
| const sal_Char * pBegin2, |
| const sal_Char * pEnd2) |
| { |
| DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pBegin2 && pBegin2 <= pEnd2, |
| "INetMIME::equalIgnoreCase(): Bad sequences"); |
| |
| if (pEnd1 - pBegin1 != pEnd2 - pBegin2) |
| return false; |
| while (pBegin1 != pEnd1) |
| if (toUpperCase(*pBegin1++) != toUpperCase(*pBegin2++)) |
| return false; |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1, |
| const sal_Char * pEnd1, |
| const sal_Char * pString2) |
| { |
| DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2, |
| "INetMIME::equalIgnoreCase(): Bad sequences"); |
| |
| while (*pString2 != 0) |
| if (pBegin1 == pEnd1 |
| || toUpperCase(*pBegin1++) != toUpperCase(*pString2++)) |
| return false; |
| return pBegin1 == pEnd1; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::equalIgnoreCase(const sal_Unicode * pBegin1, |
| const sal_Unicode * pEnd1, |
| const sal_Char * pString2) |
| { |
| DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2, |
| "INetMIME::equalIgnoreCase(): Bad sequences"); |
| |
| while (*pString2 != 0) |
| if (pBegin1 == pEnd1 |
| || toUpperCase(*pBegin1++) != toUpperCase(*pString2++)) |
| return false; |
| return pBegin1 == pEnd1; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::skipLinearWhiteSpace(const sal_Char * pBegin, |
| const sal_Char * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipLinearWhiteSpace(): Bad sequence"); |
| |
| while (pBegin != pEnd) |
| switch (*pBegin) |
| { |
| case '\t': |
| case ' ': |
| ++pBegin; |
| break; |
| |
| case 0x0D: // CR |
| if (startsWithLineFolding(pBegin, pEnd)) |
| pBegin += 3; |
| else |
| return pBegin; |
| break; |
| |
| default: |
| return pBegin; |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Unicode * INetMIME::skipLinearWhiteSpace(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipLinearWhiteSpace(): Bad sequence"); |
| |
| while (pBegin != pEnd) |
| switch (*pBegin) |
| { |
| case '\t': |
| case ' ': |
| ++pBegin; |
| break; |
| |
| case 0x0D: // CR |
| if (startsWithLineFolding(pBegin, pEnd)) |
| pBegin += 3; |
| else |
| return pBegin; |
| break; |
| |
| default: |
| return pBegin; |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::skipComment(const sal_Char * pBegin, |
| const sal_Char * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipComment(): Bad sequence"); |
| |
| if (pBegin != pEnd && *pBegin == '(') |
| { |
| sal_uInt32 nLevel = 0; |
| for (const sal_Char * p = pBegin; p != pEnd;) |
| switch (*p++) |
| { |
| case '(': |
| ++nLevel; |
| break; |
| |
| case ')': |
| if (--nLevel == 0) |
| return p; |
| break; |
| |
| case '\\': |
| if (p != pEnd) |
| ++p; |
| break; |
| } |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Unicode * INetMIME::skipComment(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipComment(): Bad sequence"); |
| |
| if (pBegin != pEnd && *pBegin == '(') |
| { |
| sal_uInt32 nLevel = 0; |
| for (const sal_Unicode * p = pBegin; p != pEnd;) |
| switch (*p++) |
| { |
| case '(': |
| ++nLevel; |
| break; |
| |
| case ')': |
| if (--nLevel == 0) |
| return p; |
| break; |
| |
| case '\\': |
| if (p != pEnd) |
| ++p; |
| break; |
| } |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::skipLinearWhiteSpaceComment(const sal_Char * |
| pBegin, |
| const sal_Char * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence"); |
| |
| while (pBegin != pEnd) |
| switch (*pBegin) |
| { |
| case '\t': |
| case ' ': |
| ++pBegin; |
| break; |
| |
| case 0x0D: // CR |
| if (startsWithLineFolding(pBegin, pEnd)) |
| pBegin += 3; |
| else |
| return pBegin; |
| break; |
| |
| case '(': |
| { |
| const sal_Char * p = skipComment(pBegin, pEnd); |
| if (p == pBegin) |
| return pBegin; |
| pBegin = p; |
| break; |
| } |
| |
| default: |
| return pBegin; |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Unicode * INetMIME::skipLinearWhiteSpaceComment(const sal_Unicode * |
| pBegin, |
| const sal_Unicode * |
| pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence"); |
| |
| while (pBegin != pEnd) |
| switch (*pBegin) |
| { |
| case '\t': |
| case ' ': |
| ++pBegin; |
| break; |
| |
| case 0x0D: // CR |
| if (startsWithLineFolding(pBegin, pEnd)) |
| pBegin += 3; |
| else |
| return pBegin; |
| break; |
| |
| case '(': |
| { |
| const sal_Unicode * p = skipComment(pBegin, pEnd); |
| if (p == pBegin) |
| return pBegin; |
| pBegin = p; |
| break; |
| } |
| |
| default: |
| return pBegin; |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::skipQuotedString(const sal_Char * pBegin, |
| const sal_Char * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipQuotedString(): Bad sequence"); |
| |
| if (pBegin != pEnd && *pBegin == '"') |
| for (const sal_Char * p = pBegin + 1; p != pEnd;) |
| switch (*p++) |
| { |
| case 0x0D: // CR |
| if (pEnd - p < 2 || *p++ != 0x0A // LF |
| || !isWhiteSpace(*p++)) |
| return pBegin; |
| break; |
| |
| case '"': |
| return p; |
| |
| case '\\': |
| if (p != pEnd) |
| ++p; |
| break; |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Unicode * INetMIME::skipQuotedString(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::skipQuotedString(): Bad sequence"); |
| |
| if (pBegin != pEnd && *pBegin == '"') |
| for (const sal_Unicode * p = pBegin + 1; p != pEnd;) |
| switch (*p++) |
| { |
| case 0x0D: // CR |
| if (pEnd - p < 2 || *p++ != 0x0A // LF |
| || !isWhiteSpace(*p++)) |
| return pBegin; |
| break; |
| |
| case '"': |
| return p; |
| |
| case '\\': |
| if (p != pEnd) |
| ++p; |
| break; |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::scanAtom(const sal_Char * pBegin, |
| const sal_Char * pEnd) |
| { |
| while (pBegin != pEnd && isAtomChar(*pBegin)) |
| ++pBegin; |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Unicode * INetMIME::scanAtom(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd) |
| { |
| while (pBegin != pEnd && isAtomChar(*pBegin)) |
| ++pBegin; |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::scanUnsigned(const sal_Char *& rBegin, const sal_Char * pEnd, |
| bool bLeadingZeroes, sal_uInt32 & rValue) |
| { |
| sal_uInt64 nTheValue = 0; |
| const sal_Char * p = rBegin; |
| for ( ; p != pEnd; ++p) |
| { |
| int nWeight = getWeight(*p); |
| if (nWeight < 0) |
| break; |
| nTheValue = 10 * nTheValue + nWeight; |
| if (nTheValue > std::numeric_limits< sal_uInt32 >::max()) |
| return false; |
| } |
| if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1))) |
| return false; |
| rBegin = p; |
| rValue = sal_uInt32(nTheValue); |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::scanUnsigned(const sal_Unicode *& rBegin, |
| const sal_Unicode * pEnd, bool bLeadingZeroes, |
| sal_uInt32 & rValue) |
| { |
| sal_uInt64 nTheValue = 0; |
| const sal_Unicode * p = rBegin; |
| for ( ; p != pEnd; ++p) |
| { |
| int nWeight = getWeight(*p); |
| if (nWeight < 0) |
| break; |
| nTheValue = 10 * nTheValue + nWeight; |
| if (nTheValue > std::numeric_limits< sal_uInt32 >::max()) |
| return false; |
| } |
| if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1))) |
| return false; |
| rBegin = p; |
| rValue = sal_uInt32(nTheValue); |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::scanUnsignedHex(const sal_Char *& rBegin, |
| const sal_Char * pEnd, bool bLeadingZeroes, |
| sal_uInt32 & rValue) |
| { |
| sal_uInt64 nTheValue = 0; |
| const sal_Char * p = rBegin; |
| for ( p = rBegin; p != pEnd; ++p) |
| { |
| int nWeight = getHexWeight(*p); |
| if (nWeight < 0) |
| break; |
| nTheValue = nTheValue << 4 | nWeight; |
| if (nTheValue > std::numeric_limits< sal_uInt32 >::max()) |
| return false; |
| } |
| if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1))) |
| return false; |
| rBegin = p; |
| rValue = sal_uInt32(nTheValue); |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::scanUnsignedHex(const sal_Unicode *& rBegin, |
| const sal_Unicode * pEnd, bool bLeadingZeroes, |
| sal_uInt32 & rValue) |
| { |
| sal_uInt64 nTheValue = 0; |
| const sal_Unicode * p = rBegin; |
| for ( ; p != pEnd; ++p) |
| { |
| int nWeight = getHexWeight(*p); |
| if (nWeight < 0) |
| break; |
| nTheValue = nTheValue << 4 | nWeight; |
| if (nTheValue > std::numeric_limits< sal_uInt32 >::max()) |
| return false; |
| } |
| if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1))) |
| return false; |
| rBegin = p; |
| rValue = sal_uInt32(nTheValue); |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::scanQuotedBlock(const sal_Char * pBegin, |
| const sal_Char * pEnd, |
| sal_uInt32 nOpening, |
| sal_uInt32 nClosing, |
| sal_Size & rLength, |
| bool & rModify) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::scanQuotedBlock(): Bad sequence"); |
| |
| if (pBegin != pEnd && static_cast< unsigned char >(*pBegin) == nOpening) |
| { |
| ++rLength; |
| ++pBegin; |
| while (pBegin != pEnd) |
| if (static_cast< unsigned char >(*pBegin) == nClosing) |
| { |
| ++rLength; |
| return ++pBegin; |
| } |
| else |
| { |
| sal_uInt32 c = *pBegin++; |
| switch (c) |
| { |
| case 0x0D: // CR |
| if (pBegin != pEnd && *pBegin == 0x0A) // LF |
| if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1])) |
| { |
| ++rLength; |
| rModify = true; |
| pBegin += 2; |
| } |
| else |
| { |
| rLength += 3; |
| rModify = true; |
| ++pBegin; |
| } |
| else |
| ++rLength; |
| break; |
| |
| case '\\': |
| ++rLength; |
| if (pBegin != pEnd) |
| { |
| if (startsWithLineBreak(pBegin, pEnd) |
| && (pEnd - pBegin < 3 |
| || !isWhiteSpace(pBegin[2]))) |
| { |
| rLength += 3; |
| rModify = true; |
| pBegin += 2; |
| } |
| else |
| ++pBegin; |
| } |
| break; |
| |
| default: |
| ++rLength; |
| if (!isUSASCII(c)) |
| rModify = true; |
| break; |
| } |
| } |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Unicode * INetMIME::scanQuotedBlock(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd, |
| sal_uInt32 nOpening, |
| sal_uInt32 nClosing, |
| sal_Size & rLength, |
| bool & rModify) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIME::scanQuotedBlock(): Bad sequence"); |
| |
| if (pBegin != pEnd && *pBegin == nOpening) |
| { |
| ++rLength; |
| ++pBegin; |
| while (pBegin != pEnd) |
| if (*pBegin == nClosing) |
| { |
| ++rLength; |
| return ++pBegin; |
| } |
| else |
| { |
| sal_uInt32 c = *pBegin++; |
| switch (c) |
| { |
| case 0x0D: // CR |
| if (pBegin != pEnd && *pBegin == 0x0A) // LF |
| if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1])) |
| { |
| ++rLength; |
| rModify = true; |
| pBegin += 2; |
| } |
| else |
| { |
| rLength += 3; |
| rModify = true; |
| ++pBegin; |
| } |
| else |
| ++rLength; |
| break; |
| |
| case '\\': |
| ++rLength; |
| if (pBegin != pEnd) |
| { |
| if (startsWithLineBreak(pBegin, pEnd) |
| && (pEnd - pBegin < 3 |
| || !isWhiteSpace(pBegin[2]))) |
| { |
| rLength += 3; |
| rModify = true; |
| pBegin += 2; |
| } |
| else |
| ++pBegin; |
| } |
| break; |
| |
| default: |
| ++rLength; |
| if (!isUSASCII(c)) |
| rModify = true; |
| break; |
| } |
| } |
| } |
| return pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| sal_Char const * INetMIME::scanParameters(sal_Char const * pBegin, |
| sal_Char const * pEnd, |
| INetContentTypeParameterList * |
| pParameters) |
| { |
| ParameterList aList; |
| sal_Char const * pParameterBegin = pBegin; |
| for (sal_Char const * p = pParameterBegin;; pParameterBegin = p) |
| { |
| pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd); |
| if (pParameterBegin == pEnd || *pParameterBegin != ';') |
| break; |
| p = pParameterBegin + 1; |
| |
| sal_Char const * pAttributeBegin = skipLinearWhiteSpaceComment(p, |
| pEnd); |
| p = pAttributeBegin; |
| bool bDowncaseAttribute = false; |
| while (p != pEnd && isTokenChar(*p) && *p != '*') |
| { |
| bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p); |
| ++p; |
| } |
| if (p == pAttributeBegin) |
| break; |
| ByteString aAttribute( |
| pAttributeBegin, static_cast< xub_StrLen >(p - pAttributeBegin)); |
| if (bDowncaseAttribute) |
| aAttribute.ToLowerAscii(); |
| |
| sal_uInt32 nSection = 0; |
| if (p != pEnd && *p == '*') |
| { |
| ++p; |
| if (p != pEnd && isDigit(*p) |
| && !scanUnsigned(p, pEnd, false, nSection)) |
| break; |
| } |
| |
| bool bPresent; |
| Parameter ** pPos = aList.find(aAttribute, nSection, bPresent); |
| if (bPresent) |
| break; |
| |
| bool bExtended = false; |
| if (p != pEnd && *p == '*') |
| { |
| ++p; |
| bExtended = true; |
| } |
| |
| p = skipLinearWhiteSpaceComment(p, pEnd); |
| |
| if (p == pEnd || *p != '=') |
| break; |
| |
| p = skipLinearWhiteSpaceComment(p + 1, pEnd); |
| |
| ByteString aCharset; |
| ByteString aLanguage; |
| ByteString aValue; |
| if (bExtended) |
| { |
| if (nSection == 0) |
| { |
| sal_Char const * pCharsetBegin = p; |
| bool bDowncaseCharset = false; |
| while (p != pEnd && isTokenChar(*p) && *p != '\'') |
| { |
| bDowncaseCharset = bDowncaseCharset || isUpperCase(*p); |
| ++p; |
| } |
| if (p == pCharsetBegin) |
| break; |
| if (pParameters) |
| { |
| aCharset = ByteString( |
| pCharsetBegin, |
| static_cast< xub_StrLen >(p - pCharsetBegin)); |
| if (bDowncaseCharset) |
| aCharset.ToLowerAscii(); |
| } |
| |
| if (p == pEnd || *p != '\'') |
| break; |
| ++p; |
| |
| sal_Char const * pLanguageBegin = p; |
| bool bDowncaseLanguage = false; |
| int nLetters = 0; |
| for (; p != pEnd; ++p) |
| if (isAlpha(*p)) |
| { |
| if (++nLetters > 8) |
| break; |
| bDowncaseLanguage = bDowncaseLanguage |
| || isUpperCase(*p); |
| } |
| else if (*p == '-') |
| { |
| if (nLetters == 0) |
| break; |
| nLetters = 0; |
| } |
| else |
| break; |
| if (nLetters == 0 || nLetters > 8) |
| break; |
| if (pParameters) |
| { |
| aLanguage = ByteString( |
| pLanguageBegin, |
| static_cast< xub_StrLen >(p - pLanguageBegin)); |
| if (bDowncaseLanguage) |
| aLanguage.ToLowerAscii(); |
| } |
| |
| if (p == pEnd || *p != '\'') |
| break; |
| ++p; |
| } |
| if (pParameters) |
| while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p))) |
| { |
| if (*p == '%') |
| { |
| if (p + 2 < pEnd) |
| { |
| int nWeight1 = getHexWeight(p[1]); |
| int nWeight2 = getHexWeight(p[2]); |
| if (nWeight1 >= 0 && nWeight2 >= 0) |
| { |
| aValue += sal_Char(nWeight1 << 4 | nWeight2); |
| p += 3; |
| continue; |
| } |
| } |
| } |
| aValue += *p++; |
| } |
| else |
| while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p))) |
| ++p; |
| } |
| else if (p != pEnd && *p == '"') |
| if (pParameters) |
| { |
| bool bInvalid = false; |
| for (++p;;) |
| { |
| if (p == pEnd) |
| { |
| bInvalid = true; |
| break; |
| } |
| else if (*p == '"') |
| { |
| ++p; |
| break; |
| } |
| else if (*p == 0x0D) // CR |
| { |
| if (pEnd - p < 3 || p[1] != 0x0A // LF |
| || !isWhiteSpace(p[2])) |
| { |
| bInvalid = true; |
| break; |
| } |
| p += 2; |
| } |
| else if (*p == '\\' && ++p == pEnd) |
| { |
| bInvalid = true; |
| break; |
| } |
| aValue += *p++; |
| } |
| if (bInvalid) |
| break; |
| } |
| else |
| { |
| sal_Char const * pStringEnd = skipQuotedString(p, pEnd); |
| if (p == pStringEnd) |
| break; |
| p = pStringEnd; |
| } |
| else |
| { |
| sal_Char const * pTokenBegin = p; |
| while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p))) |
| ++p; |
| if (p == pTokenBegin) |
| break; |
| if (pParameters) |
| aValue = ByteString( |
| pTokenBegin, static_cast< xub_StrLen >(p - pTokenBegin)); |
| } |
| |
| *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue, |
| nSection, bExtended); |
| } |
| return parseParameters(aList, pParameters) ? pParameterBegin : pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| sal_Unicode const * INetMIME::scanParameters(sal_Unicode const * pBegin, |
| sal_Unicode const * pEnd, |
| INetContentTypeParameterList * |
| pParameters) |
| { |
| ParameterList aList; |
| sal_Unicode const * pParameterBegin = pBegin; |
| for (sal_Unicode const * p = pParameterBegin;; pParameterBegin = p) |
| { |
| pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd); |
| if (pParameterBegin == pEnd || *pParameterBegin != ';') |
| break; |
| p = pParameterBegin + 1; |
| |
| sal_Unicode const * pAttributeBegin |
| = skipLinearWhiteSpaceComment(p, pEnd); |
| p = pAttributeBegin; |
| bool bDowncaseAttribute = false; |
| while (p != pEnd && isTokenChar(*p) && *p != '*') |
| { |
| bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p); |
| ++p; |
| } |
| if (p == pAttributeBegin) |
| break; |
| ByteString aAttribute = ByteString( |
| pAttributeBegin, static_cast< xub_StrLen >(p - pAttributeBegin), |
| RTL_TEXTENCODING_ASCII_US); |
| if (bDowncaseAttribute) |
| aAttribute.ToLowerAscii(); |
| |
| sal_uInt32 nSection = 0; |
| if (p != pEnd && *p == '*') |
| { |
| ++p; |
| if (p != pEnd && isDigit(*p) |
| && !scanUnsigned(p, pEnd, false, nSection)) |
| break; |
| } |
| |
| bool bPresent; |
| Parameter ** pPos = aList.find(aAttribute, nSection, bPresent); |
| if (bPresent) |
| break; |
| |
| bool bExtended = false; |
| if (p != pEnd && *p == '*') |
| { |
| ++p; |
| bExtended = true; |
| } |
| |
| p = skipLinearWhiteSpaceComment(p, pEnd); |
| |
| if (p == pEnd || *p != '=') |
| break; |
| |
| p = skipLinearWhiteSpaceComment(p + 1, pEnd); |
| |
| ByteString aCharset; |
| ByteString aLanguage; |
| ByteString aValue; |
| if (bExtended) |
| { |
| if (nSection == 0) |
| { |
| sal_Unicode const * pCharsetBegin = p; |
| bool bDowncaseCharset = false; |
| while (p != pEnd && isTokenChar(*p) && *p != '\'') |
| { |
| bDowncaseCharset = bDowncaseCharset || isUpperCase(*p); |
| ++p; |
| } |
| if (p == pCharsetBegin) |
| break; |
| if (pParameters) |
| { |
| aCharset = ByteString( |
| pCharsetBegin, |
| static_cast< xub_StrLen >(p - pCharsetBegin), |
| RTL_TEXTENCODING_ASCII_US); |
| if (bDowncaseCharset) |
| aCharset.ToLowerAscii(); |
| } |
| |
| if (p == pEnd || *p != '\'') |
| break; |
| ++p; |
| |
| sal_Unicode const * pLanguageBegin = p; |
| bool bDowncaseLanguage = false; |
| int nLetters = 0; |
| for (; p != pEnd; ++p) |
| if (isAlpha(*p)) |
| { |
| if (++nLetters > 8) |
| break; |
| bDowncaseLanguage = bDowncaseLanguage |
| || isUpperCase(*p); |
| } |
| else if (*p == '-') |
| { |
| if (nLetters == 0) |
| break; |
| nLetters = 0; |
| } |
| else |
| break; |
| if (nLetters == 0 || nLetters > 8) |
| break; |
| if (pParameters) |
| { |
| aLanguage = ByteString( |
| pLanguageBegin, |
| static_cast< xub_StrLen >(p - pLanguageBegin), |
| RTL_TEXTENCODING_ASCII_US); |
| if (bDowncaseLanguage) |
| aLanguage.ToLowerAscii(); |
| } |
| |
| if (p == pEnd || *p != '\'') |
| break; |
| ++p; |
| } |
| if (pParameters) |
| { |
| INetMIMEStringOutputSink |
| aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT); |
| while (p != pEnd) |
| { |
| sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd); |
| if (isUSASCII(nChar) && !isTokenChar(nChar)) |
| break; |
| if (nChar == '%' && p + 1 < pEnd) |
| { |
| int nWeight1 = getHexWeight(p[0]); |
| int nWeight2 = getHexWeight(p[1]); |
| if (nWeight1 >= 0 && nWeight2 >= 0) |
| { |
| aSink << sal_Char(nWeight1 << 4 | nWeight2); |
| p += 2; |
| continue; |
| } |
| } |
| INetMIME::writeUTF8(aSink, nChar); |
| } |
| aValue = aSink.takeBuffer(); |
| } |
| else |
| while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p))) |
| ++p; |
| } |
| else if (p != pEnd && *p == '"') |
| if (pParameters) |
| { |
| INetMIMEStringOutputSink |
| aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT); |
| bool bInvalid = false; |
| for (++p;;) |
| { |
| if (p == pEnd) |
| { |
| bInvalid = true; |
| break; |
| } |
| sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd); |
| if (nChar == '"') |
| break; |
| else if (nChar == 0x0D) // CR |
| { |
| if (pEnd - p < 2 || *p++ != 0x0A // LF |
| || !isWhiteSpace(*p)) |
| { |
| bInvalid = true; |
| break; |
| } |
| nChar = sal_uChar(*p++); |
| } |
| else if (nChar == '\\') |
| { |
| if (p == pEnd) |
| { |
| bInvalid = true; |
| break; |
| } |
| nChar = INetMIME::getUTF32Character(p, pEnd); |
| } |
| INetMIME::writeUTF8(aSink, nChar); |
| } |
| if (bInvalid) |
| break; |
| aValue = aSink.takeBuffer(); |
| } |
| else |
| { |
| sal_Unicode const * pStringEnd = skipQuotedString(p, pEnd); |
| if (p == pStringEnd) |
| break; |
| p = pStringEnd; |
| } |
| else |
| { |
| sal_Unicode const * pTokenBegin = p; |
| while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p))) |
| ++p; |
| if (p == pTokenBegin) |
| break; |
| if (pParameters) |
| aValue = ByteString( |
| pTokenBegin, static_cast< xub_StrLen >(p - pTokenBegin), |
| RTL_TEXTENCODING_UTF8); |
| } |
| |
| *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue, |
| nSection, bExtended); |
| } |
| return parseParameters(aList, pParameters) ? pParameterBegin : pBegin; |
| } |
| |
| //============================================================================ |
| // static |
| const sal_Char * INetMIME::getCharsetName(rtl_TextEncoding eEncoding) |
| { |
| if (rtl_isOctetTextEncoding(eEncoding)) |
| { |
| char const * p = rtl_getMimeCharsetFromTextEncoding(eEncoding); |
| DBG_ASSERT(p, "INetMIME::getCharsetName(): Unsupported encoding"); |
| return p; |
| } |
| else |
| switch (eEncoding) |
| { |
| case RTL_TEXTENCODING_UCS4: |
| return "ISO-10646-UCS-4"; |
| |
| case RTL_TEXTENCODING_UCS2: |
| return "ISO-10646-UCS-2"; |
| |
| default: |
| DBG_ERROR("INetMIME::getCharsetName(): Unsupported encoding"); |
| return 0; |
| } |
| } |
| |
| //============================================================================ |
| namespace unnamed_tools_inetmime { |
| |
| struct EncodingEntry |
| { |
| sal_Char const * m_aName; |
| rtl_TextEncoding m_eEncoding; |
| }; |
| |
| //============================================================================ |
| // The source for the following table is <ftp://ftp.iana.org/in-notes/iana/ |
| // assignments/character-sets> as of Jan, 21 2000 12:46:00, unless otherwise |
| // noted: |
| EncodingEntry const aEncodingMap[] |
| = { { "US-ASCII", RTL_TEXTENCODING_ASCII_US }, |
| { "ANSI_X3.4-1968", RTL_TEXTENCODING_ASCII_US }, |
| { "ISO-IR-6", RTL_TEXTENCODING_ASCII_US }, |
| { "ANSI_X3.4-1986", RTL_TEXTENCODING_ASCII_US }, |
| { "ISO_646.IRV:1991", RTL_TEXTENCODING_ASCII_US }, |
| { "ASCII", RTL_TEXTENCODING_ASCII_US }, |
| { "ISO646-US", RTL_TEXTENCODING_ASCII_US }, |
| { "US", RTL_TEXTENCODING_ASCII_US }, |
| { "IBM367", RTL_TEXTENCODING_ASCII_US }, |
| { "CP367", RTL_TEXTENCODING_ASCII_US }, |
| { "CSASCII", RTL_TEXTENCODING_ASCII_US }, |
| { "ISO-8859-1", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "ISO_8859-1:1987", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "ISO-IR-100", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "ISO_8859-1", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "LATIN1", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "L1", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "IBM819", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "CP819", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "CSISOLATIN1", RTL_TEXTENCODING_ISO_8859_1 }, |
| { "ISO-8859-2", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "ISO_8859-2:1987", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "ISO-IR-101", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "ISO_8859-2", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "LATIN2", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "L2", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "CSISOLATIN2", RTL_TEXTENCODING_ISO_8859_2 }, |
| { "ISO-8859-3", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "ISO_8859-3:1988", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "ISO-IR-109", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "ISO_8859-3", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "LATIN3", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "L3", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "CSISOLATIN3", RTL_TEXTENCODING_ISO_8859_3 }, |
| { "ISO-8859-4", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "ISO_8859-4:1988", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "ISO-IR-110", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "ISO_8859-4", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "LATIN4", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "L4", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "CSISOLATIN4", RTL_TEXTENCODING_ISO_8859_4 }, |
| { "ISO-8859-5", RTL_TEXTENCODING_ISO_8859_5 }, |
| { "ISO_8859-5:1988", RTL_TEXTENCODING_ISO_8859_5 }, |
| { "ISO-IR-144", RTL_TEXTENCODING_ISO_8859_5 }, |
| { "ISO_8859-5", RTL_TEXTENCODING_ISO_8859_5 }, |
| { "CYRILLIC", RTL_TEXTENCODING_ISO_8859_5 }, |
| { "CSISOLATINCYRILLIC", RTL_TEXTENCODING_ISO_8859_5 }, |
| { "ISO-8859-6", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ISO_8859-6:1987", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ISO-IR-127", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ISO_8859-6", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ECMA-114", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ASMO-708", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ARABIC", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "CSISOLATINARABIC", RTL_TEXTENCODING_ISO_8859_6 }, |
| { "ISO-8859-7", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "ISO_8859-7:1987", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "ISO-IR-126", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "ISO_8859-7", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "ELOT_928", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "ECMA-118", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "GREEK", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "GREEK8", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "CSISOLATINGREEK", RTL_TEXTENCODING_ISO_8859_7 }, |
| { "ISO-8859-8", RTL_TEXTENCODING_ISO_8859_8 }, |
| { "ISO_8859-8:1988", RTL_TEXTENCODING_ISO_8859_8 }, |
| { "ISO-IR-138", RTL_TEXTENCODING_ISO_8859_8 }, |
| { "ISO_8859-8", RTL_TEXTENCODING_ISO_8859_8 }, |
| { "HEBREW", RTL_TEXTENCODING_ISO_8859_8 }, |
| { "CSISOLATINHEBREW", RTL_TEXTENCODING_ISO_8859_8 }, |
| { "ISO-8859-9", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "ISO_8859-9:1989", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "ISO-IR-148", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "ISO_8859-9", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "LATIN5", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "L5", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "CSISOLATIN5", RTL_TEXTENCODING_ISO_8859_9 }, |
| { "ISO-8859-14", RTL_TEXTENCODING_ISO_8859_14 }, // RFC 2047 |
| { "ISO_8859-15", RTL_TEXTENCODING_ISO_8859_15 }, |
| { "ISO-8859-15", RTL_TEXTENCODING_ISO_8859_15 }, // RFC 2047 |
| { "MACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN }, |
| { "MAC", RTL_TEXTENCODING_APPLE_ROMAN }, |
| { "CSMACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN }, |
| { "IBM437", RTL_TEXTENCODING_IBM_437 }, |
| { "CP437", RTL_TEXTENCODING_IBM_437 }, |
| { "437", RTL_TEXTENCODING_IBM_437 }, |
| { "CSPC8CODEPAGE437", RTL_TEXTENCODING_IBM_437 }, |
| { "IBM850", RTL_TEXTENCODING_IBM_850 }, |
| { "CP850", RTL_TEXTENCODING_IBM_850 }, |
| { "850", RTL_TEXTENCODING_IBM_850 }, |
| { "CSPC850MULTILINGUAL", RTL_TEXTENCODING_IBM_850 }, |
| { "IBM860", RTL_TEXTENCODING_IBM_860 }, |
| { "CP860", RTL_TEXTENCODING_IBM_860 }, |
| { "860", RTL_TEXTENCODING_IBM_860 }, |
| { "CSIBM860", RTL_TEXTENCODING_IBM_860 }, |
| { "IBM861", RTL_TEXTENCODING_IBM_861 }, |
| { "CP861", RTL_TEXTENCODING_IBM_861 }, |
| { "861", RTL_TEXTENCODING_IBM_861 }, |
| { "CP-IS", RTL_TEXTENCODING_IBM_861 }, |
| { "CSIBM861", RTL_TEXTENCODING_IBM_861 }, |
| { "IBM863", RTL_TEXTENCODING_IBM_863 }, |
| { "CP863", RTL_TEXTENCODING_IBM_863 }, |
| { "863", RTL_TEXTENCODING_IBM_863 }, |
| { "CSIBM863", RTL_TEXTENCODING_IBM_863 }, |
| { "IBM865", RTL_TEXTENCODING_IBM_865 }, |
| { "CP865", RTL_TEXTENCODING_IBM_865 }, |
| { "865", RTL_TEXTENCODING_IBM_865 }, |
| { "CSIBM865", RTL_TEXTENCODING_IBM_865 }, |
| { "IBM775", RTL_TEXTENCODING_IBM_775 }, |
| { "CP775", RTL_TEXTENCODING_IBM_775 }, |
| { "CSPC775BALTIC", RTL_TEXTENCODING_IBM_775 }, |
| { "IBM852", RTL_TEXTENCODING_IBM_852 }, |
| { "CP852", RTL_TEXTENCODING_IBM_852 }, |
| { "852", RTL_TEXTENCODING_IBM_852 }, |
| { "CSPCP852", RTL_TEXTENCODING_IBM_852 }, |
| { "IBM855", RTL_TEXTENCODING_IBM_855 }, |
| { "CP855", RTL_TEXTENCODING_IBM_855 }, |
| { "855", RTL_TEXTENCODING_IBM_855 }, |
| { "CSIBM855", RTL_TEXTENCODING_IBM_855 }, |
| { "IBM857", RTL_TEXTENCODING_IBM_857 }, |
| { "CP857", RTL_TEXTENCODING_IBM_857 }, |
| { "857", RTL_TEXTENCODING_IBM_857 }, |
| { "CSIBM857", RTL_TEXTENCODING_IBM_857 }, |
| { "IBM862", RTL_TEXTENCODING_IBM_862 }, |
| { "CP862", RTL_TEXTENCODING_IBM_862 }, |
| { "862", RTL_TEXTENCODING_IBM_862 }, |
| { "CSPC862LATINHEBREW", RTL_TEXTENCODING_IBM_862 }, |
| { "IBM864", RTL_TEXTENCODING_IBM_864 }, |
| { "CP864", RTL_TEXTENCODING_IBM_864 }, |
| { "CSIBM864", RTL_TEXTENCODING_IBM_864 }, |
| { "IBM866", RTL_TEXTENCODING_IBM_866 }, |
| { "CP866", RTL_TEXTENCODING_IBM_866 }, |
| { "866", RTL_TEXTENCODING_IBM_866 }, |
| { "CSIBM866", RTL_TEXTENCODING_IBM_866 }, |
| { "IBM869", RTL_TEXTENCODING_IBM_869 }, |
| { "CP869", RTL_TEXTENCODING_IBM_869 }, |
| { "869", RTL_TEXTENCODING_IBM_869 }, |
| { "CP-GR", RTL_TEXTENCODING_IBM_869 }, |
| { "CSIBM869", RTL_TEXTENCODING_IBM_869 }, |
| { "WINDOWS-1250", RTL_TEXTENCODING_MS_1250 }, |
| { "WINDOWS-1251", RTL_TEXTENCODING_MS_1251 }, |
| { "WINDOWS-1253", RTL_TEXTENCODING_MS_1253 }, |
| { "WINDOWS-1254", RTL_TEXTENCODING_MS_1254 }, |
| { "WINDOWS-1255", RTL_TEXTENCODING_MS_1255 }, |
| { "WINDOWS-1256", RTL_TEXTENCODING_MS_1256 }, |
| { "WINDOWS-1257", RTL_TEXTENCODING_MS_1257 }, |
| { "WINDOWS-1258", RTL_TEXTENCODING_MS_1258 }, |
| { "SHIFT_JIS", RTL_TEXTENCODING_SHIFT_JIS }, |
| { "MS_KANJI", RTL_TEXTENCODING_SHIFT_JIS }, |
| { "CSSHIFTJIS", RTL_TEXTENCODING_SHIFT_JIS }, |
| { "GB2312", RTL_TEXTENCODING_GB_2312 }, |
| { "CSGB2312", RTL_TEXTENCODING_GB_2312 }, |
| { "BIG5", RTL_TEXTENCODING_BIG5 }, |
| { "CSBIG5", RTL_TEXTENCODING_BIG5 }, |
| { "EUC-JP", RTL_TEXTENCODING_EUC_JP }, |
| { "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", |
| RTL_TEXTENCODING_EUC_JP }, |
| { "CSEUCPKDFMTJAPANESE", RTL_TEXTENCODING_EUC_JP }, |
| { "ISO-2022-JP", RTL_TEXTENCODING_ISO_2022_JP }, |
| { "CSISO2022JP", RTL_TEXTENCODING_ISO_2022_JP }, |
| { "ISO-2022-CN", RTL_TEXTENCODING_ISO_2022_CN }, |
| { "KOI8-R", RTL_TEXTENCODING_KOI8_R }, |
| { "CSKOI8R", RTL_TEXTENCODING_KOI8_R }, |
| { "UTF-7", RTL_TEXTENCODING_UTF7 }, |
| { "UTF-8", RTL_TEXTENCODING_UTF8 }, |
| { "ISO-8859-10", RTL_TEXTENCODING_ISO_8859_10 }, // RFC 2047 |
| { "ISO-8859-13", RTL_TEXTENCODING_ISO_8859_13 }, // RFC 2047 |
| { "EUC-KR", RTL_TEXTENCODING_EUC_KR }, |
| { "CSEUCKR", RTL_TEXTENCODING_EUC_KR }, |
| { "ISO-2022-KR", RTL_TEXTENCODING_ISO_2022_KR }, |
| { "CSISO2022KR", RTL_TEXTENCODING_ISO_2022_KR }, |
| { "ISO-10646-UCS-4", RTL_TEXTENCODING_UCS4 }, |
| { "CSUCS4", RTL_TEXTENCODING_UCS4 }, |
| { "ISO-10646-UCS-2", RTL_TEXTENCODING_UCS2 }, |
| { "CSUNICODE", RTL_TEXTENCODING_UCS2 } }; |
| |
| //============================================================================ |
| template< typename T > |
| inline rtl_TextEncoding getCharsetEncoding_Impl(T const * pBegin, |
| T const * pEnd) |
| { |
| for (sal_Size i = 0; i < sizeof aEncodingMap / sizeof (EncodingEntry); |
| ++i) |
| if (INetMIME::equalIgnoreCase(pBegin, pEnd, aEncodingMap[i].m_aName)) |
| return aEncodingMap[i].m_eEncoding; |
| return RTL_TEXTENCODING_DONTKNOW; |
| } |
| |
| } |
| |
| //============================================================================ |
| // static |
| rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Char const * pBegin, |
| sal_Char const * pEnd) |
| { |
| return getCharsetEncoding_Impl(pBegin, pEnd); |
| } |
| |
| //============================================================================ |
| // static |
| rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Unicode const * pBegin, |
| sal_Unicode const * pEnd) |
| { |
| return getCharsetEncoding_Impl(pBegin, pEnd); |
| } |
| |
| //============================================================================ |
| // static |
| INetMIMECharsetList_Impl * |
| INetMIME::createPreferredCharsetList(rtl_TextEncoding eEncoding) |
| { |
| static const sal_uInt32 aUSASCIIRanges[] = { 0, 0x7F, sal_uInt32(-1) }; |
| |
| static const sal_uInt32 aISO88591Ranges[] = { 0, 0xFF, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88592Ranges[] |
| = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0, |
| 0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, |
| 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xCE, 0xD3, 0xD4, 0xD6, 0xD7, |
| 0xDA, 0xDA, 0xDC, 0xDD, 0xDF, 0xDF, 0xE1, 0xE2, 0xE4, 0xE4, |
| 0xE7, 0xE7, 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF3, 0xF4, |
| 0xF6, 0xF7, 0xFA, 0xFA, 0xFC, 0xFD, 0x102, 0x107, 0x10C, 0x111, |
| 0x118, 0x11B, 0x139, 0x13A, 0x13D, 0x13E, 0x141, 0x144, |
| 0x147, 0x148, 0x150, 0x151, 0x154, 0x155, 0x158, 0x15B, |
| 0x15E, 0x165, 0x16E, 0x171, 0x179, 0x17E, 0x2C7, 0x2C7, |
| 0x2D8, 0x2D9, 0x2DB, 0x2DB, 0x2DD, 0x2DD, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-2.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88593Ranges[] |
| = { 0, 0xA0, 0xA3, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0, |
| 0xB2, 0xB5, 0xB7, 0xB8, 0xBD, 0xBD, 0xC0, 0xC2, 0xC4, 0xC4, |
| 0xC7, 0xCF, 0xD1, 0xD4, 0xD6, 0xD7, 0xD9, 0xDC, 0xDF, 0xE2, |
| 0xE4, 0xE4, 0xE7, 0xEF, 0xF1, 0xF4, 0xF6, 0xF7, 0xF9, 0xFC, |
| 0x108, 0x10B, 0x11C, 0x121, 0x124, 0x127, 0x130, 0x131, |
| 0x134, 0x135, 0x15C, 0x15F, 0x16C, 0x16D, 0x17B, 0x17C, |
| 0x2D8, 0x2D9, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-3.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88594Ranges[] |
| = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xAF, 0xB0, |
| 0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB, |
| 0xCD, 0xCE, 0xD4, 0xD8, 0xDA, 0xDC, 0xDF, 0xDF, 0xE1, 0xE6, |
| 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF4, 0xF8, 0xFA, 0xFC, |
| 0x100, 0x101, 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113, |
| 0x116, 0x119, 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F, |
| 0x136, 0x138, 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D, |
| 0x156, 0x157, 0x160, 0x161, 0x166, 0x16B, 0x172, 0x173, |
| 0x17D, 0x17E, 0x2C7, 0x2C7, 0x2D9, 0x2D9, 0x2DB, 0x2DB, |
| sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-4.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88595Ranges[] |
| = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0x401, 0x40C, 0x40E, 0x44F, |
| 0x451, 0x45C, 0x45E, 0x45F, 0x2116, 0x2116, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-5.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88596Ranges[] |
| = { 0, 0xA0, 0xA4, 0xA4, 0xAD, 0xAD, 0x60C, 0x60C, 0x61B, 0x61B, |
| 0x61F, 0x61F, 0x621, 0x63A, 0x640, 0x652, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-6.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88597Ranges[] |
| = { 0, 0xA0, 0xA3, 0xA3, 0xA6, 0xA9, 0xAB, 0xAD, 0xB0, 0xB3, |
| 0xB7, 0xB7, 0xBB, 0xBB, 0xBD, 0xBD, 0x384, 0x386, 0x388, 0x38A, |
| 0x38C, 0x38C, 0x38E, 0x3A1, 0x3A3, 0x3CE, 0x2015, 0x2015, |
| 0x2018, 0x2019, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-7.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO88598Ranges[] |
| = { 0, 0xA0, 0xA2, 0xA9, 0xAB, 0xB9, 0xBB, 0xBE, 0xD7, 0xD7, |
| 0xF7, 0xF7, 0x5D0, 0x5EA, 0x200E, 0x200F, 0x2017, 0x2017, |
| sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-8.TXT> version |
| // 1.1 of 2000-Jan-03 |
| |
| static const sal_uInt32 aISO88599Ranges[] |
| = { 0, 0xCF, 0xD1, 0xDC, 0xDF, 0xEF, 0xF1, 0xFC, 0xFF, 0xFF, |
| 0x11E, 0x11F, 0x130, 0x131, 0x15E, 0x15F, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-9.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO885910Ranges[] |
| = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0xB0, 0xB0, 0xB7, 0xB7, |
| 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xD0, 0xD3, 0xD6, |
| 0xD8, 0xD8, 0xDA, 0xDF, 0xE1, 0xE6, 0xE9, 0xE9, 0xEB, 0xEB, |
| 0xED, 0xF0, 0xF3, 0xF6, 0xF8, 0xF8, 0xFA, 0xFE, 0x100, 0x101, |
| 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113, 0x116, 0x119, |
| 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F, 0x136, 0x138, |
| 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D, 0x160, 0x161, |
| 0x166, 0x16B, 0x172, 0x173, 0x17D, 0x17E, 0x2015, 0x2015, |
| sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-10.TXT> version |
| // 1.1 of 1999 October 11 |
| |
| static const sal_uInt32 aISO885913Ranges[] |
| = { 0, 0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA9, 0xA9, 0xAB, 0xAE, |
| 0xB0, 0xB3, 0xB5, 0xB7, 0xB9, 0xB9, 0xBB, 0xBE, 0xC4, 0xC6, |
| 0xC9, 0xC9, 0xD3, 0xD3, 0xD5, 0xD8, 0xDC, 0xDC, 0xDF, 0xDF, |
| 0xE4, 0xE6, 0xE9, 0xE9, 0xF3, 0xF3, 0xF5, 0xF8, 0xFC, 0xFC, |
| 0x100, 0x101, 0x104, 0x107, 0x10C, 0x10D, 0x112, 0x113, |
| 0x116, 0x119, 0x122, 0x123, 0x12A, 0x12B, 0x12E, 0x12F, |
| 0x136, 0x137, 0x13B, 0x13C, 0x141, 0x146, 0x14C, 0x14D, |
| 0x156, 0x157, 0x15A, 0x15B, 0x160, 0x161, 0x16A, 0x16B, |
| 0x172, 0x173, 0x179, 0x17E, 0x2019, 0x2019, 0x201C, 0x201E, |
| sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-13.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO885914Ranges[] |
| = { 0, 0xA0, 0xA3, 0xA3, 0xA7, 0xA7, 0xA9, 0xA9, 0xAD, 0xAE, |
| 0xB6, 0xB6, 0xC0, 0xCF, 0xD1, 0xD6, 0xD8, 0xDD, 0xDF, 0xEF, |
| 0xF1, 0xF6, 0xF8, 0xFD, 0xFF, 0xFF, 0x10A, 0x10B, 0x120, 0x121, |
| 0x174, 0x178, 0x1E02, 0x1E03, 0x1E0A, 0x1E0B, 0x1E1E, 0x1E1F, |
| 0x1E40, 0x1E41, 0x1E56, 0x1E57, 0x1E60, 0x1E61, 0x1E6A, 0x1E6B, |
| 0x1E80, 0x1E85, 0x1EF2, 0x1EF3, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-14.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aISO885915Ranges[] |
| = { 0, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xB3, 0xB5, 0xB7, |
| 0xB9, 0xBB, 0xBF, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178, |
| 0x17D, 0x17E, 0x20AC, 0x20AC, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-15.TXT> version |
| // 1.0 of 1999 July 27 |
| |
| static const sal_uInt32 aKOI8RRanges[] |
| = { 0, 0x7F, 0xA0, 0xA0, 0xA9, 0xA9, 0xB0, 0xB0, 0xB2, 0xB2, |
| 0xB7, 0xB7, 0xF7, 0xF7, 0x401, 0x401, 0x410, 0x44F, 0x451, 0x451, |
| 0x2219, 0x221A, 0x2248, 0x2248, 0x2264, 0x2265, 0x2320, 0x2321, |
| 0x2500, 0x2500, 0x2502, 0x2502, 0x250C, 0x250C, 0x2510, 0x2510, |
| 0x2514, 0x2514, 0x2518, 0x2518, 0x251C, 0x251C, 0x2524, 0x2524, |
| 0x252C, 0x252C, 0x2534, 0x2534, 0x253C, 0x253C, 0x2550, 0x256C, |
| 0x2580, 0x2580, 0x2584, 0x2584, 0x2588, 0x2588, 0x258C, 0x258C, |
| 0x2590, 0x2593, 0x25A0, 0x25A0, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT> |
| // version 1.0 of 18 August 1999 |
| |
| #if defined WNT |
| static const sal_uInt32 aWindows1252Ranges[] |
| = { 0, 0x7F, 0xA0, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178, |
| 0x17D, 0x17E, 0x192, 0x192, 0x2C6, 0x2C6, 0x2DC, 0x2DC, |
| 0x2013, 0x2014, 0x2018, 0x201A, 0x201C, 0x201E, 0x2020, 0x2022, |
| 0x2026, 0x2026, 0x2030, 0x2030, 0x2039, 0x203A, 0x20AC, 0x20AC, |
| 0x2122, 0x2122, sal_uInt32(-1) }; |
| // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/ |
| // CP1252.TXT> version 2.01 of 04/15/98 |
| #endif // WNT |
| |
| INetMIMECharsetList_Impl * pList = new INetMIMECharsetList_Impl; |
| switch (eEncoding) |
| { |
| case RTL_TEXTENCODING_MS_1252: |
| #if defined WNT |
| pList->prepend(Charset(RTL_TEXTENCODING_MS_1252, |
| aWindows1252Ranges)); |
| #endif // WNT |
| case RTL_TEXTENCODING_ISO_8859_1: |
| case RTL_TEXTENCODING_UTF7: |
| case RTL_TEXTENCODING_UTF8: |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_2: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2, |
| aISO88592Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_3: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_3, |
| aISO88593Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_4: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4, |
| aISO88594Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_5: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5, |
| aISO88595Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_6: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6, |
| aISO88596Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_7: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7, |
| aISO88597Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_8: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8, |
| aISO88598Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_9: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9, |
| aISO88599Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_10: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_10, |
| aISO885910Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_13: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_13, |
| aISO885913Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_14: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_14, |
| aISO885914Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_ISO_8859_15: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_15, |
| aISO885915Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1250: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2, |
| aISO88592Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1251: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5, |
| aISO88595Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1253: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7, |
| aISO88597Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1254: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9, |
| aISO88599Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1255: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8, |
| aISO88598Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1256: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6, |
| aISO88596Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_MS_1257: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4, |
| aISO88594Ranges)); |
| break; |
| |
| case RTL_TEXTENCODING_KOI8_R: |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5, |
| aISO88595Ranges)); |
| pList->prepend(Charset(RTL_TEXTENCODING_KOI8_R, aKOI8RRanges)); |
| break; |
| |
| default: //@@@ more cases are missing! |
| DBG_ERROR("INetMIME::createPreferredCharsetList():" |
| " Unsupported encoding"); |
| break; |
| } |
| pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_1, aISO88591Ranges)); |
| pList->prepend(Charset(RTL_TEXTENCODING_ASCII_US, aUSASCIIRanges)); |
| return pList; |
| } |
| |
| //============================================================================ |
| // static |
| sal_Unicode * INetMIME::convertToUnicode(const sal_Char * pBegin, |
| const sal_Char * pEnd, |
| rtl_TextEncoding eEncoding, |
| sal_Size & rSize) |
| { |
| if (eEncoding == RTL_TEXTENCODING_DONTKNOW) |
| return 0; |
| rtl_TextToUnicodeConverter hConverter |
| = rtl_createTextToUnicodeConverter(eEncoding); |
| rtl_TextToUnicodeContext hContext |
| = rtl_createTextToUnicodeContext(hConverter); |
| sal_Unicode * pBuffer; |
| sal_uInt32 nInfo; |
| for (sal_Size nBufferSize = pEnd - pBegin;; |
| nBufferSize += nBufferSize / 3 + 1) |
| { |
| pBuffer = new sal_Unicode[nBufferSize]; |
| sal_Size nSrcCvtBytes; |
| rSize = rtl_convertTextToUnicode( |
| hConverter, hContext, pBegin, pEnd - pBegin, pBuffer, |
| nBufferSize, |
| RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
| | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
| | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR, |
| &nInfo, &nSrcCvtBytes); |
| if (nInfo != RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) |
| break; |
| delete[] pBuffer; |
| rtl_resetTextToUnicodeContext(hConverter, hContext); |
| } |
| rtl_destroyTextToUnicodeContext(hConverter, hContext); |
| rtl_destroyTextToUnicodeConverter(hConverter); |
| if (nInfo != 0) |
| { |
| delete[] pBuffer; |
| pBuffer = 0; |
| } |
| return pBuffer; |
| } |
| |
| //============================================================================ |
| // static |
| sal_Char * INetMIME::convertFromUnicode(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd, |
| rtl_TextEncoding eEncoding, |
| sal_Size & rSize) |
| { |
| if (eEncoding == RTL_TEXTENCODING_DONTKNOW) |
| return 0; |
| rtl_UnicodeToTextConverter hConverter |
| = rtl_createUnicodeToTextConverter(eEncoding); |
| rtl_UnicodeToTextContext hContext |
| = rtl_createUnicodeToTextContext(hConverter); |
| sal_Char * pBuffer; |
| sal_uInt32 nInfo; |
| for (sal_Size nBufferSize = pEnd - pBegin;; |
| nBufferSize += nBufferSize / 3 + 1) |
| { |
| pBuffer = new sal_Char[nBufferSize]; |
| sal_Size nSrcCvtBytes; |
| rSize = rtl_convertUnicodeToText( |
| hConverter, hContext, pBegin, pEnd - pBegin, pBuffer, |
| nBufferSize, |
| RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
| | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR |
| | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
| | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR, |
| &nInfo, &nSrcCvtBytes); |
| if (nInfo != RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL) |
| break; |
| delete[] pBuffer; |
| rtl_resetUnicodeToTextContext(hConverter, hContext); |
| } |
| rtl_destroyUnicodeToTextContext(hConverter, hContext); |
| rtl_destroyUnicodeToTextConverter(hConverter); |
| if (nInfo != 0) |
| { |
| delete[] pBuffer; |
| pBuffer = 0; |
| } |
| return pBuffer; |
| } |
| |
| //============================================================================ |
| // static |
| void INetMIME::writeUTF8(INetMIMEOutputSink & rSink, sal_uInt32 nChar) |
| { |
| // See RFC 2279 for a discussion of UTF-8. |
| DBG_ASSERT(nChar < 0x80000000, "INetMIME::writeUTF8(): Bad char"); |
| |
| if (nChar < 0x80) |
| rSink << sal_Char(nChar); |
| else if (nChar < 0x800) |
| rSink << sal_Char(nChar >> 6 | 0xC0) |
| << sal_Char((nChar & 0x3F) | 0x80); |
| else if (nChar < 0x10000) |
| rSink << sal_Char(nChar >> 12 | 0xE0) |
| << sal_Char((nChar >> 6 & 0x3F) | 0x80) |
| << sal_Char((nChar & 0x3F) | 0x80); |
| else if (nChar < 0x200000) |
| rSink << sal_Char(nChar >> 18 | 0xF0) |
| << sal_Char((nChar >> 12 & 0x3F) | 0x80) |
| << sal_Char((nChar >> 6 & 0x3F) | 0x80) |
| << sal_Char((nChar & 0x3F) | 0x80); |
| else if (nChar < 0x4000000) |
| rSink << sal_Char(nChar >> 24 | 0xF8) |
| << sal_Char((nChar >> 18 & 0x3F) | 0x80) |
| << sal_Char((nChar >> 12 & 0x3F) | 0x80) |
| << sal_Char((nChar >> 6 & 0x3F) | 0x80) |
| << sal_Char((nChar & 0x3F) | 0x80); |
| else |
| rSink << sal_Char(nChar >> 30 | 0xFC) |
| << sal_Char((nChar >> 24 & 0x3F) | 0x80) |
| << sal_Char((nChar >> 18 & 0x3F) | 0x80) |
| << sal_Char((nChar >> 12 & 0x3F) | 0x80) |
| << sal_Char((nChar >> 6 & 0x3F) | 0x80) |
| << sal_Char((nChar & 0x3F) | 0x80); |
| } |
| |
| //============================================================================ |
| // static |
| void INetMIME::writeUnsigned(INetMIMEOutputSink & rSink, sal_uInt32 nValue, |
| int nMinDigits) |
| { |
| sal_Char aBuffer[10]; |
| // max unsigned 32 bit value (4294967295) has 10 places |
| sal_Char * p = aBuffer; |
| for (; nValue > 0; nValue /= 10) |
| *p++ = sal_Char(getDigit(nValue % 10)); |
| nMinDigits -= p - aBuffer; |
| while (nMinDigits-- > 0) |
| rSink << '0'; |
| while (p != aBuffer) |
| rSink << *--p; |
| } |
| |
| //============================================================================ |
| // static |
| void INetMIME::writeDateTime(INetMIMEOutputSink & rSink, |
| const DateTime & rUTC) |
| { |
| static const sal_Char aDay[7][3] |
| = { { 'M', 'o', 'n' }, |
| { 'T', 'u', 'e' }, |
| { 'W', 'e', 'd' }, |
| { 'T', 'h', 'u' }, |
| { 'F', 'r', 'i' }, |
| { 'S', 'a', 't' }, |
| { 'S', 'u', 'n' } }; |
| const sal_Char * pTheDay = aDay[rUTC.GetDayOfWeek()]; |
| rSink.write(pTheDay, pTheDay + 3); |
| rSink << ", "; |
| writeUnsigned(rSink, rUTC.GetDay()); |
| rSink << ' '; |
| static const sal_Char aMonth[12][3] |
| = { { 'J', 'a', 'n' }, |
| { 'F', 'e', 'b' }, |
| { 'M', 'a', 'r' }, |
| { 'A', 'p', 'r' }, |
| { 'M', 'a', 'y' }, |
| { 'J', 'u', 'n' }, |
| { 'J', 'u', 'l' }, |
| { 'A', 'u', 'g' }, |
| { 'S', 'e', 'p' }, |
| { 'O', 'c', 't' }, |
| { 'N', 'o', 'v' }, |
| { 'D', 'e', 'c' } }; |
| const sal_Char * pTheMonth = aMonth[rUTC.GetMonth() - 1]; |
| rSink.write(pTheMonth, pTheMonth + 3); |
| rSink << ' '; |
| writeUnsigned(rSink, rUTC.GetYear()); |
| rSink << ' '; |
| writeUnsigned(rSink, rUTC.GetHour(), 2); |
| rSink << ':'; |
| writeUnsigned(rSink, rUTC.GetMin(), 2); |
| rSink << ':'; |
| writeUnsigned(rSink, rUTC.GetSec(), 2); |
| rSink << " +0000"; |
| } |
| |
| //============================================================================ |
| // static |
| void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink, |
| HeaderFieldType eType, |
| const ByteString & rBody, |
| rtl_TextEncoding ePreferredEncoding, |
| bool bInitialSpace) |
| { |
| writeHeaderFieldBody(rSink, eType, |
| UniString(rBody, RTL_TEXTENCODING_UTF8), |
| ePreferredEncoding, bInitialSpace); |
| } |
| |
| //============================================================================ |
| // static |
| void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink, |
| HeaderFieldType eType, |
| const UniString & rBody, |
| rtl_TextEncoding ePreferredEncoding, |
| bool bInitialSpace) |
| { |
| if (eType == HEADER_FIELD_TEXT) |
| { |
| INetMIMEEncodedWordOutputSink |
| aOutput(rSink, INetMIMEEncodedWordOutputSink::CONTEXT_TEXT, |
| bInitialSpace ? |
| INetMIMEEncodedWordOutputSink::SPACE_ALWAYS : |
| INetMIMEEncodedWordOutputSink::SPACE_NO, |
| ePreferredEncoding); |
| aOutput.write(rBody.GetBuffer(), rBody.GetBuffer() + rBody.Len()); |
| aOutput.flush(); |
| } |
| else |
| { |
| enum Brackets { BRACKETS_OUTSIDE, BRACKETS_OPENING, BRACKETS_INSIDE }; |
| Brackets eBrackets = BRACKETS_OUTSIDE; |
| |
| const sal_Unicode * pBodyPtr = rBody.GetBuffer(); |
| const sal_Unicode * pBodyEnd = pBodyPtr + rBody.Len(); |
| while (pBodyPtr != pBodyEnd) |
| switch (*pBodyPtr) |
| { |
| case '\t': |
| case ' ': |
| // A WSP adds to accumulated space: |
| bInitialSpace = true; |
| ++pBodyPtr; |
| break; |
| |
| case '(': |
| { |
| // Write a pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING) |
| { |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| eBrackets = BRACKETS_INSIDE; |
| } |
| |
| // Write the comment, introducing encoded-words where |
| // necessary: |
| int nLevel = 0; |
| INetMIMEEncodedWordOutputSink |
| aOutput( |
| rSink, |
| INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT, |
| INetMIMEEncodedWordOutputSink::SPACE_NO, |
| ePreferredEncoding); |
| while (pBodyPtr != pBodyEnd) |
| switch (*pBodyPtr) |
| { |
| case '(': |
| aOutput.flush(); |
| if (rSink.getColumn() |
| + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '('; |
| bInitialSpace = false; |
| ++nLevel; |
| ++pBodyPtr; |
| break; |
| |
| case ')': |
| aOutput.flush(); |
| if (rSink.getColumn() |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| rSink << ')'; |
| ++pBodyPtr; |
| if (--nLevel == 0) |
| goto comment_done; |
| break; |
| |
| case '\\': |
| if (++pBodyPtr == pBodyEnd) |
| break; |
| default: |
| aOutput << *pBodyPtr++; |
| break; |
| } |
| comment_done: |
| break; |
| } |
| |
| case '<': |
| // Write an already pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING) |
| { |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| } |
| |
| // Remember this '<' as pending, and open a bracketed |
| // block: |
| eBrackets = BRACKETS_OPENING; |
| ++pBodyPtr; |
| break; |
| |
| case '>': |
| // Write a pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING) |
| { |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| } |
| |
| // Write this '>', and close any bracketed block: |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '>'; |
| bInitialSpace = false; |
| eBrackets = BRACKETS_OUTSIDE; |
| ++pBodyPtr; |
| break; |
| |
| case ',': |
| case ':': |
| case ';': |
| case '\\': |
| case ']': |
| // Write a pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING) |
| { |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| eBrackets = BRACKETS_INSIDE; |
| } |
| |
| // Write this specials: |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << sal_Char(*pBodyPtr++); |
| bInitialSpace = false; |
| break; |
| |
| case '\x0D': // CR |
| // A <CRLF WSP> adds to accumulated space, a <CR> not |
| // followed by <LF WSP> starts 'junk': |
| if (startsWithLineFolding(pBodyPtr, pBodyEnd)) |
| { |
| bInitialSpace = true; |
| pBodyPtr += 3; |
| break; |
| } |
| default: |
| { |
| // The next token is either one of <"." / "@" / atom / |
| // quoted-string / domain-literal>, or it's 'junk'; if it |
| // is not 'junk', it is either a 'phrase' (i.e., it may |
| // contain encoded-words) or a 'non-phrase' (i.e., it may |
| // not contain encoded-words): |
| enum Entity { ENTITY_JUNK, ENTITY_NON_PHRASE, |
| ENTITY_PHRASE }; |
| Entity eEntity = ENTITY_JUNK; |
| switch (*pBodyPtr) |
| { |
| case '.': |
| case '@': |
| case '[': |
| // A token of <"." / "@" / domain-literal> always |
| // starts a 'non-phrase': |
| eEntity = ENTITY_NON_PHRASE; |
| break; |
| |
| default: |
| if (isUSASCII(*pBodyPtr) |
| && !isAtomChar(*pBodyPtr)) |
| { |
| eEntity = ENTITY_JUNK; |
| break; |
| } |
| case '"': |
| // A token of <atom / quoted-string> can either be |
| // a 'phrase' or a 'non-phrase': |
| switch (eType) |
| { |
| case HEADER_FIELD_STRUCTURED: |
| eEntity = ENTITY_NON_PHRASE; |
| break; |
| |
| case HEADER_FIELD_PHRASE: |
| eEntity = ENTITY_PHRASE; |
| break; |
| |
| case HEADER_FIELD_MESSAGE_ID: |
| // A 'phrase' if and only if outside any |
| // bracketed block: |
| eEntity |
| = eBrackets == BRACKETS_OUTSIDE ? |
| ENTITY_PHRASE : |
| ENTITY_NON_PHRASE; |
| break; |
| |
| case HEADER_FIELD_ADDRESS: |
| { |
| // A 'non-phrase' if and only if, after |
| // skipping this token and any following |
| // <linear-white-space> and <comment>s, |
| // there is no token left, or the next |
| // token is any of <"." / "@" / ">" / "," |
| // / ";">, or the next token is <":"> and |
| // is within a bracketed block: |
| const sal_Unicode * pLookAhead = pBodyPtr; |
| if (*pLookAhead == '"') |
| { |
| pLookAhead |
| = skipQuotedString(pLookAhead, |
| pBodyEnd); |
| if (pLookAhead == pBodyPtr) |
| pLookAhead = pBodyEnd; |
| } |
| else |
| while (pLookAhead != pBodyEnd |
| && (isAtomChar(*pLookAhead) |
| || !isUSASCII( |
| *pLookAhead))) |
| ++pLookAhead; |
| while (pLookAhead != pBodyEnd) |
| switch (*pLookAhead) |
| { |
| case '\t': |
| case ' ': |
| ++pLookAhead; |
| break; |
| |
| case '(': |
| { |
| const sal_Unicode * pPast |
| = skipComment(pLookAhead, |
| pBodyEnd); |
| pLookAhead |
| = pPast == pLookAhead ? |
| pBodyEnd : pPast; |
| break; |
| } |
| |
| case ',': |
| case '.': |
| case ';': |
| case '>': |
| case '@': |
| eEntity = ENTITY_NON_PHRASE; |
| goto entity_determined; |
| |
| case ':': |
| eEntity |
| = eBrackets |
| == BRACKETS_OUTSIDE ? |
| ENTITY_PHRASE : |
| ENTITY_NON_PHRASE; |
| goto entity_determined; |
| |
| case '\x0D': // CR |
| if (startsWithLineFolding( |
| pLookAhead, pBodyEnd)) |
| { |
| pLookAhead += 3; |
| break; |
| } |
| default: |
| eEntity = ENTITY_PHRASE; |
| goto entity_determined; |
| } |
| eEntity = ENTITY_NON_PHRASE; |
| entity_determined: |
| break; |
| } |
| |
| case HEADER_FIELD_TEXT: |
| OSL_ASSERT(false); |
| break; |
| } |
| |
| // In a 'non-phrase', a non-US-ASCII character |
| // cannot be part of an <atom>, but instead the |
| // whole entity is 'junk' rather than 'non- |
| // phrase': |
| if (eEntity == ENTITY_NON_PHRASE |
| && !isUSASCII(*pBodyPtr)) |
| eEntity = ENTITY_JUNK; |
| break; |
| } |
| |
| switch (eEntity) |
| { |
| case ENTITY_JUNK: |
| { |
| // Write a pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING) |
| { |
| if (rSink.getColumn() |
| + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| eBrackets = BRACKETS_INSIDE; |
| } |
| |
| // Calculate the length of in- and output: |
| const sal_Unicode * pStart = pBodyPtr; |
| sal_Size nLength = 0; |
| bool bModify = false; |
| bool bEnd = false; |
| while (pBodyPtr != pBodyEnd && !bEnd) |
| switch (*pBodyPtr) |
| { |
| case '\x0D': // CR |
| if (startsWithLineFolding(pBodyPtr, |
| pBodyEnd)) |
| bEnd = true; |
| else if (startsWithLineBreak( |
| pBodyPtr, pBodyEnd)) |
| { |
| nLength += 3; |
| bModify = true; |
| pBodyPtr += 2; |
| } |
| else |
| { |
| ++nLength; |
| ++pBodyPtr; |
| } |
| break; |
| |
| case '\t': |
| case ' ': |
| bEnd = true; |
| break; |
| |
| default: |
| if (isVisible(*pBodyPtr)) |
| bEnd = true; |
| else if (isUSASCII(*pBodyPtr)) |
| { |
| ++nLength; |
| ++pBodyPtr; |
| } |
| else |
| { |
| nLength += getUTF8OctetCount( |
| *pBodyPtr++); |
| bModify = true; |
| } |
| break; |
| } |
| |
| // Write the output: |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| + nLength |
| > rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| bInitialSpace = false; |
| if (bModify) |
| while (pStart != pBodyPtr) |
| if (startsWithLineBreak(pStart, pBodyPtr)) |
| { |
| rSink << "\x0D\\\x0A"; // CR, '\', LF |
| pStart += 2; |
| } |
| else |
| writeUTF8(rSink, *pStart++); |
| else |
| rSink.write(pStart, pBodyPtr); |
| break; |
| } |
| |
| case ENTITY_NON_PHRASE: |
| { |
| // Calculate the length of in- and output: |
| const sal_Unicode * pStart = pBodyPtr; |
| sal_Size nLength = 0; |
| bool bBracketedBlock = false; |
| bool bSymbol = *pStart != '.' && *pStart != '@'; |
| bool bModify = false; |
| bool bEnd = false; |
| while (pBodyPtr != pBodyEnd && !bEnd) |
| switch (*pBodyPtr) |
| { |
| case '\t': |
| case ' ': |
| case '\x0D': // CR |
| { |
| const sal_Unicode * pLookAhead |
| = skipLinearWhiteSpace(pBodyPtr, |
| pBodyEnd); |
| if (pLookAhead < pBodyEnd |
| && (bSymbol ? |
| isAtomChar(*pLookAhead) |
| || *pLookAhead == '"' |
| || *pLookAhead == '[' : |
| *pLookAhead == '.' |
| || *pLookAhead == '@' |
| || (*pLookAhead == '>' |
| && eType |
| >= HEADER_FIELD_MESSAGE_ID |
| && eBrackets |
| == BRACKETS_OPENING))) |
| { |
| bModify = true; |
| pBodyPtr = pLookAhead; |
| } |
| else |
| bEnd = true; |
| break; |
| } |
| |
| case '"': |
| if (bSymbol) |
| { |
| pBodyPtr |
| = scanQuotedBlock(pBodyPtr, |
| pBodyEnd, |
| '"', '"', |
| nLength, |
| bModify); |
| bSymbol = false; |
| } |
| else |
| bEnd = true; |
| break; |
| |
| case '[': |
| if (bSymbol) |
| { |
| pBodyPtr |
| = scanQuotedBlock(pBodyPtr, |
| pBodyEnd, |
| '[', ']', |
| nLength, |
| bModify); |
| bSymbol = false; |
| } |
| else |
| bEnd = true; |
| break; |
| |
| case '.': |
| case '@': |
| if (bSymbol) |
| bEnd = true; |
| else |
| { |
| ++nLength; |
| bSymbol = true; |
| ++pBodyPtr; |
| } |
| break; |
| |
| case '>': |
| if (eBrackets == BRACKETS_OPENING |
| && eType |
| >= HEADER_FIELD_MESSAGE_ID) |
| { |
| ++nLength; |
| bBracketedBlock = true; |
| ++pBodyPtr; |
| } |
| bEnd = true; |
| break; |
| |
| default: |
| if (isAtomChar(*pBodyPtr) && bSymbol) |
| { |
| while (pBodyPtr != pBodyEnd |
| && isAtomChar(*pBodyPtr)) |
| { |
| ++nLength; |
| ++pBodyPtr; |
| } |
| bSymbol = false; |
| } |
| else |
| { |
| if (!isUSASCII(*pBodyPtr)) |
| bModify = true; |
| bEnd = true; |
| } |
| break; |
| } |
| |
| // Write a pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING |
| && !bBracketedBlock) |
| { |
| if (rSink.getColumn() |
| + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| eBrackets = BRACKETS_INSIDE; |
| } |
| |
| // Write the output: |
| if (rSink.getColumn() + (bInitialSpace ? 1 : 0) |
| + nLength |
| > rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| bInitialSpace = false; |
| if (bBracketedBlock) |
| { |
| rSink << '<'; |
| eBrackets = BRACKETS_OUTSIDE; |
| } |
| if (bModify) |
| { |
| enum Mode { MODE_PLAIN, MODE_QUOTED_STRING, |
| MODE_DOMAIN_LITERAL }; |
| Mode eMode = MODE_PLAIN; |
| while (pStart != pBodyPtr) |
| switch (*pStart) |
| { |
| case '\x0D': // CR |
| if (startsWithLineFolding( |
| pStart, pBodyPtr)) |
| { |
| if (eMode != MODE_PLAIN) |
| rSink << sal_Char( |
| pStart[2]); |
| pStart += 3; |
| } |
| else if (startsWithLineBreak( |
| pStart, pBodyPtr)) |
| { |
| rSink << "\x0D\\\x0A"; |
| // CR, '\', LF |
| pStart += 2; |
| } |
| else |
| { |
| rSink << '\x0D'; // CR |
| ++pStart; |
| } |
| break; |
| |
| case '\t': |
| case ' ': |
| if (eMode != MODE_PLAIN) |
| rSink << sal_Char(*pStart); |
| ++pStart; |
| break; |
| |
| case '"': |
| if (eMode == MODE_PLAIN) |
| eMode = MODE_QUOTED_STRING; |
| else if (eMode |
| == MODE_QUOTED_STRING) |
| eMode = MODE_PLAIN; |
| rSink << '"'; |
| ++pStart; |
| break; |
| |
| case '[': |
| if (eMode == MODE_PLAIN) |
| eMode = MODE_DOMAIN_LITERAL; |
| rSink << '['; |
| ++pStart; |
| break; |
| |
| case ']': |
| if (eMode == MODE_DOMAIN_LITERAL) |
| eMode = MODE_PLAIN; |
| rSink << ']'; |
| ++pStart; |
| break; |
| |
| case '\\': |
| rSink << '\\'; |
| if (++pStart < pBodyPtr) |
| writeUTF8(rSink, *pStart++); |
| break; |
| |
| default: |
| writeUTF8(rSink, *pStart++); |
| break; |
| } |
| } |
| else |
| rSink.write(pStart, pBodyPtr); |
| break; |
| } |
| |
| case ENTITY_PHRASE: |
| { |
| // Write a pending '<' if necessary: |
| if (eBrackets == BRACKETS_OPENING) |
| { |
| if (rSink.getColumn() |
| + (bInitialSpace ? 1 : 0) |
| >= rSink.getLineLengthLimit()) |
| rSink << INetMIMEOutputSink::endl << ' '; |
| else if (bInitialSpace) |
| rSink << ' '; |
| rSink << '<'; |
| bInitialSpace = false; |
| eBrackets = BRACKETS_INSIDE; |
| } |
| |
| // Calculate the length of in- and output: |
| const sal_Unicode * pStart = pBodyPtr; |
| bool bQuotedString = false; |
| bool bEnd = false; |
| while (pBodyPtr != pBodyEnd && !bEnd) |
| switch (*pBodyPtr) |
| { |
| case '\t': |
| case ' ': |
| case '\x0D': // CR |
| if (bQuotedString) |
| ++pBodyPtr; |
| else |
| { |
| const sal_Unicode * pLookAhead |
| = skipLinearWhiteSpace( |
| pBodyPtr, pBodyEnd); |
| if (pLookAhead != pBodyEnd |
| && (isAtomChar(*pLookAhead) |
| || !isUSASCII(*pLookAhead) |
| || *pLookAhead == '"')) |
| pBodyPtr = pLookAhead; |
| else |
| bEnd = true; |
| } |
| break; |
| |
| case '"': |
| bQuotedString = !bQuotedString; |
| ++pBodyPtr; |
| break; |
| |
| case '\\': |
| if (bQuotedString) |
| { |
| if (++pBodyPtr != pBodyEnd) |
| ++pBodyPtr; |
| } |
| else |
| bEnd = true; |
| break; |
| |
| default: |
| if (bQuotedString |
| || isAtomChar(*pBodyPtr) |
| || !isUSASCII(*pBodyPtr)) |
| ++pBodyPtr; |
| else |
| bEnd = true; |
| break; |
| } |
| |
| // Write the phrase, introducing encoded-words |
| // where necessary: |
| INetMIMEEncodedWordOutputSink |
| aOutput( |
| rSink, |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, |
| bInitialSpace ? |
| INetMIMEEncodedWordOutputSink::SPACE_ALWAYS : |
| INetMIMEEncodedWordOutputSink::SPACE_ENCODED, |
| ePreferredEncoding); |
| while (pStart != pBodyPtr) |
| switch (*pStart) |
| { |
| case '"': |
| ++pStart; |
| break; |
| |
| case '\\': |
| if (++pStart != pBodyPtr) |
| aOutput << *pStart++; |
| break; |
| |
| case '\x0D': // CR |
| pStart += 2; |
| aOutput << *pStart++; |
| break; |
| |
| default: |
| aOutput << *pStart++; |
| break; |
| } |
| bInitialSpace = aOutput.flush(); |
| break; |
| } |
| } |
| break; |
| } |
| } |
| } |
| } |
| |
| //============================================================================ |
| // static |
| bool INetMIME::translateUTF8Char(const sal_Char *& rBegin, |
| const sal_Char * pEnd, |
| rtl_TextEncoding eEncoding, |
| sal_uInt32 & rCharacter) |
| { |
| if (rBegin == pEnd || static_cast< unsigned char >(*rBegin) < 0x80 |
| || static_cast< unsigned char >(*rBegin) >= 0xFE) |
| return false; |
| |
| int nCount; |
| sal_uInt32 nMin; |
| sal_uInt32 nUCS4; |
| const sal_Char * p = rBegin; |
| if (static_cast< unsigned char >(*p) < 0xE0) |
| { |
| nCount = 1; |
| nMin = 0x80; |
| nUCS4 = static_cast< unsigned char >(*p) & 0x1F; |
| } |
| else if (static_cast< unsigned char >(*p) < 0xF0) |
| { |
| nCount = 2; |
| nMin = 0x800; |
| nUCS4 = static_cast< unsigned char >(*p) & 0xF; |
| } |
| else if (static_cast< unsigned char >(*p) < 0xF8) |
| { |
| nCount = 3; |
| nMin = 0x10000; |
| nUCS4 = static_cast< unsigned char >(*p) & 7; |
| } |
| else if (static_cast< unsigned char >(*p) < 0xFC) |
| { |
| nCount = 4; |
| nMin = 0x200000; |
| nUCS4 = static_cast< unsigned char >(*p) & 3; |
| } |
| else |
| { |
| nCount = 5; |
| nMin = 0x4000000; |
| nUCS4 = static_cast< unsigned char >(*p) & 1; |
| } |
| ++p; |
| |
| for (; nCount-- > 0; ++p) |
| if ((static_cast< unsigned char >(*p) & 0xC0) == 0x80) |
| nUCS4 = (nUCS4 << 6) | (static_cast< unsigned char >(*p) & 0x3F); |
| else |
| return false; |
| |
| if (nUCS4 < nMin || nUCS4 > 0x10FFFF) |
| return false; |
| |
| if (eEncoding >= RTL_TEXTENCODING_UCS4) |
| rCharacter = nUCS4; |
| else |
| { |
| sal_Unicode aUTF16[2]; |
| const sal_Unicode * pUTF16End = putUTF32Character(aUTF16, nUCS4); |
| sal_Size nSize; |
| sal_Char * pBuffer = convertFromUnicode(aUTF16, pUTF16End, eEncoding, |
| nSize); |
| if (!pBuffer) |
| return false; |
| DBG_ASSERT(nSize == 1, |
| "INetMIME::translateUTF8Char(): Bad conversion"); |
| rCharacter = *pBuffer; |
| delete[] pBuffer; |
| } |
| rBegin = p; |
| return true; |
| } |
| |
| //============================================================================ |
| // static |
| ByteString INetMIME::decodeUTF8(const ByteString & rText, |
| rtl_TextEncoding eEncoding) |
| { |
| const sal_Char * p = rText.GetBuffer(); |
| const sal_Char * pEnd = p + rText.Len(); |
| ByteString sDecoded; |
| while (p != pEnd) |
| { |
| sal_uInt32 nCharacter; |
| if (translateUTF8Char(p, pEnd, eEncoding, nCharacter)) |
| sDecoded += sal_Char(nCharacter); |
| else |
| sDecoded += sal_Char(*p++); |
| } |
| return sDecoded; |
| } |
| |
| //============================================================================ |
| // static |
| UniString INetMIME::decodeHeaderFieldBody(HeaderFieldType eType, |
| const ByteString & rBody) |
| { |
| // Due to a bug in INetCoreRFC822MessageStream::ConvertTo7Bit(), old |
| // versions of StarOffice send mails with header fields where encoded |
| // words can be preceded by '=', ',', '.', '"', or '(', and followed by |
| // '=', ',', '.', '"', ')', without any required white space in between. |
| // And there appear to exist some broken mailers that only encode single |
| // letters within words, like "Appel |
| // =?iso-8859-1?Q?=E0?=t=?iso-8859-1?Q?=E9?=moin", so it seems best to |
| // detect encoded words even when not properly surrounded by white space. |
| // |
| // Non US-ASCII characters in rBody are treated as ISO-8859-1. |
| // |
| // encoded-word = "=?" |
| // 1*(%x21 / %x23-27 / %x2A-2B / %x2D / %30-39 / %x41-5A / %x5E-7E) |
| // ["*" 1*8ALPHA *("-" 1*8ALPHA)] "?" |
| // ("B?" *(4base64) (4base64 / 3base64 "=" / 2base64 "==") |
| // / "Q?" 1*(%x21-3C / %x3E / %x40-7E / "=" 2HEXDIG)) |
| // "?=" |
| // |
| // base64 = ALPHA / DIGIT / "+" / "/" |
| |
| const sal_Char * pBegin = rBody.GetBuffer(); |
| const sal_Char * pEnd = pBegin + rBody.Len(); |
| |
| UniString sDecoded; |
| const sal_Char * pCopyBegin = pBegin; |
| |
| /* bool bStartEncodedWord = true; */ |
| const sal_Char * pWSPBegin = pBegin; |
| UniString sEncodedText; |
| bool bQuotedEncodedText = false; |
| sal_uInt32 nCommentLevel = 0; |
| |
| for (const sal_Char * p = pBegin; p != pEnd;) |
| { |
| if (p != pEnd && *p == '=' /* && bStartEncodedWord */) |
| { |
| const sal_Char * q = p + 1; |
| bool bEncodedWord = q != pEnd && *q++ == '?'; |
| |
| rtl_TextEncoding eCharsetEncoding = RTL_TEXTENCODING_DONTKNOW; |
| if (bEncodedWord) |
| { |
| const sal_Char * pCharsetBegin = q; |
| const sal_Char * pLanguageBegin = 0; |
| int nAlphaCount = 0; |
| for (bool bDone = false; !bDone;) |
| if (q == pEnd) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| } |
| else |
| { |
| sal_Char cChar = *q++; |
| switch (cChar) |
| { |
| case '*': |
| pLanguageBegin = q - 1; |
| nAlphaCount = 0; |
| break; |
| |
| case '-': |
| if (pLanguageBegin != 0) |
| { |
| if (nAlphaCount == 0) |
| pLanguageBegin = 0; |
| else |
| nAlphaCount = 0; |
| } |
| break; |
| |
| case '?': |
| if (pCharsetBegin == q - 1) |
| bEncodedWord = false; |
| else |
| { |
| eCharsetEncoding |
| = getCharsetEncoding( |
| pCharsetBegin, |
| pLanguageBegin == 0 |
| || nAlphaCount == 0 ? |
| q - 1 : pLanguageBegin); |
| bEncodedWord = isMIMECharsetEncoding( |
| eCharsetEncoding); |
| eCharsetEncoding |
| = translateFromMIME(eCharsetEncoding); |
| } |
| bDone = true; |
| break; |
| |
| default: |
| if (pLanguageBegin != 0 |
| && (!isAlpha(cChar) || ++nAlphaCount > 8)) |
| pLanguageBegin = 0; |
| break; |
| } |
| } |
| } |
| |
| bool bEncodingB = false; |
| if (bEncodedWord) |
| { |
| if (q == pEnd) |
| bEncodedWord = false; |
| else |
| { |
| switch (*q++) |
| { |
| case 'B': |
| case 'b': |
| bEncodingB = true; |
| break; |
| |
| case 'Q': |
| case 'q': |
| bEncodingB = false; |
| break; |
| |
| default: |
| bEncodedWord = false; |
| break; |
| } |
| } |
| } |
| |
| bEncodedWord = bEncodedWord && q != pEnd && *q++ == '?'; |
| |
| ByteString sText; |
| if (bEncodedWord) |
| { |
| if (bEncodingB) |
| { |
| for (bool bDone = false; !bDone;) |
| { |
| if (pEnd - q < 4) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| } |
| else |
| { |
| bool bFinal = false; |
| int nCount = 3; |
| sal_uInt32 nValue = 0; |
| for (int nShift = 18; nShift >= 0; nShift -= 6) |
| { |
| int nWeight = getBase64Weight(*q++); |
| if (nWeight == -2) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| break; |
| } |
| if (nWeight == -1) |
| { |
| if (!bFinal) |
| { |
| if (nShift >= 12) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| break; |
| } |
| bFinal = true; |
| nCount = nShift == 6 ? 1 : 2; |
| } |
| } |
| else |
| nValue |= nWeight << nShift; |
| } |
| if (bEncodedWord) |
| { |
| for (int nShift = 16; nCount-- > 0; |
| nShift -= 8) |
| sText += sal_Char(nValue >> nShift |
| & 0xFF); |
| if (*q == '?') |
| { |
| ++q; |
| bDone = true; |
| } |
| if (bFinal && !bDone) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| const sal_Char * pEncodedTextBegin = q; |
| const sal_Char * pEncodedTextCopyBegin = q; |
| for (bool bDone = false; !bDone;) |
| if (q == pEnd) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| } |
| else |
| { |
| sal_uInt32 nChar = *q++; |
| switch (nChar) |
| { |
| case '=': |
| { |
| if (pEnd - q < 2) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| break; |
| } |
| int nDigit1 = getHexWeight(q[0]); |
| int nDigit2 = getHexWeight(q[1]); |
| if (nDigit1 < 0 || nDigit2 < 0) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| break; |
| } |
| sText += rBody.Copy( |
| static_cast< xub_StrLen >( |
| pEncodedTextCopyBegin - pBegin), |
| static_cast< xub_StrLen >( |
| q - 1 - pEncodedTextCopyBegin)); |
| sText += sal_Char(nDigit1 << 4 | nDigit2); |
| q += 2; |
| pEncodedTextCopyBegin = q; |
| break; |
| } |
| |
| case '?': |
| if (q - pEncodedTextBegin > 1) |
| sText += rBody.Copy( |
| static_cast< xub_StrLen >( |
| pEncodedTextCopyBegin - pBegin), |
| static_cast< xub_StrLen >( |
| q - 1 - pEncodedTextCopyBegin)); |
| else |
| bEncodedWord = false; |
| bDone = true; |
| break; |
| |
| case '_': |
| sText += rBody.Copy( |
| static_cast< xub_StrLen >( |
| pEncodedTextCopyBegin - pBegin), |
| static_cast< xub_StrLen >( |
| q - 1 - pEncodedTextCopyBegin)); |
| sText += ' '; |
| pEncodedTextCopyBegin = q; |
| break; |
| |
| default: |
| if (!isVisible(nChar)) |
| { |
| bEncodedWord = false; |
| bDone = true; |
| } |
| break; |
| } |
| } |
| } |
| } |
| |
| bEncodedWord = bEncodedWord && q != pEnd && *q++ == '='; |
| |
| // if (bEncodedWord && q != pEnd) |
| // switch (*q) |
| // { |
| // case '\t': |
| // case ' ': |
| // case '"': |
| // case ')': |
| // case ',': |
| // case '.': |
| // case '=': |
| // break; |
| // |
| // default: |
| // bEncodedWord = false; |
| // break; |
| // } |
| |
| sal_Unicode * pUnicodeBuffer = 0; |
| sal_Size nUnicodeSize = 0; |
| if (bEncodedWord) |
| { |
| pUnicodeBuffer |
| = convertToUnicode(sText.GetBuffer(), |
| sText.GetBuffer() + sText.Len(), |
| eCharsetEncoding, nUnicodeSize); |
| if (pUnicodeBuffer == 0) |
| bEncodedWord = false; |
| } |
| |
| if (bEncodedWord) |
| { |
| appendISO88591(sDecoded, pCopyBegin, pWSPBegin); |
| if (eType == HEADER_FIELD_TEXT) |
| sDecoded.Append( |
| pUnicodeBuffer, |
| static_cast< xub_StrLen >(nUnicodeSize)); |
| else if (nCommentLevel == 0) |
| { |
| sEncodedText.Append( |
| pUnicodeBuffer, |
| static_cast< xub_StrLen >(nUnicodeSize)); |
| if (!bQuotedEncodedText) |
| { |
| const sal_Unicode * pTextPtr = pUnicodeBuffer; |
| const sal_Unicode * pTextEnd = pTextPtr |
| + nUnicodeSize; |
| for (; pTextPtr != pTextEnd; ++pTextPtr) |
| if (!isEncodedWordTokenChar(*pTextPtr)) |
| { |
| bQuotedEncodedText = true; |
| break; |
| } |
| } |
| } |
| else |
| { |
| const sal_Unicode * pTextPtr = pUnicodeBuffer; |
| const sal_Unicode * pTextEnd = pTextPtr + nUnicodeSize; |
| for (; pTextPtr != pTextEnd; ++pTextPtr) |
| { |
| switch (*pTextPtr) |
| { |
| case '(': |
| case ')': |
| case '\\': |
| case '\x0D': |
| case '=': |
| sDecoded += '\\'; |
| break; |
| } |
| sDecoded += *pTextPtr; |
| } |
| } |
| delete[] pUnicodeBuffer; |
| p = q; |
| pCopyBegin = p; |
| |
| pWSPBegin = p; |
| while (p != pEnd && isWhiteSpace(*p)) |
| ++p; |
| /* bStartEncodedWord = p != pWSPBegin; */ |
| continue; |
| } |
| } |
| |
| if (sEncodedText.Len() != 0) |
| { |
| if (bQuotedEncodedText) |
| { |
| sDecoded += '"'; |
| const sal_Unicode * pTextPtr = sEncodedText.GetBuffer(); |
| const sal_Unicode * pTextEnd = pTextPtr + sEncodedText.Len(); |
| for (;pTextPtr != pTextEnd; ++pTextPtr) |
| { |
| switch (*pTextPtr) |
| { |
| case '"': |
| case '\\': |
| case '\x0D': |
| sDecoded += '\\'; |
| break; |
| } |
| sDecoded += *pTextPtr; |
| } |
| sDecoded += '"'; |
| } |
| else |
| sDecoded += sEncodedText; |
| sEncodedText.Erase(); |
| bQuotedEncodedText = false; |
| } |
| |
| if (p == pEnd) |
| break; |
| |
| switch (*p++) |
| { |
| // case '\t': |
| // case ' ': |
| // case ',': |
| // case '.': |
| // case '=': |
| // bStartEncodedWord = true; |
| // break; |
| |
| case '"': |
| if (eType != HEADER_FIELD_TEXT && nCommentLevel == 0) |
| { |
| const sal_Char * pQuotedStringEnd |
| = skipQuotedString(p - 1, pEnd); |
| p = pQuotedStringEnd == p - 1 ? pEnd : pQuotedStringEnd; |
| } |
| /* bStartEncodedWord = true; */ |
| break; |
| |
| case '(': |
| if (eType != HEADER_FIELD_TEXT) |
| ++nCommentLevel; |
| /* bStartEncodedWord = true; */ |
| break; |
| |
| case ')': |
| if (nCommentLevel > 0) |
| --nCommentLevel; |
| /* bStartEncodedWord = false; */ |
| break; |
| |
| default: |
| { |
| const sal_Char * pUTF8Begin = p - 1; |
| const sal_Char * pUTF8End = pUTF8Begin; |
| sal_uInt32 nCharacter; |
| if (translateUTF8Char(pUTF8End, pEnd, RTL_TEXTENCODING_UCS4, |
| nCharacter)) |
| { |
| appendISO88591(sDecoded, pCopyBegin, p - 1); |
| sal_Unicode aUTF16Buf[2]; |
| xub_StrLen nUTF16Len = static_cast< xub_StrLen >( |
| putUTF32Character(aUTF16Buf, nCharacter) - aUTF16Buf); |
| sDecoded.Append(aUTF16Buf, nUTF16Len); |
| p = pUTF8End; |
| pCopyBegin = p; |
| } |
| /* bStartEncodedWord = false; */ |
| break; |
| } |
| } |
| pWSPBegin = p; |
| } |
| |
| appendISO88591(sDecoded, pCopyBegin, pEnd); |
| return sDecoded; |
| } |
| |
| //============================================================================ |
| // |
| // INetMIMEOutputSink |
| // |
| //============================================================================ |
| |
| // virtual |
| sal_Size INetMIMEOutputSink::writeSequence(const sal_Char * pSequence) |
| { |
| sal_Size nLength = rtl_str_getLength(pSequence); |
| writeSequence(pSequence, pSequence + nLength); |
| return nLength; |
| } |
| |
| //============================================================================ |
| // virtual |
| void INetMIMEOutputSink::writeSequence(const sal_uInt32 * pBegin, |
| const sal_uInt32 * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIMEOutputSink::writeSequence(): Bad sequence"); |
| |
| sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin]; |
| sal_Char * pBufferEnd = pBufferBegin; |
| while (pBegin != pEnd) |
| { |
| DBG_ASSERT(*pBegin < 256, |
| "INetMIMEOutputSink::writeSequence(): Bad octet"); |
| *pBufferEnd++ = sal_Char(*pBegin++); |
| } |
| writeSequence(pBufferBegin, pBufferEnd); |
| delete[] pBufferBegin; |
| } |
| |
| //============================================================================ |
| // virtual |
| void INetMIMEOutputSink::writeSequence(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIMEOutputSink::writeSequence(): Bad sequence"); |
| |
| sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin]; |
| sal_Char * pBufferEnd = pBufferBegin; |
| while (pBegin != pEnd) |
| { |
| DBG_ASSERT(*pBegin < 256, |
| "INetMIMEOutputSink::writeSequence(): Bad octet"); |
| *pBufferEnd++ = sal_Char(*pBegin++); |
| } |
| writeSequence(pBufferBegin, pBufferEnd); |
| delete[] pBufferBegin; |
| } |
| |
| //============================================================================ |
| // virtual |
| ErrCode INetMIMEOutputSink::getError() const |
| { |
| return ERRCODE_NONE; |
| } |
| |
| //============================================================================ |
| void INetMIMEOutputSink::writeLineEnd() |
| { |
| static const sal_Char aCRLF[2] = { 0x0D, 0x0A }; |
| writeSequence(aCRLF, aCRLF + 2); |
| m_nColumn = 0; |
| } |
| |
| //============================================================================ |
| // |
| // INetMIMEStringOutputSink |
| // |
| //============================================================================ |
| |
| // virtual |
| void INetMIMEStringOutputSink::writeSequence(const sal_Char * pBegin, |
| const sal_Char * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIMEStringOutputSink::writeSequence(): Bad sequence"); |
| |
| m_bOverflow = m_bOverflow |
| || pEnd - pBegin > STRING_MAXLEN - m_aBuffer.Len(); |
| if (!m_bOverflow) |
| m_aBuffer.Append(pBegin, static_cast< xub_StrLen >(pEnd - pBegin)); |
| } |
| |
| //============================================================================ |
| // virtual |
| ErrCode INetMIMEStringOutputSink::getError() const |
| { |
| return m_bOverflow ? ERRCODE_IO_OUTOFMEMORY : ERRCODE_NONE; |
| } |
| |
| //============================================================================ |
| // |
| // INetMIMEUnicodeOutputSink |
| // |
| //============================================================================ |
| |
| // virtual |
| void INetMIMEUnicodeOutputSink::writeSequence(const sal_Char * pBegin, |
| const sal_Char * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence"); |
| |
| sal_Unicode * pBufferBegin = new sal_Unicode[pEnd - pBegin]; |
| sal_Unicode * pBufferEnd = pBufferBegin; |
| while (pBegin != pEnd) |
| *pBufferEnd++ = sal_uChar(*pBegin++); |
| writeSequence(pBufferBegin, pBufferEnd); |
| delete[] pBufferBegin; |
| } |
| |
| //============================================================================ |
| // virtual |
| void INetMIMEUnicodeOutputSink::writeSequence(const sal_uInt32 * pBegin, |
| const sal_uInt32 * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence"); |
| |
| sal_Unicode * pBufferBegin = new sal_Unicode[pEnd - pBegin]; |
| sal_Unicode * pBufferEnd = pBufferBegin; |
| while (pBegin != pEnd) |
| { |
| DBG_ASSERT(*pBegin < 256, |
| "INetMIMEOutputSink::writeSequence(): Bad octet"); |
| *pBufferEnd++ = sal_Unicode(*pBegin++); |
| } |
| writeSequence(pBufferBegin, pBufferEnd); |
| delete[] pBufferBegin; |
| } |
| |
| //============================================================================ |
| // virtual |
| void INetMIMEUnicodeOutputSink::writeSequence(const sal_Unicode * pBegin, |
| const sal_Unicode * pEnd) |
| { |
| DBG_ASSERT(pBegin && pBegin <= pEnd, |
| "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence"); |
| |
| m_bOverflow = m_bOverflow |
| || pEnd - pBegin > STRING_MAXLEN - m_aBuffer.Len(); |
| if (!m_bOverflow) |
| m_aBuffer.Append(pBegin, static_cast< xub_StrLen >(pEnd - pBegin)); |
| } |
| |
| //============================================================================ |
| // virtual |
| ErrCode INetMIMEUnicodeOutputSink::getError() const |
| { |
| return m_bOverflow ? ERRCODE_IO_OUTOFMEMORY : ERRCODE_NONE; |
| } |
| |
| //============================================================================ |
| // |
| // INetMIMEEncodedWordOutputSink |
| // |
| //============================================================================ |
| |
| static const sal_Char aEscape[128] |
| = { INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x00 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x01 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x02 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x03 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x04 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x05 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x06 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x07 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x08 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x09 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0A |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0B |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0C |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0D |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0E |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0F |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x10 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x11 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x12 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x13 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x14 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x15 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x16 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x17 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x18 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x19 |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1A |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1B |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1C |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1D |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1E |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1F |
| 0, // ' ' |
| 0, // '!' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '"' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '#' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '$' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '%' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '&' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ''' |
| INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '(' |
| INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ')' |
| 0, // '*' |
| 0, // '+' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ',' |
| 0, // '-' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '.' |
| 0, // '/' |
| 0, // '0' |
| 0, // '1' |
| 0, // '2' |
| 0, // '3' |
| 0, // '4' |
| 0, // '5' |
| 0, // '6' |
| 0, // '7' |
| 0, // '8' |
| 0, // '9' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ':' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ';' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '<' |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '=' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '>' |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '?' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '@' |
| 0, // 'A' |
| 0, // 'B' |
| 0, // 'C' |
| 0, // 'D' |
| 0, // 'E' |
| 0, // 'F' |
| 0, // 'G' |
| 0, // 'H' |
| 0, // 'I' |
| 0, // 'J' |
| 0, // 'K' |
| 0, // 'L' |
| 0, // 'M' |
| 0, // 'N' |
| 0, // 'O' |
| 0, // 'P' |
| 0, // 'Q' |
| 0, // 'R' |
| 0, // 'S' |
| 0, // 'T' |
| 0, // 'U' |
| 0, // 'V' |
| 0, // 'W' |
| 0, // 'X' |
| 0, // 'Y' |
| 0, // 'Z' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '[' |
| INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '\' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ']' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '^' |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '_' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '`' |
| 0, // 'a' |
| 0, // 'b' |
| 0, // 'c' |
| 0, // 'd' |
| 0, // 'e' |
| 0, // 'f' |
| 0, // 'g' |
| 0, // 'h' |
| 0, // 'i' |
| 0, // 'j' |
| 0, // 'k' |
| 0, // 'l' |
| 0, // 'm' |
| 0, // 'n' |
| 0, // 'o' |
| 0, // 'p' |
| 0, // 'q' |
| 0, // 'r' |
| 0, // 's' |
| 0, // 't' |
| 0, // 'u' |
| 0, // 'v' |
| 0, // 'w' |
| 0, // 'x' |
| 0, // 'y' |
| 0, // 'z' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '{' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '|' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '}' |
| INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '~' |
| INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE }; // DEL |
| |
| inline bool |
| INetMIMEEncodedWordOutputSink::needsEncodedWordEscape(sal_uInt32 nChar) const |
| { |
| return !INetMIME::isUSASCII(nChar) || aEscape[nChar] & m_eContext; |
| } |
| |
| //============================================================================ |
| void INetMIMEEncodedWordOutputSink::finish(bool bWriteTrailer) |
| { |
| if (m_eInitialSpace == SPACE_ALWAYS && m_nExtraSpaces == 0) |
| m_nExtraSpaces = 1; |
| |
| if (m_eEncodedWordState == STATE_SECOND_EQUALS) |
| { |
| // If the text is already an encoded word, copy it verbatim: |
| sal_uInt32 nSize = m_pBufferEnd - m_pBuffer; |
| switch (m_ePrevCoding) |
| { |
| case CODING_QUOTED: |
| m_rSink << '"'; |
| case CODING_NONE: |
| if (m_eInitialSpace == SPACE_ENCODED && m_nExtraSpaces == 0) |
| m_nExtraSpaces = 1; |
| for (; m_nExtraSpaces > 1; --m_nExtraSpaces) |
| { |
| if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| if (m_nExtraSpaces == 1) |
| { |
| if (m_rSink.getColumn() + nSize |
| >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| break; |
| |
| case CODING_ENCODED: |
| { |
| const sal_Char * pCharsetName |
| = INetMIME::getCharsetName(m_ePrevMIMEEncoding); |
| while (m_nExtraSpaces-- > 0) |
| { |
| if (m_rSink.getColumn() |
| > m_rSink.getLineLengthLimit() - 3) |
| m_rSink << "?=" << INetMIMEOutputSink::endl << " =?" |
| << pCharsetName << "?Q?"; |
| m_rSink << '_'; |
| } |
| m_rSink << "?="; |
| } |
| case CODING_ENCODED_TERMINATED: |
| if (m_rSink.getColumn() + nSize |
| > m_rSink.getLineLengthLimit() - 1) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| break; |
| } |
| m_rSink.write(m_pBuffer, m_pBufferEnd); |
| m_eCoding = CODING_ENCODED_TERMINATED; |
| } |
| else |
| { |
| // If the text itself is too long to fit into a single line, make it |
| // into multiple encoded words: |
| switch (m_eCoding) |
| { |
| case CODING_NONE: |
| if (m_nExtraSpaces == 0) |
| { |
| DBG_ASSERT(m_ePrevCoding == CODING_NONE |
| || m_pBuffer == m_pBufferEnd, |
| "INetMIMEEncodedWordOutputSink::finish():" |
| " Bad state"); |
| if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer) |
| > m_rSink.getLineLengthLimit()) |
| m_eCoding = CODING_ENCODED; |
| } |
| else |
| { |
| OSL_ASSERT(m_pBufferEnd >= m_pBuffer); |
| if (static_cast< std::size_t >(m_pBufferEnd - m_pBuffer) |
| > m_rSink.getLineLengthLimit() - 1) |
| { |
| m_eCoding = CODING_ENCODED; |
| } |
| } |
| break; |
| |
| case CODING_QUOTED: |
| if (m_nExtraSpaces == 0) |
| { |
| DBG_ASSERT(m_ePrevCoding == CODING_NONE, |
| "INetMIMEEncodedWordOutputSink::finish():" |
| " Bad state"); |
| if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer) |
| + m_nQuotedEscaped |
| > m_rSink.getLineLengthLimit() - 2) |
| m_eCoding = CODING_ENCODED; |
| } |
| else if ((m_pBufferEnd - m_pBuffer) + m_nQuotedEscaped |
| > m_rSink.getLineLengthLimit() - 3) |
| m_eCoding = CODING_ENCODED; |
| break; |
| |
| default: |
| break; |
| } |
| |
| switch (m_eCoding) |
| { |
| case CODING_NONE: |
| switch (m_ePrevCoding) |
| { |
| case CODING_QUOTED: |
| if (m_rSink.getColumn() + m_nExtraSpaces |
| + (m_pBufferEnd - m_pBuffer) |
| < m_rSink.getLineLengthLimit()) |
| m_eCoding = CODING_QUOTED; |
| else |
| m_rSink << '"'; |
| break; |
| |
| case CODING_ENCODED: |
| m_rSink << "?="; |
| break; |
| |
| default: |
| break; |
| } |
| for (; m_nExtraSpaces > 1; --m_nExtraSpaces) |
| { |
| if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| if (m_nExtraSpaces == 1) |
| { |
| if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer) |
| >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| m_rSink.write(m_pBuffer, m_pBufferEnd); |
| if (m_eCoding == CODING_QUOTED && bWriteTrailer) |
| { |
| m_rSink << '"'; |
| m_eCoding = CODING_NONE; |
| } |
| break; |
| |
| case CODING_QUOTED: |
| { |
| bool bInsertLeadingQuote = true; |
| sal_uInt32 nSize = (m_pBufferEnd - m_pBuffer) |
| + m_nQuotedEscaped + 2; |
| switch (m_ePrevCoding) |
| { |
| case CODING_QUOTED: |
| if (m_rSink.getColumn() + m_nExtraSpaces + nSize - 1 |
| < m_rSink.getLineLengthLimit()) |
| { |
| bInsertLeadingQuote = false; |
| --nSize; |
| } |
| else |
| m_rSink << '"'; |
| break; |
| |
| case CODING_ENCODED: |
| m_rSink << "?="; |
| break; |
| |
| default: |
| break; |
| } |
| for (; m_nExtraSpaces > 1; --m_nExtraSpaces) |
| { |
| if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| if (m_nExtraSpaces == 1) |
| { |
| if (m_rSink.getColumn() + nSize |
| >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| if (bInsertLeadingQuote) |
| m_rSink << '"'; |
| for (const sal_Unicode * p = m_pBuffer; p != m_pBufferEnd; |
| ++p) |
| { |
| if (INetMIME::needsQuotedStringEscape(*p)) |
| m_rSink << '\\'; |
| m_rSink << sal_Char(*p); |
| } |
| if (bWriteTrailer) |
| { |
| m_rSink << '"'; |
| m_eCoding = CODING_NONE; |
| } |
| break; |
| } |
| |
| case CODING_ENCODED: |
| { |
| rtl_TextEncoding eCharsetEncoding |
| = m_pEncodingList-> |
| getPreferredEncoding(RTL_TEXTENCODING_UTF8); |
| rtl_TextEncoding eMIMEEncoding |
| = INetMIME::translateToMIME(eCharsetEncoding); |
| |
| // The non UTF-8 code will only work for stateless single byte |
| // character encodings (see also below): |
| sal_Char * pTargetBuffer = NULL; |
| sal_Size nTargetSize = 0; |
| sal_uInt32 nSize; |
| if (eMIMEEncoding == RTL_TEXTENCODING_UTF8) |
| { |
| nSize = 0; |
| for (sal_Unicode const * p = m_pBuffer; |
| p != m_pBufferEnd;) |
| { |
| sal_uInt32 nUTF32 |
| = INetMIME::getUTF32Character(p, m_pBufferEnd); |
| nSize += needsEncodedWordEscape(nUTF32) ? |
| 3 * INetMIME::getUTF8OctetCount(nUTF32) : |
| 1; |
| // only US-ASCII characters (that are converted to |
| // a single byte by UTF-8) need no encoded word |
| // escapes... |
| } |
| } |
| else |
| { |
| rtl_UnicodeToTextConverter hConverter |
| = rtl_createUnicodeToTextConverter(eCharsetEncoding); |
| rtl_UnicodeToTextContext hContext |
| = rtl_createUnicodeToTextContext(hConverter); |
| for (sal_Size nBufferSize = m_pBufferEnd - m_pBuffer;; |
| nBufferSize += nBufferSize / 3 + 1) |
| { |
| pTargetBuffer = new sal_Char[nBufferSize]; |
| sal_uInt32 nInfo; |
| sal_Size nSrcCvtBytes; |
| nTargetSize |
| = rtl_convertUnicodeToText( |
| hConverter, hContext, m_pBuffer, |
| m_pBufferEnd - m_pBuffer, pTargetBuffer, |
| nBufferSize, |
| RTL_UNICODETOTEXT_FLAGS_UNDEFINED_IGNORE |
| | RTL_UNICODETOTEXT_FLAGS_INVALID_IGNORE, |
| &nInfo, &nSrcCvtBytes); |
| if (!(nInfo |
| & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL)) |
| break; |
| delete[] pTargetBuffer; |
| pTargetBuffer = NULL; |
| rtl_resetUnicodeToTextContext(hConverter, hContext); |
| } |
| rtl_destroyUnicodeToTextContext(hConverter, hContext); |
| rtl_destroyUnicodeToTextConverter(hConverter); |
| |
| nSize = nTargetSize; |
| for (sal_Size k = 0; k < nTargetSize; ++k) |
| if (needsEncodedWordEscape(sal_uChar( |
| pTargetBuffer[k]))) |
| nSize += 2; |
| } |
| |
| const sal_Char * pCharsetName |
| = INetMIME::getCharsetName(eMIMEEncoding); |
| sal_uInt32 nWrapperSize = rtl_str_getLength(pCharsetName) + 7; |
| // '=?', '?Q?', '?=' |
| |
| switch (m_ePrevCoding) |
| { |
| case CODING_QUOTED: |
| m_rSink << '"'; |
| case CODING_NONE: |
| if (m_eInitialSpace == SPACE_ENCODED |
| && m_nExtraSpaces == 0) |
| m_nExtraSpaces = 1; |
| nSize += nWrapperSize; |
| for (; m_nExtraSpaces > 1; --m_nExtraSpaces) |
| { |
| if (m_rSink.getColumn() |
| >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| if (m_nExtraSpaces == 1) |
| { |
| if (m_rSink.getColumn() + nSize |
| >= m_rSink.getLineLengthLimit()) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << ' '; |
| } |
| m_rSink << "=?" << pCharsetName << "?Q?"; |
| break; |
| |
| case CODING_ENCODED: |
| if (m_ePrevMIMEEncoding != eMIMEEncoding |
| || m_rSink.getColumn() + m_nExtraSpaces + nSize |
| > m_rSink.getLineLengthLimit() - 2) |
| { |
| m_rSink << "?="; |
| if (m_rSink.getColumn() + nWrapperSize |
| + m_nExtraSpaces + nSize |
| > m_rSink.getLineLengthLimit() - 1) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << " =?" << pCharsetName << "?Q?"; |
| } |
| while (m_nExtraSpaces-- > 0) |
| { |
| if (m_rSink.getColumn() |
| > m_rSink.getLineLengthLimit() - 3) |
| m_rSink << "?=" << INetMIMEOutputSink::endl |
| << " =?" << pCharsetName << "?Q?"; |
| m_rSink << '_'; |
| } |
| break; |
| |
| case CODING_ENCODED_TERMINATED: |
| if (m_rSink.getColumn() + nWrapperSize |
| + m_nExtraSpaces + nSize |
| > m_rSink.getLineLengthLimit() - 1) |
| m_rSink << INetMIMEOutputSink::endl; |
| m_rSink << " =?" << pCharsetName << "?Q?"; |
| while (m_nExtraSpaces-- > 0) |
| { |
| if (m_rSink.getColumn() |
| > m_rSink.getLineLengthLimit() - 3) |
| m_rSink << "?=" << INetMIMEOutputSink::endl |
| << " =?" << pCharsetName << "?Q?"; |
| m_rSink << '_'; |
| } |
| break; |
| } |
| |
| // The non UTF-8 code will only work for stateless single byte |
| // character encodings (see also above): |
| if (eMIMEEncoding == RTL_TEXTENCODING_UTF8) |
| { |
| bool bInitial = true; |
| for (sal_Unicode const * p = m_pBuffer; |
| p != m_pBufferEnd;) |
| { |
| sal_uInt32 nUTF32 |
| = INetMIME::getUTF32Character(p, m_pBufferEnd); |
| bool bEscape = needsEncodedWordEscape(nUTF32); |
| sal_uInt32 nWidth |
| = bEscape ? |
| 3 * INetMIME::getUTF8OctetCount(nUTF32) : 1; |
| // only US-ASCII characters (that are converted to |
| // a single byte by UTF-8) need no encoded word |
| // escapes... |
| if (!bInitial |
| && m_rSink.getColumn() + nWidth + 2 |
| > m_rSink.getLineLengthLimit()) |
| m_rSink << "?=" << INetMIMEOutputSink::endl |
| << " =?" << pCharsetName << "?Q?"; |
| if (bEscape) |
| { |
| DBG_ASSERT( |
| nUTF32 < 0x10FFFF, |
| "INetMIMEEncodedWordOutputSink::finish():" |
| " Bad char"); |
| if (nUTF32 < 0x80) |
| INetMIME::writeEscapeSequence(m_rSink, |
| nUTF32); |
| else if (nUTF32 < 0x800) |
| { |
| INetMIME::writeEscapeSequence(m_rSink, |
| (nUTF32 >> 6) |
| | 0xC0); |
| INetMIME::writeEscapeSequence(m_rSink, |
| (nUTF32 & 0x3F) |
| | 0x80); |
| } |
| else if (nUTF32 < 0x10000) |
| { |
| INetMIME::writeEscapeSequence(m_rSink, |
| (nUTF32 >> 12) |
| | 0xE0); |
| INetMIME::writeEscapeSequence(m_rSink, |
| ((nUTF32 >> 6) |
| & 0x3F) |
| | 0x80); |
| INetMIME::writeEscapeSequence(m_rSink, |
| (nUTF32 & 0x3F) |
| | 0x80); |
| } |
| else |
| { |
| INetMIME::writeEscapeSequence(m_rSink, |
| (nUTF32 >> 18) |
| | 0xF0); |
| INetMIME::writeEscapeSequence(m_rSink, |
| ((nUTF32 >> 12) |
| & 0x3F) |
| | 0x80); |
| INetMIME::writeEscapeSequence(m_rSink, |
| ((nUTF32 >> 6) |
| & 0x3F) |
| | 0x80); |
| INetMIME::writeEscapeSequence(m_rSink, |
| (nUTF32 & 0x3F) |
| | 0x80); |
| } |
| } |
| else |
| m_rSink << sal_Char(nUTF32); |
| bInitial = false; |
| } |
| } |
| else |
| { |
| for (sal_Size k = 0; k < nTargetSize; ++k) |
| { |
| sal_uInt32 nUCS4 = sal_uChar(pTargetBuffer[k]); |
| bool bEscape = needsEncodedWordEscape(nUCS4); |
| if (k > 0 |
| && m_rSink.getColumn() + (bEscape ? 5 : 3) |
| > m_rSink.getLineLengthLimit()) |
| m_rSink << "?=" << INetMIMEOutputSink::endl |
| << " =?" << pCharsetName << "?Q?"; |
| if (bEscape) |
| INetMIME::writeEscapeSequence(m_rSink, nUCS4); |
| else |
| m_rSink << sal_Char(nUCS4); |
| } |
| delete[] pTargetBuffer; |
| } |
| |
| if (bWriteTrailer) |
| { |
| m_rSink << "?="; |
| m_eCoding = CODING_ENCODED_TERMINATED; |
| } |
| |
| m_ePrevMIMEEncoding = eMIMEEncoding; |
| break; |
| } |
| |
| default: |
| OSL_ASSERT(false); |
| break; |
| } |
| } |
| |
| m_eInitialSpace = SPACE_NO; |
| m_nExtraSpaces = 0; |
| m_pEncodingList->reset(); |
| m_pBufferEnd = m_pBuffer; |
| m_ePrevCoding = m_eCoding; |
| m_eCoding = CODING_NONE; |
| m_nQuotedEscaped = 0; |
| m_eEncodedWordState = STATE_INITIAL; |
| } |
| |
| //============================================================================ |
| INetMIMEEncodedWordOutputSink::~INetMIMEEncodedWordOutputSink() |
| { |
| rtl_freeMemory(m_pBuffer); |
| delete m_pEncodingList; |
| } |
| |
| //============================================================================ |
| INetMIMEEncodedWordOutputSink & |
| INetMIMEEncodedWordOutputSink::operator <<(sal_uInt32 nChar) |
| { |
| if (nChar == ' ') |
| { |
| if (m_pBufferEnd != m_pBuffer) |
| finish(false); |
| ++m_nExtraSpaces; |
| } |
| else |
| { |
| // Check for an already encoded word: |
| switch (m_eEncodedWordState) |
| { |
| case STATE_INITIAL: |
| if (nChar == '=') |
| m_eEncodedWordState = STATE_FIRST_EQUALS; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_FIRST_EQUALS: |
| if (nChar == '?') |
| m_eEncodedWordState = STATE_FIRST_EQUALS; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_FIRST_QUESTION: |
| if (INetMIME::isEncodedWordTokenChar(nChar)) |
| m_eEncodedWordState = STATE_CHARSET; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_CHARSET: |
| if (nChar == '?') |
| m_eEncodedWordState = STATE_SECOND_QUESTION; |
| else if (!INetMIME::isEncodedWordTokenChar(nChar)) |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_SECOND_QUESTION: |
| if (nChar == 'B' || nChar == 'Q' |
| || nChar == 'b' || nChar == 'q') |
| m_eEncodedWordState = STATE_ENCODING; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_ENCODING: |
| if (nChar == '?') |
| m_eEncodedWordState = STATE_THIRD_QUESTION; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_THIRD_QUESTION: |
| if (INetMIME::isVisible(nChar) && nChar != '?') |
| m_eEncodedWordState = STATE_ENCODED_TEXT; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_ENCODED_TEXT: |
| if (nChar == '?') |
| m_eEncodedWordState = STATE_FOURTH_QUESTION; |
| else if (!INetMIME::isVisible(nChar)) |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_FOURTH_QUESTION: |
| if (nChar == '=') |
| m_eEncodedWordState = STATE_SECOND_EQUALS; |
| else |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_SECOND_EQUALS: |
| m_eEncodedWordState = STATE_BAD; |
| break; |
| |
| case STATE_BAD: |
| break; |
| } |
| |
| // Update encoding: |
| m_pEncodingList->includes(nChar); |
| |
| // Update coding: |
| enum { TENQ = 1, // CONTEXT_TEXT, CODING_ENCODED |
| CENQ = 2, // CONTEXT_COMMENT, CODING_ENCODED |
| PQTD = 4, // CONTEXT_PHRASE, CODING_QUOTED |
| PENQ = 8 }; // CONTEXT_PHRASE, CODING_ENCODED |
| static const sal_Char aMinimal[128] |
| = { TENQ | CENQ | PENQ, // 0x00 |
| TENQ | CENQ | PENQ, // 0x01 |
| TENQ | CENQ | PENQ, // 0x02 |
| TENQ | CENQ | PENQ, // 0x03 |
| TENQ | CENQ | PENQ, // 0x04 |
| TENQ | CENQ | PENQ, // 0x05 |
| TENQ | CENQ | PENQ, // 0x06 |
| TENQ | CENQ | PENQ, // 0x07 |
| TENQ | CENQ | PENQ, // 0x08 |
| TENQ | CENQ | PENQ, // 0x09 |
| TENQ | CENQ | PENQ, // 0x0A |
| TENQ | CENQ | PENQ, // 0x0B |
| TENQ | CENQ | PENQ, // 0x0C |
| TENQ | CENQ | PENQ, // 0x0D |
| TENQ | CENQ | PENQ, // 0x0E |
| TENQ | CENQ | PENQ, // 0x0F |
| TENQ | CENQ | PENQ, // 0x10 |
| TENQ | CENQ | PENQ, // 0x11 |
| TENQ | CENQ | PENQ, // 0x12 |
| TENQ | CENQ | PENQ, // 0x13 |
| TENQ | CENQ | PENQ, // 0x14 |
| TENQ | CENQ | PENQ, // 0x15 |
| TENQ | CENQ | PENQ, // 0x16 |
| TENQ | CENQ | PENQ, // 0x17 |
| TENQ | CENQ | PENQ, // 0x18 |
| TENQ | CENQ | PENQ, // 0x19 |
| TENQ | CENQ | PENQ, // 0x1A |
| TENQ | CENQ | PENQ, // 0x1B |
| TENQ | CENQ | PENQ, // 0x1C |
| TENQ | CENQ | PENQ, // 0x1D |
| TENQ | CENQ | PENQ, // 0x1E |
| TENQ | CENQ | PENQ, // 0x1F |
| 0, // ' ' |
| 0, // '!' |
| PQTD , // '"' |
| 0, // '#' |
| 0, // '$' |
| 0, // '%' |
| 0, // '&' |
| 0, // ''' |
| CENQ | PQTD , // '(' |
| CENQ | PQTD , // ')' |
| 0, // '*' |
| 0, // '+' |
| PQTD , // ',' |
| 0, // '-' |
| PQTD , // '.' |
| 0, // '/' |
| 0, // '0' |
| 0, // '1' |
| 0, // '2' |
| 0, // '3' |
| 0, // '4' |
| 0, // '5' |
| 0, // '6' |
| 0, // '7' |
| 0, // '8' |
| 0, // '9' |
| PQTD , // ':' |
| PQTD , // ';' |
| PQTD , // '<' |
| 0, // '=' |
| PQTD , // '>' |
| 0, // '?' |
| PQTD , // '@' |
| 0, // 'A' |
| 0, // 'B' |
| 0, // 'C' |
| 0, // 'D' |
| 0, // 'E' |
| 0, // 'F' |
| 0, // 'G' |
| 0, // 'H' |
| 0, // 'I' |
| 0, // 'J' |
| 0, // 'K' |
| 0, // 'L' |
| 0, // 'M' |
| 0, // 'N' |
| 0, // 'O' |
| 0, // 'P' |
| 0, // 'Q' |
| 0, // 'R' |
| 0, // 'S' |
| 0, // 'T' |
| 0, // 'U' |
| 0, // 'V' |
| 0, // 'W' |
| 0, // 'X' |
| 0, // 'Y' |
| 0, // 'Z' |
| PQTD , // '[' |
| CENQ | PQTD , // '\' |
| PQTD , // ']' |
| 0, // '^' |
| 0, // '_' |
| 0, // '`' |
| 0, // 'a' |
| 0, // 'b' |
| 0, // 'c' |
| 0, // 'd' |
| 0, // 'e' |
| 0, // 'f' |
| 0, // 'g' |
| 0, // 'h' |
| 0, // 'i' |
| 0, // 'j' |
| 0, // 'k' |
| 0, // 'l' |
| 0, // 'm' |
| 0, // 'n' |
| 0, // 'o' |
| 0, // 'p' |
| 0, // 'q' |
| 0, // 'r' |
| 0, // 's' |
| 0, // 't' |
| 0, // 'u' |
| 0, // 'v' |
| 0, // 'w' |
| 0, // 'x' |
| 0, // 'y' |
| 0, // 'z' |
| 0, // '{' |
| 0, // '|' |
| 0, // '}' |
| 0, // '~' |
| TENQ | CENQ | PENQ }; // DEL |
| Coding eNewCoding = !INetMIME::isUSASCII(nChar) ? CODING_ENCODED : |
| m_eContext == CONTEXT_PHRASE ? |
| Coding(aMinimal[nChar] >> 2) : |
| aMinimal[nChar] & m_eContext ? CODING_ENCODED : |
| CODING_NONE; |
| if (eNewCoding > m_eCoding) |
| m_eCoding = eNewCoding; |
| if (m_eCoding == CODING_QUOTED |
| && INetMIME::needsQuotedStringEscape(nChar)) |
| ++m_nQuotedEscaped; |
| |
| // Append to buffer: |
| if (sal_uInt32(m_pBufferEnd - m_pBuffer) == m_nBufferSize) |
| { |
| m_pBuffer |
| = static_cast< sal_Unicode * >( |
| rtl_reallocateMemory(m_pBuffer, |
| (m_nBufferSize + BUFFER_SIZE) |
| * sizeof (sal_Unicode))); |
| m_pBufferEnd = m_pBuffer + m_nBufferSize; |
| m_nBufferSize += BUFFER_SIZE; |
| } |
| *m_pBufferEnd++ = sal_Unicode(nChar); |
| } |
| return *this; |
| } |
| |
| //============================================================================ |
| // |
| // INetContentTypeParameterList |
| // |
| //============================================================================ |
| |
| void INetContentTypeParameterList::Clear() |
| { |
| while (Count() > 0) |
| delete static_cast< INetContentTypeParameter * >(Remove(Count() - 1)); |
| } |
| |
| //============================================================================ |
| const INetContentTypeParameter * |
| INetContentTypeParameterList::find(const ByteString & rAttribute) const |
| { |
| for (sal_uIntPtr i = 0; i < Count(); ++i) |
| { |
| const INetContentTypeParameter * pParameter = GetObject(i); |
| if (pParameter->m_sAttribute.EqualsIgnoreCaseAscii(rAttribute)) |
| return pParameter; |
| } |
| return 0; |
| } |
| |