xref: /AOO41X/main/tools/source/inet/inetmime.cxx (revision 89b56da77b74925c286b3e777681ba8dda16bf41)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_tools.hxx"
26 
27 #include <cstddef>
28 #include <limits>
29 
30 #include "rtl/tencinfo.h"
31 #include <tools/datetime.hxx>
32 #include <tools/inetmime.hxx>
33 
34 namespace unnamed_tools_inetmime {} using namespace unnamed_tools_inetmime;
35     // unnamed namespaces don't work well yet
36 
37 //============================================================================
38 namespace unnamed_tools_inetmime {
39 
40 class Charset
41 {
42     rtl_TextEncoding m_eEncoding;
43     const sal_uInt32 * m_pRanges;
44 
45 public:
46     inline Charset(rtl_TextEncoding eTheEncoding,
47                    const sal_uInt32 * pTheRanges);
48 
getEncoding() const49     rtl_TextEncoding getEncoding() const { return m_eEncoding; }
50 
51     bool contains(sal_uInt32 nChar) const;
52 };
53 
Charset(rtl_TextEncoding eTheEncoding,const sal_uInt32 * pTheRanges)54 inline Charset::Charset(rtl_TextEncoding eTheEncoding,
55                         const sal_uInt32 * pTheRanges):
56     m_eEncoding(eTheEncoding),
57     m_pRanges(pTheRanges)
58 {
59     DBG_ASSERT(m_pRanges, "Charset::Charset(): Bad ranges");
60 }
61 
62 //============================================================================
63 void appendISO88591(UniString & rText, sal_Char const * pBegin,
64                     sal_Char const * pEnd);
65 
66 }
67 
68 //============================================================================
69 class INetMIMECharsetList_Impl
70 {
71     struct Node
72     {
73         Charset m_aCharset;
74         bool m_bDisabled;
75         Node * m_pNext;
76 
77         inline Node(const Charset & rTheCharset, bool bTheDisabled,
78                     Node * pTheNext);
79     };
80 
81     Node * m_pFirst;
82 
83 public:
INetMIMECharsetList_Impl()84     INetMIMECharsetList_Impl(): m_pFirst(0) {}
85 
86     ~INetMIMECharsetList_Impl();
87 
prepend(const Charset & rCharset)88     void prepend(const Charset & rCharset)
89     { m_pFirst = new Node(rCharset, false, m_pFirst); }
90 
91     void includes(sal_uInt32 nChar);
92 
93     rtl_TextEncoding getPreferredEncoding(rtl_TextEncoding eDefault
94                                               = RTL_TEXTENCODING_DONTKNOW)
95         const;
96 
97     void reset();
98 };
99 
Node(const Charset & rTheCharset,bool bTheDisabled,Node * pTheNext)100 inline INetMIMECharsetList_Impl::Node::Node(const Charset & rTheCharset,
101                                             bool bTheDisabled,
102                                             Node * pTheNext):
103     m_aCharset(rTheCharset),
104     m_bDisabled(bTheDisabled),
105     m_pNext(pTheNext)
106 {}
107 
108 //============================================================================
109 namespace unnamed_tools_inetmime {
110 
111 struct Parameter
112 {
113     Parameter * m_pNext;
114     ByteString m_aAttribute;
115     ByteString m_aCharset;
116     ByteString m_aLanguage;
117     ByteString m_aValue;
118     sal_uInt32 m_nSection;
119     bool m_bExtended;
120 
121     inline Parameter(Parameter * pTheNext, ByteString const & rTheAttribute,
122                      ByteString const & rTheCharset,
123                      ByteString const & rTheLanguage,
124                      ByteString const & rTheValue, sal_uInt32 nTheSection,
125                      bool bTheExtended);
126 };
127 
Parameter(Parameter * pTheNext,ByteString const & rTheAttribute,ByteString const & rTheCharset,ByteString const & rTheLanguage,ByteString const & rTheValue,sal_uInt32 nTheSection,bool bTheExtended)128 inline Parameter::Parameter(Parameter * pTheNext,
129                             ByteString const & rTheAttribute,
130                             ByteString const & rTheCharset,
131                             ByteString const & rTheLanguage,
132                             ByteString const & rTheValue,
133                             sal_uInt32 nTheSection, bool bTheExtended):
134     m_pNext(pTheNext),
135     m_aAttribute(rTheAttribute),
136     m_aCharset(rTheCharset),
137     m_aLanguage(rTheLanguage),
138     m_aValue(rTheValue),
139     m_nSection(nTheSection),
140     m_bExtended(bTheExtended)
141 {}
142 
143 //============================================================================
144 struct ParameterList
145 {
146     Parameter * m_pList;
147 
ParameterListunnamed_tools_inetmime::ParameterList148     ParameterList(): m_pList(0) {}
149 
150     inline ~ParameterList();
151 
152     Parameter ** find(ByteString const & rAttribute, sal_uInt32 nSection,
153                       bool & rPresent);
154 };
155 
~ParameterList()156 inline ParameterList::~ParameterList()
157 {
158     while (m_pList)
159     {
160         Parameter * pNext = m_pList->m_pNext;
161         delete m_pList;
162         m_pList = pNext;
163     }
164 }
165 
166 //============================================================================
167 bool parseParameters(ParameterList const & rInput,
168                      INetContentTypeParameterList * pOutput);
169 
170 }
171 
172 //============================================================================
173 //
174 //  Charset
175 //
176 //============================================================================
177 
contains(sal_uInt32 nChar) const178 bool Charset::contains(sal_uInt32 nChar) const
179 {
180     for (const sal_uInt32 * p = m_pRanges;;)
181     {
182         if (nChar < *p++)
183             return false;
184         if (nChar <= *p++)
185             return true;
186     }
187 }
188 
189 //============================================================================
190 //
191 //  appendISO88591
192 //
193 //============================================================================
194 
195 namespace unnamed_tools_inetmime {
196 
appendISO88591(UniString & rText,sal_Char const * pBegin,sal_Char const * pEnd)197 void appendISO88591(UniString & rText, sal_Char const * pBegin,
198                     sal_Char const * pEnd)
199 {
200     xub_StrLen nLength = static_cast< xub_StrLen >(pEnd - pBegin);
201     sal_Unicode * pBuffer = new sal_Unicode[nLength];
202     for (sal_Unicode * p = pBuffer; pBegin != pEnd;)
203         *p++ = sal_uChar(*pBegin++);
204     rText.Append(pBuffer, nLength);
205     delete[] pBuffer;
206 }
207 
208 }
209 
210 //============================================================================
211 //
212 //  INetMIMECharsetList_Impl
213 //
214 //============================================================================
215 
~INetMIMECharsetList_Impl()216 INetMIMECharsetList_Impl::~INetMIMECharsetList_Impl()
217 {
218     while (m_pFirst)
219     {
220         Node * pRemove = m_pFirst;
221         m_pFirst = m_pFirst->m_pNext;
222         delete pRemove;
223     }
224 }
225 
226 //============================================================================
includes(sal_uInt32 nChar)227 void INetMIMECharsetList_Impl::includes(sal_uInt32 nChar)
228 {
229     for (Node * p = m_pFirst; p; p = p->m_pNext)
230         if (!(p->m_bDisabled || p->m_aCharset.contains(nChar)))
231             p->m_bDisabled = true;
232 }
233 
234 //============================================================================
235 rtl_TextEncoding
getPreferredEncoding(rtl_TextEncoding eDefault) const236 INetMIMECharsetList_Impl::getPreferredEncoding(rtl_TextEncoding eDefault)
237     const
238 {
239     for (Node * p = m_pFirst; p; p = p->m_pNext)
240         if (!p->m_bDisabled)
241             return p->m_aCharset.getEncoding();
242     return eDefault;
243 }
244 
245 //============================================================================
reset()246 void INetMIMECharsetList_Impl::reset()
247 {
248     for (Node * p = m_pFirst; p; p = p->m_pNext)
249         p->m_bDisabled = false;
250 }
251 
252 //============================================================================
253 //
254 //  ParameterList
255 //
256 //============================================================================
257 
find(ByteString const & rAttribute,sal_uInt32 nSection,bool & rPresent)258 Parameter ** ParameterList::find(ByteString const & rAttribute,
259                                  sal_uInt32 nSection, bool & rPresent)
260 {
261     Parameter ** p = &m_pList;
262     for (; *p; p = &(*p)->m_pNext)
263     {
264         StringCompare eCompare = rAttribute.CompareTo((*p)->m_aAttribute);
265         if (eCompare == COMPARE_GREATER)
266             break;
267         else if (eCompare == COMPARE_EQUAL)
268         {
269             if (nSection > (*p)->m_nSection)
270                 break;
271             else if (nSection == (*p)->m_nSection)
272             {
273                 rPresent = true;
274                 return p;
275             }
276         }
277     }
278     rPresent = false;
279     return p;
280 }
281 
282 //============================================================================
283 //
284 //  parseParameters
285 //
286 //============================================================================
287 
288 namespace unnamed_tools_inetmime {
289 
parseParameters(ParameterList const & rInput,INetContentTypeParameterList * pOutput)290 bool parseParameters(ParameterList const & rInput,
291                      INetContentTypeParameterList * pOutput)
292 {
293     if (pOutput)
294         pOutput->Clear();
295 
296     Parameter * pPrev = 0;
297     for (Parameter * p = rInput.m_pList; p; p = p->m_pNext)
298     {
299         if (p->m_nSection > 0
300             && (!pPrev
301                 || pPrev->m_nSection != p->m_nSection - 1
302                 || pPrev->m_aAttribute != p->m_aAttribute))
303             return false;
304         pPrev = p;
305     }
306 
307     if (pOutput)
308         for (Parameter * p = rInput.m_pList; p;)
309         {
310             bool bCharset = p->m_aCharset.Len() != 0;
311             rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
312             if (bCharset)
313                 eEncoding
314                     = INetMIME::getCharsetEncoding(p->m_aCharset.GetBuffer(),
315                                                    p->m_aCharset.GetBuffer()
316                                                        + rInput.m_pList->
317                                                              m_aCharset.
318                                                                  Len());
319             UniString aValue;
320             bool bBadEncoding = false;
321             Parameter * pNext = p;
322             do
323             {
324                 sal_Size nSize;
325                 sal_Unicode * pUnicode
326                     = INetMIME::convertToUnicode(pNext->m_aValue.GetBuffer(),
327                                                  pNext->m_aValue.GetBuffer()
328                                                      + pNext->m_aValue.Len(),
329                                                  bCharset && p->m_bExtended ?
330                                                      eEncoding :
331                                                      RTL_TEXTENCODING_UTF8,
332                                                  nSize);
333                 if (!pUnicode && !(bCharset && p->m_bExtended))
334                     pUnicode = INetMIME::convertToUnicode(
335                                    pNext->m_aValue.GetBuffer(),
336                                    pNext->m_aValue.GetBuffer()
337                                        + pNext->m_aValue.Len(),
338                                    RTL_TEXTENCODING_ISO_8859_1, nSize);
339                 if (!pUnicode)
340                 {
341                     bBadEncoding = true;
342                     break;
343                 }
344                 aValue += UniString(pUnicode, static_cast< xub_StrLen >(nSize));
345                 delete[] pUnicode;
346                 pNext = pNext->m_pNext;
347             }
348             while (pNext && pNext->m_nSection > 0);
349             if (bBadEncoding)
350             {
351                 aValue.Erase();
352                 for (pNext = p;;)
353                 {
354                     if (pNext->m_bExtended)
355                         for (xub_StrLen i = 0; i < pNext->m_aValue.Len(); ++i)
356                             aValue += sal_Unicode(
357                                 sal_Unicode(
358                                     sal_uChar(pNext->m_aValue.GetChar(i)))
359                                 | 0xF800);
360                     else
361                         for (xub_StrLen i = 0; i < pNext->m_aValue.Len(); ++i)
362                             aValue
363                                 += sal_Unicode(sal_uChar
364                                                    (pNext->
365                                                         m_aValue.GetChar(i)));
366                     pNext = pNext->m_pNext;
367                     if (!pNext || pNext->m_nSection == 0)
368                         break;
369                 };
370             }
371             pOutput->Insert(new INetContentTypeParameter(p->m_aAttribute,
372                                                              p->m_aCharset,
373                                                              p->m_aLanguage,
374                                                              aValue,
375                                                              !bBadEncoding),
376                                 LIST_APPEND);
377             p = pNext;
378         }
379     return true;
380 }
381 
382 }
383 
384 //============================================================================
385 //
386 //  INetMIME
387 //
388 //============================================================================
389 
390 // static
isAtomChar(sal_uInt32 nChar)391 bool INetMIME::isAtomChar(sal_uInt32 nChar)
392 {
393     static const bool aMap[128]
394         = { false, false, false, false, false, false, false, false,
395             false, false, false, false, false, false, false, false,
396             false, false, false, false, false, false, false, false,
397             false, false, false, false, false, false, false, false,
398             false,  true, false,  true,  true,  true,  true,  true, // !"#$%&'
399             false, false,  true,  true, false,  true, false,  true, //()*+,-./
400              true,  true,  true,  true,  true,  true,  true,  true, //01234567
401              true,  true, false, false, false,  true, false,  true, //89:;<=>?
402             false,  true,  true,  true,  true,  true,  true,  true, //@ABCDEFG
403              true,  true,  true,  true,  true,  true,  true,  true, //HIJKLMNO
404              true,  true,  true,  true,  true,  true,  true,  true, //PQRSTUVW
405              true,  true,  true, false, false, false,  true,  true, //XYZ[\]^_
406              true,  true,  true,  true,  true,  true,  true,  true, //`abcdefg
407              true,  true,  true,  true,  true,  true,  true,  true, //hijklmno
408              true,  true,  true,  true,  true,  true,  true,  true, //pqrstuvw
409              true,  true,  true,  true,  true,  true,  true, false  //xyz{|}~
410           };
411     return isUSASCII(nChar) && aMap[nChar];
412 }
413 
414 //============================================================================
415 // static
isTokenChar(sal_uInt32 nChar)416 bool INetMIME::isTokenChar(sal_uInt32 nChar)
417 {
418     static const sal_Char aMap[128]
419         = { false, false, false, false, false, false, false, false,
420             false, false, false, false, false, false, false, false,
421             false, false, false, false, false, false, false, false,
422             false, false, false, false, false, false, false, false,
423             false,  true, false,  true,  true,  true,  true,  true, // !"#$%&'
424             false, false,  true,  true, false,  true,  true, false, //()*+,-./
425              true,  true,  true,  true,  true,  true,  true,  true, //01234567
426              true,  true, false, false, false, false, false, false, //89:;<=>?
427             false,  true,  true,  true,  true,  true,  true,  true, //@ABCDEFG
428              true,  true,  true,  true,  true,  true,  true,  true, //HIJKLMNO
429              true,  true,  true,  true,  true,  true,  true,  true, //PQRSTUVW
430              true,  true,  true, false, false, false,  true,  true, //XYZ[\]^_
431              true,  true,  true,  true,  true,  true,  true,  true, //`abcdefg
432              true,  true,  true,  true,  true,  true,  true,  true, //hijklmno
433              true,  true,  true,  true,  true,  true,  true,  true, //pqrstuvw
434              true,  true,  true,  true,  true,  true,  true, false  //xyz{|}~
435           };
436     return isUSASCII(nChar) && aMap[nChar];
437 }
438 
439 //============================================================================
440 // static
isEncodedWordTokenChar(sal_uInt32 nChar)441 bool INetMIME::isEncodedWordTokenChar(sal_uInt32 nChar)
442 {
443     static const sal_Char aMap[128]
444         = { false, false, false, false, false, false, false, false,
445             false, false, false, false, false, false, false, false,
446             false, false, false, false, false, false, false, false,
447             false, false, false, false, false, false, false, false,
448             false,  true, false,  true,  true,  true,  true,  true, // !"#$%&'
449             false, false,  true,  true, false,  true, false, false, //()*+,-./
450              true,  true,  true,  true,  true,  true,  true,  true, //01234567
451              true,  true, false, false, false, false, false, false, //89:;<=>?
452             false,  true,  true,  true,  true,  true,  true,  true, //@ABCDEFG
453              true,  true,  true,  true,  true,  true,  true,  true, //HIJKLMNO
454              true,  true,  true,  true,  true,  true,  true,  true, //PQRSTUVW
455              true,  true,  true, false, false, false,  true,  true, //XYZ[\]^_
456              true,  true,  true,  true,  true,  true,  true,  true, //`abcdefg
457              true,  true,  true,  true,  true,  true,  true,  true, //hijklmno
458              true,  true,  true,  true,  true,  true,  true,  true, //pqrstuvw
459              true,  true,  true,  true,  true,  true,  true, false  //xyz{|}~
460           };
461     return isUSASCII(nChar) && aMap[nChar];
462 }
463 
464 //============================================================================
465 // static
isIMAPAtomChar(sal_uInt32 nChar)466 bool INetMIME::isIMAPAtomChar(sal_uInt32 nChar)
467 {
468     static const sal_Char aMap[128]
469         = { false, false, false, false, false, false, false, false,
470             false, false, false, false, false, false, false, false,
471             false, false, false, false, false, false, false, false,
472             false, false, false, false, false, false, false, false,
473             false,  true, false,  true,  true, false,  true,  true, // !"#$%&'
474             false, false, false,  true,  true,  true,  true,  true, //()*+,-./
475              true,  true,  true,  true,  true,  true,  true,  true, //01234567
476              true,  true,  true,  true,  true,  true,  true,  true, //89:;<=>?
477              true,  true,  true,  true,  true,  true,  true,  true, //@ABCDEFG
478              true,  true,  true,  true,  true,  true,  true,  true, //HIJKLMNO
479              true,  true,  true,  true,  true,  true,  true,  true, //PQRSTUVW
480              true,  true,  true,  true, false,  true,  true,  true, //XYZ[\]^_
481              true,  true,  true,  true,  true,  true,  true,  true, //`abcdefg
482              true,  true,  true,  true,  true,  true,  true,  true, //hijklmno
483              true,  true,  true,  true,  true,  true,  true,  true, //pqrstuvw
484              true,  true,  true, false,  true,  true,  true, false  //xyz{|}~
485           };
486     return isUSASCII(nChar) && aMap[nChar];
487 }
488 
489 //============================================================================
490 // static
getDigit(int nWeight)491 sal_uInt32 INetMIME::getDigit(int nWeight)
492 {
493     DBG_ASSERT(nWeight >= 0 && nWeight < 10,
494                "INetMIME::getDigit(): Bad weight");
495 
496     static const sal_Char aDigits[16]
497         = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
498     return aDigits[nWeight];
499 }
500 
501 //============================================================================
502 // static
getHexDigit(int nWeight)503 sal_uInt32 INetMIME::getHexDigit(int nWeight)
504 {
505     DBG_ASSERT(nWeight >= 0 && nWeight < 16,
506                "INetMIME::getHexDigit(): Bad weight");
507 
508     static const sal_Char aDigits[16]
509         = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
510             'D', 'E', 'F' };
511     return aDigits[nWeight];
512 }
513 
514 //============================================================================
515 // static
getBase64Digit(int nWeight)516 sal_uInt32 INetMIME::getBase64Digit(int nWeight)
517 {
518     DBG_ASSERT(nWeight >= 0 && nWeight < 64,
519                "INetMIME::getBase64Digit(): Bad weight");
520 
521     static const sal_Char aDigits[64]
522         = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
523             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
524             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
525             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
526             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
527     return aDigits[nWeight];
528 }
529 
530 //============================================================================
531 // static
equalIgnoreCase(const sal_Char * pBegin1,const sal_Char * pEnd1,const sal_Char * pBegin2,const sal_Char * pEnd2)532 bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1,
533                                const sal_Char * pEnd1,
534                                const sal_Char * pBegin2,
535                                const sal_Char * pEnd2)
536 {
537     DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pBegin2 && pBegin2 <= pEnd2,
538                "INetMIME::equalIgnoreCase(): Bad sequences");
539 
540     if (pEnd1 - pBegin1 != pEnd2 - pBegin2)
541         return false;
542     while (pBegin1 != pEnd1)
543         if (toUpperCase(*pBegin1++) != toUpperCase(*pBegin2++))
544             return false;
545     return true;
546 }
547 
548 //============================================================================
549 // static
equalIgnoreCase(const sal_Char * pBegin1,const sal_Char * pEnd1,const sal_Char * pString2)550 bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1,
551                                const sal_Char * pEnd1,
552                                const sal_Char * pString2)
553 {
554     DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2,
555                "INetMIME::equalIgnoreCase(): Bad sequences");
556 
557     while (*pString2 != 0)
558         if (pBegin1 == pEnd1
559             || toUpperCase(*pBegin1++) != toUpperCase(*pString2++))
560             return false;
561     return pBegin1 == pEnd1;
562 }
563 
564 //============================================================================
565 // static
equalIgnoreCase(const sal_Unicode * pBegin1,const sal_Unicode * pEnd1,const sal_Char * pString2)566 bool INetMIME::equalIgnoreCase(const sal_Unicode * pBegin1,
567                                const sal_Unicode * pEnd1,
568                                const sal_Char * pString2)
569 {
570     DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2,
571                "INetMIME::equalIgnoreCase(): Bad sequences");
572 
573     while (*pString2 != 0)
574         if (pBegin1 == pEnd1
575             || toUpperCase(*pBegin1++) != toUpperCase(*pString2++))
576             return false;
577     return pBegin1 == pEnd1;
578 }
579 
580 //============================================================================
581 // static
skipLinearWhiteSpace(const sal_Char * pBegin,const sal_Char * pEnd)582 const sal_Char * INetMIME::skipLinearWhiteSpace(const sal_Char * pBegin,
583                                                 const sal_Char * pEnd)
584 {
585     DBG_ASSERT(pBegin && pBegin <= pEnd,
586                "INetMIME::skipLinearWhiteSpace(): Bad sequence");
587 
588     while (pBegin != pEnd)
589         switch (*pBegin)
590         {
591             case '\t':
592             case ' ':
593                 ++pBegin;
594                 break;
595 
596             case 0x0D: // CR
597                 if (startsWithLineFolding(pBegin, pEnd))
598                     pBegin += 3;
599                 else
600                     return pBegin;
601                 break;
602 
603             default:
604                 return pBegin;
605         }
606     return pBegin;
607 }
608 
609 //============================================================================
610 // static
skipLinearWhiteSpace(const sal_Unicode * pBegin,const sal_Unicode * pEnd)611 const sal_Unicode * INetMIME::skipLinearWhiteSpace(const sal_Unicode * pBegin,
612                                                    const sal_Unicode * pEnd)
613 {
614     DBG_ASSERT(pBegin && pBegin <= pEnd,
615                "INetMIME::skipLinearWhiteSpace(): Bad sequence");
616 
617     while (pBegin != pEnd)
618         switch (*pBegin)
619         {
620             case '\t':
621             case ' ':
622                 ++pBegin;
623                 break;
624 
625             case 0x0D: // CR
626                 if (startsWithLineFolding(pBegin, pEnd))
627                     pBegin += 3;
628                 else
629                     return pBegin;
630                 break;
631 
632             default:
633                 return pBegin;
634         }
635     return pBegin;
636 }
637 
638 //============================================================================
639 // static
skipComment(const sal_Char * pBegin,const sal_Char * pEnd)640 const sal_Char * INetMIME::skipComment(const sal_Char * pBegin,
641                                        const sal_Char * pEnd)
642 {
643     DBG_ASSERT(pBegin && pBegin <= pEnd,
644                "INetMIME::skipComment(): Bad sequence");
645 
646     if (pBegin != pEnd && *pBegin == '(')
647     {
648         sal_uInt32 nLevel = 0;
649         for (const sal_Char * p = pBegin; p != pEnd;)
650             switch (*p++)
651             {
652                 case '(':
653                     ++nLevel;
654                     break;
655 
656                 case ')':
657                     if (--nLevel == 0)
658                         return p;
659                     break;
660 
661                 case '\\':
662                     if (p != pEnd)
663                         ++p;
664                     break;
665             }
666     }
667     return pBegin;
668 }
669 
670 //============================================================================
671 // static
skipComment(const sal_Unicode * pBegin,const sal_Unicode * pEnd)672 const sal_Unicode * INetMIME::skipComment(const sal_Unicode * pBegin,
673                                           const sal_Unicode * pEnd)
674 {
675     DBG_ASSERT(pBegin && pBegin <= pEnd,
676                "INetMIME::skipComment(): Bad sequence");
677 
678     if (pBegin != pEnd && *pBegin == '(')
679     {
680         sal_uInt32 nLevel = 0;
681         for (const sal_Unicode * p = pBegin; p != pEnd;)
682             switch (*p++)
683             {
684                 case '(':
685                     ++nLevel;
686                     break;
687 
688                 case ')':
689                     if (--nLevel == 0)
690                         return p;
691                     break;
692 
693                 case '\\':
694                     if (p != pEnd)
695                         ++p;
696                     break;
697             }
698     }
699     return pBegin;
700 }
701 
702 //============================================================================
703 // static
skipLinearWhiteSpaceComment(const sal_Char * pBegin,const sal_Char * pEnd)704 const sal_Char * INetMIME::skipLinearWhiteSpaceComment(const sal_Char *
705                                                            pBegin,
706                                                        const sal_Char * pEnd)
707 {
708     DBG_ASSERT(pBegin && pBegin <= pEnd,
709                "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence");
710 
711     while (pBegin != pEnd)
712         switch (*pBegin)
713         {
714             case '\t':
715             case ' ':
716                 ++pBegin;
717                 break;
718 
719             case 0x0D: // CR
720                 if (startsWithLineFolding(pBegin, pEnd))
721                     pBegin += 3;
722                 else
723                     return pBegin;
724                 break;
725 
726             case '(':
727             {
728                 const sal_Char * p = skipComment(pBegin, pEnd);
729                 if (p == pBegin)
730                     return pBegin;
731                 pBegin = p;
732                 break;
733             }
734 
735             default:
736                 return pBegin;
737         }
738     return pBegin;
739 }
740 
741 //============================================================================
742 // static
skipLinearWhiteSpaceComment(const sal_Unicode * pBegin,const sal_Unicode * pEnd)743 const sal_Unicode * INetMIME::skipLinearWhiteSpaceComment(const sal_Unicode *
744                                                               pBegin,
745                                                           const sal_Unicode *
746                                                               pEnd)
747 {
748     DBG_ASSERT(pBegin && pBegin <= pEnd,
749                "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence");
750 
751     while (pBegin != pEnd)
752         switch (*pBegin)
753         {
754             case '\t':
755             case ' ':
756                 ++pBegin;
757                 break;
758 
759             case 0x0D: // CR
760                 if (startsWithLineFolding(pBegin, pEnd))
761                     pBegin += 3;
762                 else
763                     return pBegin;
764                 break;
765 
766             case '(':
767             {
768                 const sal_Unicode * p = skipComment(pBegin, pEnd);
769                 if (p == pBegin)
770                     return pBegin;
771                 pBegin = p;
772                 break;
773             }
774 
775             default:
776                 return pBegin;
777         }
778     return pBegin;
779 }
780 
781 //============================================================================
782 // static
skipQuotedString(const sal_Char * pBegin,const sal_Char * pEnd)783 const sal_Char * INetMIME::skipQuotedString(const sal_Char * pBegin,
784                                             const sal_Char * pEnd)
785 {
786     DBG_ASSERT(pBegin && pBegin <= pEnd,
787                "INetMIME::skipQuotedString(): Bad sequence");
788 
789     if (pBegin != pEnd && *pBegin == '"')
790         for (const sal_Char * p = pBegin + 1; p != pEnd;)
791             switch (*p++)
792             {
793                 case 0x0D: // CR
794                     if (pEnd - p < 2 || *p++ != 0x0A // LF
795                         || !isWhiteSpace(*p++))
796                         return pBegin;
797                     break;
798 
799                 case '"':
800                     return p;
801 
802                 case '\\':
803                     if (p != pEnd)
804                         ++p;
805                     break;
806             }
807     return pBegin;
808 }
809 
810 //============================================================================
811 // static
skipQuotedString(const sal_Unicode * pBegin,const sal_Unicode * pEnd)812 const sal_Unicode * INetMIME::skipQuotedString(const sal_Unicode * pBegin,
813                                                const sal_Unicode * pEnd)
814 {
815     DBG_ASSERT(pBegin && pBegin <= pEnd,
816                "INetMIME::skipQuotedString(): Bad sequence");
817 
818     if (pBegin != pEnd && *pBegin == '"')
819         for (const sal_Unicode * p = pBegin + 1; p != pEnd;)
820             switch (*p++)
821             {
822                 case 0x0D: // CR
823                     if (pEnd - p < 2 || *p++ != 0x0A // LF
824                         || !isWhiteSpace(*p++))
825                         return pBegin;
826                     break;
827 
828                 case '"':
829                     return p;
830 
831                 case '\\':
832                     if (p != pEnd)
833                         ++p;
834                     break;
835             }
836     return pBegin;
837 }
838 
839 //============================================================================
840 // static
scanAtom(const sal_Char * pBegin,const sal_Char * pEnd)841 const sal_Char * INetMIME::scanAtom(const sal_Char * pBegin,
842                                     const sal_Char * pEnd)
843 {
844     while (pBegin != pEnd && isAtomChar(*pBegin))
845         ++pBegin;
846     return pBegin;
847 }
848 
849 //============================================================================
850 // static
scanAtom(const sal_Unicode * pBegin,const sal_Unicode * pEnd)851 const sal_Unicode * INetMIME::scanAtom(const sal_Unicode * pBegin,
852                                        const sal_Unicode * pEnd)
853 {
854     while (pBegin != pEnd && isAtomChar(*pBegin))
855         ++pBegin;
856     return pBegin;
857 }
858 
859 //============================================================================
860 // static
scanUnsigned(const sal_Char * & rBegin,const sal_Char * pEnd,bool bLeadingZeroes,sal_uInt32 & rValue)861 bool INetMIME::scanUnsigned(const sal_Char *& rBegin, const sal_Char * pEnd,
862                             bool bLeadingZeroes, sal_uInt32 & rValue)
863 {
864     sal_uInt64 nTheValue = 0;
865     const sal_Char * p = rBegin;
866     for ( ; p != pEnd; ++p)
867     {
868         int nWeight = getWeight(*p);
869         if (nWeight < 0)
870             break;
871         nTheValue = 10 * nTheValue + nWeight;
872         if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
873             return false;
874     }
875     if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
876         return false;
877     rBegin = p;
878     rValue = sal_uInt32(nTheValue);
879     return true;
880 }
881 
882 //============================================================================
883 // static
scanUnsigned(const sal_Unicode * & rBegin,const sal_Unicode * pEnd,bool bLeadingZeroes,sal_uInt32 & rValue)884 bool INetMIME::scanUnsigned(const sal_Unicode *& rBegin,
885                             const sal_Unicode * pEnd, bool bLeadingZeroes,
886                             sal_uInt32 & rValue)
887 {
888     sal_uInt64 nTheValue = 0;
889     const sal_Unicode * p = rBegin;
890     for ( ; p != pEnd; ++p)
891     {
892         int nWeight = getWeight(*p);
893         if (nWeight < 0)
894             break;
895         nTheValue = 10 * nTheValue + nWeight;
896         if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
897             return false;
898     }
899     if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
900         return false;
901     rBegin = p;
902     rValue = sal_uInt32(nTheValue);
903     return true;
904 }
905 
906 //============================================================================
907 // static
scanUnsignedHex(const sal_Char * & rBegin,const sal_Char * pEnd,bool bLeadingZeroes,sal_uInt32 & rValue)908 bool INetMIME::scanUnsignedHex(const sal_Char *& rBegin,
909                                const sal_Char * pEnd, bool bLeadingZeroes,
910                                sal_uInt32 & rValue)
911 {
912     sal_uInt64 nTheValue = 0;
913     const sal_Char * p = rBegin;
914     for ( p = rBegin; p != pEnd; ++p)
915     {
916         int nWeight = getHexWeight(*p);
917         if (nWeight < 0)
918             break;
919         nTheValue = nTheValue << 4 | nWeight;
920         if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
921             return false;
922     }
923     if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
924         return false;
925     rBegin = p;
926     rValue = sal_uInt32(nTheValue);
927     return true;
928 }
929 
930 //============================================================================
931 // static
scanUnsignedHex(const sal_Unicode * & rBegin,const sal_Unicode * pEnd,bool bLeadingZeroes,sal_uInt32 & rValue)932 bool INetMIME::scanUnsignedHex(const sal_Unicode *& rBegin,
933                                const sal_Unicode * pEnd, bool bLeadingZeroes,
934                                sal_uInt32 & rValue)
935 {
936     sal_uInt64 nTheValue = 0;
937     const sal_Unicode * p = rBegin;
938     for ( ; p != pEnd; ++p)
939     {
940         int nWeight = getHexWeight(*p);
941         if (nWeight < 0)
942             break;
943         nTheValue = nTheValue << 4 | nWeight;
944         if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
945             return false;
946     }
947     if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
948         return false;
949     rBegin = p;
950     rValue = sal_uInt32(nTheValue);
951     return true;
952 }
953 
954 //============================================================================
955 // static
scanQuotedBlock(const sal_Char * pBegin,const sal_Char * pEnd,sal_uInt32 nOpening,sal_uInt32 nClosing,sal_Size & rLength,bool & rModify)956 const sal_Char * INetMIME::scanQuotedBlock(const sal_Char * pBegin,
957                                            const sal_Char * pEnd,
958                                            sal_uInt32 nOpening,
959                                            sal_uInt32 nClosing,
960                                            sal_Size & rLength,
961                                            bool & rModify)
962 {
963     DBG_ASSERT(pBegin && pBegin <= pEnd,
964                "INetMIME::scanQuotedBlock(): Bad sequence");
965 
966     if (pBegin != pEnd && static_cast< unsigned char >(*pBegin) == nOpening)
967     {
968         ++rLength;
969         ++pBegin;
970         while (pBegin != pEnd)
971             if (static_cast< unsigned char >(*pBegin) == nClosing)
972             {
973                 ++rLength;
974                 return ++pBegin;
975             }
976             else
977             {
978                 sal_uInt32 c = *pBegin++;
979                 switch (c)
980                 {
981                     case 0x0D: // CR
982                         if (pBegin != pEnd && *pBegin == 0x0A) // LF
983                             if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1]))
984                             {
985                                 ++rLength;
986                                 rModify = true;
987                                 pBegin += 2;
988                             }
989                             else
990                             {
991                                 rLength += 3;
992                                 rModify = true;
993                                 ++pBegin;
994                             }
995                         else
996                             ++rLength;
997                         break;
998 
999                     case '\\':
1000                         ++rLength;
1001                         if (pBegin != pEnd)
1002                         {
1003                             if (startsWithLineBreak(pBegin, pEnd)
1004                                 && (pEnd - pBegin < 3
1005                                     || !isWhiteSpace(pBegin[2])))
1006                             {
1007                                 rLength += 3;
1008                                 rModify = true;
1009                                 pBegin += 2;
1010                             }
1011                             else
1012                                 ++pBegin;
1013                         }
1014                         break;
1015 
1016                     default:
1017                         ++rLength;
1018                         if (!isUSASCII(c))
1019                             rModify = true;
1020                         break;
1021                 }
1022             }
1023     }
1024     return pBegin;
1025 }
1026 
1027 //============================================================================
1028 // static
scanQuotedBlock(const sal_Unicode * pBegin,const sal_Unicode * pEnd,sal_uInt32 nOpening,sal_uInt32 nClosing,sal_Size & rLength,bool & rModify)1029 const sal_Unicode * INetMIME::scanQuotedBlock(const sal_Unicode * pBegin,
1030                                               const sal_Unicode * pEnd,
1031                                               sal_uInt32 nOpening,
1032                                               sal_uInt32 nClosing,
1033                                               sal_Size & rLength,
1034                                               bool & rModify)
1035 {
1036     DBG_ASSERT(pBegin && pBegin <= pEnd,
1037                "INetMIME::scanQuotedBlock(): Bad sequence");
1038 
1039     if (pBegin != pEnd && *pBegin == nOpening)
1040     {
1041         ++rLength;
1042         ++pBegin;
1043         while (pBegin != pEnd)
1044             if (*pBegin == nClosing)
1045             {
1046                 ++rLength;
1047                 return ++pBegin;
1048             }
1049             else
1050             {
1051                 sal_uInt32 c = *pBegin++;
1052                 switch (c)
1053                 {
1054                     case 0x0D: // CR
1055                         if (pBegin != pEnd && *pBegin == 0x0A) // LF
1056                             if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1]))
1057                             {
1058                                 ++rLength;
1059                                 rModify = true;
1060                                 pBegin += 2;
1061                             }
1062                             else
1063                             {
1064                                 rLength += 3;
1065                                 rModify = true;
1066                                 ++pBegin;
1067                             }
1068                         else
1069                             ++rLength;
1070                         break;
1071 
1072                     case '\\':
1073                         ++rLength;
1074                         if (pBegin != pEnd)
1075                         {
1076                             if (startsWithLineBreak(pBegin, pEnd)
1077                                 && (pEnd - pBegin < 3
1078                                     || !isWhiteSpace(pBegin[2])))
1079                             {
1080                                 rLength += 3;
1081                                 rModify = true;
1082                                 pBegin += 2;
1083                             }
1084                             else
1085                                 ++pBegin;
1086                         }
1087                         break;
1088 
1089                     default:
1090                         ++rLength;
1091                         if (!isUSASCII(c))
1092                             rModify = true;
1093                         break;
1094                 }
1095             }
1096     }
1097     return pBegin;
1098 }
1099 
1100 //============================================================================
1101 // static
scanParameters(sal_Char const * pBegin,sal_Char const * pEnd,INetContentTypeParameterList * pParameters)1102 sal_Char const * INetMIME::scanParameters(sal_Char const * pBegin,
1103                                           sal_Char const * pEnd,
1104                                           INetContentTypeParameterList *
1105                                               pParameters)
1106 {
1107     ParameterList aList;
1108     sal_Char const * pParameterBegin = pBegin;
1109     for (sal_Char const * p = pParameterBegin;; pParameterBegin = p)
1110     {
1111         pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd);
1112         if (pParameterBegin == pEnd || *pParameterBegin != ';')
1113             break;
1114         p = pParameterBegin + 1;
1115 
1116         sal_Char const * pAttributeBegin = skipLinearWhiteSpaceComment(p,
1117                                                                        pEnd);
1118         p = pAttributeBegin;
1119         bool bDowncaseAttribute = false;
1120         while (p != pEnd && isTokenChar(*p) && *p != '*')
1121         {
1122             bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p);
1123             ++p;
1124         }
1125         if (p == pAttributeBegin)
1126             break;
1127         ByteString aAttribute(
1128             pAttributeBegin, static_cast< xub_StrLen >(p - pAttributeBegin));
1129         if (bDowncaseAttribute)
1130             aAttribute.ToLowerAscii();
1131 
1132         sal_uInt32 nSection = 0;
1133         if (p != pEnd && *p == '*')
1134         {
1135             ++p;
1136             if (p != pEnd && isDigit(*p)
1137                 && !scanUnsigned(p, pEnd, false, nSection))
1138                 break;
1139         }
1140 
1141         bool bPresent;
1142         Parameter ** pPos = aList.find(aAttribute, nSection, bPresent);
1143         if (bPresent)
1144             break;
1145 
1146         bool bExtended = false;
1147         if (p != pEnd && *p == '*')
1148         {
1149             ++p;
1150             bExtended = true;
1151         }
1152 
1153         p = skipLinearWhiteSpaceComment(p, pEnd);
1154 
1155         if (p == pEnd || *p != '=')
1156             break;
1157 
1158         p = skipLinearWhiteSpaceComment(p + 1, pEnd);
1159 
1160         ByteString aCharset;
1161         ByteString aLanguage;
1162         ByteString aValue;
1163         if (bExtended)
1164         {
1165             if (nSection == 0)
1166             {
1167                 sal_Char const * pCharsetBegin = p;
1168                 bool bDowncaseCharset = false;
1169                 while (p != pEnd && isTokenChar(*p) && *p != '\'')
1170                 {
1171                     bDowncaseCharset = bDowncaseCharset || isUpperCase(*p);
1172                     ++p;
1173                 }
1174                 if (p == pCharsetBegin)
1175                     break;
1176                 if (pParameters)
1177                 {
1178                     aCharset = ByteString(
1179                         pCharsetBegin,
1180                         static_cast< xub_StrLen >(p - pCharsetBegin));
1181                     if (bDowncaseCharset)
1182                         aCharset.ToLowerAscii();
1183                 }
1184 
1185                 if (p == pEnd || *p != '\'')
1186                     break;
1187                 ++p;
1188 
1189                 sal_Char const * pLanguageBegin = p;
1190                 bool bDowncaseLanguage = false;
1191                 int nLetters = 0;
1192                 for (; p != pEnd; ++p)
1193                     if (isAlpha(*p))
1194                     {
1195                         if (++nLetters > 8)
1196                             break;
1197                         bDowncaseLanguage = bDowncaseLanguage
1198                                             || isUpperCase(*p);
1199                     }
1200                     else if (*p == '-')
1201                     {
1202                         if (nLetters == 0)
1203                             break;
1204                         nLetters = 0;
1205                     }
1206                     else
1207                         break;
1208                 if (nLetters == 0 || nLetters > 8)
1209                     break;
1210                 if (pParameters)
1211                 {
1212                     aLanguage = ByteString(
1213                         pLanguageBegin,
1214                         static_cast< xub_StrLen >(p - pLanguageBegin));
1215                     if (bDowncaseLanguage)
1216                         aLanguage.ToLowerAscii();
1217                 }
1218 
1219                 if (p == pEnd || *p != '\'')
1220                     break;
1221                 ++p;
1222             }
1223             if (pParameters)
1224                 while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
1225                 {
1226                     if (*p == '%')
1227                     {
1228                         if (p + 2 < pEnd)
1229                         {
1230                             int nWeight1 = getHexWeight(p[1]);
1231                             int nWeight2 = getHexWeight(p[2]);
1232                             if (nWeight1 >= 0 && nWeight2 >= 0)
1233                             {
1234                                 aValue += sal_Char(nWeight1 << 4 | nWeight2);
1235                                 p += 3;
1236                                 continue;
1237                             }
1238                         }
1239                     }
1240                     aValue += *p++;
1241                 }
1242             else
1243                 while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
1244                     ++p;
1245         }
1246         else if (p != pEnd && *p == '"')
1247             if (pParameters)
1248             {
1249                 bool bInvalid = false;
1250                 for (++p;;)
1251                 {
1252                     if (p == pEnd)
1253                     {
1254                         bInvalid = true;
1255                         break;
1256                     }
1257                     else if (*p == '"')
1258                     {
1259                         ++p;
1260                         break;
1261                     }
1262                     else if (*p == 0x0D) // CR
1263                     {
1264                         if (pEnd - p < 3 || p[1] != 0x0A // LF
1265                             || !isWhiteSpace(p[2]))
1266                         {
1267                             bInvalid = true;
1268                             break;
1269                         }
1270                         p += 2;
1271                     }
1272                     else if (*p == '\\' && ++p == pEnd)
1273                     {
1274                         bInvalid = true;
1275                         break;
1276                     }
1277                     aValue += *p++;
1278                 }
1279                 if (bInvalid)
1280                     break;
1281             }
1282             else
1283             {
1284                 sal_Char const * pStringEnd = skipQuotedString(p, pEnd);
1285                 if (p == pStringEnd)
1286                     break;
1287                 p = pStringEnd;
1288             }
1289         else
1290         {
1291             sal_Char const * pTokenBegin = p;
1292             while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
1293                 ++p;
1294             if (p == pTokenBegin)
1295                 break;
1296             if (pParameters)
1297                 aValue = ByteString(
1298                     pTokenBegin, static_cast< xub_StrLen >(p - pTokenBegin));
1299         }
1300 
1301         *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue,
1302                               nSection, bExtended);
1303     }
1304     return parseParameters(aList, pParameters) ? pParameterBegin : pBegin;
1305 }
1306 
1307 //============================================================================
1308 // static
scanParameters(sal_Unicode const * pBegin,sal_Unicode const * pEnd,INetContentTypeParameterList * pParameters)1309 sal_Unicode const * INetMIME::scanParameters(sal_Unicode const * pBegin,
1310                                              sal_Unicode const * pEnd,
1311                                              INetContentTypeParameterList *
1312                                                  pParameters)
1313 {
1314     ParameterList aList;
1315     sal_Unicode const * pParameterBegin = pBegin;
1316     for (sal_Unicode const * p = pParameterBegin;; pParameterBegin = p)
1317     {
1318         pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd);
1319         if (pParameterBegin == pEnd || *pParameterBegin != ';')
1320             break;
1321         p = pParameterBegin + 1;
1322 
1323         sal_Unicode const * pAttributeBegin
1324             = skipLinearWhiteSpaceComment(p, pEnd);
1325         p = pAttributeBegin;
1326         bool bDowncaseAttribute = false;
1327         while (p != pEnd && isTokenChar(*p) && *p != '*')
1328         {
1329             bDowncaseAttribute = bDowncaseAttribute || isUpperCase(*p);
1330             ++p;
1331         }
1332         if (p == pAttributeBegin)
1333             break;
1334         ByteString aAttribute = ByteString(
1335             pAttributeBegin, static_cast< xub_StrLen >(p - pAttributeBegin),
1336             RTL_TEXTENCODING_ASCII_US);
1337         if (bDowncaseAttribute)
1338             aAttribute.ToLowerAscii();
1339 
1340         sal_uInt32 nSection = 0;
1341         if (p != pEnd && *p == '*')
1342         {
1343             ++p;
1344             if (p != pEnd && isDigit(*p)
1345                 && !scanUnsigned(p, pEnd, false, nSection))
1346                 break;
1347         }
1348 
1349         bool bPresent;
1350         Parameter ** pPos = aList.find(aAttribute, nSection, bPresent);
1351         if (bPresent)
1352             break;
1353 
1354         bool bExtended = false;
1355         if (p != pEnd && *p == '*')
1356         {
1357             ++p;
1358             bExtended = true;
1359         }
1360 
1361         p = skipLinearWhiteSpaceComment(p, pEnd);
1362 
1363         if (p == pEnd || *p != '=')
1364             break;
1365 
1366         p = skipLinearWhiteSpaceComment(p + 1, pEnd);
1367 
1368         ByteString aCharset;
1369         ByteString aLanguage;
1370         ByteString aValue;
1371         if (bExtended)
1372         {
1373             if (nSection == 0)
1374             {
1375                 sal_Unicode const * pCharsetBegin = p;
1376                 bool bDowncaseCharset = false;
1377                 while (p != pEnd && isTokenChar(*p) && *p != '\'')
1378                 {
1379                     bDowncaseCharset = bDowncaseCharset || isUpperCase(*p);
1380                     ++p;
1381                 }
1382                 if (p == pCharsetBegin)
1383                     break;
1384                 if (pParameters)
1385                 {
1386                     aCharset = ByteString(
1387                         pCharsetBegin,
1388                         static_cast< xub_StrLen >(p - pCharsetBegin),
1389                         RTL_TEXTENCODING_ASCII_US);
1390                     if (bDowncaseCharset)
1391                         aCharset.ToLowerAscii();
1392                 }
1393 
1394                 if (p == pEnd || *p != '\'')
1395                     break;
1396                 ++p;
1397 
1398                 sal_Unicode const * pLanguageBegin = p;
1399                 bool bDowncaseLanguage = false;
1400                 int nLetters = 0;
1401                 for (; p != pEnd; ++p)
1402                     if (isAlpha(*p))
1403                     {
1404                         if (++nLetters > 8)
1405                             break;
1406                         bDowncaseLanguage = bDowncaseLanguage
1407                                             || isUpperCase(*p);
1408                     }
1409                     else if (*p == '-')
1410                     {
1411                         if (nLetters == 0)
1412                             break;
1413                         nLetters = 0;
1414                     }
1415                     else
1416                         break;
1417                 if (nLetters == 0 || nLetters > 8)
1418                     break;
1419                 if (pParameters)
1420                 {
1421                     aLanguage = ByteString(
1422                         pLanguageBegin,
1423                         static_cast< xub_StrLen >(p - pLanguageBegin),
1424                         RTL_TEXTENCODING_ASCII_US);
1425                     if (bDowncaseLanguage)
1426                         aLanguage.ToLowerAscii();
1427                 }
1428 
1429                 if (p == pEnd || *p != '\'')
1430                     break;
1431                 ++p;
1432             }
1433             if (pParameters)
1434             {
1435                 INetMIMEStringOutputSink
1436                     aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT);
1437                 while (p != pEnd)
1438                 {
1439                     sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd);
1440                     if (isUSASCII(nChar) && !isTokenChar(nChar))
1441                         break;
1442                     if (nChar == '%' && p + 1 < pEnd)
1443                     {
1444                         int nWeight1 = getHexWeight(p[0]);
1445                         int nWeight2 = getHexWeight(p[1]);
1446                         if (nWeight1 >= 0 && nWeight2 >= 0)
1447                         {
1448                             aSink << sal_Char(nWeight1 << 4 | nWeight2);
1449                             p += 2;
1450                             continue;
1451                         }
1452                     }
1453                     INetMIME::writeUTF8(aSink, nChar);
1454                 }
1455                 aValue = aSink.takeBuffer();
1456             }
1457             else
1458                 while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
1459                     ++p;
1460         }
1461         else if (p != pEnd && *p == '"')
1462             if (pParameters)
1463             {
1464                 INetMIMEStringOutputSink
1465                     aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT);
1466                 bool bInvalid = false;
1467                 for (++p;;)
1468                 {
1469                     if (p == pEnd)
1470                     {
1471                         bInvalid = true;
1472                         break;
1473                     }
1474                     sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd);
1475                     if (nChar == '"')
1476                         break;
1477                     else if (nChar == 0x0D) // CR
1478                     {
1479                         if (pEnd - p < 2 || *p++ != 0x0A // LF
1480                             || !isWhiteSpace(*p))
1481                         {
1482                             bInvalid = true;
1483                             break;
1484                         }
1485                         nChar = sal_uChar(*p++);
1486                     }
1487                     else if (nChar == '\\')
1488                     {
1489                         if (p == pEnd)
1490                         {
1491                             bInvalid = true;
1492                             break;
1493                         }
1494                         nChar = INetMIME::getUTF32Character(p, pEnd);
1495                     }
1496                     INetMIME::writeUTF8(aSink, nChar);
1497                 }
1498                 if (bInvalid)
1499                     break;
1500                 aValue = aSink.takeBuffer();
1501             }
1502             else
1503             {
1504                 sal_Unicode const * pStringEnd = skipQuotedString(p, pEnd);
1505                 if (p == pStringEnd)
1506                     break;
1507                 p = pStringEnd;
1508             }
1509         else
1510         {
1511             sal_Unicode const * pTokenBegin = p;
1512             while (p != pEnd && (isTokenChar(*p) || !isUSASCII(*p)))
1513                 ++p;
1514             if (p == pTokenBegin)
1515                 break;
1516             if (pParameters)
1517                 aValue = ByteString(
1518                     pTokenBegin, static_cast< xub_StrLen >(p - pTokenBegin),
1519                     RTL_TEXTENCODING_UTF8);
1520         }
1521 
1522         *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue,
1523                               nSection, bExtended);
1524     }
1525     return parseParameters(aList, pParameters) ? pParameterBegin : pBegin;
1526 }
1527 
1528 //============================================================================
1529 // static
getCharsetName(rtl_TextEncoding eEncoding)1530 const sal_Char * INetMIME::getCharsetName(rtl_TextEncoding eEncoding)
1531 {
1532     if (rtl_isOctetTextEncoding(eEncoding))
1533     {
1534         char const * p = rtl_getMimeCharsetFromTextEncoding(eEncoding);
1535         DBG_ASSERT(p, "INetMIME::getCharsetName(): Unsupported encoding");
1536         return p;
1537     }
1538     else
1539         switch (eEncoding)
1540         {
1541             case RTL_TEXTENCODING_UCS4:
1542                 return "ISO-10646-UCS-4";
1543 
1544             case RTL_TEXTENCODING_UCS2:
1545                 return "ISO-10646-UCS-2";
1546 
1547             default:
1548                 DBG_ERROR("INetMIME::getCharsetName(): Unsupported encoding");
1549                 return 0;
1550         }
1551 }
1552 
1553 //============================================================================
1554 namespace unnamed_tools_inetmime {
1555 
1556 struct EncodingEntry
1557 {
1558     sal_Char const * m_aName;
1559     rtl_TextEncoding m_eEncoding;
1560 };
1561 
1562 //============================================================================
1563 // The source for the following table is <ftp://ftp.iana.org/in-notes/iana/
1564 // assignments/character-sets> as of Jan, 21 2000 12:46:00, unless  otherwise
1565 // noted:
1566 EncodingEntry const aEncodingMap[]
1567     = { { "US-ASCII", RTL_TEXTENCODING_ASCII_US },
1568         { "ANSI_X3.4-1968", RTL_TEXTENCODING_ASCII_US },
1569         { "ISO-IR-6", RTL_TEXTENCODING_ASCII_US },
1570         { "ANSI_X3.4-1986", RTL_TEXTENCODING_ASCII_US },
1571         { "ISO_646.IRV:1991", RTL_TEXTENCODING_ASCII_US },
1572         { "ASCII", RTL_TEXTENCODING_ASCII_US },
1573         { "ISO646-US", RTL_TEXTENCODING_ASCII_US },
1574         { "US", RTL_TEXTENCODING_ASCII_US },
1575         { "IBM367", RTL_TEXTENCODING_ASCII_US },
1576         { "CP367", RTL_TEXTENCODING_ASCII_US },
1577         { "CSASCII", RTL_TEXTENCODING_ASCII_US },
1578         { "ISO-8859-1", RTL_TEXTENCODING_ISO_8859_1 },
1579         { "ISO_8859-1:1987", RTL_TEXTENCODING_ISO_8859_1 },
1580         { "ISO-IR-100", RTL_TEXTENCODING_ISO_8859_1 },
1581         { "ISO_8859-1", RTL_TEXTENCODING_ISO_8859_1 },
1582         { "LATIN1", RTL_TEXTENCODING_ISO_8859_1 },
1583         { "L1", RTL_TEXTENCODING_ISO_8859_1 },
1584         { "IBM819", RTL_TEXTENCODING_ISO_8859_1 },
1585         { "CP819", RTL_TEXTENCODING_ISO_8859_1 },
1586         { "CSISOLATIN1", RTL_TEXTENCODING_ISO_8859_1 },
1587         { "ISO-8859-2", RTL_TEXTENCODING_ISO_8859_2 },
1588         { "ISO_8859-2:1987", RTL_TEXTENCODING_ISO_8859_2 },
1589         { "ISO-IR-101", RTL_TEXTENCODING_ISO_8859_2 },
1590         { "ISO_8859-2", RTL_TEXTENCODING_ISO_8859_2 },
1591         { "LATIN2", RTL_TEXTENCODING_ISO_8859_2 },
1592         { "L2", RTL_TEXTENCODING_ISO_8859_2 },
1593         { "CSISOLATIN2", RTL_TEXTENCODING_ISO_8859_2 },
1594         { "ISO-8859-3", RTL_TEXTENCODING_ISO_8859_3 },
1595         { "ISO_8859-3:1988", RTL_TEXTENCODING_ISO_8859_3 },
1596         { "ISO-IR-109", RTL_TEXTENCODING_ISO_8859_3 },
1597         { "ISO_8859-3", RTL_TEXTENCODING_ISO_8859_3 },
1598         { "LATIN3", RTL_TEXTENCODING_ISO_8859_3 },
1599         { "L3", RTL_TEXTENCODING_ISO_8859_3 },
1600         { "CSISOLATIN3", RTL_TEXTENCODING_ISO_8859_3 },
1601         { "ISO-8859-4", RTL_TEXTENCODING_ISO_8859_4 },
1602         { "ISO_8859-4:1988", RTL_TEXTENCODING_ISO_8859_4 },
1603         { "ISO-IR-110", RTL_TEXTENCODING_ISO_8859_4 },
1604         { "ISO_8859-4", RTL_TEXTENCODING_ISO_8859_4 },
1605         { "LATIN4", RTL_TEXTENCODING_ISO_8859_4 },
1606         { "L4", RTL_TEXTENCODING_ISO_8859_4 },
1607         { "CSISOLATIN4", RTL_TEXTENCODING_ISO_8859_4 },
1608         { "ISO-8859-5", RTL_TEXTENCODING_ISO_8859_5 },
1609         { "ISO_8859-5:1988", RTL_TEXTENCODING_ISO_8859_5 },
1610         { "ISO-IR-144", RTL_TEXTENCODING_ISO_8859_5 },
1611         { "ISO_8859-5", RTL_TEXTENCODING_ISO_8859_5 },
1612         { "CYRILLIC", RTL_TEXTENCODING_ISO_8859_5 },
1613         { "CSISOLATINCYRILLIC", RTL_TEXTENCODING_ISO_8859_5 },
1614         { "ISO-8859-6", RTL_TEXTENCODING_ISO_8859_6 },
1615         { "ISO_8859-6:1987", RTL_TEXTENCODING_ISO_8859_6 },
1616         { "ISO-IR-127", RTL_TEXTENCODING_ISO_8859_6 },
1617         { "ISO_8859-6", RTL_TEXTENCODING_ISO_8859_6 },
1618         { "ECMA-114", RTL_TEXTENCODING_ISO_8859_6 },
1619         { "ASMO-708", RTL_TEXTENCODING_ISO_8859_6 },
1620         { "ARABIC", RTL_TEXTENCODING_ISO_8859_6 },
1621         { "CSISOLATINARABIC", RTL_TEXTENCODING_ISO_8859_6 },
1622         { "ISO-8859-7", RTL_TEXTENCODING_ISO_8859_7 },
1623         { "ISO_8859-7:1987", RTL_TEXTENCODING_ISO_8859_7 },
1624         { "ISO-IR-126", RTL_TEXTENCODING_ISO_8859_7 },
1625         { "ISO_8859-7", RTL_TEXTENCODING_ISO_8859_7 },
1626         { "ELOT_928", RTL_TEXTENCODING_ISO_8859_7 },
1627         { "ECMA-118", RTL_TEXTENCODING_ISO_8859_7 },
1628         { "GREEK", RTL_TEXTENCODING_ISO_8859_7 },
1629         { "GREEK8", RTL_TEXTENCODING_ISO_8859_7 },
1630         { "CSISOLATINGREEK", RTL_TEXTENCODING_ISO_8859_7 },
1631         { "ISO-8859-8", RTL_TEXTENCODING_ISO_8859_8 },
1632         { "ISO_8859-8:1988", RTL_TEXTENCODING_ISO_8859_8 },
1633         { "ISO-IR-138", RTL_TEXTENCODING_ISO_8859_8 },
1634         { "ISO_8859-8", RTL_TEXTENCODING_ISO_8859_8 },
1635         { "HEBREW", RTL_TEXTENCODING_ISO_8859_8 },
1636         { "CSISOLATINHEBREW", RTL_TEXTENCODING_ISO_8859_8 },
1637         { "ISO-8859-9", RTL_TEXTENCODING_ISO_8859_9 },
1638         { "ISO_8859-9:1989", RTL_TEXTENCODING_ISO_8859_9 },
1639         { "ISO-IR-148", RTL_TEXTENCODING_ISO_8859_9 },
1640         { "ISO_8859-9", RTL_TEXTENCODING_ISO_8859_9 },
1641         { "LATIN5", RTL_TEXTENCODING_ISO_8859_9 },
1642         { "L5", RTL_TEXTENCODING_ISO_8859_9 },
1643         { "CSISOLATIN5", RTL_TEXTENCODING_ISO_8859_9 },
1644         { "ISO-8859-14", RTL_TEXTENCODING_ISO_8859_14 }, // RFC 2047
1645         { "ISO_8859-15", RTL_TEXTENCODING_ISO_8859_15 },
1646         { "ISO-8859-15", RTL_TEXTENCODING_ISO_8859_15 }, // RFC 2047
1647         { "MACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN },
1648         { "MAC", RTL_TEXTENCODING_APPLE_ROMAN },
1649         { "CSMACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN },
1650         { "IBM437", RTL_TEXTENCODING_IBM_437 },
1651         { "CP437", RTL_TEXTENCODING_IBM_437 },
1652         { "437", RTL_TEXTENCODING_IBM_437 },
1653         { "CSPC8CODEPAGE437", RTL_TEXTENCODING_IBM_437 },
1654         { "IBM850", RTL_TEXTENCODING_IBM_850 },
1655         { "CP850", RTL_TEXTENCODING_IBM_850 },
1656         { "850", RTL_TEXTENCODING_IBM_850 },
1657         { "CSPC850MULTILINGUAL", RTL_TEXTENCODING_IBM_850 },
1658         { "IBM860", RTL_TEXTENCODING_IBM_860 },
1659         { "CP860", RTL_TEXTENCODING_IBM_860 },
1660         { "860", RTL_TEXTENCODING_IBM_860 },
1661         { "CSIBM860", RTL_TEXTENCODING_IBM_860 },
1662         { "IBM861", RTL_TEXTENCODING_IBM_861 },
1663         { "CP861", RTL_TEXTENCODING_IBM_861 },
1664         { "861", RTL_TEXTENCODING_IBM_861 },
1665         { "CP-IS", RTL_TEXTENCODING_IBM_861 },
1666         { "CSIBM861", RTL_TEXTENCODING_IBM_861 },
1667         { "IBM863", RTL_TEXTENCODING_IBM_863 },
1668         { "CP863", RTL_TEXTENCODING_IBM_863 },
1669         { "863", RTL_TEXTENCODING_IBM_863 },
1670         { "CSIBM863", RTL_TEXTENCODING_IBM_863 },
1671         { "IBM865", RTL_TEXTENCODING_IBM_865 },
1672         { "CP865", RTL_TEXTENCODING_IBM_865 },
1673         { "865", RTL_TEXTENCODING_IBM_865 },
1674         { "CSIBM865", RTL_TEXTENCODING_IBM_865 },
1675         { "IBM775", RTL_TEXTENCODING_IBM_775 },
1676         { "CP775", RTL_TEXTENCODING_IBM_775 },
1677         { "CSPC775BALTIC", RTL_TEXTENCODING_IBM_775 },
1678         { "IBM852", RTL_TEXTENCODING_IBM_852 },
1679         { "CP852", RTL_TEXTENCODING_IBM_852 },
1680         { "852", RTL_TEXTENCODING_IBM_852 },
1681         { "CSPCP852", RTL_TEXTENCODING_IBM_852 },
1682         { "IBM855", RTL_TEXTENCODING_IBM_855 },
1683         { "CP855", RTL_TEXTENCODING_IBM_855 },
1684         { "855", RTL_TEXTENCODING_IBM_855 },
1685         { "CSIBM855", RTL_TEXTENCODING_IBM_855 },
1686         { "IBM857", RTL_TEXTENCODING_IBM_857 },
1687         { "CP857", RTL_TEXTENCODING_IBM_857 },
1688         { "857", RTL_TEXTENCODING_IBM_857 },
1689         { "CSIBM857", RTL_TEXTENCODING_IBM_857 },
1690         { "IBM862", RTL_TEXTENCODING_IBM_862 },
1691         { "CP862", RTL_TEXTENCODING_IBM_862 },
1692         { "862", RTL_TEXTENCODING_IBM_862 },
1693         { "CSPC862LATINHEBREW", RTL_TEXTENCODING_IBM_862 },
1694         { "IBM864", RTL_TEXTENCODING_IBM_864 },
1695         { "CP864", RTL_TEXTENCODING_IBM_864 },
1696         { "CSIBM864", RTL_TEXTENCODING_IBM_864 },
1697         { "IBM866", RTL_TEXTENCODING_IBM_866 },
1698         { "CP866", RTL_TEXTENCODING_IBM_866 },
1699         { "866", RTL_TEXTENCODING_IBM_866 },
1700         { "CSIBM866", RTL_TEXTENCODING_IBM_866 },
1701         { "IBM869", RTL_TEXTENCODING_IBM_869 },
1702         { "CP869", RTL_TEXTENCODING_IBM_869 },
1703         { "869", RTL_TEXTENCODING_IBM_869 },
1704         { "CP-GR", RTL_TEXTENCODING_IBM_869 },
1705         { "CSIBM869", RTL_TEXTENCODING_IBM_869 },
1706         { "WINDOWS-1250", RTL_TEXTENCODING_MS_1250 },
1707         { "WINDOWS-1251", RTL_TEXTENCODING_MS_1251 },
1708         { "WINDOWS-1253", RTL_TEXTENCODING_MS_1253 },
1709         { "WINDOWS-1254", RTL_TEXTENCODING_MS_1254 },
1710         { "WINDOWS-1255", RTL_TEXTENCODING_MS_1255 },
1711         { "WINDOWS-1256", RTL_TEXTENCODING_MS_1256 },
1712         { "WINDOWS-1257", RTL_TEXTENCODING_MS_1257 },
1713         { "WINDOWS-1258", RTL_TEXTENCODING_MS_1258 },
1714         { "SHIFT_JIS", RTL_TEXTENCODING_SHIFT_JIS },
1715         { "MS_KANJI", RTL_TEXTENCODING_SHIFT_JIS },
1716         { "CSSHIFTJIS", RTL_TEXTENCODING_SHIFT_JIS },
1717         { "GB2312", RTL_TEXTENCODING_GB_2312 },
1718         { "CSGB2312", RTL_TEXTENCODING_GB_2312 },
1719         { "BIG5", RTL_TEXTENCODING_BIG5 },
1720         { "CSBIG5", RTL_TEXTENCODING_BIG5 },
1721         { "EUC-JP", RTL_TEXTENCODING_EUC_JP },
1722         { "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE",
1723           RTL_TEXTENCODING_EUC_JP },
1724         { "CSEUCPKDFMTJAPANESE", RTL_TEXTENCODING_EUC_JP },
1725         { "ISO-2022-JP", RTL_TEXTENCODING_ISO_2022_JP },
1726         { "CSISO2022JP", RTL_TEXTENCODING_ISO_2022_JP },
1727         { "ISO-2022-CN", RTL_TEXTENCODING_ISO_2022_CN },
1728         { "KOI8-R", RTL_TEXTENCODING_KOI8_R },
1729         { "CSKOI8R", RTL_TEXTENCODING_KOI8_R },
1730         { "UTF-7", RTL_TEXTENCODING_UTF7 },
1731         { "UTF-8", RTL_TEXTENCODING_UTF8 },
1732         { "ISO-8859-10", RTL_TEXTENCODING_ISO_8859_10 }, // RFC 2047
1733         { "ISO-8859-13", RTL_TEXTENCODING_ISO_8859_13 }, // RFC 2047
1734         { "EUC-KR", RTL_TEXTENCODING_EUC_KR },
1735         { "CSEUCKR", RTL_TEXTENCODING_EUC_KR },
1736         { "ISO-2022-KR", RTL_TEXTENCODING_ISO_2022_KR },
1737         { "CSISO2022KR", RTL_TEXTENCODING_ISO_2022_KR },
1738         { "ISO-10646-UCS-4", RTL_TEXTENCODING_UCS4 },
1739         { "CSUCS4", RTL_TEXTENCODING_UCS4 },
1740         { "ISO-10646-UCS-2", RTL_TEXTENCODING_UCS2 },
1741         { "CSUNICODE", RTL_TEXTENCODING_UCS2 } };
1742 
1743 //============================================================================
1744 template< typename T >
getCharsetEncoding_Impl(T const * pBegin,T const * pEnd)1745 inline rtl_TextEncoding getCharsetEncoding_Impl(T const * pBegin,
1746                                                 T const * pEnd)
1747 {
1748     for (sal_Size i = 0; i < sizeof aEncodingMap / sizeof (EncodingEntry);
1749          ++i)
1750         if (INetMIME::equalIgnoreCase(pBegin, pEnd, aEncodingMap[i].m_aName))
1751             return aEncodingMap[i].m_eEncoding;
1752     return RTL_TEXTENCODING_DONTKNOW;
1753 }
1754 
1755 }
1756 
1757 //============================================================================
1758 // static
getCharsetEncoding(sal_Char const * pBegin,sal_Char const * pEnd)1759 rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Char const * pBegin,
1760                                               sal_Char const * pEnd)
1761 {
1762     return getCharsetEncoding_Impl(pBegin, pEnd);
1763 }
1764 
1765 //============================================================================
1766 // static
getCharsetEncoding(sal_Unicode const * pBegin,sal_Unicode const * pEnd)1767 rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Unicode const * pBegin,
1768                                               sal_Unicode const * pEnd)
1769 {
1770     return getCharsetEncoding_Impl(pBegin, pEnd);
1771 }
1772 
1773 //============================================================================
1774 // static
1775 INetMIMECharsetList_Impl *
createPreferredCharsetList(rtl_TextEncoding eEncoding)1776 INetMIME::createPreferredCharsetList(rtl_TextEncoding eEncoding)
1777 {
1778     static const sal_uInt32 aUSASCIIRanges[] = { 0, 0x7F, sal_uInt32(-1) };
1779 
1780     static const sal_uInt32 aISO88591Ranges[] = { 0, 0xFF, sal_uInt32(-1) };
1781         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT> version
1782         // 1.0 of 1999 July 27
1783 
1784     static const sal_uInt32 aISO88592Ranges[]
1785         = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0,
1786             0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7,
1787             0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xCE, 0xD3, 0xD4, 0xD6, 0xD7,
1788             0xDA, 0xDA, 0xDC, 0xDD, 0xDF, 0xDF, 0xE1, 0xE2, 0xE4, 0xE4,
1789             0xE7, 0xE7, 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF3, 0xF4,
1790             0xF6, 0xF7, 0xFA, 0xFA, 0xFC, 0xFD, 0x102, 0x107, 0x10C, 0x111,
1791             0x118, 0x11B, 0x139, 0x13A, 0x13D, 0x13E, 0x141, 0x144,
1792             0x147, 0x148, 0x150, 0x151, 0x154, 0x155, 0x158, 0x15B,
1793             0x15E, 0x165, 0x16E, 0x171, 0x179, 0x17E, 0x2C7, 0x2C7,
1794             0x2D8, 0x2D9, 0x2DB, 0x2DB, 0x2DD, 0x2DD, sal_uInt32(-1) };
1795         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-2.TXT> version
1796         // 1.0 of 1999 July 27
1797 
1798     static const sal_uInt32 aISO88593Ranges[]
1799         = { 0, 0xA0, 0xA3, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0,
1800             0xB2, 0xB5, 0xB7, 0xB8, 0xBD, 0xBD, 0xC0, 0xC2, 0xC4, 0xC4,
1801             0xC7, 0xCF, 0xD1, 0xD4, 0xD6, 0xD7, 0xD9, 0xDC, 0xDF, 0xE2,
1802             0xE4, 0xE4, 0xE7, 0xEF, 0xF1, 0xF4, 0xF6, 0xF7, 0xF9, 0xFC,
1803             0x108, 0x10B, 0x11C, 0x121, 0x124, 0x127, 0x130, 0x131,
1804             0x134, 0x135, 0x15C, 0x15F, 0x16C, 0x16D, 0x17B, 0x17C,
1805             0x2D8, 0x2D9, sal_uInt32(-1) };
1806         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-3.TXT> version
1807         // 1.0 of 1999 July 27
1808 
1809     static const sal_uInt32 aISO88594Ranges[]
1810         = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xAF, 0xB0,
1811             0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB,
1812             0xCD, 0xCE, 0xD4, 0xD8, 0xDA, 0xDC, 0xDF, 0xDF, 0xE1, 0xE6,
1813             0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF4, 0xF8, 0xFA, 0xFC,
1814             0x100, 0x101, 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113,
1815             0x116, 0x119, 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F,
1816             0x136, 0x138, 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D,
1817             0x156, 0x157, 0x160, 0x161, 0x166, 0x16B, 0x172, 0x173,
1818             0x17D, 0x17E, 0x2C7, 0x2C7, 0x2D9, 0x2D9, 0x2DB, 0x2DB,
1819             sal_uInt32(-1) };
1820         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-4.TXT> version
1821         // 1.0 of 1999 July 27
1822 
1823     static const sal_uInt32 aISO88595Ranges[]
1824         = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0x401, 0x40C, 0x40E, 0x44F,
1825             0x451, 0x45C, 0x45E, 0x45F, 0x2116, 0x2116, sal_uInt32(-1) };
1826         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-5.TXT> version
1827         // 1.0 of 1999 July 27
1828 
1829     static const sal_uInt32 aISO88596Ranges[]
1830         = { 0, 0xA0, 0xA4, 0xA4, 0xAD, 0xAD, 0x60C, 0x60C, 0x61B, 0x61B,
1831             0x61F, 0x61F, 0x621, 0x63A, 0x640, 0x652, sal_uInt32(-1) };
1832         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-6.TXT> version
1833         // 1.0 of 1999 July 27
1834 
1835     static const sal_uInt32 aISO88597Ranges[]
1836         = { 0, 0xA0, 0xA3, 0xA3, 0xA6, 0xA9, 0xAB, 0xAD, 0xB0, 0xB3,
1837             0xB7, 0xB7, 0xBB, 0xBB, 0xBD, 0xBD, 0x384, 0x386, 0x388, 0x38A,
1838             0x38C, 0x38C, 0x38E, 0x3A1, 0x3A3, 0x3CE, 0x2015, 0x2015,
1839             0x2018, 0x2019, sal_uInt32(-1) };
1840         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-7.TXT> version
1841         // 1.0 of 1999 July 27
1842 
1843     static const sal_uInt32 aISO88598Ranges[]
1844         = { 0, 0xA0, 0xA2, 0xA9, 0xAB, 0xB9, 0xBB, 0xBE, 0xD7, 0xD7,
1845             0xF7, 0xF7, 0x5D0, 0x5EA, 0x200E, 0x200F, 0x2017, 0x2017,
1846             sal_uInt32(-1) };
1847         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-8.TXT> version
1848         // 1.1 of 2000-Jan-03
1849 
1850     static const sal_uInt32 aISO88599Ranges[]
1851         = { 0, 0xCF, 0xD1, 0xDC, 0xDF, 0xEF, 0xF1, 0xFC, 0xFF, 0xFF,
1852             0x11E, 0x11F, 0x130, 0x131, 0x15E, 0x15F, sal_uInt32(-1) };
1853         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-9.TXT> version
1854         // 1.0 of 1999 July 27
1855 
1856     static const sal_uInt32 aISO885910Ranges[]
1857         = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0xB0, 0xB0, 0xB7, 0xB7,
1858             0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xD0, 0xD3, 0xD6,
1859             0xD8, 0xD8, 0xDA, 0xDF, 0xE1, 0xE6, 0xE9, 0xE9, 0xEB, 0xEB,
1860             0xED, 0xF0, 0xF3, 0xF6, 0xF8, 0xF8, 0xFA, 0xFE, 0x100, 0x101,
1861             0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113, 0x116, 0x119,
1862             0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F, 0x136, 0x138,
1863             0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D, 0x160, 0x161,
1864             0x166, 0x16B, 0x172, 0x173, 0x17D, 0x17E, 0x2015, 0x2015,
1865             sal_uInt32(-1) };
1866         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-10.TXT> version
1867         // 1.1 of 1999 October 11
1868 
1869     static const sal_uInt32 aISO885913Ranges[]
1870         = { 0, 0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA9, 0xA9, 0xAB, 0xAE,
1871             0xB0, 0xB3, 0xB5, 0xB7, 0xB9, 0xB9, 0xBB, 0xBE, 0xC4, 0xC6,
1872             0xC9, 0xC9, 0xD3, 0xD3, 0xD5, 0xD8, 0xDC, 0xDC, 0xDF, 0xDF,
1873             0xE4, 0xE6, 0xE9, 0xE9, 0xF3, 0xF3, 0xF5, 0xF8, 0xFC, 0xFC,
1874             0x100, 0x101, 0x104, 0x107, 0x10C, 0x10D, 0x112, 0x113,
1875             0x116, 0x119, 0x122, 0x123, 0x12A, 0x12B, 0x12E, 0x12F,
1876             0x136, 0x137, 0x13B, 0x13C, 0x141, 0x146, 0x14C, 0x14D,
1877             0x156, 0x157, 0x15A, 0x15B, 0x160, 0x161, 0x16A, 0x16B,
1878             0x172, 0x173, 0x179, 0x17E, 0x2019, 0x2019, 0x201C, 0x201E,
1879             sal_uInt32(-1) };
1880         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-13.TXT> version
1881         // 1.0 of 1999 July 27
1882 
1883     static const sal_uInt32 aISO885914Ranges[]
1884         = { 0, 0xA0, 0xA3, 0xA3, 0xA7, 0xA7, 0xA9, 0xA9, 0xAD, 0xAE,
1885             0xB6, 0xB6, 0xC0, 0xCF, 0xD1, 0xD6, 0xD8, 0xDD, 0xDF, 0xEF,
1886             0xF1, 0xF6, 0xF8, 0xFD, 0xFF, 0xFF, 0x10A, 0x10B, 0x120, 0x121,
1887             0x174, 0x178, 0x1E02, 0x1E03, 0x1E0A, 0x1E0B, 0x1E1E, 0x1E1F,
1888             0x1E40, 0x1E41, 0x1E56, 0x1E57, 0x1E60, 0x1E61, 0x1E6A, 0x1E6B,
1889             0x1E80, 0x1E85, 0x1EF2, 0x1EF3, sal_uInt32(-1) };
1890         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-14.TXT> version
1891         // 1.0 of 1999 July 27
1892 
1893     static const sal_uInt32 aISO885915Ranges[]
1894         = { 0, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xB3, 0xB5, 0xB7,
1895             0xB9, 0xBB, 0xBF, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178,
1896             0x17D, 0x17E, 0x20AC, 0x20AC, sal_uInt32(-1) };
1897         // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-15.TXT> version
1898         // 1.0 of 1999 July 27
1899 
1900     static const sal_uInt32 aKOI8RRanges[]
1901         = { 0, 0x7F, 0xA0, 0xA0, 0xA9, 0xA9, 0xB0, 0xB0, 0xB2, 0xB2,
1902             0xB7, 0xB7, 0xF7, 0xF7, 0x401, 0x401, 0x410, 0x44F, 0x451, 0x451,
1903             0x2219, 0x221A, 0x2248, 0x2248, 0x2264, 0x2265, 0x2320, 0x2321,
1904             0x2500, 0x2500, 0x2502, 0x2502, 0x250C, 0x250C, 0x2510, 0x2510,
1905             0x2514, 0x2514, 0x2518, 0x2518, 0x251C, 0x251C, 0x2524, 0x2524,
1906             0x252C, 0x252C, 0x2534, 0x2534, 0x253C, 0x253C, 0x2550, 0x256C,
1907             0x2580, 0x2580, 0x2584, 0x2584, 0x2588, 0x2588, 0x258C, 0x258C,
1908             0x2590, 0x2593, 0x25A0, 0x25A0, sal_uInt32(-1) };
1909         // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT>
1910         // version 1.0 of 18 August 1999
1911 
1912 #if defined WNT
1913     static const sal_uInt32 aWindows1252Ranges[]
1914         = { 0, 0x7F, 0xA0, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178,
1915             0x17D, 0x17E, 0x192, 0x192, 0x2C6, 0x2C6, 0x2DC, 0x2DC,
1916             0x2013, 0x2014, 0x2018, 0x201A, 0x201C, 0x201E, 0x2020, 0x2022,
1917             0x2026, 0x2026, 0x2030, 0x2030, 0x2039, 0x203A, 0x20AC, 0x20AC,
1918             0x2122, 0x2122, sal_uInt32(-1) };
1919         // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/
1920         // CP1252.TXT> version 2.01 of 04/15/98
1921 #endif // WNT
1922 
1923     INetMIMECharsetList_Impl * pList = new INetMIMECharsetList_Impl;
1924     switch (eEncoding)
1925     {
1926         case RTL_TEXTENCODING_MS_1252:
1927 #if defined WNT
1928             pList->prepend(Charset(RTL_TEXTENCODING_MS_1252,
1929                                    aWindows1252Ranges));
1930 #endif // WNT
1931         case RTL_TEXTENCODING_ISO_8859_1:
1932         case RTL_TEXTENCODING_UTF7:
1933         case RTL_TEXTENCODING_UTF8:
1934             break;
1935 
1936         case RTL_TEXTENCODING_ISO_8859_2:
1937             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2,
1938                                    aISO88592Ranges));
1939             break;
1940 
1941         case RTL_TEXTENCODING_ISO_8859_3:
1942             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_3,
1943                                    aISO88593Ranges));
1944             break;
1945 
1946         case RTL_TEXTENCODING_ISO_8859_4:
1947             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4,
1948                                    aISO88594Ranges));
1949             break;
1950 
1951         case RTL_TEXTENCODING_ISO_8859_5:
1952             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
1953                                    aISO88595Ranges));
1954             break;
1955 
1956         case RTL_TEXTENCODING_ISO_8859_6:
1957             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6,
1958                                    aISO88596Ranges));
1959             break;
1960 
1961         case RTL_TEXTENCODING_ISO_8859_7:
1962             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7,
1963                                    aISO88597Ranges));
1964             break;
1965 
1966         case RTL_TEXTENCODING_ISO_8859_8:
1967             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8,
1968                                    aISO88598Ranges));
1969             break;
1970 
1971         case RTL_TEXTENCODING_ISO_8859_9:
1972             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9,
1973                                    aISO88599Ranges));
1974             break;
1975 
1976         case RTL_TEXTENCODING_ISO_8859_10:
1977             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_10,
1978                                    aISO885910Ranges));
1979             break;
1980 
1981         case RTL_TEXTENCODING_ISO_8859_13:
1982             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_13,
1983                                    aISO885913Ranges));
1984             break;
1985 
1986         case RTL_TEXTENCODING_ISO_8859_14:
1987             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_14,
1988                                    aISO885914Ranges));
1989             break;
1990 
1991         case RTL_TEXTENCODING_ISO_8859_15:
1992             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_15,
1993                                    aISO885915Ranges));
1994             break;
1995 
1996         case RTL_TEXTENCODING_MS_1250:
1997             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2,
1998                                    aISO88592Ranges));
1999             break;
2000 
2001         case RTL_TEXTENCODING_MS_1251:
2002             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
2003                                    aISO88595Ranges));
2004             break;
2005 
2006         case RTL_TEXTENCODING_MS_1253:
2007             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7,
2008                                    aISO88597Ranges));
2009             break;
2010 
2011         case RTL_TEXTENCODING_MS_1254:
2012             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9,
2013                                    aISO88599Ranges));
2014             break;
2015 
2016         case RTL_TEXTENCODING_MS_1255:
2017             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8,
2018                                    aISO88598Ranges));
2019             break;
2020 
2021         case RTL_TEXTENCODING_MS_1256:
2022             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6,
2023                                    aISO88596Ranges));
2024             break;
2025 
2026         case RTL_TEXTENCODING_MS_1257:
2027             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4,
2028                                    aISO88594Ranges));
2029             break;
2030 
2031         case RTL_TEXTENCODING_KOI8_R:
2032             pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
2033                                    aISO88595Ranges));
2034             pList->prepend(Charset(RTL_TEXTENCODING_KOI8_R, aKOI8RRanges));
2035             break;
2036 
2037         default: //@@@ more cases are missing!
2038             DBG_ERROR("INetMIME::createPreferredCharsetList():"
2039                           " Unsupported encoding");
2040             break;
2041     }
2042     pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_1, aISO88591Ranges));
2043     pList->prepend(Charset(RTL_TEXTENCODING_ASCII_US, aUSASCIIRanges));
2044     return pList;
2045 }
2046 
2047 //============================================================================
2048 // static
convertToUnicode(const sal_Char * pBegin,const sal_Char * pEnd,rtl_TextEncoding eEncoding,sal_Size & rSize)2049 sal_Unicode * INetMIME::convertToUnicode(const sal_Char * pBegin,
2050                                          const sal_Char * pEnd,
2051                                          rtl_TextEncoding eEncoding,
2052                                          sal_Size & rSize)
2053 {
2054     if (eEncoding == RTL_TEXTENCODING_DONTKNOW)
2055         return 0;
2056     rtl_TextToUnicodeConverter hConverter
2057         = rtl_createTextToUnicodeConverter(eEncoding);
2058     rtl_TextToUnicodeContext hContext
2059         = rtl_createTextToUnicodeContext(hConverter);
2060     sal_Unicode * pBuffer;
2061     sal_uInt32 nInfo;
2062     for (sal_Size nBufferSize = pEnd - pBegin;;
2063          nBufferSize += nBufferSize / 3 + 1)
2064     {
2065         pBuffer = new sal_Unicode[nBufferSize];
2066         sal_Size nSrcCvtBytes;
2067         rSize = rtl_convertTextToUnicode(
2068                     hConverter, hContext, pBegin, pEnd - pBegin, pBuffer,
2069                     nBufferSize,
2070                     RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
2071                         | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
2072                         | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
2073                     &nInfo, &nSrcCvtBytes);
2074         if (nInfo != RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
2075             break;
2076         delete[] pBuffer;
2077         rtl_resetTextToUnicodeContext(hConverter, hContext);
2078     }
2079     rtl_destroyTextToUnicodeContext(hConverter, hContext);
2080     rtl_destroyTextToUnicodeConverter(hConverter);
2081     if (nInfo != 0)
2082     {
2083         delete[] pBuffer;
2084         pBuffer = 0;
2085     }
2086     return pBuffer;
2087 }
2088 
2089 //============================================================================
2090 // static
convertFromUnicode(const sal_Unicode * pBegin,const sal_Unicode * pEnd,rtl_TextEncoding eEncoding,sal_Size & rSize)2091 sal_Char * INetMIME::convertFromUnicode(const sal_Unicode * pBegin,
2092                                         const sal_Unicode * pEnd,
2093                                         rtl_TextEncoding eEncoding,
2094                                         sal_Size & rSize)
2095 {
2096     if (eEncoding == RTL_TEXTENCODING_DONTKNOW)
2097         return 0;
2098     rtl_UnicodeToTextConverter hConverter
2099         = rtl_createUnicodeToTextConverter(eEncoding);
2100     rtl_UnicodeToTextContext hContext
2101         = rtl_createUnicodeToTextContext(hConverter);
2102     sal_Char * pBuffer;
2103     sal_uInt32 nInfo;
2104     for (sal_Size nBufferSize = pEnd - pBegin;;
2105          nBufferSize += nBufferSize / 3 + 1)
2106     {
2107         pBuffer = new sal_Char[nBufferSize];
2108         sal_Size nSrcCvtBytes;
2109         rSize = rtl_convertUnicodeToText(
2110                     hConverter, hContext, pBegin, pEnd - pBegin, pBuffer,
2111                     nBufferSize,
2112                     RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
2113                         | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
2114                         | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
2115                         | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR,
2116                     &nInfo, &nSrcCvtBytes);
2117         if (nInfo != RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL)
2118             break;
2119         delete[] pBuffer;
2120         rtl_resetUnicodeToTextContext(hConverter, hContext);
2121     }
2122     rtl_destroyUnicodeToTextContext(hConverter, hContext);
2123     rtl_destroyUnicodeToTextConverter(hConverter);
2124     if (nInfo != 0)
2125     {
2126         delete[] pBuffer;
2127         pBuffer = 0;
2128     }
2129     return pBuffer;
2130 }
2131 
2132 //============================================================================
2133 // static
writeUTF8(INetMIMEOutputSink & rSink,sal_uInt32 nChar)2134 void INetMIME::writeUTF8(INetMIMEOutputSink & rSink, sal_uInt32 nChar)
2135 {
2136     // See RFC 2279 for a discussion of UTF-8.
2137     DBG_ASSERT(nChar < 0x80000000, "INetMIME::writeUTF8(): Bad char");
2138 
2139     if (nChar < 0x80)
2140         rSink << sal_Char(nChar);
2141     else if (nChar < 0x800)
2142         rSink << sal_Char(nChar >> 6 | 0xC0)
2143               << sal_Char((nChar & 0x3F) | 0x80);
2144     else if (nChar < 0x10000)
2145         rSink << sal_Char(nChar >> 12 | 0xE0)
2146               << sal_Char((nChar >> 6 & 0x3F) | 0x80)
2147               << sal_Char((nChar & 0x3F) | 0x80);
2148     else if (nChar < 0x200000)
2149         rSink << sal_Char(nChar >> 18 | 0xF0)
2150               << sal_Char((nChar >> 12 & 0x3F) | 0x80)
2151               << sal_Char((nChar >> 6 & 0x3F) | 0x80)
2152               << sal_Char((nChar & 0x3F) | 0x80);
2153     else if (nChar < 0x4000000)
2154         rSink << sal_Char(nChar >> 24 | 0xF8)
2155               << sal_Char((nChar >> 18 & 0x3F) | 0x80)
2156               << sal_Char((nChar >> 12 & 0x3F) | 0x80)
2157               << sal_Char((nChar >> 6 & 0x3F) | 0x80)
2158               << sal_Char((nChar & 0x3F) | 0x80);
2159     else
2160         rSink << sal_Char(nChar >> 30 | 0xFC)
2161               << sal_Char((nChar >> 24 & 0x3F) | 0x80)
2162               << sal_Char((nChar >> 18 & 0x3F) | 0x80)
2163               << sal_Char((nChar >> 12 & 0x3F) | 0x80)
2164               << sal_Char((nChar >> 6 & 0x3F) | 0x80)
2165               << sal_Char((nChar & 0x3F) | 0x80);
2166 }
2167 
2168 //============================================================================
2169 // static
writeUnsigned(INetMIMEOutputSink & rSink,sal_uInt32 nValue,int nMinDigits)2170 void INetMIME::writeUnsigned(INetMIMEOutputSink & rSink, sal_uInt32 nValue,
2171                              int nMinDigits)
2172 {
2173     sal_Char aBuffer[10];
2174         // max unsigned 32 bit value (4294967295) has 10 places
2175     sal_Char * p = aBuffer;
2176     for (; nValue > 0; nValue /= 10)
2177         *p++ = sal_Char(getDigit(nValue % 10));
2178     nMinDigits -= p - aBuffer;
2179     while (nMinDigits-- > 0)
2180         rSink << '0';
2181     while (p != aBuffer)
2182         rSink << *--p;
2183 }
2184 
2185 //============================================================================
2186 // static
writeDateTime(INetMIMEOutputSink & rSink,const DateTime & rUTC)2187 void INetMIME::writeDateTime(INetMIMEOutputSink & rSink,
2188                              const DateTime & rUTC)
2189 {
2190     static const sal_Char aDay[7][3]
2191         = { { 'M', 'o', 'n' },
2192             { 'T', 'u', 'e' },
2193             { 'W', 'e', 'd' },
2194             { 'T', 'h', 'u' },
2195             { 'F', 'r', 'i' },
2196             { 'S', 'a', 't' },
2197             { 'S', 'u', 'n' } };
2198     const sal_Char * pTheDay = aDay[rUTC.GetDayOfWeek()];
2199     rSink.write(pTheDay, pTheDay + 3);
2200     rSink << ", ";
2201     writeUnsigned(rSink, rUTC.GetDay());
2202     rSink << ' ';
2203     static const sal_Char aMonth[12][3]
2204         = { { 'J', 'a', 'n' },
2205             { 'F', 'e', 'b' },
2206             { 'M', 'a', 'r' },
2207             { 'A', 'p', 'r' },
2208             { 'M', 'a', 'y' },
2209             { 'J', 'u', 'n' },
2210             { 'J', 'u', 'l' },
2211             { 'A', 'u', 'g' },
2212             { 'S', 'e', 'p' },
2213             { 'O', 'c', 't' },
2214             { 'N', 'o', 'v' },
2215             { 'D', 'e', 'c' } };
2216     const sal_Char * pTheMonth = aMonth[rUTC.GetMonth() - 1];
2217     rSink.write(pTheMonth, pTheMonth + 3);
2218     rSink << ' ';
2219     writeUnsigned(rSink, rUTC.GetYear());
2220     rSink << ' ';
2221     writeUnsigned(rSink, rUTC.GetHour(), 2);
2222     rSink << ':';
2223     writeUnsigned(rSink, rUTC.GetMin(), 2);
2224     rSink << ':';
2225     writeUnsigned(rSink, rUTC.GetSec(), 2);
2226     rSink << " +0000";
2227 }
2228 
2229 //============================================================================
2230 // static
writeHeaderFieldBody(INetMIMEOutputSink & rSink,HeaderFieldType eType,const ByteString & rBody,rtl_TextEncoding ePreferredEncoding,bool bInitialSpace)2231 void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink,
2232                                     HeaderFieldType eType,
2233                                     const ByteString & rBody,
2234                                     rtl_TextEncoding ePreferredEncoding,
2235                                     bool bInitialSpace)
2236 {
2237     writeHeaderFieldBody(rSink, eType,
2238                          UniString(rBody, RTL_TEXTENCODING_UTF8),
2239                          ePreferredEncoding, bInitialSpace);
2240 }
2241 
2242 //============================================================================
2243 // static
writeHeaderFieldBody(INetMIMEOutputSink & rSink,HeaderFieldType eType,const UniString & rBody,rtl_TextEncoding ePreferredEncoding,bool bInitialSpace)2244 void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink,
2245                                     HeaderFieldType eType,
2246                                     const UniString & rBody,
2247                                     rtl_TextEncoding ePreferredEncoding,
2248                                     bool bInitialSpace)
2249 {
2250     if (eType == HEADER_FIELD_TEXT)
2251     {
2252         INetMIMEEncodedWordOutputSink
2253             aOutput(rSink, INetMIMEEncodedWordOutputSink::CONTEXT_TEXT,
2254                     bInitialSpace ?
2255                         INetMIMEEncodedWordOutputSink::SPACE_ALWAYS :
2256                         INetMIMEEncodedWordOutputSink::SPACE_NO,
2257                     ePreferredEncoding);
2258         aOutput.write(rBody.GetBuffer(), rBody.GetBuffer() + rBody.Len());
2259         aOutput.flush();
2260     }
2261     else
2262     {
2263         enum Brackets { BRACKETS_OUTSIDE, BRACKETS_OPENING, BRACKETS_INSIDE };
2264         Brackets eBrackets = BRACKETS_OUTSIDE;
2265 
2266         const sal_Unicode * pBodyPtr = rBody.GetBuffer();
2267         const sal_Unicode * pBodyEnd = pBodyPtr + rBody.Len();
2268         while (pBodyPtr != pBodyEnd)
2269             switch (*pBodyPtr)
2270             {
2271                 case '\t':
2272                 case ' ':
2273                     // A WSP adds to accumulated space:
2274                     bInitialSpace = true;
2275                     ++pBodyPtr;
2276                     break;
2277 
2278                 case '(':
2279                 {
2280                     // Write a pending '<' if necessary:
2281                     if (eBrackets == BRACKETS_OPENING)
2282                     {
2283                         if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2284                                 >= rSink.getLineLengthLimit())
2285                             rSink << INetMIMEOutputSink::endl << ' ';
2286                         else if (bInitialSpace)
2287                             rSink << ' ';
2288                         rSink << '<';
2289                         bInitialSpace = false;
2290                         eBrackets = BRACKETS_INSIDE;
2291                     }
2292 
2293                     // Write the comment, introducing encoded-words where
2294                     // necessary:
2295                     int nLevel = 0;
2296                     INetMIMEEncodedWordOutputSink
2297                         aOutput(
2298                             rSink,
2299                             INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT,
2300                             INetMIMEEncodedWordOutputSink::SPACE_NO,
2301                             ePreferredEncoding);
2302                     while (pBodyPtr != pBodyEnd)
2303                         switch (*pBodyPtr)
2304                         {
2305                             case '(':
2306                                 aOutput.flush();
2307                                 if (rSink.getColumn()
2308                                             + (bInitialSpace ? 1 : 0)
2309                                         >= rSink.getLineLengthLimit())
2310                                     rSink << INetMIMEOutputSink::endl << ' ';
2311                                 else if (bInitialSpace)
2312                                     rSink << ' ';
2313                                 rSink << '(';
2314                                 bInitialSpace = false;
2315                                 ++nLevel;
2316                                 ++pBodyPtr;
2317                                 break;
2318 
2319                             case ')':
2320                                 aOutput.flush();
2321                                 if (rSink.getColumn()
2322                                         >= rSink.getLineLengthLimit())
2323                                     rSink << INetMIMEOutputSink::endl << ' ';
2324                                 rSink << ')';
2325                                 ++pBodyPtr;
2326                                 if (--nLevel == 0)
2327                                     goto comment_done;
2328                                 break;
2329 
2330                             case '\\':
2331                                 if (++pBodyPtr == pBodyEnd)
2332                                     break;
2333                             default:
2334                                 aOutput << *pBodyPtr++;
2335                                 break;
2336                         }
2337                 comment_done:
2338                     break;
2339                 }
2340 
2341                 case '<':
2342                     // Write an already pending '<' if necessary:
2343                     if (eBrackets == BRACKETS_OPENING)
2344                     {
2345                         if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2346                                 >= rSink.getLineLengthLimit())
2347                             rSink << INetMIMEOutputSink::endl << ' ';
2348                         else if (bInitialSpace)
2349                             rSink << ' ';
2350                         rSink << '<';
2351                         bInitialSpace = false;
2352                     }
2353 
2354                     // Remember this '<' as pending, and open a bracketed
2355                     // block:
2356                     eBrackets = BRACKETS_OPENING;
2357                     ++pBodyPtr;
2358                     break;
2359 
2360                 case '>':
2361                     // Write a pending '<' if necessary:
2362                     if (eBrackets == BRACKETS_OPENING)
2363                     {
2364                         if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2365                                 >= rSink.getLineLengthLimit())
2366                             rSink << INetMIMEOutputSink::endl << ' ';
2367                         else if (bInitialSpace)
2368                             rSink << ' ';
2369                         rSink << '<';
2370                         bInitialSpace = false;
2371                     }
2372 
2373                     // Write this '>', and close any bracketed block:
2374                     if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2375                             >= rSink.getLineLengthLimit())
2376                         rSink << INetMIMEOutputSink::endl << ' ';
2377                     else if (bInitialSpace)
2378                         rSink << ' ';
2379                     rSink << '>';
2380                     bInitialSpace = false;
2381                     eBrackets = BRACKETS_OUTSIDE;
2382                     ++pBodyPtr;
2383                     break;
2384 
2385                 case ',':
2386                 case ':':
2387                 case ';':
2388                 case '\\':
2389                 case ']':
2390                     // Write a pending '<' if necessary:
2391                     if (eBrackets == BRACKETS_OPENING)
2392                     {
2393                         if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2394                                 >= rSink.getLineLengthLimit())
2395                             rSink << INetMIMEOutputSink::endl << ' ';
2396                         else if (bInitialSpace)
2397                             rSink << ' ';
2398                         rSink << '<';
2399                         bInitialSpace = false;
2400                         eBrackets = BRACKETS_INSIDE;
2401                     }
2402 
2403                     // Write this specials:
2404                     if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2405                             >= rSink.getLineLengthLimit())
2406                         rSink << INetMIMEOutputSink::endl << ' ';
2407                     else if (bInitialSpace)
2408                         rSink << ' ';
2409                     rSink << sal_Char(*pBodyPtr++);
2410                     bInitialSpace = false;
2411                     break;
2412 
2413                 case '\x0D': // CR
2414                     // A <CRLF WSP> adds to accumulated space, a <CR> not
2415                     // followed by <LF WSP> starts 'junk':
2416                     if (startsWithLineFolding(pBodyPtr, pBodyEnd))
2417                     {
2418                         bInitialSpace = true;
2419                         pBodyPtr += 3;
2420                         break;
2421                     }
2422                 default:
2423                 {
2424                     // The next token is either one of <"." / "@" / atom /
2425                     // quoted-string / domain-literal>, or it's 'junk'; if it
2426                     // is not 'junk', it is either a 'phrase' (i.e., it may
2427                     // contain encoded-words) or a 'non-phrase' (i.e., it may
2428                     // not contain encoded-words):
2429                     enum Entity { ENTITY_JUNK, ENTITY_NON_PHRASE,
2430                                   ENTITY_PHRASE };
2431                     Entity eEntity = ENTITY_JUNK;
2432                     switch (*pBodyPtr)
2433                     {
2434                         case '.':
2435                         case '@':
2436                         case '[':
2437                             // A token of <"." / "@" / domain-literal> always
2438                             // starts a 'non-phrase':
2439                             eEntity = ENTITY_NON_PHRASE;
2440                             break;
2441 
2442                         default:
2443                             if (isUSASCII(*pBodyPtr)
2444                                 && !isAtomChar(*pBodyPtr))
2445                             {
2446                                 eEntity = ENTITY_JUNK;
2447                                 break;
2448                             }
2449                         case '"':
2450                             // A token of <atom / quoted-string> can either be
2451                             // a 'phrase' or a 'non-phrase':
2452                             switch (eType)
2453                             {
2454                                 case HEADER_FIELD_STRUCTURED:
2455                                     eEntity = ENTITY_NON_PHRASE;
2456                                     break;
2457 
2458                                 case HEADER_FIELD_PHRASE:
2459                                     eEntity = ENTITY_PHRASE;
2460                                     break;
2461 
2462                                 case HEADER_FIELD_MESSAGE_ID:
2463                                     // A 'phrase' if and only if outside any
2464                                     // bracketed block:
2465                                     eEntity
2466                                         = eBrackets == BRACKETS_OUTSIDE ?
2467                                               ENTITY_PHRASE :
2468                                               ENTITY_NON_PHRASE;
2469                                     break;
2470 
2471                                 case HEADER_FIELD_ADDRESS:
2472                                 {
2473                                     // A 'non-phrase' if and only if, after
2474                                     // skipping this token and any following
2475                                     // <linear-white-space> and <comment>s,
2476                                     // there is no token left, or the next
2477                                     // token is any of <"." / "@" / ">" / ","
2478                                     // / ";">, or the next token is <":"> and
2479                                     // is within a bracketed block:
2480                                     const sal_Unicode * pLookAhead = pBodyPtr;
2481                                     if (*pLookAhead == '"')
2482                                     {
2483                                         pLookAhead
2484                                             = skipQuotedString(pLookAhead,
2485                                                                pBodyEnd);
2486                                         if (pLookAhead == pBodyPtr)
2487                                             pLookAhead = pBodyEnd;
2488                                     }
2489                                     else
2490                                         while (pLookAhead != pBodyEnd
2491                                                && (isAtomChar(*pLookAhead)
2492                                                    || !isUSASCII(
2493                                                            *pLookAhead)))
2494                                             ++pLookAhead;
2495                                     while (pLookAhead != pBodyEnd)
2496                                         switch (*pLookAhead)
2497                                         {
2498                                             case '\t':
2499                                             case ' ':
2500                                                 ++pLookAhead;
2501                                                 break;
2502 
2503                                             case '(':
2504                                             {
2505                                                 const sal_Unicode * pPast
2506                                                     = skipComment(pLookAhead,
2507                                                                   pBodyEnd);
2508                                                 pLookAhead
2509                                                     = pPast == pLookAhead ?
2510                                                           pBodyEnd : pPast;
2511                                                 break;
2512                                             }
2513 
2514                                             case ',':
2515                                             case '.':
2516                                             case ';':
2517                                             case '>':
2518                                             case '@':
2519                                                 eEntity = ENTITY_NON_PHRASE;
2520                                                 goto entity_determined;
2521 
2522                                             case ':':
2523                                                 eEntity
2524                                                     = eBrackets
2525                                                          == BRACKETS_OUTSIDE ?
2526                                                           ENTITY_PHRASE :
2527                                                           ENTITY_NON_PHRASE;
2528                                                 goto entity_determined;
2529 
2530                                             case '\x0D': // CR
2531                                                 if (startsWithLineFolding(
2532                                                         pLookAhead, pBodyEnd))
2533                                                 {
2534                                                     pLookAhead += 3;
2535                                                     break;
2536                                                 }
2537                                             default:
2538                                                 eEntity = ENTITY_PHRASE;
2539                                                 goto entity_determined;
2540                                         }
2541                                     eEntity = ENTITY_NON_PHRASE;
2542                                 entity_determined:
2543                                     break;
2544                                 }
2545 
2546                                 case HEADER_FIELD_TEXT:
2547                                     OSL_ASSERT(false);
2548                                     break;
2549                             }
2550 
2551                             // In a 'non-phrase', a non-US-ASCII character
2552                             // cannot be part of an <atom>, but instead the
2553                             // whole entity is 'junk' rather than 'non-
2554                             // phrase':
2555                             if (eEntity == ENTITY_NON_PHRASE
2556                                 && !isUSASCII(*pBodyPtr))
2557                                 eEntity = ENTITY_JUNK;
2558                             break;
2559                     }
2560 
2561                     switch (eEntity)
2562                     {
2563                         case ENTITY_JUNK:
2564                         {
2565                             // Write a pending '<' if necessary:
2566                             if (eBrackets == BRACKETS_OPENING)
2567                             {
2568                                 if (rSink.getColumn()
2569                                             + (bInitialSpace ? 1 : 0)
2570                                         >= rSink.getLineLengthLimit())
2571                                     rSink << INetMIMEOutputSink::endl << ' ';
2572                                 else if (bInitialSpace)
2573                                     rSink << ' ';
2574                                 rSink << '<';
2575                                 bInitialSpace = false;
2576                                 eBrackets = BRACKETS_INSIDE;
2577                             }
2578 
2579                             // Calculate the length of in- and output:
2580                             const sal_Unicode * pStart = pBodyPtr;
2581                             sal_Size nLength = 0;
2582                             bool bModify = false;
2583                             bool bEnd = false;
2584                             while (pBodyPtr != pBodyEnd && !bEnd)
2585                                 switch (*pBodyPtr)
2586                                 {
2587                                     case '\x0D': // CR
2588                                         if (startsWithLineFolding(pBodyPtr,
2589                                                                   pBodyEnd))
2590                                             bEnd = true;
2591                                         else if (startsWithLineBreak(
2592                                                      pBodyPtr, pBodyEnd))
2593                                         {
2594                                             nLength += 3;
2595                                             bModify = true;
2596                                             pBodyPtr += 2;
2597                                         }
2598                                         else
2599                                         {
2600                                             ++nLength;
2601                                             ++pBodyPtr;
2602                                         }
2603                                         break;
2604 
2605                                     case '\t':
2606                                     case ' ':
2607                                         bEnd = true;
2608                                         break;
2609 
2610                                     default:
2611                                         if (isVisible(*pBodyPtr))
2612                                             bEnd = true;
2613                                         else if (isUSASCII(*pBodyPtr))
2614                                         {
2615                                             ++nLength;
2616                                             ++pBodyPtr;
2617                                         }
2618                                         else
2619                                         {
2620                                             nLength += getUTF8OctetCount(
2621                                                            *pBodyPtr++);
2622                                             bModify = true;
2623                                         }
2624                                         break;
2625                                 }
2626 
2627                             // Write the output:
2628                             if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2629                                         + nLength
2630                                     > rSink.getLineLengthLimit())
2631                                 rSink << INetMIMEOutputSink::endl << ' ';
2632                             else if (bInitialSpace)
2633                                 rSink << ' ';
2634                             bInitialSpace = false;
2635                             if (bModify)
2636                                 while (pStart != pBodyPtr)
2637                                     if (startsWithLineBreak(pStart, pBodyPtr))
2638                                     {
2639                                         rSink << "\x0D\\\x0A"; // CR, '\', LF
2640                                         pStart += 2;
2641                                     }
2642                                     else
2643                                         writeUTF8(rSink, *pStart++);
2644                             else
2645                                 rSink.write(pStart, pBodyPtr);
2646                             break;
2647                         }
2648 
2649                         case ENTITY_NON_PHRASE:
2650                         {
2651                             // Calculate the length of in- and output:
2652                             const sal_Unicode * pStart = pBodyPtr;
2653                             sal_Size nLength = 0;
2654                             bool bBracketedBlock = false;
2655                             bool bSymbol = *pStart != '.' && *pStart != '@';
2656                             bool bModify = false;
2657                             bool bEnd = false;
2658                             while (pBodyPtr != pBodyEnd && !bEnd)
2659                                 switch (*pBodyPtr)
2660                                 {
2661                                     case '\t':
2662                                     case ' ':
2663                                     case '\x0D': // CR
2664                                     {
2665                                         const sal_Unicode * pLookAhead
2666                                             = skipLinearWhiteSpace(pBodyPtr,
2667                                                                    pBodyEnd);
2668                                         if (pLookAhead < pBodyEnd
2669                                             && (bSymbol ?
2670                                                     isAtomChar(*pLookAhead)
2671                                                     || *pLookAhead == '"'
2672                                                     || *pLookAhead == '[' :
2673                                                     *pLookAhead == '.'
2674                                                     || *pLookAhead == '@'
2675                                                     || (*pLookAhead == '>'
2676                                                        && eType
2677                                                     >= HEADER_FIELD_MESSAGE_ID
2678                                                        && eBrackets
2679                                                          == BRACKETS_OPENING)))
2680                                         {
2681                                             bModify = true;
2682                                             pBodyPtr = pLookAhead;
2683                                         }
2684                                         else
2685                                             bEnd = true;
2686                                         break;
2687                                     }
2688 
2689                                     case '"':
2690                                         if (bSymbol)
2691                                         {
2692                                             pBodyPtr
2693                                                 = scanQuotedBlock(pBodyPtr,
2694                                                                   pBodyEnd,
2695                                                                   '"', '"',
2696                                                                   nLength,
2697                                                                   bModify);
2698                                             bSymbol = false;
2699                                         }
2700                                         else
2701                                             bEnd = true;
2702                                         break;
2703 
2704                                     case '[':
2705                                         if (bSymbol)
2706                                         {
2707                                             pBodyPtr
2708                                                 = scanQuotedBlock(pBodyPtr,
2709                                                                   pBodyEnd,
2710                                                                   '[', ']',
2711                                                                   nLength,
2712                                                                   bModify);
2713                                             bSymbol = false;
2714                                         }
2715                                         else
2716                                             bEnd = true;
2717                                         break;
2718 
2719                                     case '.':
2720                                     case '@':
2721                                         if (bSymbol)
2722                                             bEnd = true;
2723                                         else
2724                                         {
2725                                             ++nLength;
2726                                             bSymbol = true;
2727                                             ++pBodyPtr;
2728                                         }
2729                                         break;
2730 
2731                                     case '>':
2732                                         if (eBrackets == BRACKETS_OPENING
2733                                             && eType
2734                                                    >= HEADER_FIELD_MESSAGE_ID)
2735                                         {
2736                                             ++nLength;
2737                                             bBracketedBlock = true;
2738                                             ++pBodyPtr;
2739                                         }
2740                                         bEnd = true;
2741                                         break;
2742 
2743                                     default:
2744                                         if (isAtomChar(*pBodyPtr) && bSymbol)
2745                                         {
2746                                             while (pBodyPtr != pBodyEnd
2747                                                    && isAtomChar(*pBodyPtr))
2748                                             {
2749                                                 ++nLength;
2750                                                 ++pBodyPtr;
2751                                             }
2752                                             bSymbol = false;
2753                                         }
2754                                         else
2755                                         {
2756                                             if (!isUSASCII(*pBodyPtr))
2757                                                 bModify = true;
2758                                             bEnd = true;
2759                                         }
2760                                         break;
2761                                 }
2762 
2763                             // Write a pending '<' if necessary:
2764                             if (eBrackets == BRACKETS_OPENING
2765                                 && !bBracketedBlock)
2766                             {
2767                                 if (rSink.getColumn()
2768                                             + (bInitialSpace ? 1 : 0)
2769                                         >= rSink.getLineLengthLimit())
2770                                     rSink << INetMIMEOutputSink::endl << ' ';
2771                                 else if (bInitialSpace)
2772                                     rSink << ' ';
2773                                 rSink << '<';
2774                                 bInitialSpace = false;
2775                                 eBrackets = BRACKETS_INSIDE;
2776                             }
2777 
2778                             // Write the output:
2779                             if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2780                                         + nLength
2781                                     > rSink.getLineLengthLimit())
2782                                 rSink << INetMIMEOutputSink::endl << ' ';
2783                             else if (bInitialSpace)
2784                                 rSink << ' ';
2785                             bInitialSpace = false;
2786                             if (bBracketedBlock)
2787                             {
2788                                 rSink << '<';
2789                                 eBrackets = BRACKETS_OUTSIDE;
2790                             }
2791                             if (bModify)
2792                             {
2793                                 enum Mode { MODE_PLAIN, MODE_QUOTED_STRING,
2794                                             MODE_DOMAIN_LITERAL };
2795                                 Mode eMode = MODE_PLAIN;
2796                                 while (pStart != pBodyPtr)
2797                                     switch (*pStart)
2798                                     {
2799                                         case '\x0D': // CR
2800                                             if (startsWithLineFolding(
2801                                                     pStart, pBodyPtr))
2802                                             {
2803                                                 if (eMode != MODE_PLAIN)
2804                                                     rSink << sal_Char(
2805                                                                  pStart[2]);
2806                                                 pStart += 3;
2807                                             }
2808                                             else if (startsWithLineBreak(
2809                                                          pStart, pBodyPtr))
2810                                             {
2811                                                 rSink << "\x0D\\\x0A";
2812                                                     // CR, '\', LF
2813                                                 pStart += 2;
2814                                             }
2815                                             else
2816                                             {
2817                                                 rSink << '\x0D'; // CR
2818                                                 ++pStart;
2819                                             }
2820                                             break;
2821 
2822                                         case '\t':
2823                                         case ' ':
2824                                             if (eMode != MODE_PLAIN)
2825                                                 rSink << sal_Char(*pStart);
2826                                             ++pStart;
2827                                             break;
2828 
2829                                         case '"':
2830                                             if (eMode == MODE_PLAIN)
2831                                                 eMode = MODE_QUOTED_STRING;
2832                                             else if (eMode
2833                                                         == MODE_QUOTED_STRING)
2834                                                 eMode = MODE_PLAIN;
2835                                             rSink << '"';
2836                                             ++pStart;
2837                                             break;
2838 
2839                                         case '[':
2840                                             if (eMode == MODE_PLAIN)
2841                                                 eMode = MODE_DOMAIN_LITERAL;
2842                                             rSink << '[';
2843                                             ++pStart;
2844                                             break;
2845 
2846                                         case ']':
2847                                             if (eMode == MODE_DOMAIN_LITERAL)
2848                                                 eMode = MODE_PLAIN;
2849                                             rSink << ']';
2850                                             ++pStart;
2851                                             break;
2852 
2853                                         case '\\':
2854                                             rSink << '\\';
2855                                             if (++pStart < pBodyPtr)
2856                                                 writeUTF8(rSink, *pStart++);
2857                                             break;
2858 
2859                                         default:
2860                                             writeUTF8(rSink, *pStart++);
2861                                             break;
2862                                     }
2863                             }
2864                             else
2865                                 rSink.write(pStart, pBodyPtr);
2866                             break;
2867                         }
2868 
2869                         case ENTITY_PHRASE:
2870                         {
2871                             // Write a pending '<' if necessary:
2872                             if (eBrackets == BRACKETS_OPENING)
2873                             {
2874                                 if (rSink.getColumn()
2875                                             + (bInitialSpace ? 1 : 0)
2876                                         >= rSink.getLineLengthLimit())
2877                                     rSink << INetMIMEOutputSink::endl << ' ';
2878                                 else if (bInitialSpace)
2879                                     rSink << ' ';
2880                                 rSink << '<';
2881                                 bInitialSpace = false;
2882                                 eBrackets = BRACKETS_INSIDE;
2883                             }
2884 
2885                             // Calculate the length of in- and output:
2886                             const sal_Unicode * pStart = pBodyPtr;
2887                             bool bQuotedString = false;
2888                             bool bEnd = false;
2889                             while (pBodyPtr != pBodyEnd && !bEnd)
2890                                 switch (*pBodyPtr)
2891                                 {
2892                                     case '\t':
2893                                     case ' ':
2894                                     case '\x0D': // CR
2895                                         if (bQuotedString)
2896                                             ++pBodyPtr;
2897                                         else
2898                                         {
2899                                             const sal_Unicode * pLookAhead
2900                                                 = skipLinearWhiteSpace(
2901                                                       pBodyPtr, pBodyEnd);
2902                                             if (pLookAhead != pBodyEnd
2903                                                 && (isAtomChar(*pLookAhead)
2904                                                     || !isUSASCII(*pLookAhead)
2905                                                     || *pLookAhead == '"'))
2906                                                 pBodyPtr = pLookAhead;
2907                                             else
2908                                                 bEnd = true;
2909                                         }
2910                                         break;
2911 
2912                                     case '"':
2913                                         bQuotedString = !bQuotedString;
2914                                         ++pBodyPtr;
2915                                         break;
2916 
2917                                     case '\\':
2918                                         if (bQuotedString)
2919                                         {
2920                                             if (++pBodyPtr != pBodyEnd)
2921                                                 ++pBodyPtr;
2922                                         }
2923                                         else
2924                                             bEnd = true;
2925                                         break;
2926 
2927                                     default:
2928                                         if (bQuotedString
2929                                             || isAtomChar(*pBodyPtr)
2930                                             || !isUSASCII(*pBodyPtr))
2931                                             ++pBodyPtr;
2932                                         else
2933                                             bEnd = true;
2934                                         break;
2935                                 }
2936 
2937                             // Write the phrase, introducing encoded-words
2938                             // where necessary:
2939                             INetMIMEEncodedWordOutputSink
2940                                 aOutput(
2941                                     rSink,
2942                                 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,
2943                                     bInitialSpace ?
2944                                  INetMIMEEncodedWordOutputSink::SPACE_ALWAYS :
2945                                  INetMIMEEncodedWordOutputSink::SPACE_ENCODED,
2946                                ePreferredEncoding);
2947                             while (pStart != pBodyPtr)
2948                                 switch (*pStart)
2949                                 {
2950                                     case '"':
2951                                         ++pStart;
2952                                         break;
2953 
2954                                     case '\\':
2955                                         if (++pStart != pBodyPtr)
2956                                             aOutput << *pStart++;
2957                                         break;
2958 
2959                                     case '\x0D': // CR
2960                                         pStart += 2;
2961                                         aOutput << *pStart++;
2962                                         break;
2963 
2964                                     default:
2965                                         aOutput << *pStart++;
2966                                         break;
2967                                 }
2968                             bInitialSpace = aOutput.flush();
2969                             break;
2970                         }
2971                     }
2972                     break;
2973                 }
2974             }
2975     }
2976 }
2977 
2978 //============================================================================
2979 // static
translateUTF8Char(const sal_Char * & rBegin,const sal_Char * pEnd,rtl_TextEncoding eEncoding,sal_uInt32 & rCharacter)2980 bool INetMIME::translateUTF8Char(const sal_Char *& rBegin,
2981                                  const sal_Char * pEnd,
2982                                  rtl_TextEncoding eEncoding,
2983                                  sal_uInt32 & rCharacter)
2984 {
2985     if (rBegin == pEnd || static_cast< unsigned char >(*rBegin) < 0x80
2986         || static_cast< unsigned char >(*rBegin) >= 0xFE)
2987         return false;
2988 
2989     int nCount;
2990     sal_uInt32 nMin;
2991     sal_uInt32 nUCS4;
2992     const sal_Char * p = rBegin;
2993     if (static_cast< unsigned char >(*p) < 0xE0)
2994     {
2995         nCount = 1;
2996         nMin = 0x80;
2997         nUCS4 = static_cast< unsigned char >(*p) & 0x1F;
2998     }
2999     else if (static_cast< unsigned char >(*p) < 0xF0)
3000     {
3001         nCount = 2;
3002         nMin = 0x800;
3003         nUCS4 = static_cast< unsigned char >(*p) & 0xF;
3004     }
3005     else if (static_cast< unsigned char >(*p) < 0xF8)
3006     {
3007         nCount = 3;
3008         nMin = 0x10000;
3009         nUCS4 = static_cast< unsigned char >(*p) & 7;
3010     }
3011     else if (static_cast< unsigned char >(*p) < 0xFC)
3012     {
3013         nCount = 4;
3014         nMin = 0x200000;
3015         nUCS4 = static_cast< unsigned char >(*p) & 3;
3016     }
3017     else
3018     {
3019         nCount = 5;
3020         nMin = 0x4000000;
3021         nUCS4 = static_cast< unsigned char >(*p) & 1;
3022     }
3023     ++p;
3024 
3025     for (; nCount-- > 0; ++p)
3026         if ((static_cast< unsigned char >(*p) & 0xC0) == 0x80)
3027             nUCS4 = (nUCS4 << 6) | (static_cast< unsigned char >(*p) & 0x3F);
3028         else
3029             return false;
3030 
3031     if (nUCS4 < nMin || nUCS4 > 0x10FFFF)
3032         return false;
3033 
3034     if (eEncoding >= RTL_TEXTENCODING_UCS4)
3035         rCharacter = nUCS4;
3036     else
3037     {
3038         sal_Unicode aUTF16[2];
3039         const sal_Unicode * pUTF16End = putUTF32Character(aUTF16, nUCS4);
3040         sal_Size nSize;
3041         sal_Char * pBuffer = convertFromUnicode(aUTF16, pUTF16End, eEncoding,
3042                                                 nSize);
3043         if (!pBuffer)
3044             return false;
3045         DBG_ASSERT(nSize == 1,
3046                    "INetMIME::translateUTF8Char(): Bad conversion");
3047         rCharacter = *pBuffer;
3048         delete[] pBuffer;
3049     }
3050     rBegin = p;
3051     return true;
3052 }
3053 
3054 //============================================================================
3055 // static
decodeUTF8(const ByteString & rText,rtl_TextEncoding eEncoding)3056 ByteString INetMIME::decodeUTF8(const ByteString & rText,
3057                                 rtl_TextEncoding eEncoding)
3058 {
3059     const sal_Char * p = rText.GetBuffer();
3060     const sal_Char * pEnd = p + rText.Len();
3061     ByteString sDecoded;
3062     while (p != pEnd)
3063     {
3064         sal_uInt32 nCharacter;
3065         if (translateUTF8Char(p, pEnd, eEncoding, nCharacter))
3066             sDecoded += sal_Char(nCharacter);
3067         else
3068             sDecoded += sal_Char(*p++);
3069     }
3070     return sDecoded;
3071 }
3072 
3073 //============================================================================
3074 // static
decodeHeaderFieldBody(HeaderFieldType eType,const ByteString & rBody)3075 UniString INetMIME::decodeHeaderFieldBody(HeaderFieldType eType,
3076                                           const ByteString & rBody)
3077 {
3078     // Due to a bug in INetCoreRFC822MessageStream::ConvertTo7Bit(), old
3079     // versions of StarOffice send mails with header fields where encoded
3080     // words can be preceded by '=', ',', '.', '"', or '(', and followed by
3081     // '=', ',', '.', '"', ')', without any required white space in between.
3082     // And there appear to exist some broken mailers that only encode single
3083     // letters within words, like "Appel
3084     // =?iso-8859-1?Q?=E0?=t=?iso-8859-1?Q?=E9?=moin", so it seems best to
3085     // detect encoded words even when not propperly surrounded by white space.
3086     //
3087     // Non US-ASCII characters in rBody are treated as ISO-8859-1.
3088     //
3089     // encoded-word = "=?"
3090     //     1*(%x21 / %x23-27 / %x2A-2B / %x2D / %30-39 / %x41-5A / %x5E-7E)
3091     //     ["*" 1*8ALPHA *("-" 1*8ALPHA)] "?"
3092     //     ("B?" *(4base64) (4base64 / 3base64 "=" / 2base64 "==")
3093     //      / "Q?" 1*(%x21-3C / %x3E / %x40-7E / "=" 2HEXDIG))
3094     //     "?="
3095     //
3096     // base64 = ALPHA / DIGIT / "+" / "/"
3097 
3098     const sal_Char * pBegin = rBody.GetBuffer();
3099     const sal_Char * pEnd = pBegin + rBody.Len();
3100 
3101     UniString sDecoded;
3102     const sal_Char * pCopyBegin = pBegin;
3103 
3104     /* bool bStartEncodedWord = true; */
3105     const sal_Char * pWSPBegin = pBegin;
3106     UniString sEncodedText;
3107     bool bQuotedEncodedText = false;
3108     sal_uInt32 nCommentLevel = 0;
3109 
3110     for (const sal_Char * p = pBegin; p != pEnd;)
3111     {
3112         if (p != pEnd && *p == '=' /* && bStartEncodedWord */)
3113         {
3114             const sal_Char * q = p + 1;
3115             bool bEncodedWord = q != pEnd && *q++ == '?';
3116 
3117             rtl_TextEncoding eCharsetEncoding = RTL_TEXTENCODING_DONTKNOW;
3118             if (bEncodedWord)
3119             {
3120                 const sal_Char * pCharsetBegin = q;
3121                 const sal_Char * pLanguageBegin = 0;
3122                 int nAlphaCount = 0;
3123                 for (bool bDone = false; !bDone;)
3124                     if (q == pEnd)
3125                     {
3126                         bEncodedWord = false;
3127                         bDone = true;
3128                     }
3129                     else
3130                     {
3131                         sal_Char cChar = *q++;
3132                         switch (cChar)
3133                         {
3134                             case '*':
3135                                 pLanguageBegin = q - 1;
3136                                 nAlphaCount = 0;
3137                                 break;
3138 
3139                             case '-':
3140                                 if (pLanguageBegin != 0)
3141                                 {
3142                                     if (nAlphaCount == 0)
3143                                         pLanguageBegin = 0;
3144                                     else
3145                                         nAlphaCount = 0;
3146                                 }
3147                                 break;
3148 
3149                             case '?':
3150                                 if (pCharsetBegin == q - 1)
3151                                     bEncodedWord = false;
3152                                 else
3153                                 {
3154                                     eCharsetEncoding
3155                                         = getCharsetEncoding(
3156                                               pCharsetBegin,
3157                                               pLanguageBegin == 0
3158                                               || nAlphaCount == 0 ?
3159                                                   q - 1 : pLanguageBegin);
3160                                     bEncodedWord = isMIMECharsetEncoding(
3161                                                        eCharsetEncoding);
3162                                     eCharsetEncoding
3163                                         = translateFromMIME(eCharsetEncoding);
3164                                 }
3165                                 bDone = true;
3166                                 break;
3167 
3168                             default:
3169                                 if (pLanguageBegin != 0
3170                                     && (!isAlpha(cChar) || ++nAlphaCount > 8))
3171                                     pLanguageBegin = 0;
3172                                 break;
3173                         }
3174                     }
3175             }
3176 
3177             bool bEncodingB = false;
3178             if (bEncodedWord)
3179             {
3180                 if (q == pEnd)
3181                     bEncodedWord = false;
3182                 else
3183                 {
3184                     switch (*q++)
3185                     {
3186                         case 'B':
3187                         case 'b':
3188                             bEncodingB = true;
3189                             break;
3190 
3191                         case 'Q':
3192                         case 'q':
3193                             bEncodingB = false;
3194                             break;
3195 
3196                         default:
3197                             bEncodedWord = false;
3198                             break;
3199                     }
3200                 }
3201             }
3202 
3203             bEncodedWord = bEncodedWord && q != pEnd && *q++ == '?';
3204 
3205             ByteString sText;
3206             if (bEncodedWord)
3207             {
3208                 if (bEncodingB)
3209                 {
3210                     for (bool bDone = false; !bDone;)
3211                     {
3212                         if (pEnd - q < 4)
3213                         {
3214                             bEncodedWord = false;
3215                             bDone = true;
3216                         }
3217                         else
3218                         {
3219                             bool bFinal = false;
3220                             int nCount = 3;
3221                             sal_uInt32 nValue = 0;
3222                             for (int nShift = 18; nShift >= 0; nShift -= 6)
3223                             {
3224                                 int nWeight = getBase64Weight(*q++);
3225                                 if (nWeight == -2)
3226                                 {
3227                                     bEncodedWord = false;
3228                                     bDone = true;
3229                                     break;
3230                                 }
3231                                 if (nWeight == -1)
3232                                 {
3233                                     if (!bFinal)
3234                                     {
3235                                         if (nShift >= 12)
3236                                         {
3237                                             bEncodedWord = false;
3238                                             bDone = true;
3239                                             break;
3240                                         }
3241                                         bFinal = true;
3242                                         nCount = nShift == 6 ? 1 : 2;
3243                                     }
3244                                 }
3245                                 else
3246                                     nValue |= nWeight << nShift;
3247                             }
3248                             if (bEncodedWord)
3249                             {
3250                                 for (int nShift = 16; nCount-- > 0;
3251                                      nShift -= 8)
3252                                     sText += sal_Char(nValue >> nShift
3253                                                           & 0xFF);
3254                                 if (*q == '?')
3255                                 {
3256                                     ++q;
3257                                     bDone = true;
3258                                 }
3259                                 if (bFinal && !bDone)
3260                                 {
3261                                     bEncodedWord = false;
3262                                     bDone = true;
3263                                 }
3264                             }
3265                         }
3266                     }
3267                 }
3268                 else
3269                 {
3270                     const sal_Char * pEncodedTextBegin = q;
3271                     const sal_Char * pEncodedTextCopyBegin = q;
3272                     for (bool bDone = false; !bDone;)
3273                         if (q == pEnd)
3274                         {
3275                             bEncodedWord = false;
3276                             bDone = true;
3277                         }
3278                         else
3279                         {
3280                             sal_uInt32 nChar = *q++;
3281                             switch (nChar)
3282                             {
3283                                 case '=':
3284                                 {
3285                                     if (pEnd - q < 2)
3286                                     {
3287                                         bEncodedWord = false;
3288                                         bDone = true;
3289                                         break;
3290                                     }
3291                                     int nDigit1 = getHexWeight(q[0]);
3292                                     int nDigit2 = getHexWeight(q[1]);
3293                                     if (nDigit1 < 0 || nDigit2 < 0)
3294                                     {
3295                                         bEncodedWord = false;
3296                                         bDone = true;
3297                                         break;
3298                                     }
3299                                     sText += rBody.Copy(
3300                                         static_cast< xub_StrLen >(
3301                                             pEncodedTextCopyBegin - pBegin),
3302                                         static_cast< xub_StrLen >(
3303                                             q - 1 - pEncodedTextCopyBegin));
3304                                     sText += sal_Char(nDigit1 << 4 | nDigit2);
3305                                     q += 2;
3306                                     pEncodedTextCopyBegin = q;
3307                                     break;
3308                                 }
3309 
3310                                 case '?':
3311                                     if (q - pEncodedTextBegin > 1)
3312                                         sText += rBody.Copy(
3313                                             static_cast< xub_StrLen >(
3314                                                 pEncodedTextCopyBegin - pBegin),
3315                                             static_cast< xub_StrLen >(
3316                                                 q - 1 - pEncodedTextCopyBegin));
3317                                     else
3318                                         bEncodedWord = false;
3319                                     bDone = true;
3320                                     break;
3321 
3322                                 case '_':
3323                                     sText += rBody.Copy(
3324                                         static_cast< xub_StrLen >(
3325                                             pEncodedTextCopyBegin - pBegin),
3326                                         static_cast< xub_StrLen >(
3327                                             q - 1 - pEncodedTextCopyBegin));
3328                                     sText += ' ';
3329                                     pEncodedTextCopyBegin = q;
3330                                     break;
3331 
3332                                 default:
3333                                     if (!isVisible(nChar))
3334                                     {
3335                                         bEncodedWord = false;
3336                                         bDone = true;
3337                                     }
3338                                     break;
3339                             }
3340                         }
3341                 }
3342             }
3343 
3344             bEncodedWord = bEncodedWord && q != pEnd && *q++ == '=';
3345 
3346 //          if (bEncodedWord && q != pEnd)
3347 //              switch (*q)
3348 //              {
3349 //                  case '\t':
3350 //                  case ' ':
3351 //                  case '"':
3352 //                  case ')':
3353 //                  case ',':
3354 //                  case '.':
3355 //                  case '=':
3356 //                      break;
3357 //
3358 //                  default:
3359 //                      bEncodedWord = false;
3360 //                      break;
3361 //              }
3362 
3363             sal_Unicode * pUnicodeBuffer = 0;
3364             sal_Size nUnicodeSize = 0;
3365             if (bEncodedWord)
3366             {
3367                 pUnicodeBuffer
3368                     = convertToUnicode(sText.GetBuffer(),
3369                                        sText.GetBuffer() + sText.Len(),
3370                                        eCharsetEncoding, nUnicodeSize);
3371                 if (pUnicodeBuffer == 0)
3372                     bEncodedWord = false;
3373             }
3374 
3375             if (bEncodedWord)
3376             {
3377                 appendISO88591(sDecoded, pCopyBegin, pWSPBegin);
3378                 if (eType == HEADER_FIELD_TEXT)
3379                     sDecoded.Append(
3380                         pUnicodeBuffer,
3381                         static_cast< xub_StrLen >(nUnicodeSize));
3382                 else if (nCommentLevel == 0)
3383                 {
3384                     sEncodedText.Append(
3385                         pUnicodeBuffer,
3386                         static_cast< xub_StrLen >(nUnicodeSize));
3387                     if (!bQuotedEncodedText)
3388                     {
3389                         const sal_Unicode * pTextPtr = pUnicodeBuffer;
3390                         const sal_Unicode * pTextEnd = pTextPtr
3391                                                            + nUnicodeSize;
3392                         for (; pTextPtr != pTextEnd; ++pTextPtr)
3393                             if (!isEncodedWordTokenChar(*pTextPtr))
3394                             {
3395                                 bQuotedEncodedText = true;
3396                                 break;
3397                             }
3398                     }
3399                 }
3400                 else
3401                 {
3402                     const sal_Unicode * pTextPtr = pUnicodeBuffer;
3403                     const sal_Unicode * pTextEnd = pTextPtr + nUnicodeSize;
3404                     for (; pTextPtr != pTextEnd; ++pTextPtr)
3405                     {
3406                         switch (*pTextPtr)
3407                         {
3408                             case '(':
3409                             case ')':
3410                             case '\\':
3411                             case '\x0D':
3412                             case '=':
3413                                 sDecoded += '\\';
3414                                 break;
3415                         }
3416                         sDecoded += *pTextPtr;
3417                     }
3418                 }
3419                 delete[] pUnicodeBuffer;
3420                 p = q;
3421                 pCopyBegin = p;
3422 
3423                 pWSPBegin = p;
3424                 while (p != pEnd && isWhiteSpace(*p))
3425                     ++p;
3426                 /* bStartEncodedWord = p != pWSPBegin; */
3427                 continue;
3428             }
3429         }
3430 
3431         if (sEncodedText.Len() != 0)
3432         {
3433             if (bQuotedEncodedText)
3434             {
3435                 sDecoded += '"';
3436                 const sal_Unicode * pTextPtr = sEncodedText.GetBuffer();
3437                 const sal_Unicode * pTextEnd = pTextPtr + sEncodedText.Len();
3438                 for (;pTextPtr != pTextEnd; ++pTextPtr)
3439                 {
3440                     switch (*pTextPtr)
3441                     {
3442                         case '"':
3443                         case '\\':
3444                         case '\x0D':
3445                             sDecoded += '\\';
3446                             break;
3447                     }
3448                     sDecoded += *pTextPtr;
3449                 }
3450                 sDecoded += '"';
3451             }
3452             else
3453                 sDecoded += sEncodedText;
3454             sEncodedText.Erase();
3455             bQuotedEncodedText = false;
3456         }
3457 
3458         if (p == pEnd)
3459             break;
3460 
3461         switch (*p++)
3462         {
3463 //          case '\t':
3464 //          case ' ':
3465 //          case ',':
3466 //          case '.':
3467 //          case '=':
3468 //              bStartEncodedWord = true;
3469 //              break;
3470 
3471             case '"':
3472                 if (eType != HEADER_FIELD_TEXT && nCommentLevel == 0)
3473                 {
3474                     const sal_Char * pQuotedStringEnd
3475                         = skipQuotedString(p - 1, pEnd);
3476                     p = pQuotedStringEnd == p - 1 ? pEnd : pQuotedStringEnd;
3477                 }
3478                 /* bStartEncodedWord = true; */
3479                 break;
3480 
3481             case '(':
3482                 if (eType != HEADER_FIELD_TEXT)
3483                     ++nCommentLevel;
3484                 /* bStartEncodedWord = true; */
3485                 break;
3486 
3487             case ')':
3488                 if (nCommentLevel > 0)
3489                     --nCommentLevel;
3490                 /* bStartEncodedWord = false; */
3491                 break;
3492 
3493             default:
3494             {
3495                 const sal_Char * pUTF8Begin = p - 1;
3496                 const sal_Char * pUTF8End = pUTF8Begin;
3497                 sal_uInt32 nCharacter;
3498                 if (translateUTF8Char(pUTF8End, pEnd, RTL_TEXTENCODING_UCS4,
3499                                       nCharacter))
3500                 {
3501                     appendISO88591(sDecoded, pCopyBegin, p - 1);
3502                     sal_Unicode aUTF16Buf[2];
3503                     xub_StrLen nUTF16Len = static_cast< xub_StrLen >(
3504                         putUTF32Character(aUTF16Buf, nCharacter) - aUTF16Buf);
3505                     sDecoded.Append(aUTF16Buf, nUTF16Len);
3506                     p = pUTF8End;
3507                     pCopyBegin = p;
3508                 }
3509                 /* bStartEncodedWord = false; */
3510                 break;
3511             }
3512         }
3513         pWSPBegin = p;
3514     }
3515 
3516     appendISO88591(sDecoded, pCopyBegin, pEnd);
3517     return sDecoded;
3518 }
3519 
3520 //============================================================================
3521 //
3522 //  INetMIMEOutputSink
3523 //
3524 //============================================================================
3525 
3526 // virtual
writeSequence(const sal_Char * pSequence)3527 sal_Size INetMIMEOutputSink::writeSequence(const sal_Char * pSequence)
3528 {
3529     sal_Size nLength = rtl_str_getLength(pSequence);
3530     writeSequence(pSequence, pSequence + nLength);
3531     return nLength;
3532 }
3533 
3534 //============================================================================
3535 // virtual
writeSequence(const sal_uInt32 * pBegin,const sal_uInt32 * pEnd)3536 void INetMIMEOutputSink::writeSequence(const sal_uInt32 * pBegin,
3537                                        const sal_uInt32 * pEnd)
3538 {
3539     DBG_ASSERT(pBegin && pBegin <= pEnd,
3540                "INetMIMEOutputSink::writeSequence(): Bad sequence");
3541 
3542     sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin];
3543     sal_Char * pBufferEnd = pBufferBegin;
3544     while (pBegin != pEnd)
3545     {
3546         DBG_ASSERT(*pBegin < 256,
3547                    "INetMIMEOutputSink::writeSequence(): Bad octet");
3548         *pBufferEnd++ = sal_Char(*pBegin++);
3549     }
3550     writeSequence(pBufferBegin, pBufferEnd);
3551     delete[] pBufferBegin;
3552 }
3553 
3554 //============================================================================
3555 // virtual
writeSequence(const sal_Unicode * pBegin,const sal_Unicode * pEnd)3556 void INetMIMEOutputSink::writeSequence(const sal_Unicode * pBegin,
3557                                        const sal_Unicode * pEnd)
3558 {
3559     DBG_ASSERT(pBegin && pBegin <= pEnd,
3560                "INetMIMEOutputSink::writeSequence(): Bad sequence");
3561 
3562     sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin];
3563     sal_Char * pBufferEnd = pBufferBegin;
3564     while (pBegin != pEnd)
3565     {
3566         DBG_ASSERT(*pBegin < 256,
3567                    "INetMIMEOutputSink::writeSequence(): Bad octet");
3568         *pBufferEnd++ = sal_Char(*pBegin++);
3569     }
3570     writeSequence(pBufferBegin, pBufferEnd);
3571     delete[] pBufferBegin;
3572 }
3573 
3574 //============================================================================
3575 // virtual
getError() const3576 ErrCode INetMIMEOutputSink::getError() const
3577 {
3578     return ERRCODE_NONE;
3579 }
3580 
3581 //============================================================================
writeLineEnd()3582 void INetMIMEOutputSink::writeLineEnd()
3583 {
3584     static const sal_Char aCRLF[2] = { 0x0D, 0x0A };
3585     writeSequence(aCRLF, aCRLF + 2);
3586     m_nColumn = 0;
3587 }
3588 
3589 //============================================================================
3590 //
3591 //  INetMIMEStringOutputSink
3592 //
3593 //============================================================================
3594 
3595 // virtual
writeSequence(const sal_Char * pBegin,const sal_Char * pEnd)3596 void INetMIMEStringOutputSink::writeSequence(const sal_Char * pBegin,
3597                                              const sal_Char * pEnd)
3598 {
3599     DBG_ASSERT(pBegin && pBegin <= pEnd,
3600                "INetMIMEStringOutputSink::writeSequence(): Bad sequence");
3601 
3602     m_bOverflow = m_bOverflow
3603                   || pEnd - pBegin > STRING_MAXLEN - m_aBuffer.Len();
3604     if (!m_bOverflow)
3605         m_aBuffer.Append(pBegin, static_cast< xub_StrLen >(pEnd - pBegin));
3606 }
3607 
3608 //============================================================================
3609 // virtual
getError() const3610 ErrCode INetMIMEStringOutputSink::getError() const
3611 {
3612     return m_bOverflow ? ERRCODE_IO_OUTOFMEMORY : ERRCODE_NONE;
3613 }
3614 
3615 //============================================================================
3616 //
3617 //  INetMIMEUnicodeOutputSink
3618 //
3619 //============================================================================
3620 
3621 // virtual
writeSequence(const sal_Char * pBegin,const sal_Char * pEnd)3622 void INetMIMEUnicodeOutputSink::writeSequence(const sal_Char * pBegin,
3623                                               const sal_Char * pEnd)
3624 {
3625     DBG_ASSERT(pBegin && pBegin <= pEnd,
3626                "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence");
3627 
3628     sal_Unicode * pBufferBegin = new sal_Unicode[pEnd - pBegin];
3629     sal_Unicode * pBufferEnd = pBufferBegin;
3630     while (pBegin != pEnd)
3631         *pBufferEnd++ = sal_uChar(*pBegin++);
3632     writeSequence(pBufferBegin, pBufferEnd);
3633     delete[] pBufferBegin;
3634 }
3635 
3636 //============================================================================
3637 // virtual
writeSequence(const sal_uInt32 * pBegin,const sal_uInt32 * pEnd)3638 void INetMIMEUnicodeOutputSink::writeSequence(const sal_uInt32 * pBegin,
3639                                               const sal_uInt32 * pEnd)
3640 {
3641     DBG_ASSERT(pBegin && pBegin <= pEnd,
3642                "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence");
3643 
3644     sal_Unicode * pBufferBegin = new sal_Unicode[pEnd - pBegin];
3645     sal_Unicode * pBufferEnd = pBufferBegin;
3646     while (pBegin != pEnd)
3647     {
3648         DBG_ASSERT(*pBegin < 256,
3649                    "INetMIMEOutputSink::writeSequence(): Bad octet");
3650         *pBufferEnd++ = sal_Unicode(*pBegin++);
3651     }
3652     writeSequence(pBufferBegin, pBufferEnd);
3653     delete[] pBufferBegin;
3654 }
3655 
3656 //============================================================================
3657 // virtual
writeSequence(const sal_Unicode * pBegin,const sal_Unicode * pEnd)3658 void INetMIMEUnicodeOutputSink::writeSequence(const sal_Unicode * pBegin,
3659                                               const sal_Unicode * pEnd)
3660 {
3661     DBG_ASSERT(pBegin && pBegin <= pEnd,
3662                "INetMIMEUnicodeOutputSink::writeSequence(): Bad sequence");
3663 
3664     m_bOverflow = m_bOverflow
3665                   || pEnd - pBegin > STRING_MAXLEN - m_aBuffer.Len();
3666     if (!m_bOverflow)
3667         m_aBuffer.Append(pBegin, static_cast< xub_StrLen >(pEnd - pBegin));
3668 }
3669 
3670 //============================================================================
3671 // virtual
getError() const3672 ErrCode INetMIMEUnicodeOutputSink::getError() const
3673 {
3674     return m_bOverflow ? ERRCODE_IO_OUTOFMEMORY : ERRCODE_NONE;
3675 }
3676 
3677 //============================================================================
3678 //
3679 //  INetMIMEEncodedWordOutputSink
3680 //
3681 //============================================================================
3682 
3683 static const sal_Char aEscape[128]
3684     = { INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x00
3685         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x01
3686         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x02
3687         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x03
3688         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x04
3689         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x05
3690         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x06
3691         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x07
3692         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x08
3693         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x09
3694         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x0A
3695         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x0B
3696         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x0C
3697         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x0D
3698         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x0E
3699         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x0F
3700         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x10
3701         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x11
3702         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x12
3703         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x13
3704         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x14
3705         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x15
3706         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x16
3707         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x17
3708         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x18
3709         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x19
3710         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x1A
3711         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x1B
3712         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x1C
3713         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x1D
3714         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x1E
3715         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // 0x1F
3716         0,   // ' '
3717         0,   // '!'
3718         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '"'
3719         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '#'
3720         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '$'
3721         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '%'
3722         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '&'
3723         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '''
3724         INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '('
3725         INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // ')'
3726         0,   // '*'
3727         0,   // '+'
3728         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // ','
3729         0,   // '-'
3730         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '.'
3731         0,   // '/'
3732         0,   // '0'
3733         0,   // '1'
3734         0,   // '2'
3735         0,   // '3'
3736         0,   // '4'
3737         0,   // '5'
3738         0,   // '6'
3739         0,   // '7'
3740         0,   // '8'
3741         0,   // '9'
3742         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // ':'
3743         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // ';'
3744         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '<'
3745         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '='
3746         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '>'
3747         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '?'
3748         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '@'
3749         0,   // 'A'
3750         0,   // 'B'
3751         0,   // 'C'
3752         0,   // 'D'
3753         0,   // 'E'
3754         0,   // 'F'
3755         0,   // 'G'
3756         0,   // 'H'
3757         0,   // 'I'
3758         0,   // 'J'
3759         0,   // 'K'
3760         0,   // 'L'
3761         0,   // 'M'
3762         0,   // 'N'
3763         0,   // 'O'
3764         0,   // 'P'
3765         0,   // 'Q'
3766         0,   // 'R'
3767         0,   // 'S'
3768         0,   // 'T'
3769         0,   // 'U'
3770         0,   // 'V'
3771         0,   // 'W'
3772         0,   // 'X'
3773         0,   // 'Y'
3774         0,   // 'Z'
3775         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '['
3776         INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '\'
3777         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // ']'
3778         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '^'
3779         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '_'
3780         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '`'
3781         0,   // 'a'
3782         0,   // 'b'
3783         0,   // 'c'
3784         0,   // 'd'
3785         0,   // 'e'
3786         0,   // 'f'
3787         0,   // 'g'
3788         0,   // 'h'
3789         0,   // 'i'
3790         0,   // 'j'
3791         0,   // 'k'
3792         0,   // 'l'
3793         0,   // 'm'
3794         0,   // 'n'
3795         0,   // 'o'
3796         0,   // 'p'
3797         0,   // 'q'
3798         0,   // 'r'
3799         0,   // 's'
3800         0,   // 't'
3801         0,   // 'u'
3802         0,   // 'v'
3803         0,   // 'w'
3804         0,   // 'x'
3805         0,   // 'y'
3806         0,   // 'z'
3807         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '{'
3808         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '|'
3809         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '}'
3810         INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,   // '~'
3811         INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE }; // DEL
3812 
3813 inline bool
needsEncodedWordEscape(sal_uInt32 nChar) const3814 INetMIMEEncodedWordOutputSink::needsEncodedWordEscape(sal_uInt32 nChar) const
3815 {
3816     return !INetMIME::isUSASCII(nChar) || aEscape[nChar] & m_eContext;
3817 }
3818 
3819 //============================================================================
finish(bool bWriteTrailer)3820 void INetMIMEEncodedWordOutputSink::finish(bool bWriteTrailer)
3821 {
3822     if (m_eInitialSpace == SPACE_ALWAYS && m_nExtraSpaces == 0)
3823         m_nExtraSpaces = 1;
3824 
3825     if (m_eEncodedWordState == STATE_SECOND_EQUALS)
3826     {
3827         // If the text is already an encoded word, copy it verbatim:
3828         sal_uInt32 nSize = m_pBufferEnd - m_pBuffer;
3829         switch (m_ePrevCoding)
3830         {
3831             case CODING_QUOTED:
3832                 m_rSink << '"';
3833             case CODING_NONE:
3834                 if (m_eInitialSpace == SPACE_ENCODED && m_nExtraSpaces == 0)
3835                     m_nExtraSpaces = 1;
3836                 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3837                 {
3838                     if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3839                         m_rSink << INetMIMEOutputSink::endl;
3840                     m_rSink << ' ';
3841                 }
3842                 if (m_nExtraSpaces == 1)
3843                 {
3844                     if (m_rSink.getColumn() + nSize
3845                             >= m_rSink.getLineLengthLimit())
3846                         m_rSink << INetMIMEOutputSink::endl;
3847                     m_rSink << ' ';
3848                 }
3849                 break;
3850 
3851             case CODING_ENCODED:
3852             {
3853                 const sal_Char * pCharsetName
3854                  = INetMIME::getCharsetName(m_ePrevMIMEEncoding);
3855                 while (m_nExtraSpaces-- > 0)
3856                 {
3857                     if (m_rSink.getColumn()
3858                             > m_rSink.getLineLengthLimit() - 3)
3859                         m_rSink << "?=" << INetMIMEOutputSink::endl << " =?"
3860                                 << pCharsetName << "?Q?";
3861                     m_rSink << '_';
3862                 }
3863                 m_rSink << "?=";
3864             }
3865             case CODING_ENCODED_TERMINATED:
3866                 if (m_rSink.getColumn() + nSize
3867                         > m_rSink.getLineLengthLimit() - 1)
3868                     m_rSink << INetMIMEOutputSink::endl;
3869                 m_rSink << ' ';
3870                 break;
3871         }
3872         m_rSink.write(m_pBuffer, m_pBufferEnd);
3873         m_eCoding = CODING_ENCODED_TERMINATED;
3874     }
3875     else
3876     {
3877         // If the text itself is too long to fit into a single line, make it
3878         // into multiple encoded words:
3879         switch (m_eCoding)
3880         {
3881             case CODING_NONE:
3882                 if (m_nExtraSpaces == 0)
3883                 {
3884                     DBG_ASSERT(m_ePrevCoding == CODING_NONE
3885                                || m_pBuffer == m_pBufferEnd,
3886                                "INetMIMEEncodedWordOutputSink::finish():"
3887                                    " Bad state");
3888                     if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
3889                             > m_rSink.getLineLengthLimit())
3890                         m_eCoding = CODING_ENCODED;
3891                 }
3892                 else
3893                 {
3894                     OSL_ASSERT(m_pBufferEnd >= m_pBuffer);
3895                     if (static_cast< std::size_t >(m_pBufferEnd - m_pBuffer)
3896                         > m_rSink.getLineLengthLimit() - 1)
3897                     {
3898                         m_eCoding = CODING_ENCODED;
3899                     }
3900                 }
3901                 break;
3902 
3903             case CODING_QUOTED:
3904                 if (m_nExtraSpaces == 0)
3905                 {
3906                     DBG_ASSERT(m_ePrevCoding == CODING_NONE,
3907                                "INetMIMEEncodedWordOutputSink::finish():"
3908                                    " Bad state");
3909                     if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
3910                                 + m_nQuotedEscaped
3911                             > m_rSink.getLineLengthLimit() - 2)
3912                         m_eCoding = CODING_ENCODED;
3913                 }
3914                 else if ((m_pBufferEnd - m_pBuffer) + m_nQuotedEscaped
3915                              > m_rSink.getLineLengthLimit() - 3)
3916                     m_eCoding = CODING_ENCODED;
3917                 break;
3918 
3919             default:
3920                 break;
3921         }
3922 
3923         switch (m_eCoding)
3924         {
3925             case CODING_NONE:
3926                 switch (m_ePrevCoding)
3927                 {
3928                     case CODING_QUOTED:
3929                         if (m_rSink.getColumn() + m_nExtraSpaces
3930                                     + (m_pBufferEnd - m_pBuffer)
3931                                 < m_rSink.getLineLengthLimit())
3932                             m_eCoding = CODING_QUOTED;
3933                         else
3934                             m_rSink << '"';
3935                         break;
3936 
3937                     case CODING_ENCODED:
3938                         m_rSink << "?=";
3939                         break;
3940 
3941                     default:
3942                         break;
3943                 }
3944                 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3945                 {
3946                     if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3947                         m_rSink << INetMIMEOutputSink::endl;
3948                     m_rSink << ' ';
3949                 }
3950                 if (m_nExtraSpaces == 1)
3951                 {
3952                     if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
3953                             >= m_rSink.getLineLengthLimit())
3954                         m_rSink << INetMIMEOutputSink::endl;
3955                     m_rSink << ' ';
3956                 }
3957                 m_rSink.write(m_pBuffer, m_pBufferEnd);
3958                 if (m_eCoding == CODING_QUOTED && bWriteTrailer)
3959                 {
3960                     m_rSink << '"';
3961                     m_eCoding = CODING_NONE;
3962                 }
3963                 break;
3964 
3965             case CODING_QUOTED:
3966             {
3967                 bool bInsertLeadingQuote = true;
3968                 sal_uInt32 nSize = (m_pBufferEnd - m_pBuffer)
3969                                        + m_nQuotedEscaped + 2;
3970                 switch (m_ePrevCoding)
3971                 {
3972                     case CODING_QUOTED:
3973                         if (m_rSink.getColumn() + m_nExtraSpaces + nSize - 1
3974                                 < m_rSink.getLineLengthLimit())
3975                         {
3976                             bInsertLeadingQuote = false;
3977                             --nSize;
3978                         }
3979                         else
3980                             m_rSink << '"';
3981                         break;
3982 
3983                     case CODING_ENCODED:
3984                         m_rSink << "?=";
3985                         break;
3986 
3987                     default:
3988                         break;
3989                 }
3990                 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3991                 {
3992                     if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3993                         m_rSink << INetMIMEOutputSink::endl;
3994                     m_rSink << ' ';
3995                 }
3996                 if (m_nExtraSpaces == 1)
3997                 {
3998                     if (m_rSink.getColumn() + nSize
3999                             >= m_rSink.getLineLengthLimit())
4000                         m_rSink << INetMIMEOutputSink::endl;
4001                     m_rSink << ' ';
4002                 }
4003                 if (bInsertLeadingQuote)
4004                     m_rSink << '"';
4005                 for (const sal_Unicode * p = m_pBuffer; p != m_pBufferEnd;
4006                      ++p)
4007                 {
4008                     if (INetMIME::needsQuotedStringEscape(*p))
4009                         m_rSink << '\\';
4010                     m_rSink << sal_Char(*p);
4011                 }
4012                 if (bWriteTrailer)
4013                 {
4014                     m_rSink << '"';
4015                     m_eCoding = CODING_NONE;
4016                 }
4017                 break;
4018             }
4019 
4020             case CODING_ENCODED:
4021             {
4022                 rtl_TextEncoding eCharsetEncoding
4023                     = m_pEncodingList->
4024                           getPreferredEncoding(RTL_TEXTENCODING_UTF8);
4025                 rtl_TextEncoding eMIMEEncoding
4026                     = INetMIME::translateToMIME(eCharsetEncoding);
4027 
4028                 // The non UTF-8 code will only work for stateless single byte
4029                 // character encodings (see also below):
4030                 sal_Char * pTargetBuffer = NULL;
4031                 sal_Size nTargetSize = 0;
4032                 sal_uInt32 nSize;
4033                 if (eMIMEEncoding == RTL_TEXTENCODING_UTF8)
4034                 {
4035                     nSize = 0;
4036                     for (sal_Unicode const * p = m_pBuffer;
4037                          p != m_pBufferEnd;)
4038                     {
4039                         sal_uInt32 nUTF32
4040                             = INetMIME::getUTF32Character(p, m_pBufferEnd);
4041                         nSize += needsEncodedWordEscape(nUTF32) ?
4042                                      3 * INetMIME::getUTF8OctetCount(nUTF32) :
4043                                      1;
4044                             // only US-ASCII characters (that are converted to
4045                             // a single byte by UTF-8) need no encoded word
4046                             // escapes...
4047                     }
4048                 }
4049                 else
4050                 {
4051                     rtl_UnicodeToTextConverter hConverter
4052                         = rtl_createUnicodeToTextConverter(eCharsetEncoding);
4053                     rtl_UnicodeToTextContext hContext
4054                         = rtl_createUnicodeToTextContext(hConverter);
4055                     for (sal_Size nBufferSize = m_pBufferEnd - m_pBuffer;;
4056                          nBufferSize += nBufferSize / 3 + 1)
4057                     {
4058                         pTargetBuffer = new sal_Char[nBufferSize];
4059                         sal_uInt32 nInfo;
4060                         sal_Size nSrcCvtBytes;
4061                         nTargetSize
4062                             = rtl_convertUnicodeToText(
4063                                   hConverter, hContext, m_pBuffer,
4064                                   m_pBufferEnd - m_pBuffer, pTargetBuffer,
4065                                   nBufferSize,
4066                                   RTL_UNICODETOTEXT_FLAGS_UNDEFINED_IGNORE
4067                                      | RTL_UNICODETOTEXT_FLAGS_INVALID_IGNORE,
4068                                   &nInfo, &nSrcCvtBytes);
4069                         if (!(nInfo
4070                                   & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL))
4071                             break;
4072                         delete[] pTargetBuffer;
4073                         pTargetBuffer = NULL;
4074                         rtl_resetUnicodeToTextContext(hConverter, hContext);
4075                     }
4076                     rtl_destroyUnicodeToTextContext(hConverter, hContext);
4077                     rtl_destroyUnicodeToTextConverter(hConverter);
4078 
4079                     nSize = nTargetSize;
4080                     for (sal_Size k = 0; k < nTargetSize; ++k)
4081                         if (needsEncodedWordEscape(sal_uChar(
4082                                                        pTargetBuffer[k])))
4083                             nSize += 2;
4084                 }
4085 
4086                 const sal_Char * pCharsetName
4087                     = INetMIME::getCharsetName(eMIMEEncoding);
4088                 sal_uInt32 nWrapperSize = rtl_str_getLength(pCharsetName) + 7;
4089                     // '=?', '?Q?', '?='
4090 
4091                 switch (m_ePrevCoding)
4092                 {
4093                     case CODING_QUOTED:
4094                         m_rSink << '"';
4095                     case CODING_NONE:
4096                         if (m_eInitialSpace == SPACE_ENCODED
4097                             && m_nExtraSpaces == 0)
4098                             m_nExtraSpaces = 1;
4099                         nSize += nWrapperSize;
4100                         for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
4101                         {
4102                             if (m_rSink.getColumn()
4103                                     >= m_rSink.getLineLengthLimit())
4104                                 m_rSink << INetMIMEOutputSink::endl;
4105                             m_rSink << ' ';
4106                         }
4107                         if (m_nExtraSpaces == 1)
4108                         {
4109                             if (m_rSink.getColumn() + nSize
4110                                     >= m_rSink.getLineLengthLimit())
4111                             m_rSink << INetMIMEOutputSink::endl;
4112                             m_rSink << ' ';
4113                         }
4114                         m_rSink << "=?" << pCharsetName << "?Q?";
4115                         break;
4116 
4117                     case CODING_ENCODED:
4118                         if (m_ePrevMIMEEncoding != eMIMEEncoding
4119                             || m_rSink.getColumn() + m_nExtraSpaces + nSize
4120                                    > m_rSink.getLineLengthLimit() - 2)
4121                         {
4122                             m_rSink << "?=";
4123                             if (m_rSink.getColumn() + nWrapperSize
4124                                         + m_nExtraSpaces + nSize
4125                                     > m_rSink.getLineLengthLimit() - 1)
4126                                 m_rSink << INetMIMEOutputSink::endl;
4127                             m_rSink << " =?" << pCharsetName << "?Q?";
4128                         }
4129                         while (m_nExtraSpaces-- > 0)
4130                         {
4131                             if (m_rSink.getColumn()
4132                                     > m_rSink.getLineLengthLimit() - 3)
4133                                 m_rSink << "?=" << INetMIMEOutputSink::endl
4134                                         << " =?" << pCharsetName << "?Q?";
4135                             m_rSink << '_';
4136                         }
4137                         break;
4138 
4139                     case CODING_ENCODED_TERMINATED:
4140                         if (m_rSink.getColumn() + nWrapperSize
4141                                     + m_nExtraSpaces + nSize
4142                                 > m_rSink.getLineLengthLimit() - 1)
4143                             m_rSink << INetMIMEOutputSink::endl;
4144                         m_rSink << " =?" << pCharsetName << "?Q?";
4145                         while (m_nExtraSpaces-- > 0)
4146                         {
4147                             if (m_rSink.getColumn()
4148                                     > m_rSink.getLineLengthLimit() - 3)
4149                                 m_rSink << "?=" << INetMIMEOutputSink::endl
4150                                         << " =?" << pCharsetName << "?Q?";
4151                             m_rSink << '_';
4152                         }
4153                         break;
4154                 }
4155 
4156                 // The non UTF-8 code will only work for stateless single byte
4157                 // character encodings (see also above):
4158                 if (eMIMEEncoding == RTL_TEXTENCODING_UTF8)
4159                 {
4160                     bool bInitial = true;
4161                     for (sal_Unicode const * p = m_pBuffer;
4162                          p != m_pBufferEnd;)
4163                     {
4164                         sal_uInt32 nUTF32
4165                             = INetMIME::getUTF32Character(p, m_pBufferEnd);
4166                         bool bEscape = needsEncodedWordEscape(nUTF32);
4167                         sal_uInt32 nWidth
4168                             = bEscape ?
4169                                   3 * INetMIME::getUTF8OctetCount(nUTF32) : 1;
4170                             // only US-ASCII characters (that are converted to
4171                             // a single byte by UTF-8) need no encoded word
4172                             // escapes...
4173                         if (!bInitial
4174                             && m_rSink.getColumn() + nWidth + 2
4175                                    > m_rSink.getLineLengthLimit())
4176                             m_rSink << "?=" << INetMIMEOutputSink::endl
4177                                     << " =?" << pCharsetName << "?Q?";
4178                         if (bEscape)
4179                         {
4180                             DBG_ASSERT(
4181                                 nUTF32 < 0x10FFFF,
4182                                 "INetMIMEEncodedWordOutputSink::finish():"
4183                                     " Bad char");
4184                             if (nUTF32 < 0x80)
4185                                 INetMIME::writeEscapeSequence(m_rSink,
4186                                                               nUTF32);
4187                             else if (nUTF32 < 0x800)
4188                             {
4189                                 INetMIME::writeEscapeSequence(m_rSink,
4190                                                               (nUTF32 >> 6)
4191                                                                   | 0xC0);
4192                                 INetMIME::writeEscapeSequence(m_rSink,
4193                                                               (nUTF32 & 0x3F)
4194                                                                   | 0x80);
4195                             }
4196                             else if (nUTF32 < 0x10000)
4197                             {
4198                                 INetMIME::writeEscapeSequence(m_rSink,
4199                                                               (nUTF32 >> 12)
4200                                                                   | 0xE0);
4201                                 INetMIME::writeEscapeSequence(m_rSink,
4202                                                               ((nUTF32 >> 6)
4203                                                                       & 0x3F)
4204                                                                   | 0x80);
4205                                 INetMIME::writeEscapeSequence(m_rSink,
4206                                                               (nUTF32 & 0x3F)
4207                                                                   | 0x80);
4208                             }
4209                             else
4210                             {
4211                                 INetMIME::writeEscapeSequence(m_rSink,
4212                                                               (nUTF32 >> 18)
4213                                                                   | 0xF0);
4214                                 INetMIME::writeEscapeSequence(m_rSink,
4215                                                               ((nUTF32 >> 12)
4216                                                                       & 0x3F)
4217                                                                   | 0x80);
4218                                 INetMIME::writeEscapeSequence(m_rSink,
4219                                                               ((nUTF32 >> 6)
4220                                                                       & 0x3F)
4221                                                                   | 0x80);
4222                                 INetMIME::writeEscapeSequence(m_rSink,
4223                                                               (nUTF32 & 0x3F)
4224                                                                   | 0x80);
4225                             }
4226                         }
4227                         else
4228                             m_rSink << sal_Char(nUTF32);
4229                         bInitial = false;
4230                     }
4231                 }
4232                 else
4233                 {
4234                     for (sal_Size k = 0; k < nTargetSize; ++k)
4235                     {
4236                         sal_uInt32 nUCS4 = sal_uChar(pTargetBuffer[k]);
4237                         bool bEscape = needsEncodedWordEscape(nUCS4);
4238                         if (k > 0
4239                             && m_rSink.getColumn() + (bEscape ? 5 : 3)
4240                                    > m_rSink.getLineLengthLimit())
4241                             m_rSink << "?=" << INetMIMEOutputSink::endl
4242                                     << " =?" << pCharsetName << "?Q?";
4243                         if (bEscape)
4244                             INetMIME::writeEscapeSequence(m_rSink, nUCS4);
4245                         else
4246                             m_rSink << sal_Char(nUCS4);
4247                     }
4248                     delete[] pTargetBuffer;
4249                 }
4250 
4251                 if (bWriteTrailer)
4252                 {
4253                     m_rSink << "?=";
4254                     m_eCoding = CODING_ENCODED_TERMINATED;
4255                 }
4256 
4257                 m_ePrevMIMEEncoding = eMIMEEncoding;
4258                 break;
4259             }
4260 
4261             default:
4262                 OSL_ASSERT(false);
4263                 break;
4264         }
4265     }
4266 
4267     m_eInitialSpace = SPACE_NO;
4268     m_nExtraSpaces = 0;
4269     m_pEncodingList->reset();
4270     m_pBufferEnd = m_pBuffer;
4271     m_ePrevCoding = m_eCoding;
4272     m_eCoding = CODING_NONE;
4273     m_nQuotedEscaped = 0;
4274     m_eEncodedWordState = STATE_INITIAL;
4275 }
4276 
4277 //============================================================================
~INetMIMEEncodedWordOutputSink()4278 INetMIMEEncodedWordOutputSink::~INetMIMEEncodedWordOutputSink()
4279 {
4280     rtl_freeMemory(m_pBuffer);
4281     delete m_pEncodingList;
4282 }
4283 
4284 //============================================================================
4285 INetMIMEEncodedWordOutputSink &
operator <<(sal_uInt32 nChar)4286 INetMIMEEncodedWordOutputSink::operator <<(sal_uInt32 nChar)
4287 {
4288     if (nChar == ' ')
4289     {
4290         if (m_pBufferEnd != m_pBuffer)
4291             finish(false);
4292         ++m_nExtraSpaces;
4293     }
4294     else
4295     {
4296         // Check for an already encoded word:
4297         switch (m_eEncodedWordState)
4298         {
4299             case STATE_INITIAL:
4300                 if (nChar == '=')
4301                     m_eEncodedWordState = STATE_FIRST_EQUALS;
4302                 else
4303                     m_eEncodedWordState = STATE_BAD;
4304                 break;
4305 
4306             case STATE_FIRST_EQUALS:
4307                 if (nChar == '?')
4308                     m_eEncodedWordState = STATE_FIRST_EQUALS;
4309                 else
4310                     m_eEncodedWordState = STATE_BAD;
4311                 break;
4312 
4313             case STATE_FIRST_QUESTION:
4314                 if (INetMIME::isEncodedWordTokenChar(nChar))
4315                     m_eEncodedWordState = STATE_CHARSET;
4316                 else
4317                     m_eEncodedWordState = STATE_BAD;
4318                 break;
4319 
4320             case STATE_CHARSET:
4321                 if (nChar == '?')
4322                     m_eEncodedWordState = STATE_SECOND_QUESTION;
4323                 else if (!INetMIME::isEncodedWordTokenChar(nChar))
4324                     m_eEncodedWordState = STATE_BAD;
4325                 break;
4326 
4327             case STATE_SECOND_QUESTION:
4328                 if (nChar == 'B' || nChar == 'Q'
4329                     || nChar == 'b' || nChar == 'q')
4330                     m_eEncodedWordState = STATE_ENCODING;
4331                 else
4332                     m_eEncodedWordState = STATE_BAD;
4333                 break;
4334 
4335             case STATE_ENCODING:
4336                 if (nChar == '?')
4337                     m_eEncodedWordState = STATE_THIRD_QUESTION;
4338                 else
4339                     m_eEncodedWordState = STATE_BAD;
4340                 break;
4341 
4342             case STATE_THIRD_QUESTION:
4343                 if (INetMIME::isVisible(nChar) && nChar != '?')
4344                     m_eEncodedWordState = STATE_ENCODED_TEXT;
4345                 else
4346                     m_eEncodedWordState = STATE_BAD;
4347                 break;
4348 
4349             case STATE_ENCODED_TEXT:
4350                 if (nChar == '?')
4351                     m_eEncodedWordState = STATE_FOURTH_QUESTION;
4352                 else if (!INetMIME::isVisible(nChar))
4353                     m_eEncodedWordState = STATE_BAD;
4354                 break;
4355 
4356             case STATE_FOURTH_QUESTION:
4357                 if (nChar == '=')
4358                     m_eEncodedWordState = STATE_SECOND_EQUALS;
4359                 else
4360                     m_eEncodedWordState = STATE_BAD;
4361                 break;
4362 
4363             case STATE_SECOND_EQUALS:
4364                 m_eEncodedWordState = STATE_BAD;
4365                 break;
4366 
4367             case STATE_BAD:
4368                 break;
4369         }
4370 
4371         // Update encoding:
4372         m_pEncodingList->includes(nChar);
4373 
4374         // Update coding:
4375         enum { TENQ = 1,   // CONTEXT_TEXT, CODING_ENCODED
4376                CENQ = 2,   // CONTEXT_COMMENT, CODING_ENCODED
4377                PQTD = 4,   // CONTEXT_PHRASE, CODING_QUOTED
4378                PENQ = 8 }; // CONTEXT_PHRASE, CODING_ENCODED
4379         static const sal_Char aMinimal[128]
4380             = { TENQ | CENQ        | PENQ,   // 0x00
4381                 TENQ | CENQ        | PENQ,   // 0x01
4382                 TENQ | CENQ        | PENQ,   // 0x02
4383                 TENQ | CENQ        | PENQ,   // 0x03
4384                 TENQ | CENQ        | PENQ,   // 0x04
4385                 TENQ | CENQ        | PENQ,   // 0x05
4386                 TENQ | CENQ        | PENQ,   // 0x06
4387                 TENQ | CENQ        | PENQ,   // 0x07
4388                 TENQ | CENQ        | PENQ,   // 0x08
4389                 TENQ | CENQ        | PENQ,   // 0x09
4390                 TENQ | CENQ        | PENQ,   // 0x0A
4391                 TENQ | CENQ        | PENQ,   // 0x0B
4392                 TENQ | CENQ        | PENQ,   // 0x0C
4393                 TENQ | CENQ        | PENQ,   // 0x0D
4394                 TENQ | CENQ        | PENQ,   // 0x0E
4395                 TENQ | CENQ        | PENQ,   // 0x0F
4396                 TENQ | CENQ        | PENQ,   // 0x10
4397                 TENQ | CENQ        | PENQ,   // 0x11
4398                 TENQ | CENQ        | PENQ,   // 0x12
4399                 TENQ | CENQ        | PENQ,   // 0x13
4400                 TENQ | CENQ        | PENQ,   // 0x14
4401                 TENQ | CENQ        | PENQ,   // 0x15
4402                 TENQ | CENQ        | PENQ,   // 0x16
4403                 TENQ | CENQ        | PENQ,   // 0x17
4404                 TENQ | CENQ        | PENQ,   // 0x18
4405                 TENQ | CENQ        | PENQ,   // 0x19
4406                 TENQ | CENQ        | PENQ,   // 0x1A
4407                 TENQ | CENQ        | PENQ,   // 0x1B
4408                 TENQ | CENQ        | PENQ,   // 0x1C
4409                 TENQ | CENQ        | PENQ,   // 0x1D
4410                 TENQ | CENQ        | PENQ,   // 0x1E
4411                 TENQ | CENQ        | PENQ,   // 0x1F
4412                                         0,   // ' '
4413                                         0,   // '!'
4414                               PQTD       ,   // '"'
4415                                         0,   // '#'
4416                                         0,   // '$'
4417                                         0,   // '%'
4418                                         0,   // '&'
4419                                         0,   // '''
4420                        CENQ | PQTD       ,   // '('
4421                        CENQ | PQTD       ,   // ')'
4422                                         0,   // '*'
4423                                         0,   // '+'
4424                               PQTD       ,   // ','
4425                                         0,   // '-'
4426                               PQTD       ,   // '.'
4427                                         0,   // '/'
4428                                         0,   // '0'
4429                                         0,   // '1'
4430                                         0,   // '2'
4431                                         0,   // '3'
4432                                         0,   // '4'
4433                                         0,   // '5'
4434                                         0,   // '6'
4435                                         0,   // '7'
4436                                         0,   // '8'
4437                                         0,   // '9'
4438                               PQTD       ,   // ':'
4439                               PQTD       ,   // ';'
4440                               PQTD       ,   // '<'
4441                                         0,   // '='
4442                               PQTD       ,   // '>'
4443                                         0,   // '?'
4444                               PQTD       ,   // '@'
4445                                         0,   // 'A'
4446                                         0,   // 'B'
4447                                         0,   // 'C'
4448                                         0,   // 'D'
4449                                         0,   // 'E'
4450                                         0,   // 'F'
4451                                         0,   // 'G'
4452                                         0,   // 'H'
4453                                         0,   // 'I'
4454                                         0,   // 'J'
4455                                         0,   // 'K'
4456                                         0,   // 'L'
4457                                         0,   // 'M'
4458                                         0,   // 'N'
4459                                         0,   // 'O'
4460                                         0,   // 'P'
4461                                         0,   // 'Q'
4462                                         0,   // 'R'
4463                                         0,   // 'S'
4464                                         0,   // 'T'
4465                                         0,   // 'U'
4466                                         0,   // 'V'
4467                                         0,   // 'W'
4468                                         0,   // 'X'
4469                                         0,   // 'Y'
4470                                         0,   // 'Z'
4471                               PQTD       ,   // '['
4472                        CENQ | PQTD       ,   // '\'
4473                               PQTD       ,   // ']'
4474                                         0,   // '^'
4475                                         0,   // '_'
4476                                         0,   // '`'
4477                                         0,   // 'a'
4478                                         0,   // 'b'
4479                                         0,   // 'c'
4480                                         0,   // 'd'
4481                                         0,   // 'e'
4482                                         0,   // 'f'
4483                                         0,   // 'g'
4484                                         0,   // 'h'
4485                                         0,   // 'i'
4486                                         0,   // 'j'
4487                                         0,   // 'k'
4488                                         0,   // 'l'
4489                                         0,   // 'm'
4490                                         0,   // 'n'
4491                                         0,   // 'o'
4492                                         0,   // 'p'
4493                                         0,   // 'q'
4494                                         0,   // 'r'
4495                                         0,   // 's'
4496                                         0,   // 't'
4497                                         0,   // 'u'
4498                                         0,   // 'v'
4499                                         0,   // 'w'
4500                                         0,   // 'x'
4501                                         0,   // 'y'
4502                                         0,   // 'z'
4503                                         0,   // '{'
4504                                         0,   // '|'
4505                                         0,   // '}'
4506                                         0,   // '~'
4507                 TENQ | CENQ        | PENQ }; // DEL
4508         Coding eNewCoding = !INetMIME::isUSASCII(nChar) ? CODING_ENCODED :
4509                             m_eContext == CONTEXT_PHRASE ?
4510                                 Coding(aMinimal[nChar] >> 2) :
4511                             aMinimal[nChar] & m_eContext ? CODING_ENCODED :
4512                                                            CODING_NONE;
4513         if (eNewCoding > m_eCoding)
4514             m_eCoding = eNewCoding;
4515         if (m_eCoding == CODING_QUOTED
4516             && INetMIME::needsQuotedStringEscape(nChar))
4517             ++m_nQuotedEscaped;
4518 
4519         // Append to buffer:
4520         if (sal_uInt32(m_pBufferEnd - m_pBuffer) == m_nBufferSize)
4521         {
4522             m_pBuffer
4523                 = static_cast< sal_Unicode * >(
4524                       rtl_reallocateMemory(m_pBuffer,
4525                                            (m_nBufferSize + BUFFER_SIZE)
4526                                                * sizeof (sal_Unicode)));
4527             m_pBufferEnd = m_pBuffer + m_nBufferSize;
4528             m_nBufferSize += BUFFER_SIZE;
4529         }
4530         *m_pBufferEnd++ = sal_Unicode(nChar);
4531     }
4532     return *this;
4533 }
4534 
4535 //============================================================================
4536 //
4537 //  INetContentTypeParameterList
4538 //
4539 //============================================================================
4540 
Clear()4541 void INetContentTypeParameterList::Clear()
4542 {
4543     while (Count() > 0)
4544         delete static_cast< INetContentTypeParameter * >(Remove(Count() - 1));
4545 }
4546 
4547 //============================================================================
4548 const INetContentTypeParameter *
find(const ByteString & rAttribute) const4549 INetContentTypeParameterList::find(const ByteString & rAttribute) const
4550 {
4551     for (sal_uIntPtr i = 0; i < Count(); ++i)
4552     {
4553         const INetContentTypeParameter * pParameter = GetObject(i);
4554         if (pParameter->m_sAttribute.EqualsIgnoreCaseAscii(rAttribute))
4555             return pParameter;
4556     }
4557     return 0;
4558 }
4559 
4560