File: | home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx |
Warning: | line 145, column 22 Array access (from variable 'pStr') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
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/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
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 . | |||
18 | */ | |||
19 | ||||
20 | #include "fastserializer.hxx" | |||
21 | ||||
22 | #include <com/sun/star/xml/sax/FastTokenHandler.hpp> | |||
23 | #include <rtl/math.h> | |||
24 | #include <sal/log.hxx> | |||
25 | #include <comphelper/processfactory.hxx> | |||
26 | #include <comphelper/sequence.hxx> | |||
27 | ||||
28 | #include <string.h> | |||
29 | ||||
30 | #if OSL_DEBUG_LEVEL1 > 0 | |||
31 | #include <iostream> | |||
32 | #include <set> | |||
33 | #endif | |||
34 | ||||
35 | using ::std::vector; | |||
36 | using ::com::sun::star::uno::Sequence; | |||
37 | using ::com::sun::star::io::XOutputStream; | |||
38 | ||||
39 | #define HAS_NAMESPACE(x)((x & 0xffff0000) != 0) ((x & 0xffff0000) != 0) | |||
40 | #define NAMESPACE(x)(x >> 16) (x >> 16) | |||
41 | #define TOKEN(x)(x & 0xffff) (x & 0xffff) | |||
42 | // number of characters without terminating 0 | |||
43 | #define N_CHARS(string)((sizeof(sal_n_array_size(string))) - 1) (SAL_N_ELEMENTS(string)(sizeof(sal_n_array_size(string))) - 1) | |||
44 | ||||
45 | const char sClosingBracket[] = ">"; | |||
46 | const char sSlashAndClosingBracket[] = "/>"; | |||
47 | const char sColon[] = ":"; | |||
48 | const char sOpeningBracket[] = "<"; | |||
49 | const char sOpeningBracketAndSlash[] = "</"; | |||
50 | const char sQuote[] = "\""; | |||
51 | const char sEqualSignAndQuote[] = "=\""; | |||
52 | const char sSpace[] = " "; | |||
53 | const char sXmlHeader[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"; | |||
54 | ||||
55 | namespace sax_fastparser { | |||
56 | FastSaxSerializer::FastSaxSerializer( const css::uno::Reference< css::io::XOutputStream >& xOutputStream ) | |||
57 | : maCachedOutputStream() | |||
58 | , maMarkStack() | |||
59 | , mbMarkStackEmpty(true) | |||
60 | , mpDoubleStr(nullptr) | |||
61 | , mnDoubleStrCapacity(RTL_STR_MAX_VALUEOFDOUBLE25) | |||
62 | , mbXescape(true) | |||
63 | { | |||
64 | rtl_string_new_WithLength(&mpDoubleStr, mnDoubleStrCapacity); | |||
65 | mxFastTokenHandler = css::xml::sax::FastTokenHandler::create( | |||
66 | ::comphelper::getProcessComponentContext()); | |||
67 | assert(xOutputStream.is())(static_cast <bool> (xOutputStream.is()) ? void (0) : __assert_fail ("xOutputStream.is()", "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 67, __extension__ __PRETTY_FUNCTION__)); // cannot do anything without that | |||
68 | maCachedOutputStream.setOutputStream( xOutputStream ); | |||
69 | } | |||
70 | ||||
71 | FastSaxSerializer::~FastSaxSerializer() | |||
72 | { | |||
73 | rtl_string_release(mpDoubleStr); | |||
74 | } | |||
75 | ||||
76 | void FastSaxSerializer::startDocument() | |||
77 | { | |||
78 | writeBytes(sXmlHeader, N_CHARS(sXmlHeader)((sizeof(sal_n_array_size(sXmlHeader))) - 1)); | |||
79 | } | |||
80 | ||||
81 | void FastSaxSerializer::write( double value ) | |||
82 | { | |||
83 | rtl_math_doubleToString( | |||
84 | &mpDoubleStr, &mnDoubleStrCapacity, 0, value, rtl_math_StringFormat_G, | |||
85 | RTL_STR_MAX_VALUEOFDOUBLE25 - RTL_CONSTASCII_LENGTH("-x.E-xxx")((sal_Int32)((sizeof(sal_n_array_size("-x.E-xxx")))-1)), '.', nullptr, | |||
86 | 0, true); | |||
87 | ||||
88 | write(mpDoubleStr->buffer, mpDoubleStr->length); | |||
89 | // and "clear" the string | |||
90 | mpDoubleStr->length = 0; | |||
91 | mnDoubleStrCapacity = RTL_STR_MAX_VALUEOFDOUBLE25; | |||
92 | } | |||
93 | ||||
94 | void FastSaxSerializer::write( const OUString& sOutput, bool bEscape ) | |||
95 | { | |||
96 | write( OUStringToOString(sOutput, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))), bEscape ); | |||
97 | ||||
98 | } | |||
99 | ||||
100 | void FastSaxSerializer::write( const OString& sOutput, bool bEscape ) | |||
101 | { | |||
102 | write( sOutput.getStr(), sOutput.getLength(), bEscape ); | |||
103 | } | |||
104 | ||||
105 | /** Characters not allowed in XML 1.0 | |||
106 | XML 1.1 would exclude only U+0000 | |||
107 | */ | |||
108 | static bool invalidChar( char c ) | |||
109 | { | |||
110 | if (static_cast<unsigned char>(c) >= 0x20) | |||
111 | return false; | |||
112 | ||||
113 | switch (c) | |||
114 | { | |||
115 | case 0x09: | |||
116 | case 0x0a: | |||
117 | case 0x0d: | |||
118 | return false; | |||
119 | } | |||
120 | return true; | |||
121 | } | |||
122 | ||||
123 | static bool isHexDigit( char c ) | |||
124 | { | |||
125 | return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'); | |||
126 | } | |||
127 | ||||
128 | void FastSaxSerializer::write( const char* pStr, sal_Int32 nLen, bool bEscape ) | |||
129 | { | |||
130 | if (nLen == -1) | |||
131 | nLen = pStr ? strlen(pStr) : 0; | |||
132 | ||||
133 | if (!bEscape
| |||
134 | { | |||
135 | writeBytes( pStr, nLen ); | |||
136 | return; | |||
137 | } | |||
138 | ||||
139 | bool bGood = true; | |||
140 | const sal_Int32 kXescapeLen = 7; | |||
141 | char bufXescape[kXescapeLen+1]; | |||
142 | sal_Int32 nNextXescape = 0; | |||
143 | for (sal_Int32 i = 0; i < nLen; ++i) | |||
144 | { | |||
145 | char c = pStr[ i ]; | |||
| ||||
146 | switch( c ) | |||
147 | { | |||
148 | case '<': writeBytes( "<", 4 ); break; | |||
149 | case '>': writeBytes( ">", 4 ); break; | |||
150 | case '&': writeBytes( "&", 5 ); break; | |||
151 | case '\'': writeBytes( "'", 6 ); break; | |||
152 | case '"': writeBytes( """, 6 ); break; | |||
153 | case '\t': | |||
154 | #if 0 | |||
155 | // Seems OOXML prefers the _xHHHH_ escape over the | |||
156 | // entity in *some* cases, apparently in attribute | |||
157 | // values but not in element data. | |||
158 | // Would need to distinguish at a higher level. | |||
159 | if (mbXescape) | |||
160 | { | |||
161 | snprintf( bufXescape, kXescapeLen+1, "_x%04x_", | |||
162 | static_cast<unsigned int>(static_cast<unsigned char>(c))); | |||
163 | writeBytes( bufXescape, kXescapeLen); | |||
164 | } | |||
165 | else | |||
166 | #endif | |||
167 | { | |||
168 | writeBytes( "	", 4 ); | |||
169 | } | |||
170 | break; | |||
171 | case '\n': | |||
172 | #if 0 | |||
173 | if (mbXescape) | |||
174 | { | |||
175 | snprintf( bufXescape, kXescapeLen+1, "_x%04x_", | |||
176 | static_cast<unsigned int>(static_cast<unsigned char>(c))); | |||
177 | writeBytes( bufXescape, kXescapeLen); | |||
178 | } | |||
179 | else | |||
180 | #endif | |||
181 | { | |||
182 | writeBytes( " ", 5 ); | |||
183 | } | |||
184 | break; | |||
185 | case '\r': | |||
186 | #if 0 | |||
187 | if (mbXescape) | |||
188 | { | |||
189 | snprintf( bufXescape, kXescapeLen+1, "_x%04x_", | |||
190 | static_cast<unsigned int>(static_cast<unsigned char>(c))); | |||
191 | writeBytes( bufXescape, kXescapeLen); | |||
192 | } | |||
193 | else | |||
194 | #endif | |||
195 | { | |||
196 | writeBytes( " ", 5 ); | |||
197 | } | |||
198 | break; | |||
199 | default: | |||
200 | if (mbXescape) | |||
201 | { | |||
202 | char c1, c2, c3, c4; | |||
203 | // Escape characters not valid in XML 1.0 as | |||
204 | // _xHHHH_. A literal "_xHHHH_" has to be | |||
205 | // escaped as _x005F_xHHHH_ (effectively | |||
206 | // escaping the leading '_'). | |||
207 | // See ECMA-376-1:2016 page 3736, | |||
208 | // 22.4.2.4 bstr (Basic String) | |||
209 | // for reference. | |||
210 | if (c == '_' && i >= nNextXescape && i <= nLen - kXescapeLen && | |||
211 | pStr[i+6] == '_' && | |||
212 | ((pStr[i+1] | 0x20) == 'x') && | |||
213 | isHexDigit( c1 = pStr[i+2] ) && | |||
214 | isHexDigit( c2 = pStr[i+3] ) && | |||
215 | isHexDigit( c3 = pStr[i+4] ) && | |||
216 | isHexDigit( c4 = pStr[i+5] )) | |||
217 | { | |||
218 | // OOXML has the odd habit to write some | |||
219 | // names using this that when re-saving | |||
220 | // should *not* be escaped, specifically | |||
221 | // _x0020_ for blanks in w:xpath values. | |||
222 | if (!(c1 == '0' && c2 == '0' && c3 == '2' && c4 == '0')) | |||
223 | { | |||
224 | // When encountering "_x005F_xHHHH_" | |||
225 | // assume that is an already escaped | |||
226 | // sequence that was not unescaped and | |||
227 | // shall be written as is, to not end | |||
228 | // up with "_x005F_x005F_xHHHH_" and | |||
229 | // repeated... | |||
230 | if (c1 == '0' && c2 == '0' && c3 == '5' && (c4 | 0x20) == 'f' && | |||
231 | i + kXescapeLen <= nLen - 6 && | |||
232 | pStr[i+kXescapeLen+5] == '_' && | |||
233 | ((pStr[i+kXescapeLen+0] | 0x20) == 'x') && | |||
234 | isHexDigit( pStr[i+kXescapeLen+1] ) && | |||
235 | isHexDigit( pStr[i+kXescapeLen+2] ) && | |||
236 | isHexDigit( pStr[i+kXescapeLen+3] ) && | |||
237 | isHexDigit( pStr[i+kXescapeLen+4] )) | |||
238 | { | |||
239 | writeBytes( &c, 1 ); | |||
240 | // Remember this fake escapement. | |||
241 | nNextXescape = i + kXescapeLen + 6; | |||
242 | } | |||
243 | else | |||
244 | { | |||
245 | writeBytes( "_x005F_", kXescapeLen); | |||
246 | // Remember this escapement so in | |||
247 | // _xHHHH_xHHHH_ only the first '_' | |||
248 | // is escaped. | |||
249 | nNextXescape = i + kXescapeLen; | |||
250 | } | |||
251 | break; | |||
252 | } | |||
253 | } | |||
254 | if (invalidChar(c)) | |||
255 | { | |||
256 | snprintf( bufXescape, kXescapeLen+1, "_x%04x_", | |||
257 | static_cast<unsigned int>(static_cast<unsigned char>(c))); | |||
258 | writeBytes( bufXescape, kXescapeLen); | |||
259 | break; | |||
260 | } | |||
261 | /* TODO: also U+FFFE and U+FFFF are not allowed | |||
262 | * in XML 1.0, assuming we're writing UTF-8 | |||
263 | * those should be escaped as well to be | |||
264 | * conformant. Likely that would involve | |||
265 | * scanning for both encoded sequences and | |||
266 | * write as _xHHHH_? */ | |||
267 | } | |||
268 | #if OSL_DEBUG_LEVEL1 > 0 | |||
269 | else | |||
270 | { | |||
271 | if (bGood && invalidChar(pStr[i])) | |||
272 | { | |||
273 | bGood = false; | |||
274 | // The SAL_WARN() for the single character is | |||
275 | // issued in writeBytes(), just gather for the | |||
276 | // SAL_WARN_IF() below. | |||
277 | } | |||
278 | } | |||
279 | #endif | |||
280 | writeBytes( &c, 1 ); | |||
281 | break; | |||
282 | } | |||
283 | } | |||
284 | SAL_WARN_IF( !bGood && nLen > 1, "sax", "in '" << OString(pStr,std::min<sal_Int32>(nLen,42)) << "'")do { if (true && (!bGood && nLen > 1)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "sax")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "in '" << OString(pStr,std::min<sal_Int32 >(nLen,42)) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "284" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "in '" << OString(pStr,std::min< sal_Int32>(nLen,42)) << "'"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "in '" << OString(pStr,std::min<sal_Int32>(nLen,42)) << "'" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "284" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "in '" << OString(pStr,std::min<sal_Int32 >(nLen,42)) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "284" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "in '" << OString(pStr,std::min< sal_Int32>(nLen,42)) << "'"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "in '" << OString(pStr,std::min<sal_Int32>(nLen,42)) << "'" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "284" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
285 | } | |||
286 | ||||
287 | void FastSaxSerializer::endDocument() | |||
288 | { | |||
289 | assert(mbMarkStackEmpty && maMarkStack.empty())(static_cast <bool> (mbMarkStackEmpty && maMarkStack .empty()) ? void (0) : __assert_fail ("mbMarkStackEmpty && maMarkStack.empty()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 289, __extension__ __PRETTY_FUNCTION__)); | |||
290 | maCachedOutputStream.flush(); | |||
291 | } | |||
292 | ||||
293 | void FastSaxSerializer::writeId( ::sal_Int32 nElement ) | |||
294 | { | |||
295 | if( HAS_NAMESPACE( nElement )((nElement & 0xffff0000) != 0) ) { | |||
296 | auto const Namespace(mxFastTokenHandler->getUTF8Identifier(NAMESPACE(nElement)(nElement >> 16))); | |||
297 | assert(Namespace.hasElements())(static_cast <bool> (Namespace.hasElements()) ? void (0 ) : __assert_fail ("Namespace.hasElements()", "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 297, __extension__ __PRETTY_FUNCTION__)); | |||
298 | writeBytes(Namespace); | |||
299 | writeBytes(sColon, N_CHARS(sColon)((sizeof(sal_n_array_size(sColon))) - 1)); | |||
300 | auto const Element(mxFastTokenHandler->getUTF8Identifier(TOKEN(nElement)(nElement & 0xffff))); | |||
301 | assert(Element.hasElements())(static_cast <bool> (Element.hasElements()) ? void (0) : __assert_fail ("Element.hasElements()", "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 301, __extension__ __PRETTY_FUNCTION__)); | |||
302 | writeBytes(Element); | |||
303 | } else { | |||
304 | auto const Element(mxFastTokenHandler->getUTF8Identifier(nElement)); | |||
305 | assert(Element.hasElements())(static_cast <bool> (Element.hasElements()) ? void (0) : __assert_fail ("Element.hasElements()", "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 305, __extension__ __PRETTY_FUNCTION__)); | |||
306 | writeBytes(Element); | |||
307 | } | |||
308 | } | |||
309 | ||||
310 | #ifdef DBG_UTIL | |||
311 | OString FastSaxSerializer::getId( ::sal_Int32 nElement ) | |||
312 | { | |||
313 | if (HAS_NAMESPACE(nElement)((nElement & 0xffff0000) != 0)) { | |||
314 | Sequence<sal_Int8> const ns( | |||
315 | mxFastTokenHandler->getUTF8Identifier(NAMESPACE(nElement)(nElement >> 16))); | |||
316 | Sequence<sal_Int8> const name( | |||
317 | mxFastTokenHandler->getUTF8Identifier(TOKEN(nElement)(nElement & 0xffff))); | |||
318 | return OString(reinterpret_cast<char const*>(ns.getConstArray()), ns.getLength()) | |||
319 | + OString(sColon, N_CHARS(sColon)((sizeof(sal_n_array_size(sColon))) - 1)) | |||
320 | + OString(reinterpret_cast<char const*>(name.getConstArray()), name.getLength()); | |||
321 | } else { | |||
322 | Sequence<sal_Int8> const name( | |||
323 | mxFastTokenHandler->getUTF8Identifier(nElement)); | |||
324 | return OString(reinterpret_cast<char const*>(name.getConstArray()), name.getLength()); | |||
325 | } | |||
326 | } | |||
327 | #endif | |||
328 | ||||
329 | void FastSaxSerializer::startFastElement( ::sal_Int32 Element, FastAttributeList const * pAttrList ) | |||
330 | { | |||
331 | if ( !mbMarkStackEmpty ) | |||
332 | { | |||
333 | maCachedOutputStream.flush(); | |||
334 | maMarkStack.top()->setCurrentElement( Element ); | |||
335 | } | |||
336 | ||||
337 | #ifdef DBG_UTIL | |||
338 | if (mbMarkStackEmpty) | |||
339 | m_DebugStartedElements.push(Element); | |||
340 | else | |||
341 | maMarkStack.top()->m_DebugStartedElements.push_back(Element); | |||
342 | #endif | |||
343 | ||||
344 | writeBytes(sOpeningBracket, N_CHARS(sOpeningBracket)((sizeof(sal_n_array_size(sOpeningBracket))) - 1)); | |||
345 | ||||
346 | writeId(Element); | |||
347 | if (pAttrList) | |||
348 | writeFastAttributeList(*pAttrList); | |||
349 | else | |||
350 | writeTokenValueList(); | |||
351 | ||||
352 | writeBytes(sClosingBracket, N_CHARS(sClosingBracket)((sizeof(sal_n_array_size(sClosingBracket))) - 1)); | |||
353 | } | |||
354 | ||||
355 | void FastSaxSerializer::endFastElement( ::sal_Int32 Element ) | |||
356 | { | |||
357 | #ifdef DBG_UTIL | |||
358 | // Well-formedness constraint: Element Type Match | |||
359 | if (mbMarkStackEmpty) | |||
360 | { | |||
361 | assert(!m_DebugStartedElements.empty())(static_cast <bool> (!m_DebugStartedElements.empty()) ? void (0) : __assert_fail ("!m_DebugStartedElements.empty()", "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 361, __extension__ __PRETTY_FUNCTION__)); | |||
362 | assert(Element == m_DebugStartedElements.top())(static_cast <bool> (Element == m_DebugStartedElements. top()) ? void (0) : __assert_fail ("Element == m_DebugStartedElements.top()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 362, __extension__ __PRETTY_FUNCTION__)); | |||
363 | m_DebugStartedElements.pop(); | |||
364 | } | |||
365 | else | |||
366 | { | |||
367 | if (dynamic_cast<ForSort*>(maMarkStack.top().get())) | |||
368 | { | |||
369 | // Sort is always well-formed fragment | |||
370 | assert(!maMarkStack.top()->m_DebugStartedElements.empty())(static_cast <bool> (!maMarkStack.top()->m_DebugStartedElements .empty()) ? void (0) : __assert_fail ("!maMarkStack.top()->m_DebugStartedElements.empty()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 370, __extension__ __PRETTY_FUNCTION__)); | |||
371 | } | |||
372 | if (maMarkStack.top()->m_DebugStartedElements.empty()) | |||
373 | { | |||
374 | maMarkStack.top()->m_DebugEndedElements.push_back(Element); | |||
375 | } | |||
376 | else | |||
377 | { | |||
378 | assert(Element == maMarkStack.top()->m_DebugStartedElements.back())(static_cast <bool> (Element == maMarkStack.top()->m_DebugStartedElements .back()) ? void (0) : __assert_fail ("Element == maMarkStack.top()->m_DebugStartedElements.back()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 378, __extension__ __PRETTY_FUNCTION__)); | |||
379 | maMarkStack.top()->m_DebugStartedElements.pop_back(); | |||
380 | } | |||
381 | } | |||
382 | #endif | |||
383 | ||||
384 | writeBytes(sOpeningBracketAndSlash, N_CHARS(sOpeningBracketAndSlash)((sizeof(sal_n_array_size(sOpeningBracketAndSlash))) - 1)); | |||
385 | ||||
386 | writeId(Element); | |||
387 | ||||
388 | writeBytes(sClosingBracket, N_CHARS(sClosingBracket)((sizeof(sal_n_array_size(sClosingBracket))) - 1)); | |||
389 | } | |||
390 | ||||
391 | void FastSaxSerializer::singleFastElement( ::sal_Int32 Element, FastAttributeList const * pAttrList ) | |||
392 | { | |||
393 | if ( !mbMarkStackEmpty ) | |||
| ||||
394 | { | |||
395 | maCachedOutputStream.flush(); | |||
396 | maMarkStack.top()->setCurrentElement( Element ); | |||
397 | } | |||
398 | ||||
399 | writeBytes(sOpeningBracket, N_CHARS(sOpeningBracket)((sizeof(sal_n_array_size(sOpeningBracket))) - 1)); | |||
400 | ||||
401 | writeId(Element); | |||
402 | if (pAttrList) | |||
403 | writeFastAttributeList(*pAttrList); | |||
404 | else | |||
405 | writeTokenValueList(); | |||
406 | ||||
407 | writeBytes(sSlashAndClosingBracket, N_CHARS(sSlashAndClosingBracket)((sizeof(sal_n_array_size(sSlashAndClosingBracket))) - 1)); | |||
408 | } | |||
409 | ||||
410 | css::uno::Reference< css::io::XOutputStream > const & FastSaxSerializer::getOutputStream() const | |||
411 | { | |||
412 | return maCachedOutputStream.getOutputStream(); | |||
413 | } | |||
414 | ||||
415 | void FastSaxSerializer::writeTokenValueList() | |||
416 | { | |||
417 | #ifdef DBG_UTIL | |||
418 | ::std::set<OString> DebugAttributes; | |||
419 | #endif | |||
420 | for (const TokenValue & rTokenValue : maTokenValues) | |||
421 | { | |||
422 | writeBytes(sSpace, N_CHARS(sSpace)((sizeof(sal_n_array_size(sSpace))) - 1)); | |||
423 | ||||
424 | sal_Int32 nToken = rTokenValue.nToken; | |||
425 | writeId(nToken); | |||
426 | ||||
427 | #ifdef DBG_UTIL | |||
428 | // Well-formedness constraint: Unique Att Spec | |||
429 | OString const nameId(getId(nToken)); | |||
430 | assert(DebugAttributes.find(nameId) == DebugAttributes.end())(static_cast <bool> (DebugAttributes.find(nameId) == DebugAttributes .end()) ? void (0) : __assert_fail ("DebugAttributes.find(nameId) == DebugAttributes.end()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 430, __extension__ __PRETTY_FUNCTION__)); | |||
431 | DebugAttributes.insert(nameId); | |||
432 | #endif | |||
433 | ||||
434 | writeBytes(sEqualSignAndQuote, N_CHARS(sEqualSignAndQuote)((sizeof(sal_n_array_size(sEqualSignAndQuote))) - 1)); | |||
435 | ||||
436 | write(rTokenValue.pValue, -1, true); | |||
437 | ||||
438 | writeBytes(sQuote, N_CHARS(sQuote)((sizeof(sal_n_array_size(sQuote))) - 1)); | |||
439 | } | |||
440 | maTokenValues.clear(); | |||
441 | } | |||
442 | ||||
443 | void FastSaxSerializer::writeFastAttributeList(FastAttributeList const & rAttrList) | |||
444 | { | |||
445 | #ifdef DBG_UTIL | |||
446 | ::std::set<OString> DebugAttributes; | |||
447 | #endif | |||
448 | const std::vector< sal_Int32 >& Tokens = rAttrList.getFastAttributeTokens(); | |||
449 | for (size_t j = 0; j < Tokens.size(); j++) | |||
450 | { | |||
451 | writeBytes(sSpace, N_CHARS(sSpace)((sizeof(sal_n_array_size(sSpace))) - 1)); | |||
452 | ||||
453 | sal_Int32 nToken = Tokens[j]; | |||
454 | writeId(nToken); | |||
455 | ||||
456 | #ifdef DBG_UTIL | |||
457 | // Well-formedness constraint: Unique Att Spec | |||
458 | OString const nameId(getId(nToken)); | |||
459 | SAL_WARN_IF(DebugAttributes.find(nameId) != DebugAttributes.end(), "sax", "Duplicate attribute: " << nameId )do { if (true && (DebugAttributes.find(nameId) != DebugAttributes .end())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sax")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Duplicate attribute: " << nameId) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "459" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Duplicate attribute: " << nameId ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Duplicate attribute: " << nameId; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "459" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Duplicate attribute: " << nameId) == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "459" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Duplicate attribute: " << nameId ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Duplicate attribute: " << nameId; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "459" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
460 | assert(DebugAttributes.find(nameId) == DebugAttributes.end())(static_cast <bool> (DebugAttributes.find(nameId) == DebugAttributes .end()) ? void (0) : __assert_fail ("DebugAttributes.find(nameId) == DebugAttributes.end()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 460, __extension__ __PRETTY_FUNCTION__)); | |||
461 | DebugAttributes.insert(nameId); | |||
462 | #endif | |||
463 | ||||
464 | writeBytes(sEqualSignAndQuote, N_CHARS(sEqualSignAndQuote)((sizeof(sal_n_array_size(sEqualSignAndQuote))) - 1)); | |||
465 | ||||
466 | const char* pAttributeValue = rAttrList.getFastAttributeValue(j); | |||
467 | ||||
468 | // tdf#127274 don't escape the special VML shape type id "#_x0000_t202" | |||
469 | bool bEscape = !(pAttributeValue && strcmp(pAttributeValue, "#_x0000_t202") == 0); | |||
470 | ||||
471 | write(pAttributeValue, rAttrList.AttributeValueLength(j), bEscape); | |||
472 | ||||
473 | writeBytes(sQuote, N_CHARS(sQuote)((sizeof(sal_n_array_size(sQuote))) - 1)); | |||
474 | } | |||
475 | } | |||
476 | ||||
477 | void FastSaxSerializer::mark(sal_Int32 const nTag, const Int32Sequence& rOrder) | |||
478 | { | |||
479 | if (rOrder.hasElements()) | |||
480 | { | |||
481 | auto pSort = std::make_shared<ForSort>(nTag, rOrder); | |||
482 | maMarkStack.push( pSort ); | |||
483 | maCachedOutputStream.setOutput( pSort ); | |||
484 | } | |||
485 | else | |||
486 | { | |||
487 | auto pMerge = std::make_shared<ForMerge>(nTag); | |||
488 | maMarkStack.push( pMerge ); | |||
489 | maCachedOutputStream.setOutput( pMerge ); | |||
490 | } | |||
491 | mbMarkStackEmpty = false; | |||
492 | } | |||
493 | ||||
494 | #ifdef DBG_UTIL | |||
495 | static void lcl_DebugMergeAppend( | |||
496 | std::deque<sal_Int32> & rLeftEndedElements, | |||
497 | std::deque<sal_Int32> & rLeftStartedElements, | |||
498 | std::deque<sal_Int32> & rRightEndedElements, | |||
499 | std::deque<sal_Int32> & rRightStartedElements) | |||
500 | { | |||
501 | while (!rRightEndedElements.empty()) | |||
502 | { | |||
503 | if (rLeftStartedElements.empty()) | |||
504 | { | |||
505 | rLeftEndedElements.push_back(rRightEndedElements.front()); | |||
506 | } | |||
507 | else | |||
508 | { | |||
509 | assert(rLeftStartedElements.back() == rRightEndedElements.front())(static_cast <bool> (rLeftStartedElements.back() == rRightEndedElements .front()) ? void (0) : __assert_fail ("rLeftStartedElements.back() == rRightEndedElements.front()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 509, __extension__ __PRETTY_FUNCTION__)); | |||
510 | rLeftStartedElements.pop_back(); | |||
511 | } | |||
512 | rRightEndedElements.pop_front(); | |||
513 | } | |||
514 | while (!rRightStartedElements.empty()) | |||
515 | { | |||
516 | rLeftStartedElements.push_back(rRightStartedElements.front()); | |||
517 | rRightStartedElements.pop_front(); | |||
518 | } | |||
519 | } | |||
520 | ||||
521 | static void lcl_DebugMergePrepend( | |||
522 | std::deque<sal_Int32> & rLeftEndedElements, | |||
523 | std::deque<sal_Int32> & rLeftStartedElements, | |||
524 | std::deque<sal_Int32> & rRightEndedElements, | |||
525 | std::deque<sal_Int32> & rRightStartedElements) | |||
526 | { | |||
527 | while (!rLeftStartedElements.empty()) | |||
528 | { | |||
529 | if (rRightEndedElements.empty()) | |||
530 | { | |||
531 | rRightStartedElements.push_front(rLeftStartedElements.back()); | |||
532 | } | |||
533 | else | |||
534 | { | |||
535 | assert(rRightEndedElements.front() == rLeftStartedElements.back())(static_cast <bool> (rRightEndedElements.front() == rLeftStartedElements .back()) ? void (0) : __assert_fail ("rRightEndedElements.front() == rLeftStartedElements.back()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 535, __extension__ __PRETTY_FUNCTION__)); | |||
536 | rRightEndedElements.pop_front(); | |||
537 | } | |||
538 | rLeftStartedElements.pop_back(); | |||
539 | } | |||
540 | while (!rLeftEndedElements.empty()) | |||
541 | { | |||
542 | rRightEndedElements.push_front(rLeftEndedElements.back()); | |||
543 | rLeftEndedElements.pop_back(); | |||
544 | } | |||
545 | } | |||
546 | #endif | |||
547 | ||||
548 | void FastSaxSerializer::mergeTopMarks( | |||
549 | sal_Int32 const nTag, sax_fastparser::MergeMarks const eMergeType) | |||
550 | { | |||
551 | SAL_WARN_IF(mbMarkStackEmpty, "sax", "Empty mark stack - nothing to merge")do { if (true && (mbMarkStackEmpty)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "sax")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "Empty mark stack - nothing to merge" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax" ), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "551" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Empty mark stack - nothing to merge") , 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Empty mark stack - nothing to merge"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "551" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Empty mark stack - nothing to merge") == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "551" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Empty mark stack - nothing to merge") , 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Empty mark stack - nothing to merge"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "551" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
552 | assert(!mbMarkStackEmpty)(static_cast <bool> (!mbMarkStackEmpty) ? void (0) : __assert_fail ("!mbMarkStackEmpty", "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 552, __extension__ __PRETTY_FUNCTION__)); // should never happen | |||
553 | if ( mbMarkStackEmpty ) | |||
554 | return; | |||
555 | ||||
556 | assert(maMarkStack.top()->m_Tag == nTag && "mark/merge tag mismatch!")(static_cast <bool> (maMarkStack.top()->m_Tag == nTag && "mark/merge tag mismatch!") ? void (0) : __assert_fail ("maMarkStack.top()->m_Tag == nTag && \"mark/merge tag mismatch!\"" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 556, __extension__ __PRETTY_FUNCTION__)); | |||
557 | (void) nTag; | |||
558 | #ifdef DBG_UTIL | |||
559 | if (dynamic_cast<ForSort*>(maMarkStack.top().get())) | |||
560 | { | |||
561 | // Sort is always well-formed fragment | |||
562 | assert(maMarkStack.top()->m_DebugStartedElements.empty())(static_cast <bool> (maMarkStack.top()->m_DebugStartedElements .empty()) ? void (0) : __assert_fail ("maMarkStack.top()->m_DebugStartedElements.empty()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 562, __extension__ __PRETTY_FUNCTION__)); | |||
563 | assert(maMarkStack.top()->m_DebugEndedElements.empty())(static_cast <bool> (maMarkStack.top()->m_DebugEndedElements .empty()) ? void (0) : __assert_fail ("maMarkStack.top()->m_DebugEndedElements.empty()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 563, __extension__ __PRETTY_FUNCTION__)); | |||
564 | } | |||
565 | lcl_DebugMergeAppend( | |||
566 | maMarkStack.top()->m_DebugEndedElements, | |||
567 | maMarkStack.top()->m_DebugStartedElements, | |||
568 | maMarkStack.top()->m_DebugPostponedEndedElements, | |||
569 | maMarkStack.top()->m_DebugPostponedStartedElements); | |||
570 | #endif | |||
571 | ||||
572 | // flush, so that we get everything in getData() | |||
573 | maCachedOutputStream.flush(); | |||
574 | ||||
575 | if (maMarkStack.size() == 1) | |||
576 | { | |||
577 | #ifdef DBG_UTIL | |||
578 | while (!maMarkStack.top()->m_DebugEndedElements.empty()) | |||
579 | { | |||
580 | assert(maMarkStack.top()->m_DebugEndedElements.front() == m_DebugStartedElements.top())(static_cast <bool> (maMarkStack.top()->m_DebugEndedElements .front() == m_DebugStartedElements.top()) ? void (0) : __assert_fail ("maMarkStack.top()->m_DebugEndedElements.front() == m_DebugStartedElements.top()" , "/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" , 580, __extension__ __PRETTY_FUNCTION__)); | |||
581 | maMarkStack.top()->m_DebugEndedElements.pop_front(); | |||
582 | m_DebugStartedElements.pop(); | |||
583 | } | |||
584 | while (!maMarkStack.top()->m_DebugStartedElements.empty()) | |||
585 | { | |||
586 | m_DebugStartedElements.push(maMarkStack.top()->m_DebugStartedElements.front()); | |||
587 | maMarkStack.top()->m_DebugStartedElements.pop_front(); | |||
588 | } | |||
589 | #endif | |||
590 | Sequence<sal_Int8> aSeq( maMarkStack.top()->getData() ); | |||
591 | maMarkStack.pop(); | |||
592 | mbMarkStackEmpty = true; | |||
593 | maCachedOutputStream.resetOutputToStream(); | |||
594 | maCachedOutputStream.writeBytes( aSeq.getConstArray(), aSeq.getLength() ); | |||
595 | return; | |||
596 | } | |||
597 | ||||
598 | #ifdef DBG_UTIL | |||
599 | ::std::deque<sal_Int32> topDebugStartedElements(maMarkStack.top()->m_DebugStartedElements); | |||
600 | ::std::deque<sal_Int32> topDebugEndedElements(maMarkStack.top()->m_DebugEndedElements); | |||
601 | #endif | |||
602 | const Int8Sequence aMerge( maMarkStack.top()->getData() ); | |||
603 | maMarkStack.pop(); | |||
604 | #ifdef DBG_UTIL | |||
605 | switch (eMergeType) | |||
606 | { | |||
607 | case MergeMarks::APPEND: | |||
608 | lcl_DebugMergeAppend( | |||
609 | maMarkStack.top()->m_DebugEndedElements, | |||
610 | maMarkStack.top()->m_DebugStartedElements, | |||
611 | topDebugEndedElements, | |||
612 | topDebugStartedElements); | |||
613 | break; | |||
614 | case MergeMarks::PREPEND: | |||
615 | if (dynamic_cast<ForSort*>(maMarkStack.top().get())) // argh... | |||
616 | { | |||
617 | lcl_DebugMergeAppend( | |||
618 | maMarkStack.top()->m_DebugEndedElements, | |||
619 | maMarkStack.top()->m_DebugStartedElements, | |||
620 | topDebugEndedElements, | |||
621 | topDebugStartedElements); | |||
622 | } | |||
623 | else | |||
624 | { | |||
625 | lcl_DebugMergePrepend( | |||
626 | topDebugEndedElements, | |||
627 | topDebugStartedElements, | |||
628 | maMarkStack.top()->m_DebugEndedElements, | |||
629 | maMarkStack.top()->m_DebugStartedElements); | |||
630 | } | |||
631 | break; | |||
632 | case MergeMarks::POSTPONE: | |||
633 | lcl_DebugMergeAppend( | |||
634 | maMarkStack.top()->m_DebugPostponedEndedElements, | |||
635 | maMarkStack.top()->m_DebugPostponedStartedElements, | |||
636 | topDebugEndedElements, | |||
637 | topDebugStartedElements); | |||
638 | break; | |||
639 | } | |||
640 | #endif | |||
641 | if (maMarkStack.empty()) | |||
642 | { | |||
643 | mbMarkStackEmpty = true; | |||
644 | maCachedOutputStream.resetOutputToStream(); | |||
645 | } | |||
646 | else | |||
647 | { | |||
648 | maCachedOutputStream.setOutput( maMarkStack.top() ); | |||
649 | } | |||
650 | ||||
651 | switch ( eMergeType ) | |||
652 | { | |||
653 | case MergeMarks::APPEND: maMarkStack.top()->append( aMerge ); break; | |||
654 | case MergeMarks::PREPEND: maMarkStack.top()->prepend( aMerge ); break; | |||
655 | case MergeMarks::POSTPONE: maMarkStack.top()->postpone( aMerge ); break; | |||
656 | } | |||
657 | } | |||
658 | ||||
659 | void FastSaxSerializer::writeBytes( const Sequence< sal_Int8 >& rData ) | |||
660 | { | |||
661 | maCachedOutputStream.writeBytes( rData.getConstArray(), rData.getLength() ); | |||
662 | } | |||
663 | ||||
664 | void FastSaxSerializer::writeBytes( const char* pStr, size_t nLen ) | |||
665 | { | |||
666 | #if OSL_DEBUG_LEVEL1 > 0 | |||
667 | { | |||
668 | bool bGood = true; | |||
669 | for (size_t i=0; i < nLen; ++i) | |||
670 | { | |||
671 | if (invalidChar(pStr[i])) | |||
672 | { | |||
673 | bGood = false; | |||
674 | SAL_WARN("sax", "FastSaxSerializer::writeBytes - illegal XML character 0x" <<do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sax")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i])); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN) , ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i])); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN) , ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
675 | std::hex << int(static_cast<unsigned char>(pStr[i])))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sax")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i])); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN) , ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i]))), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "FastSaxSerializer::writeBytes - illegal XML character 0x" << std::hex << int(static_cast<unsigned char> (pStr[i])); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN) , ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "675" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
676 | } | |||
677 | } | |||
678 | SAL_WARN_IF( !bGood && nLen > 1, "sax", "in '" << OString(pStr,std::min<sal_Int32>(nLen,42)) << "'")do { if (true && (!bGood && nLen > 1)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "sax")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "in '" << OString(pStr,std::min<sal_Int32 >(nLen,42)) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "678" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "in '" << OString(pStr,std::min< sal_Int32>(nLen,42)) << "'"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "in '" << OString(pStr,std::min<sal_Int32>(nLen,42)) << "'" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "678" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "in '" << OString(pStr,std::min<sal_Int32 >(nLen,42)) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "678" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "in '" << OString(pStr,std::min< sal_Int32>(nLen,42)) << "'"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "in '" << OString(pStr,std::min<sal_Int32>(nLen,42)) << "'" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sax"), ("/home/maarten/src/libreoffice/core/sax/source/tools/fastserializer.cxx" ":" "678" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
679 | } | |||
680 | #endif | |||
681 | maCachedOutputStream.writeBytes( reinterpret_cast<const sal_Int8*>(pStr), nLen ); | |||
682 | } | |||
683 | ||||
684 | FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForMerge::getData() | |||
685 | { | |||
686 | merge( maData, maPostponed, true ); | |||
687 | maPostponed.realloc( 0 ); | |||
688 | ||||
689 | return maData; | |||
690 | } | |||
691 | ||||
692 | #if OSL_DEBUG_LEVEL1 > 0 | |||
693 | void FastSaxSerializer::ForMerge::print( ) | |||
694 | { | |||
695 | std::cerr << "Data: "; | |||
696 | for ( sal_Int32 i=0, len=maData.getLength(); i < len; i++ ) | |||
697 | { | |||
698 | std::cerr << maData[i]; | |||
699 | } | |||
700 | ||||
701 | std::cerr << "\nPostponed: "; | |||
702 | for ( sal_Int32 i=0, len=maPostponed.getLength(); i < len; i++ ) | |||
703 | { | |||
704 | std::cerr << maPostponed[i]; | |||
705 | } | |||
706 | ||||
707 | std::cerr << "\n"; | |||
708 | } | |||
709 | #endif | |||
710 | ||||
711 | void FastSaxSerializer::ForMerge::prepend( const Int8Sequence &rWhat ) | |||
712 | { | |||
713 | merge( maData, rWhat, false ); | |||
714 | } | |||
715 | ||||
716 | void FastSaxSerializer::ForMerge::append( const css::uno::Sequence<sal_Int8> &rWhat ) | |||
717 | { | |||
718 | merge( maData, rWhat, true ); | |||
719 | } | |||
720 | ||||
721 | void FastSaxSerializer::ForMerge::postpone( const Int8Sequence &rWhat ) | |||
722 | { | |||
723 | merge( maPostponed, rWhat, true ); | |||
724 | } | |||
725 | ||||
726 | void FastSaxSerializer::ForMerge::merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend ) | |||
727 | { | |||
728 | sal_Int32 nMergeLen = rMerge.getLength(); | |||
729 | if ( nMergeLen <= 0 ) | |||
730 | return; | |||
731 | ||||
732 | sal_Int32 nTopLen = rTop.getLength(); | |||
733 | ||||
734 | rTop.realloc( nTopLen + nMergeLen ); | |||
735 | if ( bAppend ) | |||
736 | { | |||
737 | // append the rMerge to the rTop | |||
738 | memcpy( rTop.getArray() + nTopLen, rMerge.getConstArray(), nMergeLen ); | |||
739 | } | |||
740 | else | |||
741 | { | |||
742 | // prepend the rMerge to the rTop | |||
743 | memmove( rTop.getArray() + nMergeLen, rTop.getConstArray(), nTopLen ); | |||
744 | memcpy( rTop.getArray(), rMerge.getConstArray(), nMergeLen ); | |||
745 | } | |||
746 | } | |||
747 | ||||
748 | void FastSaxSerializer::ForMerge::resetData( ) | |||
749 | { | |||
750 | maData = Int8Sequence(); | |||
751 | } | |||
752 | ||||
753 | void FastSaxSerializer::ForSort::setCurrentElement( sal_Int32 nElement ) | |||
754 | { | |||
755 | vector< sal_Int32 > aOrder( comphelper::sequenceToContainer<vector<sal_Int32> >(maOrder) ); | |||
756 | if( std::find( aOrder.begin(), aOrder.end(), nElement ) != aOrder.end() ) | |||
757 | { | |||
758 | mnCurrentElement = nElement; | |||
759 | if ( maData.find( nElement ) == maData.end() ) | |||
760 | maData[ nElement ] = Int8Sequence(); | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | void FastSaxSerializer::ForSort::prepend( const Int8Sequence &rWhat ) | |||
765 | { | |||
766 | append( rWhat ); | |||
767 | } | |||
768 | ||||
769 | void FastSaxSerializer::ForSort::append( const css::uno::Sequence<sal_Int8> &rWhat ) | |||
770 | { | |||
771 | merge( maData[mnCurrentElement], rWhat, true ); | |||
772 | } | |||
773 | ||||
774 | void FastSaxSerializer::ForSort::sort() | |||
775 | { | |||
776 | // Clear the ForMerge data to avoid duplicate items | |||
777 | resetData(); | |||
778 | ||||
779 | // Sort it all | |||
780 | std::map< sal_Int32, Int8Sequence >::iterator iter; | |||
781 | for ( const auto nIndex : std::as_const(maOrder) ) | |||
782 | { | |||
783 | iter = maData.find( nIndex ); | |||
784 | if ( iter != maData.end() ) | |||
785 | ForMerge::append( iter->second ); | |||
786 | } | |||
787 | } | |||
788 | ||||
789 | FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForSort::getData() | |||
790 | { | |||
791 | sort( ); | |||
792 | return ForMerge::getData(); | |||
793 | } | |||
794 | ||||
795 | #if OSL_DEBUG_LEVEL1 > 0 | |||
796 | void FastSaxSerializer::ForSort::print( ) | |||
797 | { | |||
798 | for ( const auto& [rElement, rData] : maData ) | |||
799 | { | |||
800 | std::cerr << "pair: " << rElement; | |||
801 | for ( sal_Int32 i=0, len=rData.getLength(); i < len; ++i ) | |||
802 | std::cerr << rData[i]; | |||
803 | std::cerr << "\n"; | |||
804 | } | |||
805 | ||||
806 | sort( ); | |||
807 | ForMerge::print(); | |||
808 | } | |||
809 | #endif | |||
810 | ||||
811 | } // namespace sax_fastparser | |||
812 | ||||
813 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |