27#include <com/sun/star/io/IOException.hpp>
28#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
29#include <com/sun/star/lang/XServiceInfo.hpp>
30#include <com/sun/star/uno/XComponentContext.hpp>
31#include <com/sun/star/util/XCloneable.hpp>
32#include <com/sun/star/xml/sax/SAXInvalidCharacterException.hpp>
33#include <com/sun/star/xml/sax/XWriter.hpp>
40#include <osl/diagnose.h>
41#include <rtl/character.hxx>
45using namespace ::
cppu;
55#define SEQUENCESIZE 1024
56#define MAXCOLUMNCOUNT 72
68enum SaxInvalidCharacterError
81inline bool operator<(
const ReplacementPair& lhs,
const ReplacementPair& rhs)
83 return lhs.replacement.compareTo(rhs.replacement) < 0;
90 ::std::stack<OUString> m_DebugStartedElements;
94 Reference<XOutputStream> m_out;
95 Sequence<sal_Int8> m_Sequence;
98 sal_Int32 nLastLineFeedPos;
99 sal_uInt32 nCurrentPos;
100 bool m_bStartElementFinished;
102 std::vector<ReplacementPair> m_Replacements;
105 sal_uInt32 writeSequence();
114 bool convertToXML(
const sal_Unicode* pStr, sal_Int32 nStrLen,
bool bDoNormalization,
115 bool bNormalizeWhitespace,
sal_Int8* pTarget, sal_uInt32& rPos);
117 void FinishStartElement();
120 const ReplacementPair* findXMLReplacement(
const sal_Unicode* pStr, sal_Int32 nStrLen);
123 explicit SaxWriterHelper(Reference<XOutputStream>
const& m_TempOut)
126 , mp_Sequence(
nullptr)
127 , nLastLineFeedPos(0)
129 , m_bStartElementFinished(
true)
131 OSL_ENSURE(
SEQUENCESIZE > 50,
"Sequence cache size too small");
132 mp_Sequence = m_Sequence.getArray();
136 OSL_ENSURE(!nCurrentPos,
"cached Sequence not written");
137 OSL_ENSURE(m_bStartElementFinished,
"StartElement not completely written");
141 void insertIndentation(sal_uInt32
m_nLevel);
147 bool writeString(
const OUString& rWriteOutString,
bool bDoNormalization,
148 bool bNormalizeWhitespace);
150 sal_uInt32 GetLastColumnCount()
const noexcept
152 return static_cast<sal_uInt32
>(nCurrentPos - nLastLineFeedPos);
156 void startDocument();
162 SaxInvalidCharacterError startElement(
const OUString& rName,
163 const Reference<XAttributeList>& xAttribs);
165 bool FinishEmptyElement();
171 bool endElement(
const OUString& rName);
179 bool processingInstruction(
const OUString&
rTarget,
const OUString& rData);
189 bool comment(
const OUString& rComment);
195 void setCustomEntityNames(
196 const ::css::uno::Sequence<::css::beans::Pair<::rtl::OUString, ::rtl::OUString>>&
200 sal_Int32 calcXMLByteLength(
const OUString& rStr,
bool bDoNormalization,
201 bool bNormalizeWhitespace);
204const bool g_bValidCharsBelow32[32] = {
207 false,
false,
false,
false,
false,
false,
false,
false,
208 false,
true,
true,
false,
false,
true,
false,
false,
209 false,
false,
false,
false,
false,
false,
false,
false,
210 false,
false,
false,
false,
false,
false,
false,
false
218 if (aChar < 32 || aChar >= 0xd800)
219 bRet = ((aChar < 32 && !g_bValidCharsBelow32[aChar]) || aChar == 0xffff || aChar == 0xfffe);
227sal_uInt32 SaxWriterHelper::writeSequence()
231 m_out->writeBytes(m_Sequence);
236 throw SAXException(
"IO exception during writing", Reference<XInterface>(), anyEx);
242void SaxWriterHelper::AddBytes(
sal_Int8* pTarget, sal_uInt32& rPos,
const sal_Int8* pBytes,
247 memcpy(&(pTarget[rPos]), pBytes,
nCount);
251 rPos = writeSequence();
255 memcpy(&(pTarget[rPos]), &pBytes[
nCount], nRestCount);
259 AddBytes(pTarget, rPos, &pBytes[
nCount], nRestCount);
262void SaxWriterHelper::setCustomEntityNames(
263 const ::css::uno::Sequence<::css::beans::Pair<::rtl::OUString, ::rtl::OUString>>& replacements)
265 m_Replacements.resize(replacements.size());
266 for (
size_t i = 0;
i < replacements.size(); ++
i)
268 m_Replacements[
i].name = replacements[
i].First;
269 m_Replacements[
i].replacement = replacements[
i].Second;
271 if (replacements.size() > 1)
272 std::sort(m_Replacements.begin(), m_Replacements.end());
282bool SaxWriterHelper::convertToXML(
const sal_Unicode* pStr, sal_Int32 nStrLen,
283 bool bDoNormalization,
bool bNormalizeWhitespace,
284 sal_Int8* pTarget, sal_uInt32& rPos)
287 sal_uInt32 nSurrogate = 0;
289 for (sal_Int32
i = 0;
i < nStrLen;
i++)
292 if (IsInvalidChar(c))
294 else if ((c >= 0x0001) && (c <= 0x007F))
296 if (bDoNormalization)
303 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"&"), 5);
306 memcpy(&(pTarget[rPos]),
"&", 5);
314 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"<"), 4);
317 memcpy(&(pTarget[rPos]),
"<", 4);
325 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
">"), 4);
328 memcpy(&(pTarget[rPos]),
">", 4);
336 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"'"), 6);
339 memcpy(&(pTarget[rPos]),
"'", 6);
347 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"""), 6);
350 memcpy(&(pTarget[rPos]),
""", 6);
358 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"
"), 6);
361 memcpy(&(pTarget[rPos]),
"
", 6);
368 if (bNormalizeWhitespace)
371 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"
"),
375 memcpy(&(pTarget[rPos]),
"
", 6);
382 nLastLineFeedPos = rPos;
389 if (bNormalizeWhitespace)
392 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
"	"),
396 memcpy(&(pTarget[rPos]),
"	", 6);
409 pTarget[rPos] =
static_cast<sal_Int8>(c);
417 pTarget[rPos] =
static_cast<sal_Int8>(c);
419 nLastLineFeedPos = rPos;
426 if (bDoNormalization && !m_Replacements.empty())
429 const ReplacementPair* it = findXMLReplacement(&pStr[
i], nStrLen -
i);
434 OString
name = ::rtl::OUStringToOString(it->name, RTL_TEXTENCODING_UTF8);
436 AddBytes(pTarget, rPos,
reinterpret_cast<sal_Int8 const*
>(
name.getStr()),
440 memcpy(&(pTarget[rPos]),
name.getStr(),
name.getLength());
441 rPos +=
name.getLength();
443 i += it->replacement.getLength() - 1;
449 if (rtl::isHighSurrogate(c))
454 OSL_FAIL(
"left-over Unicode surrogate");
459 else if (rtl::isLowSurrogate(c))
464 nSurrogate = rtl::combineSurrogates(nSurrogate, c);
466 sal_Int8(0x80 | ((nSurrogate >> 12) & 0x3F)),
467 sal_Int8(0x80 | ((nSurrogate >> 6) & 0x3F)),
468 sal_Int8(0x80 | ((nSurrogate >> 0) & 0x3F)) };
470 AddBytes(pTarget, rPos, aBytes, 4);
473 pTarget[rPos] = aBytes[0];
475 pTarget[rPos] = aBytes[1];
477 pTarget[rPos] = aBytes[2];
479 pTarget[rPos] = aBytes[3];
485 OSL_FAIL(
"illegal Unicode character");
495 = {
sal_Int8(0xE0 | ((c >> 12) & 0x0F)),
sal_Int8(0x80 | ((c >> 6) & 0x3F)),
496 sal_Int8(0x80 | ((c >> 0) & 0x3F)) };
498 AddBytes(pTarget, rPos, aBytes, 3);
501 pTarget[rPos] = aBytes[0];
503 pTarget[rPos] = aBytes[1];
505 pTarget[rPos] = aBytes[2];
512 = {
sal_Int8(0xC0 | ((c >> 6) & 0x1F)),
sal_Int8(0x80 | ((c >> 0) & 0x3F)) };
514 AddBytes(pTarget, rPos, aBytes, 2);
517 pTarget[rPos] = aBytes[0];
519 pTarget[rPos] = aBytes[1];
525 OSL_ENSURE(rPos <=
SEQUENCESIZE,
"not reset current position");
527 rPos = writeSequence();
530 if ((nSurrogate != 0) && !rtl::isHighSurrogate(c))
532 OSL_FAIL(
"left-over Unicode surrogate");
539 OSL_FAIL(
"left-over Unicode surrogate");
545void SaxWriterHelper::FinishStartElement()
547 if (!m_bStartElementFinished)
549 mp_Sequence[nCurrentPos] =
'>';
552 nCurrentPos = writeSequence();
553 m_bStartElementFinished =
true;
557void SaxWriterHelper::insertIndentation(sal_uInt32
m_nLevel)
559 FinishStartElement();
564 mp_Sequence[nCurrentPos] =
LINEFEED;
565 nLastLineFeedPos = nCurrentPos;
567 memset(&(mp_Sequence[nCurrentPos]), 32,
m_nLevel);
570 nCurrentPos = writeSequence();
578 AddBytes(mp_Sequence, nCurrentPos, pBytes.get(),
nCount);
580 nLastLineFeedPos = nCurrentPos -
nCount;
582 nCurrentPos = writeSequence();
587 mp_Sequence[nCurrentPos] =
LINEFEED;
588 nLastLineFeedPos = nCurrentPos;
591 nCurrentPos = writeSequence();
595bool SaxWriterHelper::writeString(
const OUString& rWriteOutString,
bool bDoNormalization,
596 bool bNormalizeWhitespace)
598 FinishStartElement();
599 return convertToXML(rWriteOutString.getStr(), rWriteOutString.getLength(), bDoNormalization,
600 bNormalizeWhitespace, mp_Sequence, nCurrentPos);
603void SaxWriterHelper::startDocument()
605 const char pc[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
606 const int nLen = strlen(
pc);
609 memcpy(mp_Sequence,
pc, nLen);
614 AddBytes(mp_Sequence, nCurrentPos,
reinterpret_cast<sal_Int8 const*
>(
pc), nLen);
616 OSL_ENSURE(nCurrentPos <=
SEQUENCESIZE,
"not reset current position");
618 nCurrentPos = writeSequence();
619 mp_Sequence[nCurrentPos] =
LINEFEED;
622 nCurrentPos = writeSequence();
629void CheckValidName(OUString
const& rName)
634 assert(!rName.isEmpty());
635 bool hasColon(
false);
636 for (sal_Int32
i = 0;
i < rName.getLength(); ++
i)
638 auto const c(rName[
i]);
642 SAL_WARN_IF(hasColon,
"sax",
"only one colon allowed: " << rName);
643 assert(!hasColon &&
"only one colon allowed");
646 else if (!rtl::isAsciiAlphanumeric(c) && c !=
'_' && c !=
'-' && c !=
'.'
647 && !inrange(c, 0x00C0, 0x00D6) && !inrange(c, 0x00D8, 0x00F6)
648 && !inrange(c, 0x00F8, 0x02FF) && !inrange(c, 0x0370, 0x037D)
649 && !inrange(c, 0x037F, 0x1FFF) && !inrange(c, 0x200C, 0x200D)
650 && !inrange(c, 0x2070, 0x218F) && !inrange(c, 0x2C00, 0x2FEF)
651 && !inrange(c, 0x3001, 0xD7FF) && !inrange(c, 0xF900, 0xFDCF)
652 && !inrange(c, 0xFDF0, 0xFFFD) && c != 0x00B7 && !inrange(c, 0x0300, 0x036F)
653 && !inrange(c, 0x203F, 0x2040))
657 SAL_WARN(
"sax",
"unexpected character in attribute name: " << rName);
658 assert(!
"unexpected character in attribute name");
664SaxInvalidCharacterError SaxWriterHelper::startElement(
const OUString& rName,
665 const Reference<XAttributeList>& xAttribs)
667 FinishStartElement();
670 m_DebugStartedElements.push(rName);
671 ::std::set<OUString> DebugAttributes;
674 mp_Sequence[nCurrentPos] =
'<';
677 nCurrentPos = writeSequence();
679 SaxInvalidCharacterError eRet(SAX_NONE);
680 CheckValidName(rName);
684 sal_Int16 nAttribCount = xAttribs.is() ? xAttribs->getLength() : 0;
685 for (sal_Int16
i = 0;
i < nAttribCount;
i++)
687 mp_Sequence[nCurrentPos] =
' ';
690 nCurrentPos = writeSequence();
692 OUString
const& rAttrName(xAttribs->getNameByIndex(
i));
695 assert(DebugAttributes.find(rAttrName) == DebugAttributes.end());
696 DebugAttributes.insert(rAttrName);
698 CheckValidName(rAttrName);
702 mp_Sequence[nCurrentPos] =
'=';
705 nCurrentPos = writeSequence();
706 mp_Sequence[nCurrentPos] =
'"';
709 nCurrentPos = writeSequence();
711 if (!
writeString(xAttribs->getValueByIndex(
i),
true,
true) && eRet != SAX_ERROR)
714 mp_Sequence[nCurrentPos] =
'"';
717 nCurrentPos = writeSequence();
720 m_bStartElementFinished =
false;
726bool SaxWriterHelper::FinishEmptyElement()
728 if (m_bStartElementFinished)
731 mp_Sequence[nCurrentPos] =
'/';
734 nCurrentPos = writeSequence();
735 mp_Sequence[nCurrentPos] =
'>';
738 nCurrentPos = writeSequence();
740 m_bStartElementFinished =
true;
745bool SaxWriterHelper::endElement(
const OUString& rName)
747 FinishStartElement();
749 mp_Sequence[nCurrentPos] =
'<';
752 nCurrentPos = writeSequence();
753 mp_Sequence[nCurrentPos] =
'/';
756 nCurrentPos = writeSequence();
758 CheckValidName(rName);
761 mp_Sequence[nCurrentPos] =
'>';
764 nCurrentPos = writeSequence();
769void SaxWriterHelper::endDocument()
773 m_Sequence.realloc(nCurrentPos);
774 nCurrentPos = writeSequence();
779void SaxWriterHelper::clearBuffer()
781 FinishStartElement();
784 m_Sequence.realloc(nCurrentPos);
785 nCurrentPos = writeSequence();
788 mp_Sequence = m_Sequence.getArray();
792bool SaxWriterHelper::processingInstruction(
const OUString&
rTarget,
const OUString& rData)
794 FinishStartElement();
795 mp_Sequence[nCurrentPos] =
'<';
798 nCurrentPos = writeSequence();
799 mp_Sequence[nCurrentPos] =
'?';
802 nCurrentPos = writeSequence();
806 mp_Sequence[nCurrentPos] =
' ';
809 nCurrentPos = writeSequence();
814 mp_Sequence[nCurrentPos] =
'?';
817 nCurrentPos = writeSequence();
818 mp_Sequence[nCurrentPos] =
'>';
821 nCurrentPos = writeSequence();
826void SaxWriterHelper::startCDATA()
828 FinishStartElement();
831 memcpy(&(mp_Sequence[nCurrentPos]),
"<![CDATA[", 9);
835 AddBytes(mp_Sequence, nCurrentPos,
reinterpret_cast<sal_Int8 const*
>(
"<![CDATA["), 9);
837 nCurrentPos = writeSequence();
840void SaxWriterHelper::endCDATA()
842 FinishStartElement();
845 memcpy(&(mp_Sequence[nCurrentPos]),
"]]>", 3);
849 AddBytes(mp_Sequence, nCurrentPos,
reinterpret_cast<sal_Int8 const*
>(
"]]>"), 3);
851 nCurrentPos = writeSequence();
854bool SaxWriterHelper::comment(
const OUString& rComment)
856 FinishStartElement();
857 mp_Sequence[nCurrentPos] =
'<';
860 nCurrentPos = writeSequence();
861 mp_Sequence[nCurrentPos] =
'!';
864 nCurrentPos = writeSequence();
865 mp_Sequence[nCurrentPos] =
'-';
868 nCurrentPos = writeSequence();
869 mp_Sequence[nCurrentPos] =
'-';
872 nCurrentPos = writeSequence();
876 mp_Sequence[nCurrentPos] =
'-';
879 nCurrentPos = writeSequence();
880 mp_Sequence[nCurrentPos] =
'-';
883 nCurrentPos = writeSequence();
884 mp_Sequence[nCurrentPos] =
'>';
887 nCurrentPos = writeSequence();
892sal_Int32 SaxWriterHelper::calcXMLByteLength(
const OUString& rStr,
bool bDoNormalization,
893 bool bNormalizeWhitespace)
895 sal_Int32 nOutputLength = 0;
896 sal_uInt32 nSurrogate = 0;
899 sal_Int32 nStrLen = rStr.getLength();
900 for (sal_Int32
i = 0;
i < nStrLen;
i++)
902 sal_uInt16 c = pStr[
i];
903 if (!IsInvalidChar(c) && (c >= 0x0001) && (c <= 0x007F))
905 if (bDoNormalization)
924 if (bNormalizeWhitespace)
945 if (bDoNormalization && !m_Replacements.empty())
948 const ReplacementPair* it = findXMLReplacement(&pStr[
i], nStrLen -
i);
953 += ::rtl::OUStringToOString(it->name, RTL_TEXTENCODING_UTF8).getLength();
954 i += it->replacement.getLength() - 1;
960 if (rtl::isHighSurrogate(c))
965 else if (rtl::isLowSurrogate(c))
983 if ((nSurrogate != 0) && !rtl::isHighSurrogate(c))
987 return nOutputLength;
990const ReplacementPair* SaxWriterHelper::findXMLReplacement(
const sal_Unicode* pStr,
993 for (
size_t iter = 0; iter < m_Replacements.size(); ++iter)
995 if (m_Replacements[iter].replacement.getLength() > nStrLen)
997 sal_Int32 matches = m_Replacements[iter].replacement.compareTo(
998 std::u16string_view(pStr, m_Replacements[iter].replacement.getLength()));
1000 return &m_Replacements[iter];
1007class SAXWriter :
public WeakImplHelper<XWriter, XServiceInfo>
1011 : m_bDocStarted(
false)
1013 , m_bForceLineBreak(
false)
1014 , m_bAllowLineBreak(
false)
1020 virtual void SAL_CALL setOutputStream(
const Reference<XOutputStream>& aStream)
override
1025 if (m_out == aStream && m_pSaxWriterHelper && m_bDocStarted)
1026 m_pSaxWriterHelper->clearBuffer();
1030 m_pSaxWriterHelper.reset(
new SaxWriterHelper(m_out));
1031 m_bDocStarted =
false;
1036 catch (
const SAXException& e)
1038 throw css::lang::WrappedTargetRuntimeException(e.Message, getXWeak(),
1039 e.WrappedException);
1042 virtual Reference<XOutputStream> SAL_CALL
getOutputStream()
override {
return m_out; }
1045 virtual void SAL_CALL startDocument()
override;
1047 virtual void SAL_CALL endDocument()
override;
1049 virtual void SAL_CALL startElement(
const OUString&
aName,
1050 const Reference<XAttributeList>& xAttribs)
override;
1052 virtual void SAL_CALL endElement(
const OUString&
aName)
override;
1054 virtual void SAL_CALL characters(
const OUString& aChars)
override;
1056 virtual void SAL_CALL ignorableWhitespace(
const OUString& aWhitespaces)
override;
1057 virtual void SAL_CALL processingInstruction(
const OUString& aTarget,
1058 const OUString&
aData)
override;
1059 virtual void SAL_CALL setDocumentLocator(
const Reference<XLocator>& xLocator)
override;
1060 virtual void SAL_CALL setCustomEntityNames(
1061 const ::css::uno::Sequence<::css::beans::Pair<::rtl::OUString, ::rtl::OUString>>&
1062 replacements)
override;
1065 virtual void SAL_CALL startCDATA()
override;
1066 virtual void SAL_CALL endCDATA()
override;
1067 virtual void SAL_CALL comment(
const OUString& sComment)
override;
1068 virtual void SAL_CALL
unknown(
const OUString& sString)
override;
1069 virtual void SAL_CALL allowLineBreak()
override;
1077 sal_Int32 getIndentPrefixLength(sal_Int32 nFirstLineBreakOccurrence)
noexcept;
1079 Reference<XOutputStream> m_out;
1080 std::unique_ptr<SaxWriterHelper> m_pSaxWriterHelper;
1083 bool m_bDocStarted : 1;
1084 bool m_bIsCDATA : 1;
1085 bool m_bForceLineBreak : 1;
1086 bool m_bAllowLineBreak : 1;
1090sal_Int32 SAXWriter::getIndentPrefixLength(sal_Int32 nFirstLineBreakOccurrence)
noexcept
1093 if (m_pSaxWriterHelper)
1095 if (m_bForceLineBreak
1096 || (m_bAllowLineBreak
1097 && ((nFirstLineBreakOccurrence + m_pSaxWriterHelper->GetLastColumnCount())
1101 m_bForceLineBreak =
false;
1102 m_bAllowLineBreak =
false;
1106bool isFirstCharWhitespace(
const sal_Unicode*
p)
noexcept {
return *
p ==
' '; }
1109OUString SAXWriter::getImplementationName() {
return "com.sun.star.extensions.xml.sax.Writer"; }
1118Sequence<OUString> SAXWriter::getSupportedServiceNames()
1120 return {
"com.sun.star.xml.sax.Writer" };
1123void SAXWriter::startDocument()
1125 if (m_bDocStarted || !m_out.is() || !m_pSaxWriterHelper)
1127 throw SAXException();
1129 m_bDocStarted =
true;
1130 m_pSaxWriterHelper->startDocument();
1133void SAXWriter::endDocument()
1137 throw SAXException(
"endDocument called before startDocument", Reference<XInterface>(),
1142 throw SAXException(
"unexpected end of document", Reference<XInterface>(),
Any());
1144 m_pSaxWriterHelper->endDocument();
1147 m_out->closeOutput();
1152 throw SAXException(
"IO exception during closing the IO Stream", Reference<XInterface>(),
1157void SAXWriter::startElement(
const OUString&
aName,
const Reference<XAttributeList>& xAttribs)
1161 SAXException except;
1162 except.Message =
"startElement called before startDocument";
1167 SAXException except;
1168 except.Message =
"startElement call not allowed with CDATA sections";
1173 if (m_bAllowLineBreak)
1175 sal_Int32 nAttribCount = xAttribs.is() ? xAttribs->getLength() : 0;
1178 nLength += m_pSaxWriterHelper->calcXMLByteLength(
aName,
false,
false);
1181 for (
n = 0; n < static_cast<sal_Int16>(nAttribCount);
n++)
1184 OUString tmp = xAttribs->getNameByIndex(
n);
1186 nLength += m_pSaxWriterHelper->calcXMLByteLength(tmp,
false,
false);
1190 tmp = xAttribs->getValueByIndex(
n);
1192 nLength += m_pSaxWriterHelper->calcXMLByteLength(tmp,
true,
true);
1201 sal_Int32 nPrefix(getIndentPrefixLength(
nLength));
1205 m_pSaxWriterHelper->insertIndentation(nPrefix);
1207 SaxInvalidCharacterError eRet(m_pSaxWriterHelper->startElement(
aName, xAttribs));
1211 if (eRet == SAX_WARNING)
1213 SAXInvalidCharacterException except;
1214 except.Message =
"Invalid character during XML-Export in an attribute value";
1217 else if (eRet == SAX_ERROR)
1219 SAXException except;
1220 except.Message =
"Invalid character during XML-Export";
1225void SAXWriter::endElement(
const OUString&
aName)
1229 throw SAXException();
1235 throw SAXException();
1241 assert(!m_pSaxWriterHelper->m_DebugStartedElements.empty());
1243 assert(
aName == m_pSaxWriterHelper->m_DebugStartedElements.top());
1244 m_pSaxWriterHelper->m_DebugStartedElements.pop();
1247 if (m_pSaxWriterHelper->FinishEmptyElement())
1248 m_bForceLineBreak =
false;
1253 if (m_bAllowLineBreak)
1254 nLength = 3 + m_pSaxWriterHelper->calcXMLByteLength(
aName,
false,
false);
1255 sal_Int32 nPrefix = getIndentPrefixLength(
nLength);
1258 m_pSaxWriterHelper->insertIndentation(nPrefix);
1260 bRet = m_pSaxWriterHelper->endElement(
aName);
1265 SAXException except;
1266 except.Message =
"Invalid character during XML-Export";
1271void SAXWriter::characters(
const OUString& aChars)
1275 SAXException except;
1276 except.Message =
"characters method called before startDocument";
1280 bool bThrowException(
false);
1281 if (!aChars.isEmpty())
1284 bThrowException = !m_pSaxWriterHelper->writeString(aChars,
false,
false);
1291 sal_Int32 nIndentPrefix(-1);
1292 if (m_bAllowLineBreak)
1295 sal_Int32 nFirstLineBreakOccurrence = aChars.indexOf(
LINEFEED);
1297 nLength = m_pSaxWriterHelper->calcXMLByteLength(aChars, !m_bIsCDATA,
false);
1298 nIndentPrefix = getIndentPrefixLength(
1299 nFirstLineBreakOccurrence >= 0 ? nFirstLineBreakOccurrence :
nLength);
1302 nIndentPrefix = getIndentPrefixLength(
nLength);
1305 if (nIndentPrefix >= 0)
1307 if (isFirstCharWhitespace(aChars.getStr()))
1308 m_pSaxWriterHelper->insertIndentation(nIndentPrefix - 1);
1310 m_pSaxWriterHelper->insertIndentation(nIndentPrefix);
1312 bThrowException = !m_pSaxWriterHelper->writeString(aChars,
true,
false);
1315 if (bThrowException)
1317 SAXInvalidCharacterException except;
1318 except.Message =
"Invalid character during XML-Export";
1323void SAXWriter::ignorableWhitespace(
const OUString&)
1327 throw SAXException();
1330 m_bForceLineBreak =
true;
1333void SAXWriter::processingInstruction(
const OUString& aTarget,
const OUString&
aData)
1335 if (!m_bDocStarted || m_bIsCDATA)
1337 throw SAXException();
1341 if (m_bAllowLineBreak)
1344 nLength += m_pSaxWriterHelper->calcXMLByteLength(aTarget,
false,
false);
1348 nLength += m_pSaxWriterHelper->calcXMLByteLength(
aData,
false,
false);
1353 sal_Int32 nPrefix = getIndentPrefixLength(
nLength);
1356 m_pSaxWriterHelper->insertIndentation(nPrefix);
1358 if (!m_pSaxWriterHelper->processingInstruction(aTarget,
aData))
1360 SAXException except;
1361 except.Message =
"Invalid character during XML-Export";
1366void SAXWriter::setDocumentLocator(
const Reference<XLocator>&) {}
1368void SAXWriter::setCustomEntityNames(
1369 const ::css::uno::Sequence<::css::beans::Pair<::rtl::OUString, ::rtl::OUString>>& replacements)
1371 m_pSaxWriterHelper->setCustomEntityNames(replacements);
1374void SAXWriter::startCDATA()
1376 if (!m_bDocStarted || m_bIsCDATA)
1378 throw SAXException();
1381 sal_Int32 nPrefix = getIndentPrefixLength(9);
1383 m_pSaxWriterHelper->insertIndentation(nPrefix);
1385 m_pSaxWriterHelper->startCDATA();
1390void SAXWriter::endCDATA()
1392 if (!m_bDocStarted || !m_bIsCDATA)
1394 SAXException except;
1395 except.Message =
"endCDATA was called without startCDATA";
1399 sal_Int32 nPrefix = getIndentPrefixLength(3);
1401 m_pSaxWriterHelper->insertIndentation(nPrefix);
1403 m_pSaxWriterHelper->endCDATA();
1408void SAXWriter::comment(
const OUString& sComment)
1410 if (!m_bDocStarted || m_bIsCDATA)
1412 throw SAXException();
1416 if (m_bAllowLineBreak)
1419 nLength += m_pSaxWriterHelper->calcXMLByteLength(sComment,
false,
false);
1424 sal_Int32 nPrefix = getIndentPrefixLength(
nLength);
1426 m_pSaxWriterHelper->insertIndentation(nPrefix);
1428 if (!m_pSaxWriterHelper->comment(sComment))
1430 SAXException except;
1431 except.Message =
"Invalid character during XML-Export";
1436void SAXWriter::allowLineBreak()
1438 if (!m_bDocStarted || m_bAllowLineBreak)
1440 throw SAXException();
1443 m_bAllowLineBreak =
true;
1446void SAXWriter::unknown(
const OUString& sString)
1450 throw SAXException();
1454 throw SAXException();
1457 if (sString.startsWith(
"<?xml"))
1461 if (m_bAllowLineBreak)
1462 nLength = m_pSaxWriterHelper->calcXMLByteLength(sString,
false,
false);
1464 sal_Int32 nPrefix = getIndentPrefixLength(
nLength);
1466 m_pSaxWriterHelper->insertIndentation(nPrefix);
1468 if (!m_pSaxWriterHelper->writeString(sString,
false,
false))
1470 SAXException except;
1471 except.Message =
"Invalid character during XML-Export";
1478extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1480 css::uno::Sequence<css::uno::Any>
const&)
1482 return cppu::acquire(
new SAXWriter);
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
constexpr OUStringLiteral aData
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
Any SAL_CALL getCaughtException()
bool getOutputStream(ProgramOptions const &options, OString const &extension, std::ostream **ppOutputStream, OString &targetSourceFileName, OString &tmpSourceFileName)
sal_uInt32 writeString(sal_uInt8 *buffer, const sal_Unicode *v)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_extensions_xml_sax_Writer_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
bool operator<(const wwFont &r1, const wwFont &r2)
const sal_Int32 nBytesCount