bump product version to 5.0.4.1
[LibreOffice.git] / tools / source / inet / inetmime.cxx
blobd1ec8379489b9ec60cd1a9b0245769b9f1683589
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cstddef>
21 #include <limits>
23 #include <osl/diagnose.h>
24 #include <rtl/ustring.hxx>
25 #include <rtl/strbuf.hxx>
26 #include <rtl/tencinfo.h>
27 #include <tools/inetmime.hxx>
28 #include <rtl/character.hxx>
30 namespace unnamed_tools_inetmime {} using namespace unnamed_tools_inetmime;
31 // unnamed namespaces don't work well yet
33 namespace unnamed_tools_inetmime {
35 class Charset
37 rtl_TextEncoding m_eEncoding;
38 const sal_uInt32 * m_pRanges;
40 public:
41 inline Charset(rtl_TextEncoding eTheEncoding,
42 const sal_uInt32 * pTheRanges);
44 rtl_TextEncoding getEncoding() const { return m_eEncoding; }
46 bool contains(sal_uInt32 nChar) const;
49 inline Charset::Charset(rtl_TextEncoding eTheEncoding,
50 const sal_uInt32 * pTheRanges):
51 m_eEncoding(eTheEncoding),
52 m_pRanges(pTheRanges)
54 DBG_ASSERT(m_pRanges, "Charset::Charset(): Bad ranges");
57 void appendISO88591(OUString & rText, sal_Char const * pBegin,
58 sal_Char const * pEnd);
62 class INetMIMECharsetList_Impl
64 struct Node
66 Charset m_aCharset;
67 bool m_bDisabled;
68 Node * m_pNext;
70 inline Node(const Charset & rTheCharset, bool bTheDisabled,
71 Node * pTheNext);
74 Node * m_pFirst;
76 public:
77 INetMIMECharsetList_Impl(): m_pFirst(0) {}
79 ~INetMIMECharsetList_Impl();
81 void prepend(const Charset & rCharset)
82 { m_pFirst = new Node(rCharset, false, m_pFirst); }
84 void includes(sal_uInt32 nChar);
86 rtl_TextEncoding getPreferredEncoding(rtl_TextEncoding eDefault
87 = RTL_TEXTENCODING_DONTKNOW)
88 const;
90 void reset();
93 inline INetMIMECharsetList_Impl::Node::Node(const Charset & rTheCharset,
94 bool bTheDisabled,
95 Node * pTheNext):
96 m_aCharset(rTheCharset),
97 m_bDisabled(bTheDisabled),
98 m_pNext(pTheNext)
101 namespace unnamed_tools_inetmime {
103 struct Parameter
105 Parameter * m_pNext;
106 OString m_aAttribute;
107 OString m_aCharset;
108 OString m_aLanguage;
109 OString m_aValue;
110 sal_uInt32 m_nSection;
111 bool m_bExtended;
113 inline Parameter(Parameter * pTheNext, const OString& rTheAttribute,
114 const OString& rTheCharset,
115 const OString& rTheLanguage,
116 const OString& rTheValue, sal_uInt32 nTheSection,
117 bool bTheExtended);
120 inline Parameter::Parameter(Parameter * pTheNext,
121 const OString& rTheAttribute,
122 const OString& rTheCharset,
123 const OString& rTheLanguage,
124 const OString& rTheValue,
125 sal_uInt32 nTheSection, bool bTheExtended):
126 m_pNext(pTheNext),
127 m_aAttribute(rTheAttribute),
128 m_aCharset(rTheCharset),
129 m_aLanguage(rTheLanguage),
130 m_aValue(rTheValue),
131 m_nSection(nTheSection),
132 m_bExtended(bTheExtended)
135 struct ParameterList
137 Parameter * m_pList;
139 ParameterList(): m_pList(0) {}
141 inline ~ParameterList();
143 Parameter ** find(const OString& rAttribute, sal_uInt32 nSection,
144 bool & rPresent);
147 inline ParameterList::~ParameterList()
149 while (m_pList)
151 Parameter * pNext = m_pList->m_pNext;
152 delete m_pList;
153 m_pList = pNext;
157 bool parseParameters(ParameterList const & rInput,
158 INetContentTypeParameterList * pOutput);
162 // Charset
164 bool Charset::contains(sal_uInt32 nChar) const
166 for (const sal_uInt32 * p = m_pRanges;;)
168 if (nChar < *p++)
169 return false;
170 if (nChar <= *p++)
171 return true;
175 // appendISO88591
177 namespace unnamed_tools_inetmime {
179 void appendISO88591(OUString & rText, sal_Char const * pBegin,
180 sal_Char const * pEnd)
182 sal_Int32 nLength = pEnd - pBegin;
183 sal_Unicode * pBuffer = new sal_Unicode[nLength];
184 for (sal_Unicode * p = pBuffer; pBegin != pEnd;)
185 *p++ = static_cast<unsigned char>(*pBegin++);
186 rText += OUString(pBuffer, nLength);
187 delete[] pBuffer;
192 // INetMIMECharsetList_Impl
194 INetMIMECharsetList_Impl::~INetMIMECharsetList_Impl()
196 while (m_pFirst)
198 Node * pRemove = m_pFirst;
199 m_pFirst = m_pFirst->m_pNext;
200 delete pRemove;
204 void INetMIMECharsetList_Impl::includes(sal_uInt32 nChar)
206 for (Node * p = m_pFirst; p; p = p->m_pNext)
207 if (!(p->m_bDisabled || p->m_aCharset.contains(nChar)))
208 p->m_bDisabled = true;
211 rtl_TextEncoding INetMIMECharsetList_Impl::getPreferredEncoding(rtl_TextEncoding eDefault)
212 const
214 for (Node * p = m_pFirst; p; p = p->m_pNext)
215 if (!p->m_bDisabled)
216 return p->m_aCharset.getEncoding();
217 return eDefault;
220 void INetMIMECharsetList_Impl::reset()
222 for (Node * p = m_pFirst; p; p = p->m_pNext)
223 p->m_bDisabled = false;
226 // ParameterList
228 Parameter ** ParameterList::find(const OString& rAttribute,
229 sal_uInt32 nSection, bool & rPresent)
231 Parameter ** p = &m_pList;
232 for (; *p; p = &(*p)->m_pNext)
234 sal_Int32 nCompare = rAttribute.compareTo((*p)->m_aAttribute);
235 if (nCompare > 0)
236 break;
237 else if (nCompare == 0)
239 if (nSection > (*p)->m_nSection)
240 break;
241 else if (nSection == (*p)->m_nSection)
243 rPresent = true;
244 return p;
248 rPresent = false;
249 return p;
252 // parseParameters
254 namespace unnamed_tools_inetmime {
256 bool parseParameters(ParameterList const & rInput,
257 INetContentTypeParameterList * pOutput)
259 if (pOutput)
260 pOutput->Clear();
262 Parameter * pPrev = 0;
263 for (Parameter * p = rInput.m_pList; p; p = p->m_pNext)
265 if (p->m_nSection > 0
266 && (!pPrev
267 || pPrev->m_nSection != p->m_nSection - 1
268 || pPrev->m_aAttribute != p->m_aAttribute))
269 return false;
270 pPrev = p;
273 if (pOutput)
274 for (Parameter * p = rInput.m_pList; p;)
276 bool bCharset = !p->m_aCharset.isEmpty();
277 rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
278 if (bCharset)
279 eEncoding
280 = INetMIME::getCharsetEncoding(p->m_aCharset.getStr(),
281 p->m_aCharset.getStr()
282 + rInput.m_pList->
283 m_aCharset.
284 getLength());
285 OUString aValue;
286 bool bBadEncoding = false;
287 Parameter * pNext = p;
290 sal_Size nSize;
291 sal_Unicode * pUnicode
292 = INetMIME::convertToUnicode(pNext->m_aValue.getStr(),
293 pNext->m_aValue.getStr()
294 + pNext->m_aValue.getLength(),
295 bCharset && p->m_bExtended ?
296 eEncoding :
297 RTL_TEXTENCODING_UTF8,
298 nSize);
299 if (!pUnicode && !(bCharset && p->m_bExtended))
300 pUnicode = INetMIME::convertToUnicode(
301 pNext->m_aValue.getStr(),
302 pNext->m_aValue.getStr()
303 + pNext->m_aValue.getLength(),
304 RTL_TEXTENCODING_ISO_8859_1, nSize);
305 if (!pUnicode)
307 bBadEncoding = true;
308 break;
310 aValue += OUString(pUnicode, static_cast<sal_Int32>(nSize));
311 delete[] pUnicode;
312 pNext = pNext->m_pNext;
314 while (pNext && pNext->m_nSection > 0);
315 if (bBadEncoding)
317 aValue.clear();
318 for (pNext = p;;)
320 if (pNext->m_bExtended)
322 for (sal_Int32 i = 0; i < pNext->m_aValue.getLength(); ++i)
323 aValue += OUString(sal_Unicode(
324 sal_Unicode(
325 static_cast<unsigned char>(pNext->m_aValue[i]))
326 | 0xF800));
328 else
330 for (sal_Int32 i = 0; i < pNext->m_aValue.getLength(); ++i)
331 aValue += OUString( sal_Unicode(static_cast<unsigned char>(pNext->m_aValue[i])) );
333 pNext = pNext->m_pNext;
334 if (!pNext || pNext->m_nSection == 0)
335 break;
338 pOutput->Append(new INetContentTypeParameter(p->m_aAttribute,
339 p->m_aCharset,
340 p->m_aLanguage,
341 aValue,
342 !bBadEncoding));
343 p = pNext;
345 return true;
350 // INetMIME
352 // static
353 bool INetMIME::isAtomChar(sal_uInt32 nChar)
355 static const bool aMap[128]
356 = { false, false, false, false, false, false, false, false,
357 false, false, false, false, false, false, false, false,
358 false, false, false, false, false, false, false, false,
359 false, false, false, false, false, false, false, false,
360 false, true, false, true, true, true, true, true, // !"#$%&'
361 false, false, true, true, false, true, false, true, //()*+,-./
362 true, true, true, true, true, true, true, true, //01234567
363 true, true, false, false, false, true, false, true, //89:;<=>?
364 false, true, true, true, true, true, true, true, //@ABCDEFG
365 true, true, true, true, true, true, true, true, //HIJKLMNO
366 true, true, true, true, true, true, true, true, //PQRSTUVW
367 true, true, true, false, false, false, true, true, //XYZ[\]^_
368 true, true, true, true, true, true, true, true, //`abcdefg
369 true, true, true, true, true, true, true, true, //hijklmno
370 true, true, true, true, true, true, true, true, //pqrstuvw
371 true, true, true, true, true, true, true, false //xyz{|}~
373 return rtl::isAscii(nChar) && aMap[nChar];
376 // static
377 bool INetMIME::isTokenChar(sal_uInt32 nChar)
379 static const bool aMap[128]
380 = { false, false, false, false, false, false, false, false,
381 false, false, false, false, false, false, false, false,
382 false, false, false, false, false, false, false, false,
383 false, false, false, false, false, false, false, false,
384 false, true, false, true, true, true, true, true, // !"#$%&'
385 false, false, true, true, false, true, true, false, //()*+,-./
386 true, true, true, true, true, true, true, true, //01234567
387 true, true, false, false, false, false, false, false, //89:;<=>?
388 false, true, true, true, true, true, true, true, //@ABCDEFG
389 true, true, true, true, true, true, true, true, //HIJKLMNO
390 true, true, true, true, true, true, true, true, //PQRSTUVW
391 true, true, true, false, false, false, true, true, //XYZ[\]^_
392 true, true, true, true, true, true, true, true, //`abcdefg
393 true, true, true, true, true, true, true, true, //hijklmno
394 true, true, true, true, true, true, true, true, //pqrstuvw
395 true, true, true, true, true, true, true, false //xyz{|}~
397 return rtl::isAscii(nChar) && aMap[nChar];
400 // static
401 bool INetMIME::isEncodedWordTokenChar(sal_uInt32 nChar)
403 static const bool aMap[128]
404 = { false, false, false, false, false, false, false, false,
405 false, false, false, false, false, false, false, false,
406 false, false, false, false, false, false, false, false,
407 false, false, false, false, false, false, false, false,
408 false, true, false, true, true, true, true, true, // !"#$%&'
409 false, false, true, true, false, true, false, false, //()*+,-./
410 true, true, true, true, true, true, true, true, //01234567
411 true, true, false, false, false, false, false, false, //89:;<=>?
412 false, true, true, true, true, true, true, true, //@ABCDEFG
413 true, true, true, true, true, true, true, true, //HIJKLMNO
414 true, true, true, true, true, true, true, true, //PQRSTUVW
415 true, true, true, false, false, false, true, true, //XYZ[\]^_
416 true, true, true, true, true, true, true, true, //`abcdefg
417 true, true, true, true, true, true, true, true, //hijklmno
418 true, true, true, true, true, true, true, true, //pqrstuvw
419 true, true, true, true, true, true, true, false //xyz{|}~
421 return rtl::isAscii(nChar) && aMap[nChar];
424 // static
425 bool INetMIME::isIMAPAtomChar(sal_uInt32 nChar)
427 static const bool aMap[128]
428 = { false, false, false, false, false, false, false, false,
429 false, false, false, false, false, false, false, false,
430 false, false, false, false, false, false, false, false,
431 false, false, false, false, false, false, false, false,
432 false, true, false, true, true, false, true, true, // !"#$%&'
433 false, false, false, true, true, true, true, true, //()*+,-./
434 true, true, true, true, true, true, true, true, //01234567
435 true, true, true, true, true, true, true, true, //89:;<=>?
436 true, true, true, true, true, true, true, true, //@ABCDEFG
437 true, true, true, true, true, true, true, true, //HIJKLMNO
438 true, true, true, true, true, true, true, true, //PQRSTUVW
439 true, true, true, true, false, true, true, true, //XYZ[\]^_
440 true, true, true, true, true, true, true, true, //`abcdefg
441 true, true, true, true, true, true, true, true, //hijklmno
442 true, true, true, true, true, true, true, true, //pqrstuvw
443 true, true, true, false, true, true, true, false //xyz{|}~
445 return rtl::isAscii(nChar) && aMap[nChar];
448 // static
449 sal_uInt32 INetMIME::getHexDigit(int nWeight)
451 DBG_ASSERT(nWeight >= 0 && nWeight < 16,
452 "INetMIME::getHexDigit(): Bad weight");
454 static const sal_Char aDigits[16]
455 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
456 'D', 'E', 'F' };
457 return aDigits[nWeight];
460 // static
461 bool INetMIME::equalIgnoreCase(const sal_Char * pBegin1,
462 const sal_Char * pEnd1,
463 const sal_Char * pString2)
465 DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2,
466 "INetMIME::equalIgnoreCase(): Bad sequences");
468 while (*pString2 != 0)
469 if (pBegin1 == pEnd1
470 || rtl::toAsciiUpperCase(*pBegin1++) != rtl::toAsciiUpperCase(*pString2++))
471 return false;
472 return pBegin1 == pEnd1;
475 // static
476 bool INetMIME::equalIgnoreCase(const sal_Unicode * pBegin1,
477 const sal_Unicode * pEnd1,
478 const sal_Char * pString2)
480 DBG_ASSERT(pBegin1 && pBegin1 <= pEnd1 && pString2,
481 "INetMIME::equalIgnoreCase(): Bad sequences");
483 while (*pString2 != 0)
484 if (pBegin1 == pEnd1
485 || rtl::toAsciiUpperCase(*pBegin1++) != rtl::toAsciiUpperCase(*pString2++))
486 return false;
487 return pBegin1 == pEnd1;
490 // static
491 const sal_Unicode * INetMIME::skipLinearWhiteSpace(const sal_Unicode * pBegin,
492 const sal_Unicode * pEnd)
494 DBG_ASSERT(pBegin && pBegin <= pEnd,
495 "INetMIME::skipLinearWhiteSpace(): Bad sequence");
497 while (pBegin != pEnd)
498 switch (*pBegin)
500 case '\t':
501 case ' ':
502 ++pBegin;
503 break;
505 case 0x0D: // CR
506 if (startsWithLineFolding(pBegin, pEnd))
507 pBegin += 3;
508 else
509 return pBegin;
510 break;
512 default:
513 return pBegin;
515 return pBegin;
518 // static
519 const sal_Unicode * INetMIME::skipComment(const sal_Unicode * pBegin,
520 const sal_Unicode * pEnd)
522 DBG_ASSERT(pBegin && pBegin <= pEnd,
523 "INetMIME::skipComment(): Bad sequence");
525 if (pBegin != pEnd && *pBegin == '(')
527 sal_uInt32 nLevel = 0;
528 for (const sal_Unicode * p = pBegin; p != pEnd;)
529 switch (*p++)
531 case '(':
532 ++nLevel;
533 break;
535 case ')':
536 if (--nLevel == 0)
537 return p;
538 break;
540 case '\\':
541 if (p != pEnd)
542 ++p;
543 break;
546 return pBegin;
549 // static
550 const sal_Unicode * INetMIME::skipLinearWhiteSpaceComment(const sal_Unicode *
551 pBegin,
552 const sal_Unicode *
553 pEnd)
555 DBG_ASSERT(pBegin && pBegin <= pEnd,
556 "INetMIME::skipLinearWhiteSpaceComment(): Bad sequence");
558 while (pBegin != pEnd)
559 switch (*pBegin)
561 case '\t':
562 case ' ':
563 ++pBegin;
564 break;
566 case 0x0D: // CR
567 if (startsWithLineFolding(pBegin, pEnd))
568 pBegin += 3;
569 else
570 return pBegin;
571 break;
573 case '(':
575 const sal_Unicode * p = skipComment(pBegin, pEnd);
576 if (p == pBegin)
577 return pBegin;
578 pBegin = p;
579 break;
582 default:
583 return pBegin;
585 return pBegin;
588 // static
589 const sal_Char * INetMIME::skipQuotedString(const sal_Char * pBegin,
590 const sal_Char * pEnd)
592 DBG_ASSERT(pBegin && pBegin <= pEnd,
593 "INetMIME::skipQuotedString(): Bad sequence");
595 if (pBegin != pEnd && *pBegin == '"')
596 for (const sal_Char * p = pBegin + 1; p != pEnd;)
597 switch (*p++)
599 case 0x0D: // CR
600 if (pEnd - p < 2 || *p++ != 0x0A // LF
601 || !isWhiteSpace(*p++))
602 return pBegin;
603 break;
605 case '"':
606 return p;
608 case '\\':
609 if (p != pEnd)
610 ++p;
611 break;
613 return pBegin;
616 // static
617 const sal_Unicode * INetMIME::skipQuotedString(const sal_Unicode * pBegin,
618 const sal_Unicode * pEnd)
620 DBG_ASSERT(pBegin && pBegin <= pEnd,
621 "INetMIME::skipQuotedString(): Bad sequence");
623 if (pBegin != pEnd && *pBegin == '"')
624 for (const sal_Unicode * p = pBegin + 1; p != pEnd;)
625 switch (*p++)
627 case 0x0D: // CR
628 if (pEnd - p < 2 || *p++ != 0x0A // LF
629 || !isWhiteSpace(*p++))
630 return pBegin;
631 break;
633 case '"':
634 return p;
636 case '\\':
637 if (p != pEnd)
638 ++p;
639 break;
641 return pBegin;
644 // static
645 bool INetMIME::scanUnsigned(const sal_Unicode *& rBegin,
646 const sal_Unicode * pEnd, bool bLeadingZeroes,
647 sal_uInt32 & rValue)
649 sal_uInt64 nTheValue = 0;
650 const sal_Unicode * p = rBegin;
651 for ( ; p != pEnd; ++p)
653 int nWeight = getWeight(*p);
654 if (nWeight < 0)
655 break;
656 nTheValue = 10 * nTheValue + nWeight;
657 if (nTheValue > std::numeric_limits< sal_uInt32 >::max())
658 return false;
660 if (nTheValue == 0 && (p == rBegin || (!bLeadingZeroes && p - rBegin != 1)))
661 return false;
662 rBegin = p;
663 rValue = sal_uInt32(nTheValue);
664 return true;
667 // static
668 const sal_Unicode * INetMIME::scanQuotedBlock(const sal_Unicode * pBegin,
669 const sal_Unicode * pEnd,
670 sal_uInt32 nOpening,
671 sal_uInt32 nClosing,
672 sal_Size & rLength,
673 bool & rModify)
675 DBG_ASSERT(pBegin && pBegin <= pEnd,
676 "INetMIME::scanQuotedBlock(): Bad sequence");
678 if (pBegin != pEnd && *pBegin == nOpening)
680 ++rLength;
681 ++pBegin;
682 while (pBegin != pEnd)
683 if (*pBegin == nClosing)
685 ++rLength;
686 return ++pBegin;
688 else
690 sal_uInt32 c = *pBegin++;
691 switch (c)
693 case 0x0D: // CR
694 if (pBegin != pEnd && *pBegin == 0x0A) // LF
695 if (pEnd - pBegin >= 2 && isWhiteSpace(pBegin[1]))
697 ++rLength;
698 rModify = true;
699 pBegin += 2;
701 else
703 rLength += 3;
704 rModify = true;
705 ++pBegin;
707 else
708 ++rLength;
709 break;
711 case '\\':
712 ++rLength;
713 if (pBegin != pEnd)
715 if (startsWithLineBreak(pBegin, pEnd)
716 && (pEnd - pBegin < 3
717 || !isWhiteSpace(pBegin[2])))
719 rLength += 3;
720 rModify = true;
721 pBegin += 2;
723 else
724 ++pBegin;
726 break;
728 default:
729 ++rLength;
730 if (!rtl::isAscii(c))
731 rModify = true;
732 break;
736 return pBegin;
739 // static
740 sal_Unicode const * INetMIME::scanParameters(sal_Unicode const * pBegin,
741 sal_Unicode const * pEnd,
742 INetContentTypeParameterList *
743 pParameters)
745 ParameterList aList;
746 sal_Unicode const * pParameterBegin = pBegin;
747 for (sal_Unicode const * p = pParameterBegin;; pParameterBegin = p)
749 pParameterBegin = skipLinearWhiteSpaceComment(p, pEnd);
750 if (pParameterBegin == pEnd || *pParameterBegin != ';')
751 break;
752 p = pParameterBegin + 1;
754 sal_Unicode const * pAttributeBegin
755 = skipLinearWhiteSpaceComment(p, pEnd);
756 p = pAttributeBegin;
757 bool bDowncaseAttribute = false;
758 while (p != pEnd && isTokenChar(*p) && *p != '*')
760 bDowncaseAttribute = bDowncaseAttribute || rtl::isAsciiUpperCase(*p);
761 ++p;
763 if (p == pAttributeBegin)
764 break;
765 OString aAttribute = OString(
766 pAttributeBegin, p - pAttributeBegin,
767 RTL_TEXTENCODING_ASCII_US);
768 if (bDowncaseAttribute)
769 aAttribute = aAttribute.toAsciiLowerCase();
771 sal_uInt32 nSection = 0;
772 if (p != pEnd && *p == '*')
774 ++p;
775 if (p != pEnd && rtl::isAsciiDigit(*p)
776 && !scanUnsigned(p, pEnd, false, nSection))
777 break;
780 bool bPresent;
781 Parameter ** pPos = aList.find(aAttribute, nSection, bPresent);
782 if (bPresent)
783 break;
785 bool bExtended = false;
786 if (p != pEnd && *p == '*')
788 ++p;
789 bExtended = true;
792 p = skipLinearWhiteSpaceComment(p, pEnd);
794 if (p == pEnd || *p != '=')
795 break;
797 p = skipLinearWhiteSpaceComment(p + 1, pEnd);
799 OString aCharset;
800 OString aLanguage;
801 OString aValue;
802 if (bExtended)
804 if (nSection == 0)
806 sal_Unicode const * pCharsetBegin = p;
807 bool bDowncaseCharset = false;
808 while (p != pEnd && isTokenChar(*p) && *p != '\'')
810 bDowncaseCharset = bDowncaseCharset || rtl::isAsciiUpperCase(*p);
811 ++p;
813 if (p == pCharsetBegin)
814 break;
815 if (pParameters)
817 aCharset = OString(
818 pCharsetBegin,
819 p - pCharsetBegin,
820 RTL_TEXTENCODING_ASCII_US);
821 if (bDowncaseCharset)
822 aCharset = aCharset.toAsciiLowerCase();
825 if (p == pEnd || *p != '\'')
826 break;
827 ++p;
829 sal_Unicode const * pLanguageBegin = p;
830 bool bDowncaseLanguage = false;
831 int nLetters = 0;
832 for (; p != pEnd; ++p)
833 if (rtl::isAsciiAlpha(*p))
835 if (++nLetters > 8)
836 break;
837 bDowncaseLanguage = bDowncaseLanguage
838 || rtl::isAsciiUpperCase(*p);
840 else if (*p == '-')
842 if (nLetters == 0)
843 break;
844 nLetters = 0;
846 else
847 break;
848 if (nLetters == 0 || nLetters > 8)
849 break;
850 if (pParameters)
852 aLanguage = OString(
853 pLanguageBegin,
854 p - pLanguageBegin,
855 RTL_TEXTENCODING_ASCII_US);
856 if (bDowncaseLanguage)
857 aLanguage = aLanguage.toAsciiLowerCase();
860 if (p == pEnd || *p != '\'')
861 break;
862 ++p;
864 if (pParameters)
866 INetMIMEStringOutputSink
867 aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT);
868 while (p != pEnd)
870 sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd);
871 if (rtl::isAscii(nChar) && !isTokenChar(nChar))
872 break;
873 if (nChar == '%' && p + 1 < pEnd)
875 int nWeight1 = getHexWeight(p[0]);
876 int nWeight2 = getHexWeight(p[1]);
877 if (nWeight1 >= 0 && nWeight2 >= 0)
879 aSink << sal_Char(nWeight1 << 4 | nWeight2);
880 p += 2;
881 continue;
884 INetMIME::writeUTF8(aSink, nChar);
886 aValue = aSink.takeBuffer();
888 else
889 while (p != pEnd && (isTokenChar(*p) || !rtl::isAscii(*p)))
890 ++p;
892 else if (p != pEnd && *p == '"')
893 if (pParameters)
895 INetMIMEStringOutputSink
896 aSink(0, INetMIMEOutputSink::NO_LINE_LENGTH_LIMIT);
897 bool bInvalid = false;
898 for (++p;;)
900 if (p == pEnd)
902 bInvalid = true;
903 break;
905 sal_uInt32 nChar = INetMIME::getUTF32Character(p, pEnd);
906 if (nChar == '"')
907 break;
908 else if (nChar == 0x0D) // CR
910 if (pEnd - p < 2 || *p++ != 0x0A // LF
911 || !isWhiteSpace(*p))
913 bInvalid = true;
914 break;
916 nChar = static_cast<unsigned char>(*p++);
918 else if (nChar == '\\')
920 if (p == pEnd)
922 bInvalid = true;
923 break;
925 nChar = INetMIME::getUTF32Character(p, pEnd);
927 INetMIME::writeUTF8(aSink, nChar);
929 if (bInvalid)
930 break;
931 aValue = aSink.takeBuffer();
933 else
935 sal_Unicode const * pStringEnd = skipQuotedString(p, pEnd);
936 if (p == pStringEnd)
937 break;
938 p = pStringEnd;
940 else
942 sal_Unicode const * pTokenBegin = p;
943 while (p != pEnd && (isTokenChar(*p) || !rtl::isAscii(*p)))
944 ++p;
945 if (p == pTokenBegin)
946 break;
947 if (pParameters)
948 aValue = OString(
949 pTokenBegin, p - pTokenBegin,
950 RTL_TEXTENCODING_UTF8);
953 *pPos = new Parameter(*pPos, aAttribute, aCharset, aLanguage, aValue,
954 nSection, bExtended);
956 return parseParameters(aList, pParameters) ? pParameterBegin : pBegin;
959 // static
960 sal_Unicode const * INetMIME::scanContentType(
961 sal_Unicode const * pBegin, sal_Unicode const * pEnd, OUString * pType,
962 OUString * pSubType, INetContentTypeParameterList * pParameters)
964 sal_Unicode const * p = INetMIME::skipLinearWhiteSpaceComment(pBegin, pEnd);
965 sal_Unicode const * pTypeBegin = p;
966 while (p != pEnd && INetMIME::isTokenChar(*p))
968 ++p;
970 if (p == pTypeBegin)
971 return 0;
972 sal_Unicode const * pTypeEnd = p;
974 p = INetMIME::skipLinearWhiteSpaceComment(p, pEnd);
975 if (p == pEnd || *p++ != '/')
976 return 0;
978 p = INetMIME::skipLinearWhiteSpaceComment(p, pEnd);
979 sal_Unicode const * pSubTypeBegin = p;
980 while (p != pEnd && INetMIME::isTokenChar(*p))
982 ++p;
984 if (p == pSubTypeBegin)
985 return 0;
986 sal_Unicode const * pSubTypeEnd = p;
988 if (pType != 0)
990 *pType = OUString(pTypeBegin, pTypeEnd - pTypeBegin).toAsciiLowerCase();
992 if (pSubType != 0)
994 *pSubType = OUString(pSubTypeBegin, pSubTypeEnd - pSubTypeBegin)
995 .toAsciiLowerCase();
998 return INetMIME::scanParameters(p, pEnd, pParameters);
1001 // static
1002 const sal_Char * INetMIME::getCharsetName(rtl_TextEncoding eEncoding)
1004 if (rtl_isOctetTextEncoding(eEncoding))
1006 char const * p = rtl_getMimeCharsetFromTextEncoding(eEncoding);
1007 DBG_ASSERT(p, "INetMIME::getCharsetName(): Unsupported encoding");
1008 return p;
1010 else
1011 switch (eEncoding)
1013 case RTL_TEXTENCODING_UCS4:
1014 return "ISO-10646-UCS-4";
1016 case RTL_TEXTENCODING_UCS2:
1017 return "ISO-10646-UCS-2";
1019 default:
1020 OSL_FAIL("INetMIME::getCharsetName(): Unsupported encoding");
1021 return 0;
1025 namespace unnamed_tools_inetmime {
1027 struct EncodingEntry
1029 sal_Char const * m_aName;
1030 rtl_TextEncoding m_eEncoding;
1033 // The source for the following table is <ftp://ftp.iana.org/in-notes/iana/
1034 // assignments/character-sets> as of Jan, 21 2000 12:46:00, unless otherwise
1035 // noted:
1036 EncodingEntry const aEncodingMap[]
1037 = { { "US-ASCII", RTL_TEXTENCODING_ASCII_US },
1038 { "ANSI_X3.4-1968", RTL_TEXTENCODING_ASCII_US },
1039 { "ISO-IR-6", RTL_TEXTENCODING_ASCII_US },
1040 { "ANSI_X3.4-1986", RTL_TEXTENCODING_ASCII_US },
1041 { "ISO_646.IRV:1991", RTL_TEXTENCODING_ASCII_US },
1042 { "ASCII", RTL_TEXTENCODING_ASCII_US },
1043 { "ISO646-US", RTL_TEXTENCODING_ASCII_US },
1044 { "US", RTL_TEXTENCODING_ASCII_US },
1045 { "IBM367", RTL_TEXTENCODING_ASCII_US },
1046 { "CP367", RTL_TEXTENCODING_ASCII_US },
1047 { "CSASCII", RTL_TEXTENCODING_ASCII_US },
1048 { "ISO-8859-1", RTL_TEXTENCODING_ISO_8859_1 },
1049 { "ISO_8859-1:1987", RTL_TEXTENCODING_ISO_8859_1 },
1050 { "ISO-IR-100", RTL_TEXTENCODING_ISO_8859_1 },
1051 { "ISO_8859-1", RTL_TEXTENCODING_ISO_8859_1 },
1052 { "LATIN1", RTL_TEXTENCODING_ISO_8859_1 },
1053 { "L1", RTL_TEXTENCODING_ISO_8859_1 },
1054 { "IBM819", RTL_TEXTENCODING_ISO_8859_1 },
1055 { "CP819", RTL_TEXTENCODING_ISO_8859_1 },
1056 { "CSISOLATIN1", RTL_TEXTENCODING_ISO_8859_1 },
1057 { "ISO-8859-2", RTL_TEXTENCODING_ISO_8859_2 },
1058 { "ISO_8859-2:1987", RTL_TEXTENCODING_ISO_8859_2 },
1059 { "ISO-IR-101", RTL_TEXTENCODING_ISO_8859_2 },
1060 { "ISO_8859-2", RTL_TEXTENCODING_ISO_8859_2 },
1061 { "LATIN2", RTL_TEXTENCODING_ISO_8859_2 },
1062 { "L2", RTL_TEXTENCODING_ISO_8859_2 },
1063 { "CSISOLATIN2", RTL_TEXTENCODING_ISO_8859_2 },
1064 { "ISO-8859-3", RTL_TEXTENCODING_ISO_8859_3 },
1065 { "ISO_8859-3:1988", RTL_TEXTENCODING_ISO_8859_3 },
1066 { "ISO-IR-109", RTL_TEXTENCODING_ISO_8859_3 },
1067 { "ISO_8859-3", RTL_TEXTENCODING_ISO_8859_3 },
1068 { "LATIN3", RTL_TEXTENCODING_ISO_8859_3 },
1069 { "L3", RTL_TEXTENCODING_ISO_8859_3 },
1070 { "CSISOLATIN3", RTL_TEXTENCODING_ISO_8859_3 },
1071 { "ISO-8859-4", RTL_TEXTENCODING_ISO_8859_4 },
1072 { "ISO_8859-4:1988", RTL_TEXTENCODING_ISO_8859_4 },
1073 { "ISO-IR-110", RTL_TEXTENCODING_ISO_8859_4 },
1074 { "ISO_8859-4", RTL_TEXTENCODING_ISO_8859_4 },
1075 { "LATIN4", RTL_TEXTENCODING_ISO_8859_4 },
1076 { "L4", RTL_TEXTENCODING_ISO_8859_4 },
1077 { "CSISOLATIN4", RTL_TEXTENCODING_ISO_8859_4 },
1078 { "ISO-8859-5", RTL_TEXTENCODING_ISO_8859_5 },
1079 { "ISO_8859-5:1988", RTL_TEXTENCODING_ISO_8859_5 },
1080 { "ISO-IR-144", RTL_TEXTENCODING_ISO_8859_5 },
1081 { "ISO_8859-5", RTL_TEXTENCODING_ISO_8859_5 },
1082 { "CYRILLIC", RTL_TEXTENCODING_ISO_8859_5 },
1083 { "CSISOLATINCYRILLIC", RTL_TEXTENCODING_ISO_8859_5 },
1084 { "ISO-8859-6", RTL_TEXTENCODING_ISO_8859_6 },
1085 { "ISO_8859-6:1987", RTL_TEXTENCODING_ISO_8859_6 },
1086 { "ISO-IR-127", RTL_TEXTENCODING_ISO_8859_6 },
1087 { "ISO_8859-6", RTL_TEXTENCODING_ISO_8859_6 },
1088 { "ECMA-114", RTL_TEXTENCODING_ISO_8859_6 },
1089 { "ASMO-708", RTL_TEXTENCODING_ISO_8859_6 },
1090 { "ARABIC", RTL_TEXTENCODING_ISO_8859_6 },
1091 { "CSISOLATINARABIC", RTL_TEXTENCODING_ISO_8859_6 },
1092 { "ISO-8859-7", RTL_TEXTENCODING_ISO_8859_7 },
1093 { "ISO_8859-7:1987", RTL_TEXTENCODING_ISO_8859_7 },
1094 { "ISO-IR-126", RTL_TEXTENCODING_ISO_8859_7 },
1095 { "ISO_8859-7", RTL_TEXTENCODING_ISO_8859_7 },
1096 { "ELOT_928", RTL_TEXTENCODING_ISO_8859_7 },
1097 { "ECMA-118", RTL_TEXTENCODING_ISO_8859_7 },
1098 { "GREEK", RTL_TEXTENCODING_ISO_8859_7 },
1099 { "GREEK8", RTL_TEXTENCODING_ISO_8859_7 },
1100 { "CSISOLATINGREEK", RTL_TEXTENCODING_ISO_8859_7 },
1101 { "ISO-8859-8", RTL_TEXTENCODING_ISO_8859_8 },
1102 { "ISO_8859-8:1988", RTL_TEXTENCODING_ISO_8859_8 },
1103 { "ISO-IR-138", RTL_TEXTENCODING_ISO_8859_8 },
1104 { "ISO_8859-8", RTL_TEXTENCODING_ISO_8859_8 },
1105 { "HEBREW", RTL_TEXTENCODING_ISO_8859_8 },
1106 { "CSISOLATINHEBREW", RTL_TEXTENCODING_ISO_8859_8 },
1107 { "ISO-8859-9", RTL_TEXTENCODING_ISO_8859_9 },
1108 { "ISO_8859-9:1989", RTL_TEXTENCODING_ISO_8859_9 },
1109 { "ISO-IR-148", RTL_TEXTENCODING_ISO_8859_9 },
1110 { "ISO_8859-9", RTL_TEXTENCODING_ISO_8859_9 },
1111 { "LATIN5", RTL_TEXTENCODING_ISO_8859_9 },
1112 { "L5", RTL_TEXTENCODING_ISO_8859_9 },
1113 { "CSISOLATIN5", RTL_TEXTENCODING_ISO_8859_9 },
1114 { "ISO-8859-14", RTL_TEXTENCODING_ISO_8859_14 }, // RFC 2047
1115 { "ISO_8859-15", RTL_TEXTENCODING_ISO_8859_15 },
1116 { "ISO-8859-15", RTL_TEXTENCODING_ISO_8859_15 }, // RFC 2047
1117 { "MACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN },
1118 { "MAC", RTL_TEXTENCODING_APPLE_ROMAN },
1119 { "CSMACINTOSH", RTL_TEXTENCODING_APPLE_ROMAN },
1120 { "IBM437", RTL_TEXTENCODING_IBM_437 },
1121 { "CP437", RTL_TEXTENCODING_IBM_437 },
1122 { "437", RTL_TEXTENCODING_IBM_437 },
1123 { "CSPC8CODEPAGE437", RTL_TEXTENCODING_IBM_437 },
1124 { "IBM850", RTL_TEXTENCODING_IBM_850 },
1125 { "CP850", RTL_TEXTENCODING_IBM_850 },
1126 { "850", RTL_TEXTENCODING_IBM_850 },
1127 { "CSPC850MULTILINGUAL", RTL_TEXTENCODING_IBM_850 },
1128 { "IBM860", RTL_TEXTENCODING_IBM_860 },
1129 { "CP860", RTL_TEXTENCODING_IBM_860 },
1130 { "860", RTL_TEXTENCODING_IBM_860 },
1131 { "CSIBM860", RTL_TEXTENCODING_IBM_860 },
1132 { "IBM861", RTL_TEXTENCODING_IBM_861 },
1133 { "CP861", RTL_TEXTENCODING_IBM_861 },
1134 { "861", RTL_TEXTENCODING_IBM_861 },
1135 { "CP-IS", RTL_TEXTENCODING_IBM_861 },
1136 { "CSIBM861", RTL_TEXTENCODING_IBM_861 },
1137 { "IBM863", RTL_TEXTENCODING_IBM_863 },
1138 { "CP863", RTL_TEXTENCODING_IBM_863 },
1139 { "863", RTL_TEXTENCODING_IBM_863 },
1140 { "CSIBM863", RTL_TEXTENCODING_IBM_863 },
1141 { "IBM865", RTL_TEXTENCODING_IBM_865 },
1142 { "CP865", RTL_TEXTENCODING_IBM_865 },
1143 { "865", RTL_TEXTENCODING_IBM_865 },
1144 { "CSIBM865", RTL_TEXTENCODING_IBM_865 },
1145 { "IBM775", RTL_TEXTENCODING_IBM_775 },
1146 { "CP775", RTL_TEXTENCODING_IBM_775 },
1147 { "CSPC775BALTIC", RTL_TEXTENCODING_IBM_775 },
1148 { "IBM852", RTL_TEXTENCODING_IBM_852 },
1149 { "CP852", RTL_TEXTENCODING_IBM_852 },
1150 { "852", RTL_TEXTENCODING_IBM_852 },
1151 { "CSPCP852", RTL_TEXTENCODING_IBM_852 },
1152 { "IBM855", RTL_TEXTENCODING_IBM_855 },
1153 { "CP855", RTL_TEXTENCODING_IBM_855 },
1154 { "855", RTL_TEXTENCODING_IBM_855 },
1155 { "CSIBM855", RTL_TEXTENCODING_IBM_855 },
1156 { "IBM857", RTL_TEXTENCODING_IBM_857 },
1157 { "CP857", RTL_TEXTENCODING_IBM_857 },
1158 { "857", RTL_TEXTENCODING_IBM_857 },
1159 { "CSIBM857", RTL_TEXTENCODING_IBM_857 },
1160 { "IBM862", RTL_TEXTENCODING_IBM_862 },
1161 { "CP862", RTL_TEXTENCODING_IBM_862 },
1162 { "862", RTL_TEXTENCODING_IBM_862 },
1163 { "CSPC862LATINHEBREW", RTL_TEXTENCODING_IBM_862 },
1164 { "IBM864", RTL_TEXTENCODING_IBM_864 },
1165 { "CP864", RTL_TEXTENCODING_IBM_864 },
1166 { "CSIBM864", RTL_TEXTENCODING_IBM_864 },
1167 { "IBM866", RTL_TEXTENCODING_IBM_866 },
1168 { "CP866", RTL_TEXTENCODING_IBM_866 },
1169 { "866", RTL_TEXTENCODING_IBM_866 },
1170 { "CSIBM866", RTL_TEXTENCODING_IBM_866 },
1171 { "IBM869", RTL_TEXTENCODING_IBM_869 },
1172 { "CP869", RTL_TEXTENCODING_IBM_869 },
1173 { "869", RTL_TEXTENCODING_IBM_869 },
1174 { "CP-GR", RTL_TEXTENCODING_IBM_869 },
1175 { "CSIBM869", RTL_TEXTENCODING_IBM_869 },
1176 { "WINDOWS-1250", RTL_TEXTENCODING_MS_1250 },
1177 { "WINDOWS-1251", RTL_TEXTENCODING_MS_1251 },
1178 { "WINDOWS-1253", RTL_TEXTENCODING_MS_1253 },
1179 { "WINDOWS-1254", RTL_TEXTENCODING_MS_1254 },
1180 { "WINDOWS-1255", RTL_TEXTENCODING_MS_1255 },
1181 { "WINDOWS-1256", RTL_TEXTENCODING_MS_1256 },
1182 { "WINDOWS-1257", RTL_TEXTENCODING_MS_1257 },
1183 { "WINDOWS-1258", RTL_TEXTENCODING_MS_1258 },
1184 { "SHIFT_JIS", RTL_TEXTENCODING_SHIFT_JIS },
1185 { "MS_KANJI", RTL_TEXTENCODING_SHIFT_JIS },
1186 { "CSSHIFTJIS", RTL_TEXTENCODING_SHIFT_JIS },
1187 { "GB2312", RTL_TEXTENCODING_GB_2312 },
1188 { "CSGB2312", RTL_TEXTENCODING_GB_2312 },
1189 { "BIG5", RTL_TEXTENCODING_BIG5 },
1190 { "CSBIG5", RTL_TEXTENCODING_BIG5 },
1191 { "EUC-JP", RTL_TEXTENCODING_EUC_JP },
1192 { "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE",
1193 RTL_TEXTENCODING_EUC_JP },
1194 { "CSEUCPKDFMTJAPANESE", RTL_TEXTENCODING_EUC_JP },
1195 { "ISO-2022-JP", RTL_TEXTENCODING_ISO_2022_JP },
1196 { "CSISO2022JP", RTL_TEXTENCODING_ISO_2022_JP },
1197 { "ISO-2022-CN", RTL_TEXTENCODING_ISO_2022_CN },
1198 { "KOI8-R", RTL_TEXTENCODING_KOI8_R },
1199 { "CSKOI8R", RTL_TEXTENCODING_KOI8_R },
1200 { "UTF-7", RTL_TEXTENCODING_UTF7 },
1201 { "UTF-8", RTL_TEXTENCODING_UTF8 },
1202 { "ISO-8859-10", RTL_TEXTENCODING_ISO_8859_10 }, // RFC 2047
1203 { "ISO-8859-13", RTL_TEXTENCODING_ISO_8859_13 }, // RFC 2047
1204 { "EUC-KR", RTL_TEXTENCODING_EUC_KR },
1205 { "CSEUCKR", RTL_TEXTENCODING_EUC_KR },
1206 { "ISO-2022-KR", RTL_TEXTENCODING_ISO_2022_KR },
1207 { "CSISO2022KR", RTL_TEXTENCODING_ISO_2022_KR },
1208 { "ISO-10646-UCS-4", RTL_TEXTENCODING_UCS4 },
1209 { "CSUCS4", RTL_TEXTENCODING_UCS4 },
1210 { "ISO-10646-UCS-2", RTL_TEXTENCODING_UCS2 },
1211 { "CSUNICODE", RTL_TEXTENCODING_UCS2 } };
1213 template< typename T >
1214 inline rtl_TextEncoding getCharsetEncoding_Impl(T const * pBegin,
1215 T const * pEnd)
1217 for (sal_Size i = 0; i < sizeof aEncodingMap / sizeof (EncodingEntry);
1218 ++i)
1219 if (INetMIME::equalIgnoreCase(pBegin, pEnd, aEncodingMap[i].m_aName))
1220 return aEncodingMap[i].m_eEncoding;
1221 return RTL_TEXTENCODING_DONTKNOW;
1226 // static
1227 rtl_TextEncoding INetMIME::getCharsetEncoding(sal_Char const * pBegin,
1228 sal_Char const * pEnd)
1230 return getCharsetEncoding_Impl(pBegin, pEnd);
1233 // static
1234 INetMIMECharsetList_Impl *
1235 INetMIME::createPreferredCharsetList(rtl_TextEncoding eEncoding)
1237 static const sal_uInt32 aUSASCIIRanges[] = { 0, 0x7F, sal_uInt32(-1) };
1239 static const sal_uInt32 aISO88591Ranges[] = { 0, 0xFF, sal_uInt32(-1) };
1240 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT> version
1241 // 1.0 of 1999 July 27
1243 static const sal_uInt32 aISO88592Ranges[]
1244 = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0,
1245 0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7,
1246 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xCE, 0xD3, 0xD4, 0xD6, 0xD7,
1247 0xDA, 0xDA, 0xDC, 0xDD, 0xDF, 0xDF, 0xE1, 0xE2, 0xE4, 0xE4,
1248 0xE7, 0xE7, 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF3, 0xF4,
1249 0xF6, 0xF7, 0xFA, 0xFA, 0xFC, 0xFD, 0x102, 0x107, 0x10C, 0x111,
1250 0x118, 0x11B, 0x139, 0x13A, 0x13D, 0x13E, 0x141, 0x144,
1251 0x147, 0x148, 0x150, 0x151, 0x154, 0x155, 0x158, 0x15B,
1252 0x15E, 0x165, 0x16E, 0x171, 0x179, 0x17E, 0x2C7, 0x2C7,
1253 0x2D8, 0x2D9, 0x2DB, 0x2DB, 0x2DD, 0x2DD, sal_uInt32(-1) };
1254 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-2.TXT> version
1255 // 1.0 of 1999 July 27
1257 static const sal_uInt32 aISO88593Ranges[]
1258 = { 0, 0xA0, 0xA3, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xB0, 0xB0,
1259 0xB2, 0xB5, 0xB7, 0xB8, 0xBD, 0xBD, 0xC0, 0xC2, 0xC4, 0xC4,
1260 0xC7, 0xCF, 0xD1, 0xD4, 0xD6, 0xD7, 0xD9, 0xDC, 0xDF, 0xE2,
1261 0xE4, 0xE4, 0xE7, 0xEF, 0xF1, 0xF4, 0xF6, 0xF7, 0xF9, 0xFC,
1262 0x108, 0x10B, 0x11C, 0x121, 0x124, 0x127, 0x130, 0x131,
1263 0x134, 0x135, 0x15C, 0x15F, 0x16C, 0x16D, 0x17B, 0x17C,
1264 0x2D8, 0x2D9, sal_uInt32(-1) };
1265 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-3.TXT> version
1266 // 1.0 of 1999 July 27
1268 static const sal_uInt32 aISO88594Ranges[]
1269 = { 0, 0xA0, 0xA4, 0xA4, 0xA7, 0xA8, 0xAD, 0xAD, 0xAF, 0xB0,
1270 0xB4, 0xB4, 0xB8, 0xB8, 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB,
1271 0xCD, 0xCE, 0xD4, 0xD8, 0xDA, 0xDC, 0xDF, 0xDF, 0xE1, 0xE6,
1272 0xE9, 0xE9, 0xEB, 0xEB, 0xED, 0xEE, 0xF4, 0xF8, 0xFA, 0xFC,
1273 0x100, 0x101, 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113,
1274 0x116, 0x119, 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F,
1275 0x136, 0x138, 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D,
1276 0x156, 0x157, 0x160, 0x161, 0x166, 0x16B, 0x172, 0x173,
1277 0x17D, 0x17E, 0x2C7, 0x2C7, 0x2D9, 0x2D9, 0x2DB, 0x2DB,
1278 sal_uInt32(-1) };
1279 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-4.TXT> version
1280 // 1.0 of 1999 July 27
1282 static const sal_uInt32 aISO88595Ranges[]
1283 = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0x401, 0x40C, 0x40E, 0x44F,
1284 0x451, 0x45C, 0x45E, 0x45F, 0x2116, 0x2116, sal_uInt32(-1) };
1285 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-5.TXT> version
1286 // 1.0 of 1999 July 27
1288 static const sal_uInt32 aISO88596Ranges[]
1289 = { 0, 0xA0, 0xA4, 0xA4, 0xAD, 0xAD, 0x60C, 0x60C, 0x61B, 0x61B,
1290 0x61F, 0x61F, 0x621, 0x63A, 0x640, 0x652, sal_uInt32(-1) };
1291 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-6.TXT> version
1292 // 1.0 of 1999 July 27
1294 static const sal_uInt32 aISO88597Ranges[]
1295 = { 0, 0xA0, 0xA3, 0xA3, 0xA6, 0xA9, 0xAB, 0xAD, 0xB0, 0xB3,
1296 0xB7, 0xB7, 0xBB, 0xBB, 0xBD, 0xBD, 0x384, 0x386, 0x388, 0x38A,
1297 0x38C, 0x38C, 0x38E, 0x3A1, 0x3A3, 0x3CE, 0x2015, 0x2015,
1298 0x2018, 0x2019, sal_uInt32(-1) };
1299 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-7.TXT> version
1300 // 1.0 of 1999 July 27
1302 static const sal_uInt32 aISO88598Ranges[]
1303 = { 0, 0xA0, 0xA2, 0xA9, 0xAB, 0xB9, 0xBB, 0xBE, 0xD7, 0xD7,
1304 0xF7, 0xF7, 0x5D0, 0x5EA, 0x200E, 0x200F, 0x2017, 0x2017,
1305 sal_uInt32(-1) };
1306 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-8.TXT> version
1307 // 1.1 of 2000-Jan-03
1309 static const sal_uInt32 aISO88599Ranges[]
1310 = { 0, 0xCF, 0xD1, 0xDC, 0xDF, 0xEF, 0xF1, 0xFC, 0xFF, 0xFF,
1311 0x11E, 0x11F, 0x130, 0x131, 0x15E, 0x15F, sal_uInt32(-1) };
1312 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-9.TXT> version
1313 // 1.0 of 1999 July 27
1315 static const sal_uInt32 aISO885910Ranges[]
1316 = { 0, 0xA0, 0xA7, 0xA7, 0xAD, 0xAD, 0xB0, 0xB0, 0xB7, 0xB7,
1317 0xC1, 0xC6, 0xC9, 0xC9, 0xCB, 0xCB, 0xCD, 0xD0, 0xD3, 0xD6,
1318 0xD8, 0xD8, 0xDA, 0xDF, 0xE1, 0xE6, 0xE9, 0xE9, 0xEB, 0xEB,
1319 0xED, 0xF0, 0xF3, 0xF6, 0xF8, 0xF8, 0xFA, 0xFE, 0x100, 0x101,
1320 0x104, 0x105, 0x10C, 0x10D, 0x110, 0x113, 0x116, 0x119,
1321 0x122, 0x123, 0x128, 0x12B, 0x12E, 0x12F, 0x136, 0x138,
1322 0x13B, 0x13C, 0x145, 0x146, 0x14A, 0x14D, 0x160, 0x161,
1323 0x166, 0x16B, 0x172, 0x173, 0x17D, 0x17E, 0x2015, 0x2015,
1324 sal_uInt32(-1) };
1325 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-10.TXT> version
1326 // 1.1 of 1999 October 11
1328 static const sal_uInt32 aISO885913Ranges[]
1329 = { 0, 0xA0, 0xA2, 0xA4, 0xA6, 0xA7, 0xA9, 0xA9, 0xAB, 0xAE,
1330 0xB0, 0xB3, 0xB5, 0xB7, 0xB9, 0xB9, 0xBB, 0xBE, 0xC4, 0xC6,
1331 0xC9, 0xC9, 0xD3, 0xD3, 0xD5, 0xD8, 0xDC, 0xDC, 0xDF, 0xDF,
1332 0xE4, 0xE6, 0xE9, 0xE9, 0xF3, 0xF3, 0xF5, 0xF8, 0xFC, 0xFC,
1333 0x100, 0x101, 0x104, 0x107, 0x10C, 0x10D, 0x112, 0x113,
1334 0x116, 0x119, 0x122, 0x123, 0x12A, 0x12B, 0x12E, 0x12F,
1335 0x136, 0x137, 0x13B, 0x13C, 0x141, 0x146, 0x14C, 0x14D,
1336 0x156, 0x157, 0x15A, 0x15B, 0x160, 0x161, 0x16A, 0x16B,
1337 0x172, 0x173, 0x179, 0x17E, 0x2019, 0x2019, 0x201C, 0x201E,
1338 sal_uInt32(-1) };
1339 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-13.TXT> version
1340 // 1.0 of 1999 July 27
1342 static const sal_uInt32 aISO885914Ranges[]
1343 = { 0, 0xA0, 0xA3, 0xA3, 0xA7, 0xA7, 0xA9, 0xA9, 0xAD, 0xAE,
1344 0xB6, 0xB6, 0xC0, 0xCF, 0xD1, 0xD6, 0xD8, 0xDD, 0xDF, 0xEF,
1345 0xF1, 0xF6, 0xF8, 0xFD, 0xFF, 0xFF, 0x10A, 0x10B, 0x120, 0x121,
1346 0x174, 0x178, 0x1E02, 0x1E03, 0x1E0A, 0x1E0B, 0x1E1E, 0x1E1F,
1347 0x1E40, 0x1E41, 0x1E56, 0x1E57, 0x1E60, 0x1E61, 0x1E6A, 0x1E6B,
1348 0x1E80, 0x1E85, 0x1EF2, 0x1EF3, sal_uInt32(-1) };
1349 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-14.TXT> version
1350 // 1.0 of 1999 July 27
1352 static const sal_uInt32 aISO885915Ranges[]
1353 = { 0, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xB3, 0xB5, 0xB7,
1354 0xB9, 0xBB, 0xBF, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178,
1355 0x17D, 0x17E, 0x20AC, 0x20AC, sal_uInt32(-1) };
1356 // <ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-15.TXT> version
1357 // 1.0 of 1999 July 27
1359 static const sal_uInt32 aKOI8RRanges[]
1360 = { 0, 0x7F, 0xA0, 0xA0, 0xA9, 0xA9, 0xB0, 0xB0, 0xB2, 0xB2,
1361 0xB7, 0xB7, 0xF7, 0xF7, 0x401, 0x401, 0x410, 0x44F, 0x451, 0x451,
1362 0x2219, 0x221A, 0x2248, 0x2248, 0x2264, 0x2265, 0x2320, 0x2321,
1363 0x2500, 0x2500, 0x2502, 0x2502, 0x250C, 0x250C, 0x2510, 0x2510,
1364 0x2514, 0x2514, 0x2518, 0x2518, 0x251C, 0x251C, 0x2524, 0x2524,
1365 0x252C, 0x252C, 0x2534, 0x2534, 0x253C, 0x253C, 0x2550, 0x256C,
1366 0x2580, 0x2580, 0x2584, 0x2584, 0x2588, 0x2588, 0x258C, 0x258C,
1367 0x2590, 0x2593, 0x25A0, 0x25A0, sal_uInt32(-1) };
1368 // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT>
1369 // version 1.0 of 18 August 1999
1371 #if defined WNT
1372 static const sal_uInt32 aWindows1252Ranges[]
1373 = { 0, 0x7F, 0xA0, 0xFF, 0x152, 0x153, 0x160, 0x161, 0x178, 0x178,
1374 0x17D, 0x17E, 0x192, 0x192, 0x2C6, 0x2C6, 0x2DC, 0x2DC,
1375 0x2013, 0x2014, 0x2018, 0x201A, 0x201C, 0x201E, 0x2020, 0x2022,
1376 0x2026, 0x2026, 0x2030, 0x2030, 0x2039, 0x203A, 0x20AC, 0x20AC,
1377 0x2122, 0x2122, sal_uInt32(-1) };
1378 // <ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/
1379 // CP1252.TXT> version 2.01 of 04/15/98
1380 #endif // WNT
1382 INetMIMECharsetList_Impl * pList = new INetMIMECharsetList_Impl;
1383 switch (eEncoding)
1385 case RTL_TEXTENCODING_MS_1252:
1386 #if defined WNT
1387 pList->prepend(Charset(RTL_TEXTENCODING_MS_1252,
1388 aWindows1252Ranges));
1389 #endif // WNT
1390 case RTL_TEXTENCODING_ISO_8859_1:
1391 case RTL_TEXTENCODING_UTF7:
1392 case RTL_TEXTENCODING_UTF8:
1393 break;
1395 case RTL_TEXTENCODING_ISO_8859_2:
1396 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2,
1397 aISO88592Ranges));
1398 break;
1400 case RTL_TEXTENCODING_ISO_8859_3:
1401 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_3,
1402 aISO88593Ranges));
1403 break;
1405 case RTL_TEXTENCODING_ISO_8859_4:
1406 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4,
1407 aISO88594Ranges));
1408 break;
1410 case RTL_TEXTENCODING_ISO_8859_5:
1411 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
1412 aISO88595Ranges));
1413 break;
1415 case RTL_TEXTENCODING_ISO_8859_6:
1416 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6,
1417 aISO88596Ranges));
1418 break;
1420 case RTL_TEXTENCODING_ISO_8859_7:
1421 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7,
1422 aISO88597Ranges));
1423 break;
1425 case RTL_TEXTENCODING_ISO_8859_8:
1426 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8,
1427 aISO88598Ranges));
1428 break;
1430 case RTL_TEXTENCODING_ISO_8859_9:
1431 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9,
1432 aISO88599Ranges));
1433 break;
1435 case RTL_TEXTENCODING_ISO_8859_10:
1436 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_10,
1437 aISO885910Ranges));
1438 break;
1440 case RTL_TEXTENCODING_ISO_8859_13:
1441 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_13,
1442 aISO885913Ranges));
1443 break;
1445 case RTL_TEXTENCODING_ISO_8859_14:
1446 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_14,
1447 aISO885914Ranges));
1448 break;
1450 case RTL_TEXTENCODING_ISO_8859_15:
1451 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_15,
1452 aISO885915Ranges));
1453 break;
1455 case RTL_TEXTENCODING_MS_1250:
1456 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_2,
1457 aISO88592Ranges));
1458 break;
1460 case RTL_TEXTENCODING_MS_1251:
1461 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
1462 aISO88595Ranges));
1463 break;
1465 case RTL_TEXTENCODING_MS_1253:
1466 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_7,
1467 aISO88597Ranges));
1468 break;
1470 case RTL_TEXTENCODING_MS_1254:
1471 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_9,
1472 aISO88599Ranges));
1473 break;
1475 case RTL_TEXTENCODING_MS_1255:
1476 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_8,
1477 aISO88598Ranges));
1478 break;
1480 case RTL_TEXTENCODING_MS_1256:
1481 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_6,
1482 aISO88596Ranges));
1483 break;
1485 case RTL_TEXTENCODING_MS_1257:
1486 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_4,
1487 aISO88594Ranges));
1488 break;
1490 case RTL_TEXTENCODING_KOI8_R:
1491 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_5,
1492 aISO88595Ranges));
1493 pList->prepend(Charset(RTL_TEXTENCODING_KOI8_R, aKOI8RRanges));
1494 break;
1496 default: //@@@ more cases are missing!
1497 OSL_FAIL("INetMIME::createPreferredCharsetList():"
1498 " Unsupported encoding");
1499 break;
1501 pList->prepend(Charset(RTL_TEXTENCODING_ISO_8859_1, aISO88591Ranges));
1502 pList->prepend(Charset(RTL_TEXTENCODING_ASCII_US, aUSASCIIRanges));
1503 return pList;
1506 // static
1507 sal_Unicode * INetMIME::convertToUnicode(const sal_Char * pBegin,
1508 const sal_Char * pEnd,
1509 rtl_TextEncoding eEncoding,
1510 sal_Size & rSize)
1512 if (eEncoding == RTL_TEXTENCODING_DONTKNOW)
1513 return 0;
1514 rtl_TextToUnicodeConverter hConverter
1515 = rtl_createTextToUnicodeConverter(eEncoding);
1516 rtl_TextToUnicodeContext hContext
1517 = rtl_createTextToUnicodeContext(hConverter);
1518 sal_Unicode * pBuffer;
1519 sal_uInt32 nInfo;
1520 for (sal_Size nBufferSize = pEnd - pBegin;;
1521 nBufferSize += nBufferSize / 3 + 1)
1523 pBuffer = new sal_Unicode[nBufferSize];
1524 sal_Size nSrcCvtBytes;
1525 rSize = rtl_convertTextToUnicode(
1526 hConverter, hContext, pBegin, pEnd - pBegin, pBuffer,
1527 nBufferSize,
1528 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1529 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1530 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR,
1531 &nInfo, &nSrcCvtBytes);
1532 if (nInfo != RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
1533 break;
1534 delete[] pBuffer;
1535 rtl_resetTextToUnicodeContext(hConverter, hContext);
1537 rtl_destroyTextToUnicodeContext(hConverter, hContext);
1538 rtl_destroyTextToUnicodeConverter(hConverter);
1539 if (nInfo != 0)
1541 delete[] pBuffer;
1542 pBuffer = 0;
1544 return pBuffer;
1547 // static
1548 sal_Char * INetMIME::convertFromUnicode(const sal_Unicode * pBegin,
1549 const sal_Unicode * pEnd,
1550 rtl_TextEncoding eEncoding,
1551 sal_Size & rSize)
1553 if (eEncoding == RTL_TEXTENCODING_DONTKNOW)
1554 return 0;
1555 rtl_UnicodeToTextConverter hConverter
1556 = rtl_createUnicodeToTextConverter(eEncoding);
1557 rtl_UnicodeToTextContext hContext
1558 = rtl_createUnicodeToTextContext(hConverter);
1559 sal_Char * pBuffer;
1560 sal_uInt32 nInfo;
1561 for (sal_Size nBufferSize = pEnd - pBegin;;
1562 nBufferSize += nBufferSize / 3 + 1)
1564 pBuffer = new sal_Char[nBufferSize];
1565 sal_Size nSrcCvtBytes;
1566 rSize = rtl_convertUnicodeToText(
1567 hConverter, hContext, pBegin, pEnd - pBegin, pBuffer,
1568 nBufferSize,
1569 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
1570 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
1571 | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
1572 | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR,
1573 &nInfo, &nSrcCvtBytes);
1574 if (nInfo != RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL)
1575 break;
1576 delete[] pBuffer;
1577 rtl_resetUnicodeToTextContext(hConverter, hContext);
1579 rtl_destroyUnicodeToTextContext(hConverter, hContext);
1580 rtl_destroyUnicodeToTextConverter(hConverter);
1581 if (nInfo != 0)
1583 delete[] pBuffer;
1584 pBuffer = 0;
1586 return pBuffer;
1589 // static
1590 void INetMIME::writeUTF8(INetMIMEOutputSink & rSink, sal_uInt32 nChar)
1592 // See RFC 2279 for a discussion of UTF-8.
1593 DBG_ASSERT(nChar < 0x80000000, "INetMIME::writeUTF8(): Bad char");
1595 if (nChar < 0x80)
1596 rSink << sal_Char(nChar);
1597 else if (nChar < 0x800)
1598 rSink << sal_Char(nChar >> 6 | 0xC0)
1599 << sal_Char((nChar & 0x3F) | 0x80);
1600 else if (nChar < 0x10000)
1601 rSink << sal_Char(nChar >> 12 | 0xE0)
1602 << sal_Char((nChar >> 6 & 0x3F) | 0x80)
1603 << sal_Char((nChar & 0x3F) | 0x80);
1604 else if (nChar < 0x200000)
1605 rSink << sal_Char(nChar >> 18 | 0xF0)
1606 << sal_Char((nChar >> 12 & 0x3F) | 0x80)
1607 << sal_Char((nChar >> 6 & 0x3F) | 0x80)
1608 << sal_Char((nChar & 0x3F) | 0x80);
1609 else if (nChar < 0x4000000)
1610 rSink << sal_Char(nChar >> 24 | 0xF8)
1611 << sal_Char((nChar >> 18 & 0x3F) | 0x80)
1612 << sal_Char((nChar >> 12 & 0x3F) | 0x80)
1613 << sal_Char((nChar >> 6 & 0x3F) | 0x80)
1614 << sal_Char((nChar & 0x3F) | 0x80);
1615 else
1616 rSink << sal_Char(nChar >> 30 | 0xFC)
1617 << sal_Char((nChar >> 24 & 0x3F) | 0x80)
1618 << sal_Char((nChar >> 18 & 0x3F) | 0x80)
1619 << sal_Char((nChar >> 12 & 0x3F) | 0x80)
1620 << sal_Char((nChar >> 6 & 0x3F) | 0x80)
1621 << sal_Char((nChar & 0x3F) | 0x80);
1624 // static
1625 void INetMIME::writeHeaderFieldBody(INetMIMEOutputSink & rSink,
1626 HeaderFieldType eType,
1627 const OUString& rBody,
1628 rtl_TextEncoding ePreferredEncoding,
1629 bool bInitialSpace)
1631 if (eType == HEADER_FIELD_TEXT)
1633 INetMIMEEncodedWordOutputSink
1634 aOutput(rSink, INetMIMEEncodedWordOutputSink::CONTEXT_TEXT,
1635 bInitialSpace ?
1636 INetMIMEEncodedWordOutputSink::SPACE_ALWAYS :
1637 INetMIMEEncodedWordOutputSink::SPACE_NO,
1638 ePreferredEncoding);
1639 aOutput.write(rBody.getStr(), rBody.getStr() + rBody.getLength());
1640 aOutput.flush();
1642 else
1644 enum Brackets { BRACKETS_OUTSIDE, BRACKETS_OPENING, BRACKETS_INSIDE };
1645 Brackets eBrackets = BRACKETS_OUTSIDE;
1647 const sal_Unicode * pBodyPtr = rBody.getStr();
1648 const sal_Unicode * pBodyEnd = pBodyPtr + rBody.getLength();
1649 while (pBodyPtr != pBodyEnd)
1650 switch (*pBodyPtr)
1652 case '\t':
1653 case ' ':
1654 // A WSP adds to accumulated space:
1655 bInitialSpace = true;
1656 ++pBodyPtr;
1657 break;
1659 case '(':
1661 // Write a pending '<' if necessary:
1662 if (eBrackets == BRACKETS_OPENING)
1664 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
1665 >= rSink.getLineLengthLimit())
1666 rSink << INetMIMEOutputSink::endl << ' ';
1667 else if (bInitialSpace)
1668 rSink << ' ';
1669 rSink << '<';
1670 bInitialSpace = false;
1671 eBrackets = BRACKETS_INSIDE;
1674 // Write the comment, introducing encoded-words where
1675 // necessary:
1676 int nLevel = 0;
1677 INetMIMEEncodedWordOutputSink
1678 aOutput(
1679 rSink,
1680 INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT,
1681 INetMIMEEncodedWordOutputSink::SPACE_NO,
1682 ePreferredEncoding);
1683 while (pBodyPtr != pBodyEnd)
1684 switch (*pBodyPtr)
1686 case '(':
1687 aOutput.flush();
1688 if (rSink.getColumn()
1689 + (bInitialSpace ? 1 : 0)
1690 >= rSink.getLineLengthLimit())
1691 rSink << INetMIMEOutputSink::endl << ' ';
1692 else if (bInitialSpace)
1693 rSink << ' ';
1694 rSink << '(';
1695 bInitialSpace = false;
1696 ++nLevel;
1697 ++pBodyPtr;
1698 break;
1700 case ')':
1701 aOutput.flush();
1702 if (rSink.getColumn()
1703 >= rSink.getLineLengthLimit())
1704 rSink << INetMIMEOutputSink::endl << ' ';
1705 rSink << ')';
1706 ++pBodyPtr;
1707 if (--nLevel == 0)
1708 goto comment_done;
1709 break;
1711 case '\\':
1712 if (++pBodyPtr == pBodyEnd)
1713 break;
1714 default:
1715 aOutput.WriteUInt32( *pBodyPtr++ );
1716 break;
1718 comment_done:
1719 break;
1722 case '<':
1723 // Write an already pending '<' if necessary:
1724 if (eBrackets == BRACKETS_OPENING)
1726 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
1727 >= rSink.getLineLengthLimit())
1728 rSink << INetMIMEOutputSink::endl << ' ';
1729 else if (bInitialSpace)
1730 rSink << ' ';
1731 rSink << '<';
1732 bInitialSpace = false;
1735 // Remember this '<' as pending, and open a bracketed
1736 // block:
1737 eBrackets = BRACKETS_OPENING;
1738 ++pBodyPtr;
1739 break;
1741 case '>':
1742 // Write a pending '<' if necessary:
1743 if (eBrackets == BRACKETS_OPENING)
1745 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
1746 >= rSink.getLineLengthLimit())
1747 rSink << INetMIMEOutputSink::endl << ' ';
1748 else if (bInitialSpace)
1749 rSink << ' ';
1750 rSink << '<';
1751 bInitialSpace = false;
1754 // Write this '>', and close any bracketed block:
1755 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
1756 >= rSink.getLineLengthLimit())
1757 rSink << INetMIMEOutputSink::endl << ' ';
1758 else if (bInitialSpace)
1759 rSink << ' ';
1760 rSink << '>';
1761 bInitialSpace = false;
1762 eBrackets = BRACKETS_OUTSIDE;
1763 ++pBodyPtr;
1764 break;
1766 case ',':
1767 case ':':
1768 case ';':
1769 case '\\':
1770 case ']':
1771 // Write a pending '<' if necessary:
1772 if (eBrackets == BRACKETS_OPENING)
1774 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
1775 >= rSink.getLineLengthLimit())
1776 rSink << INetMIMEOutputSink::endl << ' ';
1777 else if (bInitialSpace)
1778 rSink << ' ';
1779 rSink << '<';
1780 bInitialSpace = false;
1781 eBrackets = BRACKETS_INSIDE;
1784 // Write this specials:
1785 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
1786 >= rSink.getLineLengthLimit())
1787 rSink << INetMIMEOutputSink::endl << ' ';
1788 else if (bInitialSpace)
1789 rSink << ' ';
1790 rSink << sal_Char(*pBodyPtr++);
1791 bInitialSpace = false;
1792 break;
1794 case '\x0D': // CR
1795 // A <CRLF WSP> adds to accumulated space, a <CR> not
1796 // followed by <LF WSP> starts 'junk':
1797 if (startsWithLineFolding(pBodyPtr, pBodyEnd))
1799 bInitialSpace = true;
1800 pBodyPtr += 3;
1801 break;
1803 default:
1805 // The next token is either one of <"." / "@" / atom /
1806 // quoted-string / domain-literal>, or it's 'junk'; if it
1807 // is not 'junk', it is either a 'phrase' (i.e., it may
1808 // contain encoded-words) or a 'non-phrase' (i.e., it may
1809 // not contain encoded-words):
1810 enum Entity { ENTITY_JUNK, ENTITY_NON_PHRASE,
1811 ENTITY_PHRASE };
1812 Entity eEntity = ENTITY_JUNK;
1813 switch (*pBodyPtr)
1815 case '.':
1816 case '@':
1817 case '[':
1818 // A token of <"." / "@" / domain-literal> always
1819 // starts a 'non-phrase':
1820 eEntity = ENTITY_NON_PHRASE;
1821 break;
1823 default:
1824 if (rtl::isAscii(*pBodyPtr)
1825 && !isAtomChar(*pBodyPtr))
1827 eEntity = ENTITY_JUNK;
1828 break;
1830 case '"':
1831 // A token of <atom / quoted-string> can either be
1832 // a 'phrase' or a 'non-phrase':
1833 switch (eType)
1835 case HEADER_FIELD_STRUCTURED:
1836 eEntity = ENTITY_NON_PHRASE;
1837 break;
1839 case HEADER_FIELD_PHRASE:
1840 eEntity = ENTITY_PHRASE;
1841 break;
1843 case HEADER_FIELD_MESSAGE_ID:
1844 // A 'phrase' if and only if outside any
1845 // bracketed block:
1846 eEntity
1847 = eBrackets == BRACKETS_OUTSIDE ?
1848 ENTITY_PHRASE :
1849 ENTITY_NON_PHRASE;
1850 break;
1852 case HEADER_FIELD_ADDRESS:
1854 // A 'non-phrase' if and only if, after
1855 // skipping this token and any following
1856 // <linear-white-space> and <comment>s,
1857 // there is no token left, or the next
1858 // token is any of <"." / "@" / ">" / ","
1859 // / ";">, or the next token is <":"> and
1860 // is within a bracketed block:
1861 const sal_Unicode * pLookAhead = pBodyPtr;
1862 if (*pLookAhead == '"')
1864 pLookAhead
1865 = skipQuotedString(pLookAhead,
1866 pBodyEnd);
1867 if (pLookAhead == pBodyPtr)
1868 pLookAhead = pBodyEnd;
1870 else
1871 while (pLookAhead != pBodyEnd
1872 && (isAtomChar(*pLookAhead)
1873 || !rtl::isAscii(
1874 *pLookAhead)))
1875 ++pLookAhead;
1876 while (pLookAhead != pBodyEnd)
1877 switch (*pLookAhead)
1879 case '\t':
1880 case ' ':
1881 ++pLookAhead;
1882 break;
1884 case '(':
1886 const sal_Unicode * pPast
1887 = skipComment(pLookAhead,
1888 pBodyEnd);
1889 pLookAhead
1890 = pPast == pLookAhead ?
1891 pBodyEnd : pPast;
1892 break;
1895 case ',':
1896 case '.':
1897 case ';':
1898 case '>':
1899 case '@':
1900 eEntity = ENTITY_NON_PHRASE;
1901 goto entity_determined;
1903 case ':':
1904 eEntity
1905 = eBrackets
1906 == BRACKETS_OUTSIDE ?
1907 ENTITY_PHRASE :
1908 ENTITY_NON_PHRASE;
1909 goto entity_determined;
1911 case '\x0D': // CR
1912 if (startsWithLineFolding(
1913 pLookAhead, pBodyEnd))
1915 pLookAhead += 3;
1916 break;
1918 default:
1919 eEntity = ENTITY_PHRASE;
1920 goto entity_determined;
1922 eEntity = ENTITY_NON_PHRASE;
1923 entity_determined:
1924 break;
1927 case HEADER_FIELD_TEXT:
1928 OSL_ASSERT(false);
1929 break;
1932 // In a 'non-phrase', a non-US-ASCII character
1933 // cannot be part of an <atom>, but instead the
1934 // whole entity is 'junk' rather than 'non-
1935 // phrase':
1936 if (eEntity == ENTITY_NON_PHRASE
1937 && !rtl::isAscii(*pBodyPtr))
1938 eEntity = ENTITY_JUNK;
1939 break;
1942 switch (eEntity)
1944 case ENTITY_JUNK:
1946 // Write a pending '<' if necessary:
1947 if (eBrackets == BRACKETS_OPENING)
1949 if (rSink.getColumn()
1950 + (bInitialSpace ? 1 : 0)
1951 >= rSink.getLineLengthLimit())
1952 rSink << INetMIMEOutputSink::endl << ' ';
1953 else if (bInitialSpace)
1954 rSink << ' ';
1955 rSink << '<';
1956 bInitialSpace = false;
1957 eBrackets = BRACKETS_INSIDE;
1960 // Calculate the length of in- and output:
1961 const sal_Unicode * pStart = pBodyPtr;
1962 sal_Size nLength = 0;
1963 bool bModify = false;
1964 bool bEnd = false;
1965 while (pBodyPtr != pBodyEnd && !bEnd)
1966 switch (*pBodyPtr)
1968 case '\x0D': // CR
1969 if (startsWithLineFolding(pBodyPtr,
1970 pBodyEnd))
1971 bEnd = true;
1972 else if (startsWithLineBreak(
1973 pBodyPtr, pBodyEnd))
1975 nLength += 3;
1976 bModify = true;
1977 pBodyPtr += 2;
1979 else
1981 ++nLength;
1982 ++pBodyPtr;
1984 break;
1986 case '\t':
1987 case ' ':
1988 bEnd = true;
1989 break;
1991 default:
1992 if (isVisible(*pBodyPtr))
1993 bEnd = true;
1994 else if (rtl::isAscii(*pBodyPtr))
1996 ++nLength;
1997 ++pBodyPtr;
1999 else
2001 nLength += getUTF8OctetCount(
2002 *pBodyPtr++);
2003 bModify = true;
2005 break;
2008 // Write the output:
2009 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2010 + nLength
2011 > rSink.getLineLengthLimit())
2012 rSink << INetMIMEOutputSink::endl << ' ';
2013 else if (bInitialSpace)
2014 rSink << ' ';
2015 bInitialSpace = false;
2016 if (bModify)
2017 while (pStart != pBodyPtr)
2018 if (startsWithLineBreak(pStart, pBodyPtr))
2020 rSink << "\x0D\\\x0A"; // CR, '\', LF
2021 pStart += 2;
2023 else
2024 writeUTF8(rSink, *pStart++);
2025 else
2026 rSink.write(pStart, pBodyPtr);
2027 break;
2030 case ENTITY_NON_PHRASE:
2032 // Calculate the length of in- and output:
2033 const sal_Unicode * pStart = pBodyPtr;
2034 sal_Size nLength = 0;
2035 bool bBracketedBlock = false;
2036 bool bSymbol = *pStart != '.' && *pStart != '@';
2037 bool bModify = false;
2038 bool bEnd = false;
2039 while (pBodyPtr != pBodyEnd && !bEnd)
2040 switch (*pBodyPtr)
2042 case '\t':
2043 case ' ':
2044 case '\x0D': // CR
2046 const sal_Unicode * pLookAhead
2047 = skipLinearWhiteSpace(pBodyPtr,
2048 pBodyEnd);
2049 if (pLookAhead < pBodyEnd
2050 && (bSymbol ?
2051 isAtomChar(*pLookAhead)
2052 || *pLookAhead == '"'
2053 || *pLookAhead == '[' :
2054 *pLookAhead == '.'
2055 || *pLookAhead == '@'
2056 || (*pLookAhead == '>'
2057 && eType
2058 >= HEADER_FIELD_MESSAGE_ID
2059 && eBrackets
2060 == BRACKETS_OPENING)))
2062 bModify = true;
2063 pBodyPtr = pLookAhead;
2065 else
2066 bEnd = true;
2067 break;
2070 case '"':
2071 if (bSymbol)
2073 pBodyPtr
2074 = scanQuotedBlock(pBodyPtr,
2075 pBodyEnd,
2076 '"', '"',
2077 nLength,
2078 bModify);
2079 bSymbol = false;
2081 else
2082 bEnd = true;
2083 break;
2085 case '[':
2086 if (bSymbol)
2088 pBodyPtr
2089 = scanQuotedBlock(pBodyPtr,
2090 pBodyEnd,
2091 '[', ']',
2092 nLength,
2093 bModify);
2094 bSymbol = false;
2096 else
2097 bEnd = true;
2098 break;
2100 case '.':
2101 case '@':
2102 if (bSymbol)
2103 bEnd = true;
2104 else
2106 ++nLength;
2107 bSymbol = true;
2108 ++pBodyPtr;
2110 break;
2112 case '>':
2113 if (eBrackets == BRACKETS_OPENING
2114 && eType
2115 >= HEADER_FIELD_MESSAGE_ID)
2117 ++nLength;
2118 bBracketedBlock = true;
2119 ++pBodyPtr;
2121 bEnd = true;
2122 break;
2124 default:
2125 if (isAtomChar(*pBodyPtr) && bSymbol)
2127 while (pBodyPtr != pBodyEnd
2128 && isAtomChar(*pBodyPtr))
2130 ++nLength;
2131 ++pBodyPtr;
2133 bSymbol = false;
2135 else
2137 if (!rtl::isAscii(*pBodyPtr))
2138 bModify = true;
2139 bEnd = true;
2141 break;
2144 // Write a pending '<' if necessary:
2145 if (eBrackets == BRACKETS_OPENING
2146 && !bBracketedBlock)
2148 if (rSink.getColumn()
2149 + (bInitialSpace ? 1 : 0)
2150 >= rSink.getLineLengthLimit())
2151 rSink << INetMIMEOutputSink::endl << ' ';
2152 else if (bInitialSpace)
2153 rSink << ' ';
2154 rSink << '<';
2155 bInitialSpace = false;
2156 eBrackets = BRACKETS_INSIDE;
2159 // Write the output:
2160 if (rSink.getColumn() + (bInitialSpace ? 1 : 0)
2161 + nLength
2162 > rSink.getLineLengthLimit())
2163 rSink << INetMIMEOutputSink::endl << ' ';
2164 else if (bInitialSpace)
2165 rSink << ' ';
2166 bInitialSpace = false;
2167 if (bBracketedBlock)
2169 rSink << '<';
2170 eBrackets = BRACKETS_OUTSIDE;
2172 if (bModify)
2174 enum Mode { MODE_PLAIN, MODE_QUOTED_STRING,
2175 MODE_DOMAIN_LITERAL };
2176 Mode eMode = MODE_PLAIN;
2177 while (pStart != pBodyPtr)
2178 switch (*pStart)
2180 case '\x0D': // CR
2181 if (startsWithLineFolding(
2182 pStart, pBodyPtr))
2184 if (eMode != MODE_PLAIN)
2185 rSink << sal_Char(
2186 pStart[2]);
2187 pStart += 3;
2189 else if (startsWithLineBreak(
2190 pStart, pBodyPtr))
2192 rSink << "\x0D\\\x0A";
2193 // CR, '\', LF
2194 pStart += 2;
2196 else
2198 rSink << '\x0D'; // CR
2199 ++pStart;
2201 break;
2203 case '\t':
2204 case ' ':
2205 if (eMode != MODE_PLAIN)
2206 rSink << sal_Char(*pStart);
2207 ++pStart;
2208 break;
2210 case '"':
2211 if (eMode == MODE_PLAIN)
2212 eMode = MODE_QUOTED_STRING;
2213 else if (eMode
2214 == MODE_QUOTED_STRING)
2215 eMode = MODE_PLAIN;
2216 rSink << '"';
2217 ++pStart;
2218 break;
2220 case '[':
2221 if (eMode == MODE_PLAIN)
2222 eMode = MODE_DOMAIN_LITERAL;
2223 rSink << '[';
2224 ++pStart;
2225 break;
2227 case ']':
2228 if (eMode == MODE_DOMAIN_LITERAL)
2229 eMode = MODE_PLAIN;
2230 rSink << ']';
2231 ++pStart;
2232 break;
2234 case '\\':
2235 rSink << '\\';
2236 if (++pStart < pBodyPtr)
2237 writeUTF8(rSink, *pStart++);
2238 break;
2240 default:
2241 writeUTF8(rSink, *pStart++);
2242 break;
2245 else
2246 rSink.write(pStart, pBodyPtr);
2247 break;
2250 case ENTITY_PHRASE:
2252 // Write a pending '<' if necessary:
2253 if (eBrackets == BRACKETS_OPENING)
2255 if (rSink.getColumn()
2256 + (bInitialSpace ? 1 : 0)
2257 >= rSink.getLineLengthLimit())
2258 rSink << INetMIMEOutputSink::endl << ' ';
2259 else if (bInitialSpace)
2260 rSink << ' ';
2261 rSink << '<';
2262 bInitialSpace = false;
2263 eBrackets = BRACKETS_INSIDE;
2266 // Calculate the length of in- and output:
2267 const sal_Unicode * pStart = pBodyPtr;
2268 bool bQuotedString = false;
2269 bool bEnd = false;
2270 while (pBodyPtr != pBodyEnd && !bEnd)
2271 switch (*pBodyPtr)
2273 case '\t':
2274 case ' ':
2275 case '\x0D': // CR
2276 if (bQuotedString)
2277 ++pBodyPtr;
2278 else
2280 const sal_Unicode * pLookAhead
2281 = skipLinearWhiteSpace(
2282 pBodyPtr, pBodyEnd);
2283 if (pLookAhead != pBodyEnd
2284 && (isAtomChar(*pLookAhead)
2285 || !rtl::isAscii(*pLookAhead)
2286 || *pLookAhead == '"'))
2287 pBodyPtr = pLookAhead;
2288 else
2289 bEnd = true;
2291 break;
2293 case '"':
2294 bQuotedString = !bQuotedString;
2295 ++pBodyPtr;
2296 break;
2298 case '\\':
2299 if (bQuotedString)
2301 if (++pBodyPtr != pBodyEnd)
2302 ++pBodyPtr;
2304 else
2305 bEnd = true;
2306 break;
2308 default:
2309 if (bQuotedString
2310 || isAtomChar(*pBodyPtr)
2311 || !rtl::isAscii(*pBodyPtr))
2312 ++pBodyPtr;
2313 else
2314 bEnd = true;
2315 break;
2318 // Write the phrase, introducing encoded-words
2319 // where necessary:
2320 INetMIMEEncodedWordOutputSink
2321 aOutput(
2322 rSink,
2323 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE,
2324 bInitialSpace ?
2325 INetMIMEEncodedWordOutputSink::SPACE_ALWAYS :
2326 INetMIMEEncodedWordOutputSink::SPACE_ENCODED,
2327 ePreferredEncoding);
2328 while (pStart != pBodyPtr)
2329 switch (*pStart)
2331 case '"':
2332 ++pStart;
2333 break;
2335 case '\\':
2336 if (++pStart != pBodyPtr)
2337 aOutput.WriteUInt32( *pStart++ );
2338 break;
2340 case '\x0D': // CR
2341 pStart += 2;
2342 aOutput.WriteUInt32( *pStart++ );
2343 break;
2345 default:
2346 aOutput.WriteUInt32( *pStart++ );
2347 break;
2349 bInitialSpace = aOutput.flush();
2350 break;
2353 break;
2359 // static
2360 bool INetMIME::translateUTF8Char(const sal_Char *& rBegin,
2361 const sal_Char * pEnd,
2362 rtl_TextEncoding eEncoding,
2363 sal_uInt32 & rCharacter)
2365 if (rBegin == pEnd || static_cast< unsigned char >(*rBegin) < 0x80
2366 || static_cast< unsigned char >(*rBegin) >= 0xFE)
2367 return false;
2369 int nCount;
2370 sal_uInt32 nMin;
2371 sal_uInt32 nUCS4;
2372 const sal_Char * p = rBegin;
2373 if (static_cast< unsigned char >(*p) < 0xE0)
2375 nCount = 1;
2376 nMin = 0x80;
2377 nUCS4 = static_cast< unsigned char >(*p) & 0x1F;
2379 else if (static_cast< unsigned char >(*p) < 0xF0)
2381 nCount = 2;
2382 nMin = 0x800;
2383 nUCS4 = static_cast< unsigned char >(*p) & 0xF;
2385 else if (static_cast< unsigned char >(*p) < 0xF8)
2387 nCount = 3;
2388 nMin = 0x10000;
2389 nUCS4 = static_cast< unsigned char >(*p) & 7;
2391 else if (static_cast< unsigned char >(*p) < 0xFC)
2393 nCount = 4;
2394 nMin = 0x200000;
2395 nUCS4 = static_cast< unsigned char >(*p) & 3;
2397 else
2399 nCount = 5;
2400 nMin = 0x4000000;
2401 nUCS4 = static_cast< unsigned char >(*p) & 1;
2403 ++p;
2405 for (; nCount-- > 0; ++p)
2406 if ((static_cast< unsigned char >(*p) & 0xC0) == 0x80)
2407 nUCS4 = (nUCS4 << 6) | (static_cast< unsigned char >(*p) & 0x3F);
2408 else
2409 return false;
2411 if (nUCS4 < nMin || nUCS4 > 0x10FFFF)
2412 return false;
2414 if (eEncoding >= RTL_TEXTENCODING_UCS4)
2415 rCharacter = nUCS4;
2416 else
2418 sal_Unicode aUTF16[2];
2419 const sal_Unicode * pUTF16End = putUTF32Character(aUTF16, nUCS4);
2420 sal_Size nSize;
2421 sal_Char * pBuffer = convertFromUnicode(aUTF16, pUTF16End, eEncoding,
2422 nSize);
2423 if (!pBuffer)
2424 return false;
2425 DBG_ASSERT(nSize == 1,
2426 "INetMIME::translateUTF8Char(): Bad conversion");
2427 rCharacter = *pBuffer;
2428 delete[] pBuffer;
2430 rBegin = p;
2431 return true;
2434 // static
2435 OUString INetMIME::decodeHeaderFieldBody(HeaderFieldType eType,
2436 const OString& rBody)
2438 // Due to a bug in INetCoreRFC822MessageStream::ConvertTo7Bit(), old
2439 // versions of StarOffice send mails with header fields where encoded
2440 // words can be preceded by '=', ',', '.', '"', or '(', and followed by
2441 // '=', ',', '.', '"', ')', without any required white space in between.
2442 // And there appear to exist some broken mailers that only encode single
2443 // letters within words, like "Appel
2444 // =?iso-8859-1?Q?=E0?=t=?iso-8859-1?Q?=E9?=moin", so it seems best to
2445 // detect encoded words even when not properly surrounded by white space.
2447 // Non US-ASCII characters in rBody are treated as ISO-8859-1.
2449 // encoded-word = "=?"
2450 // 1*(%x21 / %x23-27 / %x2A-2B / %x2D / %30-39 / %x41-5A / %x5E-7E)
2451 // ["*" 1*8ALPHA *("-" 1*8ALPHA)] "?"
2452 // ("B?" *(4base64) (4base64 / 3base64 "=" / 2base64 "==")
2453 // / "Q?" 1*(%x21-3C / %x3E / %x40-7E / "=" 2HEXDIG))
2454 // "?="
2456 // base64 = ALPHA / DIGIT / "+" / "/"
2458 const sal_Char * pBegin = rBody.getStr();
2459 const sal_Char * pEnd = pBegin + rBody.getLength();
2461 OUString sDecoded;
2462 const sal_Char * pCopyBegin = pBegin;
2464 /* bool bStartEncodedWord = true; */
2465 const sal_Char * pWSPBegin = pBegin;
2466 bool bQuotedEncodedText = false;
2467 sal_uInt32 nCommentLevel = 0;
2469 for (const sal_Char * p = pBegin; p != pEnd;)
2471 OUString sEncodedText;
2472 if (p != pEnd && *p == '=' /* && bStartEncodedWord */)
2474 const sal_Char * q = p + 1;
2475 bool bEncodedWord = q != pEnd && *q++ == '?';
2477 rtl_TextEncoding eCharsetEncoding = RTL_TEXTENCODING_DONTKNOW;
2478 if (bEncodedWord)
2480 const sal_Char * pCharsetBegin = q;
2481 const sal_Char * pLanguageBegin = 0;
2482 int nAlphaCount = 0;
2483 for (bool bDone = false; !bDone;)
2484 if (q == pEnd)
2486 bEncodedWord = false;
2487 bDone = true;
2489 else
2491 sal_Char cChar = *q++;
2492 switch (cChar)
2494 case '*':
2495 pLanguageBegin = q - 1;
2496 nAlphaCount = 0;
2497 break;
2499 case '-':
2500 if (pLanguageBegin != 0)
2502 if (nAlphaCount == 0)
2503 pLanguageBegin = 0;
2504 else
2505 nAlphaCount = 0;
2507 break;
2509 case '?':
2510 if (pCharsetBegin == q - 1)
2511 bEncodedWord = false;
2512 else
2514 eCharsetEncoding
2515 = getCharsetEncoding(
2516 pCharsetBegin,
2517 pLanguageBegin == 0
2518 || nAlphaCount == 0 ?
2519 q - 1 : pLanguageBegin);
2520 bEncodedWord = isMIMECharsetEncoding(
2521 eCharsetEncoding);
2522 eCharsetEncoding
2523 = translateFromMIME(eCharsetEncoding);
2525 bDone = true;
2526 break;
2528 default:
2529 if (pLanguageBegin != 0
2530 && (!rtl::isAsciiAlpha(cChar) || ++nAlphaCount > 8))
2531 pLanguageBegin = 0;
2532 break;
2537 bool bEncodingB = false;
2538 if (bEncodedWord)
2540 if (q == pEnd)
2541 bEncodedWord = false;
2542 else
2544 switch (*q++)
2546 case 'B':
2547 case 'b':
2548 bEncodingB = true;
2549 break;
2551 case 'Q':
2552 case 'q':
2553 bEncodingB = false;
2554 break;
2556 default:
2557 bEncodedWord = false;
2558 break;
2563 bEncodedWord = bEncodedWord && q != pEnd && *q++ == '?';
2565 OStringBuffer sText;
2566 if (bEncodedWord)
2568 if (bEncodingB)
2570 for (bool bDone = false; !bDone;)
2572 if (pEnd - q < 4)
2574 bEncodedWord = false;
2575 bDone = true;
2577 else
2579 bool bFinal = false;
2580 int nCount = 3;
2581 sal_uInt32 nValue = 0;
2582 for (int nShift = 18; nShift >= 0; nShift -= 6)
2584 int nWeight = getBase64Weight(*q++);
2585 if (nWeight == -2)
2587 bEncodedWord = false;
2588 bDone = true;
2589 break;
2591 if (nWeight == -1)
2593 if (!bFinal)
2595 if (nShift >= 12)
2597 bEncodedWord = false;
2598 bDone = true;
2599 break;
2601 bFinal = true;
2602 nCount = nShift == 6 ? 1 : 2;
2605 else
2606 nValue |= nWeight << nShift;
2608 if (bEncodedWord)
2610 for (int nShift = 16; nCount-- > 0; nShift -= 8)
2611 sText.append(sal_Char(nValue >> nShift & 0xFF));
2612 if (*q == '?')
2614 ++q;
2615 bDone = true;
2617 if (bFinal && !bDone)
2619 bEncodedWord = false;
2620 bDone = true;
2626 else
2628 const sal_Char * pEncodedTextBegin = q;
2629 const sal_Char * pEncodedTextCopyBegin = q;
2630 for (bool bDone = false; !bDone;)
2631 if (q == pEnd)
2633 bEncodedWord = false;
2634 bDone = true;
2636 else
2638 sal_uInt32 nChar = *q++;
2639 switch (nChar)
2641 case '=':
2643 if (pEnd - q < 2)
2645 bEncodedWord = false;
2646 bDone = true;
2647 break;
2649 int nDigit1 = getHexWeight(q[0]);
2650 int nDigit2 = getHexWeight(q[1]);
2651 if (nDigit1 < 0 || nDigit2 < 0)
2653 bEncodedWord = false;
2654 bDone = true;
2655 break;
2657 sText.append(rBody.copy(
2658 (pEncodedTextCopyBegin - pBegin),
2659 (q - 1 - pEncodedTextCopyBegin)));
2660 sText.append(sal_Char(nDigit1 << 4 | nDigit2));
2661 q += 2;
2662 pEncodedTextCopyBegin = q;
2663 break;
2666 case '?':
2667 if (q - pEncodedTextBegin > 1)
2668 sText.append(rBody.copy(
2669 (pEncodedTextCopyBegin - pBegin),
2670 (q - 1 - pEncodedTextCopyBegin)));
2671 else
2672 bEncodedWord = false;
2673 bDone = true;
2674 break;
2676 case '_':
2677 sText.append(rBody.copy(
2678 (pEncodedTextCopyBegin - pBegin),
2679 (q - 1 - pEncodedTextCopyBegin)));
2680 sText.append(' ');
2681 pEncodedTextCopyBegin = q;
2682 break;
2684 default:
2685 if (!isVisible(nChar))
2687 bEncodedWord = false;
2688 bDone = true;
2690 break;
2696 bEncodedWord = bEncodedWord && q != pEnd && *q++ == '=';
2698 sal_Unicode * pUnicodeBuffer = 0;
2699 sal_Size nUnicodeSize = 0;
2700 if (bEncodedWord)
2702 pUnicodeBuffer
2703 = convertToUnicode(sText.getStr(),
2704 sText.getStr() + sText.getLength(),
2705 eCharsetEncoding, nUnicodeSize);
2706 if (pUnicodeBuffer == 0)
2707 bEncodedWord = false;
2710 if (bEncodedWord)
2712 appendISO88591(sDecoded, pCopyBegin, pWSPBegin);
2713 if (eType == HEADER_FIELD_TEXT)
2714 sDecoded += OUString(
2715 pUnicodeBuffer,
2716 static_cast< sal_Int32 >(nUnicodeSize));
2717 else if (nCommentLevel == 0)
2719 sEncodedText = OUString(pUnicodeBuffer, nUnicodeSize);
2720 if (!bQuotedEncodedText)
2722 const sal_Unicode * pTextPtr = pUnicodeBuffer;
2723 const sal_Unicode * pTextEnd = pTextPtr
2724 + nUnicodeSize;
2725 for (; pTextPtr != pTextEnd; ++pTextPtr)
2726 if (!isEncodedWordTokenChar(*pTextPtr))
2728 bQuotedEncodedText = true;
2729 break;
2733 else
2735 const sal_Unicode * pTextPtr = pUnicodeBuffer;
2736 const sal_Unicode * pTextEnd = pTextPtr + nUnicodeSize;
2737 for (; pTextPtr != pTextEnd; ++pTextPtr)
2739 switch (*pTextPtr)
2741 case '(':
2742 case ')':
2743 case '\\':
2744 case '\x0D':
2745 case '=':
2746 sDecoded += "\\";
2747 break;
2749 sDecoded += OUString(*pTextPtr);
2752 delete[] pUnicodeBuffer;
2753 p = q;
2754 pCopyBegin = p;
2756 pWSPBegin = p;
2757 while (p != pEnd && isWhiteSpace(*p))
2758 ++p;
2759 /* bStartEncodedWord = p != pWSPBegin; */
2760 continue;
2764 if (!sEncodedText.isEmpty())
2766 if (bQuotedEncodedText)
2768 sDecoded += "\"";
2769 const sal_Unicode * pTextPtr = sEncodedText.getStr();
2770 const sal_Unicode * pTextEnd = pTextPtr + sEncodedText.getLength();
2771 for (;pTextPtr != pTextEnd; ++pTextPtr)
2773 switch (*pTextPtr)
2775 case '"':
2776 case '\\':
2777 case '\x0D':
2778 sDecoded += "\\";
2779 break;
2781 sDecoded += OUString(*pTextPtr);
2783 sDecoded += "\"";
2785 else
2786 sDecoded += sEncodedText;
2787 bQuotedEncodedText = false;
2790 if (p == pEnd)
2791 break;
2793 switch (*p++)
2795 case '"':
2796 if (eType != HEADER_FIELD_TEXT && nCommentLevel == 0)
2798 const sal_Char * pQuotedStringEnd
2799 = skipQuotedString(p - 1, pEnd);
2800 p = pQuotedStringEnd == p - 1 ? pEnd : pQuotedStringEnd;
2802 /* bStartEncodedWord = true; */
2803 break;
2805 case '(':
2806 if (eType != HEADER_FIELD_TEXT)
2807 ++nCommentLevel;
2808 /* bStartEncodedWord = true; */
2809 break;
2811 case ')':
2812 if (nCommentLevel > 0)
2813 --nCommentLevel;
2814 /* bStartEncodedWord = false; */
2815 break;
2817 default:
2819 const sal_Char * pUTF8Begin = p - 1;
2820 const sal_Char * pUTF8End = pUTF8Begin;
2821 sal_uInt32 nCharacter = 0;
2822 if (translateUTF8Char(pUTF8End, pEnd, RTL_TEXTENCODING_UCS4,
2823 nCharacter))
2825 appendISO88591(sDecoded, pCopyBegin, p - 1);
2826 sal_Unicode aUTF16Buf[2];
2827 sal_Int32 nUTF16Len = putUTF32Character(aUTF16Buf, nCharacter) - aUTF16Buf;
2828 sDecoded += OUString(aUTF16Buf, nUTF16Len);
2829 p = pUTF8End;
2830 pCopyBegin = p;
2832 /* bStartEncodedWord = false; */
2833 break;
2836 pWSPBegin = p;
2839 appendISO88591(sDecoded, pCopyBegin, pEnd);
2840 return sDecoded;
2843 // INetMIMEOutputSink
2845 // virtual
2846 sal_Size INetMIMEOutputSink::writeSequence(const sal_Char * pSequence)
2848 sal_Size nLength = rtl_str_getLength(pSequence);
2849 writeSequence(pSequence, pSequence + nLength);
2850 return nLength;
2853 // virtual
2854 void INetMIMEOutputSink::writeSequence(const sal_Unicode * pBegin,
2855 const sal_Unicode * pEnd)
2857 assert(pBegin && pBegin <= pEnd &&
2858 "INetMIMEOutputSink::writeSequence(): Bad sequence");
2860 sal_Char * pBufferBegin = new sal_Char[pEnd - pBegin];
2861 sal_Char * pBufferEnd = pBufferBegin;
2862 while (pBegin != pEnd)
2864 DBG_ASSERT(*pBegin < 256,
2865 "INetMIMEOutputSink::writeSequence(): Bad octet");
2866 *pBufferEnd++ = sal_Char(*pBegin++);
2868 writeSequence(pBufferBegin, pBufferEnd);
2869 delete[] pBufferBegin;
2872 // virtual
2873 ErrCode INetMIMEOutputSink::getError() const
2875 return ERRCODE_NONE;
2878 void INetMIMEOutputSink::writeLineEnd()
2880 static const sal_Char aCRLF[2] = { 0x0D, 0x0A };
2881 writeSequence(aCRLF, aCRLF + 2);
2882 m_nColumn = 0;
2885 // INetMIMEStringOutputSink
2887 // virtual
2888 void INetMIMEStringOutputSink::writeSequence(const sal_Char * pBegin,
2889 const sal_Char * pEnd)
2891 OSL_ENSURE(pBegin && pBegin <= pEnd,
2892 "INetMIMEStringOutputSink::writeSequence(): Bad sequence");
2894 m_aBuffer.append(pBegin, pEnd - pBegin);
2897 // virtual
2898 ErrCode INetMIMEStringOutputSink::getError() const
2900 return ERRCODE_NONE;
2903 // INetMIMEEncodedWordOutputSink
2905 static const sal_Char aEscape[128]
2906 = { INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x00
2907 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x01
2908 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x02
2909 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x03
2910 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x04
2911 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x05
2912 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x06
2913 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x07
2914 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x08
2915 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x09
2916 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0A
2917 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0B
2918 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0C
2919 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0D
2920 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0E
2921 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x0F
2922 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x10
2923 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x11
2924 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x12
2925 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x13
2926 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x14
2927 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x15
2928 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x16
2929 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x17
2930 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x18
2931 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x19
2932 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1A
2933 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1B
2934 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1C
2935 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1D
2936 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1E
2937 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // 0x1F
2938 0, // ' '
2939 0, // '!'
2940 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '"'
2941 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '#'
2942 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '$'
2943 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '%'
2944 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '&'
2945 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '''
2946 INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '('
2947 INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ')'
2948 0, // '*'
2949 0, // '+'
2950 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ','
2951 0, // '-'
2952 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '.'
2953 0, // '/'
2954 0, // '0'
2955 0, // '1'
2956 0, // '2'
2957 0, // '3'
2958 0, // '4'
2959 0, // '5'
2960 0, // '6'
2961 0, // '7'
2962 0, // '8'
2963 0, // '9'
2964 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ':'
2965 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ';'
2966 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '<'
2967 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '='
2968 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '>'
2969 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '?'
2970 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '@'
2971 0, // 'A'
2972 0, // 'B'
2973 0, // 'C'
2974 0, // 'D'
2975 0, // 'E'
2976 0, // 'F'
2977 0, // 'G'
2978 0, // 'H'
2979 0, // 'I'
2980 0, // 'J'
2981 0, // 'K'
2982 0, // 'L'
2983 0, // 'M'
2984 0, // 'N'
2985 0, // 'O'
2986 0, // 'P'
2987 0, // 'Q'
2988 0, // 'R'
2989 0, // 'S'
2990 0, // 'T'
2991 0, // 'U'
2992 0, // 'V'
2993 0, // 'W'
2994 0, // 'X'
2995 0, // 'Y'
2996 0, // 'Z'
2997 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '['
2998 INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '\'
2999 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // ']'
3000 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '^'
3001 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '_'
3002 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '`'
3003 0, // 'a'
3004 0, // 'b'
3005 0, // 'c'
3006 0, // 'd'
3007 0, // 'e'
3008 0, // 'f'
3009 0, // 'g'
3010 0, // 'h'
3011 0, // 'i'
3012 0, // 'j'
3013 0, // 'k'
3014 0, // 'l'
3015 0, // 'm'
3016 0, // 'n'
3017 0, // 'o'
3018 0, // 'p'
3019 0, // 'q'
3020 0, // 'r'
3021 0, // 's'
3022 0, // 't'
3023 0, // 'u'
3024 0, // 'v'
3025 0, // 'w'
3026 0, // 'x'
3027 0, // 'y'
3028 0, // 'z'
3029 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '{'
3030 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '|'
3031 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '}'
3032 INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE, // '~'
3033 INetMIMEEncodedWordOutputSink::CONTEXT_TEXT | INetMIMEEncodedWordOutputSink::CONTEXT_COMMENT | INetMIMEEncodedWordOutputSink::CONTEXT_PHRASE }; // DEL
3035 inline bool
3036 INetMIMEEncodedWordOutputSink::needsEncodedWordEscape(sal_uInt32 nChar) const
3038 return !rtl::isAscii(nChar) || aEscape[nChar] & m_eContext;
3041 void INetMIMEEncodedWordOutputSink::finish(bool bWriteTrailer)
3043 if (m_eInitialSpace == SPACE_ALWAYS && m_nExtraSpaces == 0)
3044 m_nExtraSpaces = 1;
3046 if (m_eEncodedWordState == STATE_SECOND_EQUALS)
3048 // If the text is already an encoded word, copy it verbatim:
3049 sal_uInt32 nSize = m_pBufferEnd - m_pBuffer;
3050 switch (m_ePrevCoding)
3052 case CODING_QUOTED:
3053 m_rSink << '"';
3054 case CODING_NONE:
3055 if (m_eInitialSpace == SPACE_ENCODED && m_nExtraSpaces == 0)
3056 m_nExtraSpaces = 1;
3057 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3059 if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3060 m_rSink << INetMIMEOutputSink::endl;
3061 m_rSink << ' ';
3063 if (m_nExtraSpaces == 1)
3065 if (m_rSink.getColumn() + nSize
3066 >= m_rSink.getLineLengthLimit())
3067 m_rSink << INetMIMEOutputSink::endl;
3068 m_rSink << ' ';
3070 break;
3072 case CODING_ENCODED:
3074 const sal_Char * pCharsetName
3075 = INetMIME::getCharsetName(m_ePrevMIMEEncoding);
3076 while (m_nExtraSpaces-- > 0)
3078 if (m_rSink.getColumn()
3079 > m_rSink.getLineLengthLimit() - 3)
3080 m_rSink << "?=" << INetMIMEOutputSink::endl << " =?"
3081 << pCharsetName << "?Q?";
3082 m_rSink << '_';
3084 m_rSink << "?=";
3086 //fall-through
3087 case CODING_ENCODED_TERMINATED:
3088 if (m_rSink.getColumn() + nSize
3089 > m_rSink.getLineLengthLimit() - 1)
3090 m_rSink << INetMIMEOutputSink::endl;
3091 m_rSink << ' ';
3092 break;
3094 m_rSink.write(m_pBuffer, m_pBufferEnd);
3095 m_eCoding = CODING_ENCODED_TERMINATED;
3097 else
3099 // If the text itself is too long to fit into a single line, make it
3100 // into multiple encoded words:
3101 switch (m_eCoding)
3103 case CODING_NONE:
3104 if (m_nExtraSpaces == 0)
3106 DBG_ASSERT(m_ePrevCoding == CODING_NONE
3107 || m_pBuffer == m_pBufferEnd,
3108 "INetMIMEEncodedWordOutputSink::finish():"
3109 " Bad state");
3110 if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
3111 > m_rSink.getLineLengthLimit())
3112 m_eCoding = CODING_ENCODED;
3114 else
3116 OSL_ASSERT(m_pBufferEnd >= m_pBuffer);
3117 if (static_cast< std::size_t >(m_pBufferEnd - m_pBuffer)
3118 > m_rSink.getLineLengthLimit() - 1)
3120 m_eCoding = CODING_ENCODED;
3123 break;
3125 case CODING_QUOTED:
3126 if (m_nExtraSpaces == 0)
3128 DBG_ASSERT(m_ePrevCoding == CODING_NONE,
3129 "INetMIMEEncodedWordOutputSink::finish():"
3130 " Bad state");
3131 if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
3132 + m_nQuotedEscaped
3133 > m_rSink.getLineLengthLimit() - 2)
3134 m_eCoding = CODING_ENCODED;
3136 else if ((m_pBufferEnd - m_pBuffer) + m_nQuotedEscaped
3137 > m_rSink.getLineLengthLimit() - 3)
3138 m_eCoding = CODING_ENCODED;
3139 break;
3141 default:
3142 break;
3145 switch (m_eCoding)
3147 case CODING_NONE:
3148 switch (m_ePrevCoding)
3150 case CODING_QUOTED:
3151 if (m_rSink.getColumn() + m_nExtraSpaces
3152 + (m_pBufferEnd - m_pBuffer)
3153 < m_rSink.getLineLengthLimit())
3154 m_eCoding = CODING_QUOTED;
3155 else
3156 m_rSink << '"';
3157 break;
3159 case CODING_ENCODED:
3160 m_rSink << "?=";
3161 break;
3163 default:
3164 break;
3166 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3168 if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3169 m_rSink << INetMIMEOutputSink::endl;
3170 m_rSink << ' ';
3172 if (m_nExtraSpaces == 1)
3174 if (m_rSink.getColumn() + (m_pBufferEnd - m_pBuffer)
3175 >= m_rSink.getLineLengthLimit())
3176 m_rSink << INetMIMEOutputSink::endl;
3177 m_rSink << ' ';
3179 m_rSink.write(m_pBuffer, m_pBufferEnd);
3180 if (m_eCoding == CODING_QUOTED && bWriteTrailer)
3182 m_rSink << '"';
3183 m_eCoding = CODING_NONE;
3185 break;
3187 case CODING_QUOTED:
3189 bool bInsertLeadingQuote = true;
3190 sal_uInt32 nSize = (m_pBufferEnd - m_pBuffer)
3191 + m_nQuotedEscaped + 2;
3192 switch (m_ePrevCoding)
3194 case CODING_QUOTED:
3195 if (m_rSink.getColumn() + m_nExtraSpaces + nSize - 1
3196 < m_rSink.getLineLengthLimit())
3198 bInsertLeadingQuote = false;
3199 --nSize;
3201 else
3202 m_rSink << '"';
3203 break;
3205 case CODING_ENCODED:
3206 m_rSink << "?=";
3207 break;
3209 default:
3210 break;
3212 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3214 if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3215 m_rSink << INetMIMEOutputSink::endl;
3216 m_rSink << ' ';
3218 if (m_nExtraSpaces == 1)
3220 if (m_rSink.getColumn() + nSize
3221 >= m_rSink.getLineLengthLimit())
3222 m_rSink << INetMIMEOutputSink::endl;
3223 m_rSink << ' ';
3225 if (bInsertLeadingQuote)
3226 m_rSink << '"';
3227 for (const sal_Unicode * p = m_pBuffer; p != m_pBufferEnd;
3228 ++p)
3230 if (INetMIME::needsQuotedStringEscape(*p))
3231 m_rSink << '\\';
3232 m_rSink << sal_Char(*p);
3234 if (bWriteTrailer)
3236 m_rSink << '"';
3237 m_eCoding = CODING_NONE;
3239 break;
3242 case CODING_ENCODED:
3244 rtl_TextEncoding eCharsetEncoding
3245 = m_pEncodingList->
3246 getPreferredEncoding(RTL_TEXTENCODING_UTF8);
3247 rtl_TextEncoding eMIMEEncoding
3248 = INetMIME::translateToMIME(eCharsetEncoding);
3250 // The non UTF-8 code will only work for stateless single byte
3251 // character encodings (see also below):
3252 sal_Char * pTargetBuffer = NULL;
3253 sal_Size nTargetSize = 0;
3254 sal_uInt32 nSize;
3255 if (eMIMEEncoding == RTL_TEXTENCODING_UTF8)
3257 nSize = 0;
3258 for (sal_Unicode const * p = m_pBuffer;
3259 p != m_pBufferEnd;)
3261 sal_uInt32 nUTF32
3262 = INetMIME::getUTF32Character(p, m_pBufferEnd);
3263 nSize += needsEncodedWordEscape(nUTF32) ?
3264 3 * INetMIME::getUTF8OctetCount(nUTF32) :
3266 // only US-ASCII characters (that are converted to
3267 // a single byte by UTF-8) need no encoded word
3268 // escapes...
3271 else
3273 rtl_UnicodeToTextConverter hConverter
3274 = rtl_createUnicodeToTextConverter(eCharsetEncoding);
3275 rtl_UnicodeToTextContext hContext
3276 = rtl_createUnicodeToTextContext(hConverter);
3277 for (sal_Size nBufferSize = m_pBufferEnd - m_pBuffer;;
3278 nBufferSize += nBufferSize / 3 + 1)
3280 pTargetBuffer = new sal_Char[nBufferSize];
3281 sal_uInt32 nInfo;
3282 sal_Size nSrcCvtBytes;
3283 nTargetSize
3284 = rtl_convertUnicodeToText(
3285 hConverter, hContext, m_pBuffer,
3286 m_pBufferEnd - m_pBuffer, pTargetBuffer,
3287 nBufferSize,
3288 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_IGNORE
3289 | RTL_UNICODETOTEXT_FLAGS_INVALID_IGNORE,
3290 &nInfo, &nSrcCvtBytes);
3291 if (!(nInfo
3292 & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL))
3293 break;
3294 delete[] pTargetBuffer;
3295 pTargetBuffer = NULL;
3296 rtl_resetUnicodeToTextContext(hConverter, hContext);
3298 rtl_destroyUnicodeToTextContext(hConverter, hContext);
3299 rtl_destroyUnicodeToTextConverter(hConverter);
3301 nSize = nTargetSize;
3302 for (sal_Size k = 0; k < nTargetSize; ++k)
3303 if (needsEncodedWordEscape(static_cast<unsigned char>(
3304 pTargetBuffer[k])))
3305 nSize += 2;
3308 const sal_Char * pCharsetName
3309 = INetMIME::getCharsetName(eMIMEEncoding);
3310 sal_uInt32 nWrapperSize = rtl_str_getLength(pCharsetName) + 7;
3311 // '=?', '?Q?', '?='
3313 switch (m_ePrevCoding)
3315 case CODING_QUOTED:
3316 m_rSink << '"';
3317 case CODING_NONE:
3318 if (m_eInitialSpace == SPACE_ENCODED
3319 && m_nExtraSpaces == 0)
3320 m_nExtraSpaces = 1;
3321 nSize += nWrapperSize;
3322 for (; m_nExtraSpaces > 1; --m_nExtraSpaces)
3324 if (m_rSink.getColumn() >= m_rSink.getLineLengthLimit())
3325 m_rSink << INetMIMEOutputSink::endl;
3326 m_rSink << ' ';
3328 if (m_nExtraSpaces == 1)
3330 if (m_rSink.getColumn() + nSize >= m_rSink.getLineLengthLimit())
3331 m_rSink << INetMIMEOutputSink::endl;
3332 m_rSink << ' ';
3334 m_rSink << "=?" << pCharsetName << "?Q?";
3335 break;
3337 case CODING_ENCODED:
3338 if (m_ePrevMIMEEncoding != eMIMEEncoding
3339 || m_rSink.getColumn() + m_nExtraSpaces + nSize
3340 > m_rSink.getLineLengthLimit() - 2)
3342 m_rSink << "?=";
3343 if (m_rSink.getColumn() + nWrapperSize
3344 + m_nExtraSpaces + nSize
3345 > m_rSink.getLineLengthLimit() - 1)
3346 m_rSink << INetMIMEOutputSink::endl;
3347 m_rSink << " =?" << pCharsetName << "?Q?";
3349 while (m_nExtraSpaces-- > 0)
3351 if (m_rSink.getColumn()
3352 > m_rSink.getLineLengthLimit() - 3)
3353 m_rSink << "?=" << INetMIMEOutputSink::endl
3354 << " =?" << pCharsetName << "?Q?";
3355 m_rSink << '_';
3357 break;
3359 case CODING_ENCODED_TERMINATED:
3360 if (m_rSink.getColumn() + nWrapperSize
3361 + m_nExtraSpaces + nSize
3362 > m_rSink.getLineLengthLimit() - 1)
3363 m_rSink << INetMIMEOutputSink::endl;
3364 m_rSink << " =?" << pCharsetName << "?Q?";
3365 while (m_nExtraSpaces-- > 0)
3367 if (m_rSink.getColumn()
3368 > m_rSink.getLineLengthLimit() - 3)
3369 m_rSink << "?=" << INetMIMEOutputSink::endl
3370 << " =?" << pCharsetName << "?Q?";
3371 m_rSink << '_';
3373 break;
3376 // The non UTF-8 code will only work for stateless single byte
3377 // character encodings (see also above):
3378 if (eMIMEEncoding == RTL_TEXTENCODING_UTF8)
3380 bool bInitial = true;
3381 for (sal_Unicode const * p = m_pBuffer;
3382 p != m_pBufferEnd;)
3384 sal_uInt32 nUTF32
3385 = INetMIME::getUTF32Character(p, m_pBufferEnd);
3386 bool bEscape = needsEncodedWordEscape(nUTF32);
3387 sal_uInt32 nWidth
3388 = bEscape ?
3389 3 * INetMIME::getUTF8OctetCount(nUTF32) : 1;
3390 // only US-ASCII characters (that are converted to
3391 // a single byte by UTF-8) need no encoded word
3392 // escapes...
3393 if (!bInitial
3394 && m_rSink.getColumn() + nWidth + 2
3395 > m_rSink.getLineLengthLimit())
3396 m_rSink << "?=" << INetMIMEOutputSink::endl
3397 << " =?" << pCharsetName << "?Q?";
3398 if (bEscape)
3400 DBG_ASSERT(
3401 nUTF32 < 0x10FFFF,
3402 "INetMIMEEncodedWordOutputSink::finish():"
3403 " Bad char");
3404 if (nUTF32 < 0x80)
3405 INetMIME::writeEscapeSequence(m_rSink,
3406 nUTF32);
3407 else if (nUTF32 < 0x800)
3409 INetMIME::writeEscapeSequence(m_rSink,
3410 (nUTF32 >> 6)
3411 | 0xC0);
3412 INetMIME::writeEscapeSequence(m_rSink,
3413 (nUTF32 & 0x3F)
3414 | 0x80);
3416 else if (nUTF32 < 0x10000)
3418 INetMIME::writeEscapeSequence(m_rSink,
3419 (nUTF32 >> 12)
3420 | 0xE0);
3421 INetMIME::writeEscapeSequence(m_rSink,
3422 ((nUTF32 >> 6)
3423 & 0x3F)
3424 | 0x80);
3425 INetMIME::writeEscapeSequence(m_rSink,
3426 (nUTF32 & 0x3F)
3427 | 0x80);
3429 else
3431 INetMIME::writeEscapeSequence(m_rSink,
3432 (nUTF32 >> 18)
3433 | 0xF0);
3434 INetMIME::writeEscapeSequence(m_rSink,
3435 ((nUTF32 >> 12)
3436 & 0x3F)
3437 | 0x80);
3438 INetMIME::writeEscapeSequence(m_rSink,
3439 ((nUTF32 >> 6)
3440 & 0x3F)
3441 | 0x80);
3442 INetMIME::writeEscapeSequence(m_rSink,
3443 (nUTF32 & 0x3F)
3444 | 0x80);
3447 else
3448 m_rSink << sal_Char(nUTF32);
3449 bInitial = false;
3452 else
3454 for (sal_Size k = 0; k < nTargetSize; ++k)
3456 sal_uInt32 nUCS4 = static_cast<unsigned char>(pTargetBuffer[k]);
3457 bool bEscape = needsEncodedWordEscape(nUCS4);
3458 if (k > 0
3459 && m_rSink.getColumn() + (bEscape ? 5 : 3)
3460 > m_rSink.getLineLengthLimit())
3461 m_rSink << "?=" << INetMIMEOutputSink::endl
3462 << " =?" << pCharsetName << "?Q?";
3463 if (bEscape)
3464 INetMIME::writeEscapeSequence(m_rSink, nUCS4);
3465 else
3466 m_rSink << sal_Char(nUCS4);
3468 delete[] pTargetBuffer;
3471 if (bWriteTrailer)
3473 m_rSink << "?=";
3474 m_eCoding = CODING_ENCODED_TERMINATED;
3477 m_ePrevMIMEEncoding = eMIMEEncoding;
3478 break;
3481 default:
3482 OSL_ASSERT(false);
3483 break;
3487 m_eInitialSpace = SPACE_NO;
3488 m_nExtraSpaces = 0;
3489 m_pEncodingList->reset();
3490 m_pBufferEnd = m_pBuffer;
3491 m_ePrevCoding = m_eCoding;
3492 m_eCoding = CODING_NONE;
3493 m_nQuotedEscaped = 0;
3494 m_eEncodedWordState = STATE_INITIAL;
3497 INetMIMEEncodedWordOutputSink::~INetMIMEEncodedWordOutputSink()
3499 rtl_freeMemory(m_pBuffer);
3500 delete m_pEncodingList;
3503 INetMIMEEncodedWordOutputSink &
3504 INetMIMEEncodedWordOutputSink::WriteUInt32(sal_uInt32 nChar)
3506 if (nChar == ' ')
3508 if (m_pBufferEnd != m_pBuffer)
3509 finish(false);
3510 ++m_nExtraSpaces;
3512 else
3514 // Check for an already encoded word:
3515 switch (m_eEncodedWordState)
3517 case STATE_INITIAL:
3518 if (nChar == '=')
3519 m_eEncodedWordState = STATE_FIRST_EQUALS;
3520 else
3521 m_eEncodedWordState = STATE_BAD;
3522 break;
3524 case STATE_FIRST_EQUALS:
3525 if (nChar == '?')
3526 m_eEncodedWordState = STATE_FIRST_EQUALS;
3527 else
3528 m_eEncodedWordState = STATE_BAD;
3529 break;
3531 case STATE_FIRST_QUESTION:
3532 if (INetMIME::isEncodedWordTokenChar(nChar))
3533 m_eEncodedWordState = STATE_CHARSET;
3534 else
3535 m_eEncodedWordState = STATE_BAD;
3536 break;
3538 case STATE_CHARSET:
3539 if (nChar == '?')
3540 m_eEncodedWordState = STATE_SECOND_QUESTION;
3541 else if (!INetMIME::isEncodedWordTokenChar(nChar))
3542 m_eEncodedWordState = STATE_BAD;
3543 break;
3545 case STATE_SECOND_QUESTION:
3546 if (nChar == 'B' || nChar == 'Q'
3547 || nChar == 'b' || nChar == 'q')
3548 m_eEncodedWordState = STATE_ENCODING;
3549 else
3550 m_eEncodedWordState = STATE_BAD;
3551 break;
3553 case STATE_ENCODING:
3554 if (nChar == '?')
3555 m_eEncodedWordState = STATE_THIRD_QUESTION;
3556 else
3557 m_eEncodedWordState = STATE_BAD;
3558 break;
3560 case STATE_THIRD_QUESTION:
3561 if (INetMIME::isVisible(nChar) && nChar != '?')
3562 m_eEncodedWordState = STATE_ENCODED_TEXT;
3563 else
3564 m_eEncodedWordState = STATE_BAD;
3565 break;
3567 case STATE_ENCODED_TEXT:
3568 if (nChar == '?')
3569 m_eEncodedWordState = STATE_FOURTH_QUESTION;
3570 else if (!INetMIME::isVisible(nChar))
3571 m_eEncodedWordState = STATE_BAD;
3572 break;
3574 case STATE_FOURTH_QUESTION:
3575 if (nChar == '=')
3576 m_eEncodedWordState = STATE_SECOND_EQUALS;
3577 else
3578 m_eEncodedWordState = STATE_BAD;
3579 break;
3581 case STATE_SECOND_EQUALS:
3582 m_eEncodedWordState = STATE_BAD;
3583 break;
3585 case STATE_BAD:
3586 break;
3589 // Update encoding:
3590 m_pEncodingList->includes(nChar);
3592 // Update coding:
3593 enum { TENQ = 1, // CONTEXT_TEXT, CODING_ENCODED
3594 CENQ = 2, // CONTEXT_COMMENT, CODING_ENCODED
3595 PQTD = 4, // CONTEXT_PHRASE, CODING_QUOTED
3596 PENQ = 8 }; // CONTEXT_PHRASE, CODING_ENCODED
3597 static const sal_Char aMinimal[128]
3598 = { TENQ | CENQ | PENQ, // 0x00
3599 TENQ | CENQ | PENQ, // 0x01
3600 TENQ | CENQ | PENQ, // 0x02
3601 TENQ | CENQ | PENQ, // 0x03
3602 TENQ | CENQ | PENQ, // 0x04
3603 TENQ | CENQ | PENQ, // 0x05
3604 TENQ | CENQ | PENQ, // 0x06
3605 TENQ | CENQ | PENQ, // 0x07
3606 TENQ | CENQ | PENQ, // 0x08
3607 TENQ | CENQ | PENQ, // 0x09
3608 TENQ | CENQ | PENQ, // 0x0A
3609 TENQ | CENQ | PENQ, // 0x0B
3610 TENQ | CENQ | PENQ, // 0x0C
3611 TENQ | CENQ | PENQ, // 0x0D
3612 TENQ | CENQ | PENQ, // 0x0E
3613 TENQ | CENQ | PENQ, // 0x0F
3614 TENQ | CENQ | PENQ, // 0x10
3615 TENQ | CENQ | PENQ, // 0x11
3616 TENQ | CENQ | PENQ, // 0x12
3617 TENQ | CENQ | PENQ, // 0x13
3618 TENQ | CENQ | PENQ, // 0x14
3619 TENQ | CENQ | PENQ, // 0x15
3620 TENQ | CENQ | PENQ, // 0x16
3621 TENQ | CENQ | PENQ, // 0x17
3622 TENQ | CENQ | PENQ, // 0x18
3623 TENQ | CENQ | PENQ, // 0x19
3624 TENQ | CENQ | PENQ, // 0x1A
3625 TENQ | CENQ | PENQ, // 0x1B
3626 TENQ | CENQ | PENQ, // 0x1C
3627 TENQ | CENQ | PENQ, // 0x1D
3628 TENQ | CENQ | PENQ, // 0x1E
3629 TENQ | CENQ | PENQ, // 0x1F
3630 0, // ' '
3631 0, // '!'
3632 PQTD , // '"'
3633 0, // '#'
3634 0, // '$'
3635 0, // '%'
3636 0, // '&'
3637 0, // '''
3638 CENQ | PQTD , // '('
3639 CENQ | PQTD , // ')'
3640 0, // '*'
3641 0, // '+'
3642 PQTD , // ','
3643 0, // '-'
3644 PQTD , // '.'
3645 0, // '/'
3646 0, // '0'
3647 0, // '1'
3648 0, // '2'
3649 0, // '3'
3650 0, // '4'
3651 0, // '5'
3652 0, // '6'
3653 0, // '7'
3654 0, // '8'
3655 0, // '9'
3656 PQTD , // ':'
3657 PQTD , // ';'
3658 PQTD , // '<'
3659 0, // '='
3660 PQTD , // '>'
3661 0, // '?'
3662 PQTD , // '@'
3663 0, // 'A'
3664 0, // 'B'
3665 0, // 'C'
3666 0, // 'D'
3667 0, // 'E'
3668 0, // 'F'
3669 0, // 'G'
3670 0, // 'H'
3671 0, // 'I'
3672 0, // 'J'
3673 0, // 'K'
3674 0, // 'L'
3675 0, // 'M'
3676 0, // 'N'
3677 0, // 'O'
3678 0, // 'P'
3679 0, // 'Q'
3680 0, // 'R'
3681 0, // 'S'
3682 0, // 'T'
3683 0, // 'U'
3684 0, // 'V'
3685 0, // 'W'
3686 0, // 'X'
3687 0, // 'Y'
3688 0, // 'Z'
3689 PQTD , // '['
3690 CENQ | PQTD , // '\'
3691 PQTD , // ']'
3692 0, // '^'
3693 0, // '_'
3694 0, // '`'
3695 0, // 'a'
3696 0, // 'b'
3697 0, // 'c'
3698 0, // 'd'
3699 0, // 'e'
3700 0, // 'f'
3701 0, // 'g'
3702 0, // 'h'
3703 0, // 'i'
3704 0, // 'j'
3705 0, // 'k'
3706 0, // 'l'
3707 0, // 'm'
3708 0, // 'n'
3709 0, // 'o'
3710 0, // 'p'
3711 0, // 'q'
3712 0, // 'r'
3713 0, // 's'
3714 0, // 't'
3715 0, // 'u'
3716 0, // 'v'
3717 0, // 'w'
3718 0, // 'x'
3719 0, // 'y'
3720 0, // 'z'
3721 0, // '{'
3722 0, // '|'
3723 0, // '}'
3724 0, // '~'
3725 TENQ | CENQ | PENQ }; // DEL
3726 Coding eNewCoding = !rtl::isAscii(nChar) ? CODING_ENCODED :
3727 m_eContext == CONTEXT_PHRASE ?
3728 Coding(aMinimal[nChar] >> 2) :
3729 aMinimal[nChar] & m_eContext ? CODING_ENCODED :
3730 CODING_NONE;
3731 if (eNewCoding > m_eCoding)
3732 m_eCoding = eNewCoding;
3733 if (m_eCoding == CODING_QUOTED
3734 && INetMIME::needsQuotedStringEscape(nChar))
3735 ++m_nQuotedEscaped;
3737 // Append to buffer:
3738 if (sal_uInt32(m_pBufferEnd - m_pBuffer) == m_nBufferSize)
3740 m_pBuffer
3741 = static_cast< sal_Unicode * >(
3742 rtl_reallocateMemory(m_pBuffer,
3743 (m_nBufferSize + BUFFER_SIZE)
3744 * sizeof (sal_Unicode)));
3745 m_pBufferEnd = m_pBuffer + m_nBufferSize;
3746 m_nBufferSize += BUFFER_SIZE;
3748 *m_pBufferEnd++ = sal_Unicode(nChar);
3750 return *this;
3753 // INetContentTypeParameterList
3755 void INetContentTypeParameterList::Clear()
3757 maEntries.clear();
3760 const INetContentTypeParameter *
3761 INetContentTypeParameterList::find(const OString& rAttribute) const
3763 boost::ptr_vector<INetContentTypeParameter>::const_iterator iter;
3764 for (iter = maEntries.begin(); iter != maEntries.end(); ++iter)
3766 if (iter->m_sAttribute.equalsIgnoreAsciiCase(rAttribute))
3767 return &(*iter);
3770 return NULL;
3773 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */