Bug Summary

File:home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx
Warning:line 1391, column 93
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name rtfdocumentimpl.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/writerfilter/source -I /home/maarten/src/libreoffice/core/writerfilter/inc -I /home/maarten/src/libreoffice/core/writerfilter/source -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx

/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx

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
10#include "rtfdocumentimpl.hxx"
11#include <algorithm>
12#include <memory>
13#include <com/sun/star/embed/XEmbeddedObject.hpp>
14#include <com/sun/star/beans/PropertyAttribute.hpp>
15#include <com/sun/star/io/WrongFormatException.hpp>
16#include <com/sun/star/lang/XServiceInfo.hpp>
17#include <com/sun/star/lang/XMultiServiceFactory.hpp>
18#include <com/sun/star/text/TextContentAnchorType.hpp>
19#include <i18nlangtag/languagetag.hxx>
20#include <unotools/ucbstreamhelper.hxx>
21#include <unotools/streamwrap.hxx>
22#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
23#include <filter/msfilter/util.hxx>
24#include <filter/msfilter/rtfutil.hxx>
25#include <comphelper/string.hxx>
26#include <tools/diagnose_ex.h>
27#include <tools/globname.hxx>
28#include <tools/datetimeutils.hxx>
29#include <comphelper/classids.hxx>
30#include <comphelper/embeddedobjectcontainer.hxx>
31#include <svl/lngmisc.hxx>
32#include <sfx2/sfxbasemodel.hxx>
33#include <sfx2/classificationhelper.hxx>
34#include <oox/mathml/import.hxx>
35#include <ooxml/resourceids.hxx>
36#include <oox/token/namespaces.hxx>
37#include <oox/drawingml/drawingmltypes.hxx>
38#include <rtl/uri.hxx>
39#include <rtl/tencinfo.h>
40#include <sal/log.hxx>
41#include <osl/diagnose.h>
42#include <oox/helper/graphichelper.hxx>
43#include <vcl/wmfexternal.hxx>
44#include <vcl/graph.hxx>
45#include <vcl/settings.hxx>
46#include <vcl/svapp.hxx>
47#include "rtfsdrimport.hxx"
48#include "rtfreferenceproperties.hxx"
49#include "rtfskipdestination.hxx"
50#include "rtftokenizer.hxx"
51#include "rtflookahead.hxx"
52
53using namespace com::sun::star;
54
55namespace
56{
57/// Returns an util::DateTime from a 'YYYY. MM. DD.' string.
58util::DateTime getDateTimeFromUserProp(const OUString& rString)
59{
60 util::DateTime aRet;
61 sal_Int32 nLen = rString.getLength();
62 if (nLen >= 4)
63 {
64 aRet.Year = rString.copy(0, 4).toInt32();
65
66 if (nLen >= 8 && rString.match(". ", 4))
67 {
68 aRet.Month = rString.copy(6, 2).toInt32();
69
70 if (nLen >= 12 && rString.match(". ", 8))
71 aRet.Day = rString.copy(10, 2).toInt32();
72 }
73 }
74 return aRet;
75}
76} // anonymous namespace
77
78namespace writerfilter::rtftok
79{
80Id getParagraphBorder(sal_uInt32 nIndex)
81{
82 static const Id aBorderIds[] = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left,
83 NS_ooxml::LN_CT_PBdr_bottom, NS_ooxml::LN_CT_PBdr_right };
84
85 return aBorderIds[nIndex];
86}
87
88void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
89 RTFOverwrite eOverwrite, bool bAttribute)
90{
91 RTFValue::Pointer_t pParent = rSprms.find(nParent, /*bFirst=*/true, /*bForWrite=*/true);
92 if (!pParent)
93 {
94 RTFSprms aAttributes;
95 if (nParent == NS_ooxml::LN_CT_TcPrBase_shd)
96 {
97 // RTF default is 'auto', see writerfilter::dmapper::CellColorHandler
98 aAttributes.set(NS_ooxml::LN_CT_Shd_color, new RTFValue(sal_uInt32(COL_AUTO)));
99 aAttributes.set(NS_ooxml::LN_CT_Shd_fill, new RTFValue(sal_uInt32(COL_AUTO)));
100 }
101 auto pParentValue = new RTFValue(aAttributes);
102 rSprms.set(nParent, pParentValue, eOverwrite);
103 pParent = pParentValue;
104 }
105 RTFSprms& rAttributes = (bAttribute ? pParent->getAttributes() : pParent->getSprms());
106 rAttributes.set(nId, pValue, eOverwrite);
107}
108
109void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
110 RTFOverwrite eOverwrite)
111{
112 putNestedAttribute(rSprms, nParent, nId, pValue, eOverwrite, false);
113}
114
115RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
116{
117 RTFValue::Pointer_t pParent = rSprms.find(nParent);
118 if (!pParent)
119 return RTFValue::Pointer_t();
120 RTFSprms& rAttributes = pParent->getAttributes();
121 return rAttributes.find(nId);
122}
123
124RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId)
125{
126 RTFValue::Pointer_t pParent = rSprms.find(nParent);
127 if (!pParent)
128 return RTFValue::Pointer_t();
129 RTFSprms& rInner = pParent->getSprms();
130 return rInner.find(nId);
131}
132
133bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
134{
135 RTFValue::Pointer_t pParent = rSprms.find(nParent);
136 if (!pParent)
137 // It doesn't even have a parent, we're done.
138 return false;
139 RTFSprms& rAttributes = pParent->getAttributes();
140 return rAttributes.erase(nId);
141}
142
143RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId)
144{
145 RTFValue::Pointer_t p = rSprms.find(nId);
146 if (p && !p->getSprms().empty())
147 return p->getSprms().back().second->getAttributes();
148
149 SAL_WARN("writerfilter.rtf", "trying to set property when no type is defined")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "trying to set property when no type is defined"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "149" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "trying to set property when no type is defined"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "trying to set property when no type is defined"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "149" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "trying to set property when no type is defined")
== 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "149" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "trying to set property when no type is defined"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "trying to set property when no type is defined"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "149" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
150 return rSprms;
151}
152
153void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue)
154{
155 RTFSprms* pAttributes = nullptr;
156 if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH_BOX)
157 for (int i = 0; i < 4; i++)
158 {
159 RTFValue::Pointer_t p = aStates.top().getParagraphSprms().find(getParagraphBorder(i));
160 if (p)
161 {
162 RTFSprms& rAttributes = p->getAttributes();
163 rAttributes.set(nId, pValue);
164 }
165 }
166 else if (aStates.top().getBorderState() == RTFBorderState::CHARACTER)
167 {
168 RTFValue::Pointer_t pPointer
169 = aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_RPrBase_bdr);
170 if (pPointer)
171 {
172 RTFSprms& rAttributes = pPointer->getAttributes();
173 rAttributes.set(nId, pValue);
174 }
175 }
176 // Attributes of the last border type
177 else if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH)
178 pAttributes
179 = &getLastAttributes(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr);
180 else if (aStates.top().getBorderState() == RTFBorderState::CELL)
181 pAttributes = &getLastAttributes(aStates.top().getTableCellSprms(),
182 NS_ooxml::LN_CT_TcPrBase_tcBorders);
183 else if (aStates.top().getBorderState() == RTFBorderState::PAGE)
184 pAttributes = &getLastAttributes(aStates.top().getSectionSprms(),
185 NS_ooxml::LN_EG_SectPrContents_pgBorders);
186 if (pAttributes)
187 pAttributes->set(nId, pValue);
188}
189
190OString DTTM22OString(long nDTTM)
191{
192 return DateTimeToOString(msfilter::util::DTTM2DateTime(nDTTM));
193}
194
195static RTFSprms lcl_getBookmarkProperties(int nPos, const OUString& rString)
196{
197 RTFSprms aAttributes;
198 auto pPos = new RTFValue(nPos);
199 if (!rString.isEmpty())
200 {
201 // If present, this should be sent first.
202 auto pString = new RTFValue(rString);
203 aAttributes.set(NS_ooxml::LN_CT_Bookmark_name, pString);
204 }
205 aAttributes.set(NS_ooxml::LN_CT_MarkupRangeBookmark_id, pPos);
206 return aAttributes;
207}
208
209const char* keywordToString(RTFKeyword nKeyword)
210{
211 for (int i = 0; i < nRTFControlWords; i++)
212 {
213 if (nKeyword == aRTFControlWords[i].GetIndex())
214 return aRTFControlWords[i].GetKeyword();
215 }
216 return nullptr;
217}
218
219static util::DateTime lcl_getDateTime(RTFParserState const& aState)
220{
221 return { 0 /*100sec*/,
222 0 /*sec*/,
223 aState.getMinute(),
224 aState.getHour(),
225 aState.getDay(),
226 aState.getMonth(),
227 static_cast<sal_Int16>(aState.getYear()),
228 false };
229}
230
231static void lcl_DestinationToMath(OUStringBuffer* pDestinationText,
232 oox::formulaimport::XmlStreamBuilder& rMathBuffer, bool& rMathNor)
233{
234 if (!pDestinationText)
235 return;
236 OUString aStr = pDestinationText->makeStringAndClear();
237 if (aStr.isEmpty())
238 return;
239 rMathBuffer.appendOpeningTag(M_TOKEN(r)(::oox::NMSP_officeMath | ::oox::XML_r));
240 if (rMathNor)
241 {
242 rMathBuffer.appendOpeningTag(M_TOKEN(rPr)(::oox::NMSP_officeMath | ::oox::XML_rPr));
243 // Same as M_TOKEN(lit)
244 rMathBuffer.appendOpeningTag(M_TOKEN(nor)(::oox::NMSP_officeMath | ::oox::XML_nor));
245 rMathBuffer.appendClosingTag(M_TOKEN(nor)(::oox::NMSP_officeMath | ::oox::XML_nor));
246 rMathBuffer.appendClosingTag(M_TOKEN(rPr)(::oox::NMSP_officeMath | ::oox::XML_rPr));
247 rMathNor = false;
248 }
249 rMathBuffer.appendOpeningTag(M_TOKEN(t)(::oox::NMSP_officeMath | ::oox::XML_t));
250 rMathBuffer.appendCharacters(aStr);
251 rMathBuffer.appendClosingTag(M_TOKEN(t)(::oox::NMSP_officeMath | ::oox::XML_t));
252 rMathBuffer.appendClosingTag(M_TOKEN(r)(::oox::NMSP_officeMath | ::oox::XML_r));
253}
254
255RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& xContext,
256 uno::Reference<io::XInputStream> const& xInputStream,
257 uno::Reference<lang::XComponent> const& xDstDoc,
258 uno::Reference<frame::XFrame> const& xFrame,
259 uno::Reference<task::XStatusIndicator> const& xStatusIndicator,
260 const utl::MediaDescriptor& rMediaDescriptor)
261 : m_xContext(xContext)
262 , m_xInputStream(xInputStream)
263 , m_xDstDoc(xDstDoc)
264 , m_xFrame(xFrame)
265 , m_xStatusIndicator(xStatusIndicator)
266 , m_pMapperStream(nullptr)
267 , m_aDefaultState(this)
268 , m_bSkipUnknown(false)
269 , m_bFirstRun(true)
270 , m_bFirstRunException(false)
271 , m_bNeedPap(true)
272 , m_bNeedCr(false)
273 , m_bNeedCrOrig(false)
274 , m_bNeedPar(true)
275 , m_bNeedFinalPar(false)
276 , m_nNestedCells(0)
277 , m_nTopLevelCells(0)
278 , m_nInheritingCells(0)
279 , m_nNestedTRLeft(0)
280 , m_nTopLevelTRLeft(0)
281 , m_nNestedCurrentCellX(0)
282 , m_nTopLevelCurrentCellX(0)
283 , m_nBackupTopLevelCurrentCellX(0)
284 , m_aTableBufferStack(1) // create top-level buffer already
285 , m_pSuperstream(nullptr)
286 , m_nStreamType(0)
287 , m_nGroupStartPos(0)
288 , m_nFormFieldType(RTFFormFieldType::NONE)
289 , m_bObject(false)
290 , m_nCurrentFontIndex(0)
291 , m_nCurrentEncoding(-1)
292 , m_nDefaultFontIndex(-1)
293 , m_nCurrentStyleIndex(0)
294 , m_bFormField(false)
295 , m_bMathNor(false)
296 , m_bIgnoreNextContSectBreak(false)
297 , m_nResetBreakOnSectBreak(RTF_invalid)
298 , m_bNeedSect(false) // done by checkFirstRun
299 , m_bWasInFrame(false)
300 , m_bHadPicture(false)
301 , m_bHadSect(false)
302 , m_nCellxMax(0)
303 , m_nListPictureId(0)
304 , m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault("InsertMode", false))
305 , m_rMediaDescriptor(rMediaDescriptor)
306 , m_hasRHeader(false)
307 , m_hasFHeader(false)
308 , m_hasRFooter(false)
309 , m_hasFFooter(false)
310 , m_bAfterCellBeforeRow(false)
311{
312 OSL_ASSERT(xInputStream.is())do { if (true && (!(xInputStream.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "312" ": "), "OSL_ASSERT: %s", "xInputStream.is()"); } }
while (false)
;
313 m_pInStream = utl::UcbStreamHelper::CreateStream(xInputStream, true);
314
315 m_xModelFactory.set(m_xDstDoc, uno::UNO_QUERY);
316
317 uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
318 m_xDstDoc, uno::UNO_QUERY);
319 if (xDocumentPropertiesSupplier.is())
320 m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
321
322 m_pGraphicHelper = std::make_shared<oox::GraphicHelper>(m_xContext, xFrame, oox::StorageRef());
323
324 m_pTokenizer = new RTFTokenizer(*this, m_pInStream.get(), m_xStatusIndicator);
325 m_pSdrImport = new RTFSdrImport(*this, m_xDstDoc);
326}
327
328RTFDocumentImpl::~RTFDocumentImpl() = default;
329
330SvStream& RTFDocumentImpl::Strm() { return *m_pInStream; }
331
332void RTFDocumentImpl::setSuperstream(RTFDocumentImpl* pSuperstream)
333{
334 m_pSuperstream = pSuperstream;
335}
336
337bool RTFDocumentImpl::isSubstream() const { return m_pSuperstream != nullptr; }
338
339void RTFDocumentImpl::finishSubstream() { checkUnicode(/*bUnicode =*/true, /*bHex =*/true); }
340
341void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId)
342{
343 resolveSubstream(nPos, nId, OUString());
344}
345void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst)
346{
347 sal_uInt64 const nCurrent = Strm().Tell();
348 // Seek to header position, parse, then seek back.
349 auto pImpl = new RTFDocumentImpl(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame,
350 m_xStatusIndicator, m_rMediaDescriptor);
351 pImpl->setSuperstream(this);
352 pImpl->m_nStreamType = nId;
353 pImpl->m_aIgnoreFirst = rIgnoreFirst;
354 if (!m_aAuthor.isEmpty())
355 {
356 pImpl->m_aAuthor = m_aAuthor;
357 m_aAuthor.clear();
358 }
359 if (!m_aAuthorInitials.isEmpty())
360 {
361 pImpl->m_aAuthorInitials = m_aAuthorInitials;
362 m_aAuthorInitials.clear();
363 }
364 pImpl->m_nDefaultFontIndex = m_nDefaultFontIndex;
365 pImpl->Strm().Seek(nPos);
366 SAL_INFO("writerfilter.rtf", "substream start")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "substream start") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "366" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "substream start"), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"substream start"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "366" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "substream start") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "366" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "substream start"), 0); } else { ::std
::ostringstream sal_detail_stream; sal_detail_stream <<
"substream start"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "366" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
367 Mapper().substream(nId, pImpl);
368 SAL_INFO("writerfilter.rtf", "substream end")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "substream end") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "368" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "substream end"), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "substream end"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "368" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "substream end") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "368" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "substream end"), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "substream end"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "368" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
369 Strm().Seek(nCurrent);
370}
371
372void RTFDocumentImpl::outputSettingsTable()
373{
374 writerfilter::Reference<Properties>::Pointer_t pProp
375 = new RTFReferenceProperties(m_aSettingsTableAttributes, m_aSettingsTableSprms);
376 RTFReferenceTable::Entries_t aSettingsTableEntries;
377 aSettingsTableEntries.insert(std::make_pair(0, pProp));
378 writerfilter::Reference<Table>::Pointer_t pTable = new RTFReferenceTable(aSettingsTableEntries);
379 Mapper().table(NS_ooxml::LN_settings_settings, pTable);
380}
381
382void RTFDocumentImpl::checkFirstRun()
383{
384 if (!m_bFirstRun)
385 return;
386
387 outputSettingsTable();
388 // start initial paragraph
389 m_bFirstRun = false;
390 assert(!m_bNeedSect || m_bFirstRunException)(static_cast <bool> (!m_bNeedSect || m_bFirstRunException
) ? void (0) : __assert_fail ("!m_bNeedSect || m_bFirstRunException"
, "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 390, __extension__ __PRETTY_FUNCTION__))
;
391 setNeedSect(true); // first call that succeeds
392
393 // set the requested default font, if there are none
394 RTFValue::Pointer_t pFont
395 = getNestedAttribute(m_aDefaultState.getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
396 NS_ooxml::LN_CT_Fonts_ascii);
397 RTFValue::Pointer_t pCurrentFont
398 = getNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
399 NS_ooxml::LN_CT_Fonts_ascii);
400 if (pFont && !pCurrentFont)
401 putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
402 NS_ooxml::LN_CT_Fonts_ascii, pFont);
403}
404
405void RTFDocumentImpl::setNeedPar(bool bNeedPar) { m_bNeedPar = bNeedPar; }
406
407void RTFDocumentImpl::setNeedSect(bool bNeedSect)
408{
409 if (!m_bNeedSect && bNeedSect && m_bFirstRun)
410 {
411 RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
412 if (aLookahead.hasTable() && aLookahead.hasColumns())
413 {
414 m_bFirstRunException = true;
415 }
416 }
417
418 // ignore setting before checkFirstRun - every keyword calls setNeedSect!
419 // except the case of a table in a multicolumn section
420 if (!m_bNeedSect && bNeedSect && (!m_bFirstRun || m_bFirstRunException))
421 {
422 if (!m_pSuperstream) // no sections in header/footer!
423 {
424 Mapper().startSectionGroup();
425 }
426 // set flag in substream too - otherwise multiple startParagraphGroup
427 m_bNeedSect = bNeedSect;
428 Mapper().startParagraphGroup();
429 setNeedPar(true);
430 }
431 else if (m_bNeedSect && !bNeedSect)
432 {
433 m_bNeedSect = bNeedSect;
434 }
435}
436
437/// Copy rProps to rStyleAttributes and rStyleSprms, but in case of nested sprms, copy their children as toplevel sprms/attributes.
438static void lcl_copyFlatten(RTFReferenceProperties& rProps, RTFSprms& rStyleAttributes,
439 RTFSprms& rStyleSprms)
440{
441 for (auto& rSprm : rProps.getSprms())
442 {
443 // createStyleProperties() puts properties to rPr, but here we need a flat list.
444 if (rSprm.first == NS_ooxml::LN_CT_Style_rPr)
445 {
446 // rPr can have both attributes and SPRMs, copy over both types.
447 RTFSprms& rRPrSprms = rSprm.second->getSprms();
448 for (const auto& rRPrSprm : rRPrSprms)
449 rStyleSprms.set(rRPrSprm.first, rRPrSprm.second);
450
451 RTFSprms& rRPrAttributes = rSprm.second->getAttributes();
452 for (const auto& rRPrAttribute : rRPrAttributes)
453 rStyleAttributes.set(rRPrAttribute.first, rRPrAttribute.second);
454 }
455 else
456 rStyleSprms.set(rSprm.first, rSprm.second);
457 }
458
459 RTFSprms& rAttributes = rProps.getAttributes();
460 for (const auto& rAttribute : rAttributes)
461 rStyleAttributes.set(rAttribute.first, rAttribute.second);
462}
463
464writerfilter::Reference<Properties>::Pointer_t
465RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType)
466{
467 RTFSprms aSprms(rSprms);
468 RTFValue::Pointer_t pAbstractList;
469 int nAbstractListId = -1;
470 RTFValue::Pointer_t pNumId
471 = getNestedSprm(aSprms, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_numId);
472 if (pNumId)
473 {
474 // We have a numbering, look up the abstract list for property
475 // deduplication and duplication.
476 auto itNumId = m_aListOverrideTable.find(pNumId->getInt());
477 if (itNumId != m_aListOverrideTable.end())
478 {
479 nAbstractListId = itNumId->second;
480 auto itAbstract = m_aListTable.find(nAbstractListId);
481 if (itAbstract != m_aListTable.end())
482 pAbstractList = itAbstract->second;
483 }
484 }
485
486 if (pAbstractList)
487 {
488 auto it = m_aInvalidListTableFirstIndents.find(nAbstractListId);
489 if (it != m_aInvalidListTableFirstIndents.end())
490 aSprms.deduplicateList(it->second);
491 }
492
493 int nStyle = 0;
494 if (!m_aStates.empty())
495 nStyle = m_aStates.top().getCurrentStyleIndex();
496 auto it = m_aStyleTableEntries.find(nStyle);
497 if (it != m_aStyleTableEntries.end())
498 {
499 // cloneAndDeduplicate() wants to know about only a single "style", so
500 // let's merge paragraph and character style properties here.
501 auto itChar = m_aStyleTableEntries.end();
502 if (!m_aStates.empty())
503 {
504 int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex();
505 itChar = m_aStyleTableEntries.find(nCharStyle);
506 }
507
508 RTFSprms aStyleSprms;
509 RTFSprms aStyleAttributes;
510 // Ensure the paragraph style is a flat list.
511 // Take paragraph style into account for character properties as well,
512 // as paragraph style may contain character properties.
513 RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get());
514 lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms);
515
516 if (itChar != m_aStyleTableEntries.end())
517 {
518 // Found active character style, then update aStyleSprms/Attributes.
519 if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
520 {
521 RTFReferenceProperties& rCharProps
522 = *static_cast<RTFReferenceProperties*>(itChar->second.get());
523 lcl_copyFlatten(rCharProps, aStyleAttributes, aStyleSprms);
524 }
525 }
526
527 // Get rid of direct formatting what is already in the style.
528 RTFSprms const sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true));
529 RTFSprms const attributes(
530 rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true));
531 return new RTFReferenceProperties(attributes, sprms);
532 }
533
534 if (pAbstractList)
535 aSprms.duplicateList(pAbstractList);
536 writerfilter::Reference<Properties>::Pointer_t pRet
537 = new RTFReferenceProperties(rAttributes, aSprms);
538 return pRet;
539}
540
541void RTFDocumentImpl::checkNeedPap()
542{
543 if (!m_bNeedPap)
544 return;
545
546 m_bNeedPap = false; // reset early, so we can avoid recursion when calling ourselves
547
548 if (m_aStates.empty())
549 return;
550
551 if (!m_aStates.top().getCurrentBuffer())
552 {
553 writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties(getProperties(
554 m_aStates.top().getParagraphAttributes(), m_aStates.top().getParagraphSprms(),
555 NS_ooxml::LN_Value_ST_StyleType_paragraph));
556
557 // Writer will ignore a page break before a text frame, so guard it with empty paragraphs
558 bool hasBreakBeforeFrame
559 = m_aStates.top().getFrame().hasProperties()
560 && m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore);
561 if (hasBreakBeforeFrame)
562 {
563 dispatchSymbol(RTF_PAR);
564 m_bNeedPap = false;
565 }
566 Mapper().props(pParagraphProperties);
567 if (hasBreakBeforeFrame)
568 dispatchSymbol(RTF_PAR);
569
570 if (m_aStates.top().getFrame().hasProperties())
571 {
572 writerfilter::Reference<Properties>::Pointer_t const pFrameProperties(
573 new RTFReferenceProperties(RTFSprms(), m_aStates.top().getFrame().getSprms()));
574 Mapper().props(pFrameProperties);
575 }
576 }
577 else
578 {
579 auto pValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
580 m_aStates.top().getParagraphSprms());
581 bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
582 }
583}
584
585void RTFDocumentImpl::runProps()
586{
587 if (!m_aStates.top().getCurrentBuffer())
588 {
589 Reference<Properties>::Pointer_t const pProperties = getProperties(
590 m_aStates.top().getCharacterAttributes(), m_aStates.top().getCharacterSprms(),
591 NS_ooxml::LN_Value_ST_StyleType_character);
592 Mapper().props(pProperties);
593 }
594 else
595 {
596 auto pValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
597 m_aStates.top().getCharacterSprms());
598 bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
599 }
600
601 // Delete the sprm, so the trackchange range will be started only once.
602 // OTOH set a boolean flag, so we'll know we need to end the range later.
603 RTFValue::Pointer_t pTrackchange
604 = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_trackchange);
605 if (pTrackchange)
606 {
607 m_aStates.top().setStartedTrackchange(true);
608 m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_trackchange);
609 }
610}
611
612void RTFDocumentImpl::runBreak()
613{
614 sal_uInt8 const sBreak[] = { 0xd };
615 Mapper().text(sBreak, 1);
616 m_bNeedCr = false;
617}
618
619void RTFDocumentImpl::tableBreak()
620{
621 runBreak();
622 Mapper().endParagraphGroup();
623 Mapper().startParagraphGroup();
624}
625
626void RTFDocumentImpl::parBreak()
627{
628 checkFirstRun();
629 checkNeedPap();
630 // end previous paragraph
631 Mapper().startCharacterGroup();
632 runBreak();
633 Mapper().endCharacterGroup();
634 Mapper().endParagraphGroup();
635
636 m_bHadPicture = false;
637
638 // start new one
639 Mapper().startParagraphGroup();
640}
641
642void RTFDocumentImpl::sectBreak(bool bFinal)
643{
644 SAL_INFO("writerfilter.rtf", __func__ << ": final? " << bFinal << ", needed? " << m_bNeedSect)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << __func__ << ": final? "
<< bFinal << ", needed? " << m_bNeedSect) ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "644" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << __func__ << ": final? " <<
bFinal << ", needed? " << m_bNeedSect), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
__func__ << ": final? " << bFinal << ", needed? "
<< m_bNeedSect; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "644" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << __func__ << ": final? " << bFinal <<
", needed? " << m_bNeedSect) == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "644" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << __func__ << ": final? " <<
bFinal << ", needed? " << m_bNeedSect), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
__func__ << ": final? " << bFinal << ", needed? "
<< m_bNeedSect; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "644" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
645 bool bNeedSect = m_bNeedSect;
646 RTFValue::Pointer_t pBreak
647 = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
648 bool bContinuous
649 = pBreak
650 && pBreak->getInt()
651 == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous);
652 // If there is no paragraph in this section, then insert a dummy one, as required by Writer,
653 // unless this is the end of the doc, we had nothing since the last section break and this is not a continuous one.
654 // Also, when pasting, it's fine to not have any paragraph inside the document at all.
655 if (m_bNeedPar && (!bFinal || m_bNeedSect || bContinuous) && !isSubstream() && m_bIsNewDoc)
656 dispatchSymbol(RTF_PAR);
657 // It's allowed to not have a non-table paragraph at the end of an RTF doc, add it now if required.
658 if (m_bNeedFinalPar && bFinal)
659 {
660 dispatchFlag(RTF_PARD);
661 dispatchSymbol(RTF_PAR);
662 m_bNeedSect = bNeedSect;
663 }
664 while (!m_nHeaderFooterPositions.empty())
665 {
666 std::pair<Id, std::size_t> aPair = m_nHeaderFooterPositions.front();
667 m_nHeaderFooterPositions.pop();
668 resolveSubstream(aPair.second, aPair.first);
669 }
670
671 // Normally a section break at the end of the doc is necessary. Unless the
672 // last control word in the document is a section break itself.
673 if (!bNeedSect || !m_bHadSect)
674 {
675 // In case the last section is a continuous one, we don't need to output a section break.
676 if (bFinal && bContinuous)
677 m_aStates.top().getSectionSprms().erase(NS_ooxml::LN_EG_SectPrContents_type);
678 }
679
680 // Section properties are a paragraph sprm.
681 auto pValue
682 = new RTFValue(m_aStates.top().getSectionAttributes(), m_aStates.top().getSectionSprms());
683 RTFSprms aAttributes;
684 RTFSprms aSprms;
685 aSprms.set(NS_ooxml::LN_CT_PPr_sectPr, pValue);
686 writerfilter::Reference<Properties>::Pointer_t pProperties
687 = new RTFReferenceProperties(aAttributes, aSprms);
688
689 if (bFinal && !m_pSuperstream)
690 // This is the end of the document, not just the end of e.g. a header.
691 // This makes sure that dmapper can set DontBalanceTextColumns=true for this section if necessary.
692 Mapper().markLastSectionGroup();
693
694 // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects.
695 Mapper().props(pProperties);
696 Mapper().endParagraphGroup();
697
698 // End Section
699 if (!m_pSuperstream)
700 {
701 m_hasFHeader = false;
702 m_hasRHeader = false;
703 m_hasRFooter = false;
704 m_hasFFooter = false;
705 Mapper().endSectionGroup();
706 }
707 m_bNeedPar = false;
708 m_bNeedSect = false;
709}
710
711Color RTFDocumentImpl::getColorTable(sal_uInt32 nIndex)
712{
713 if (!m_pSuperstream)
714 {
715 if (nIndex < m_aColorTable.size())
716 return m_aColorTable[nIndex];
717 return 0;
718 }
719
720 return m_pSuperstream->getColorTable(nIndex);
721}
722
723rtl_TextEncoding RTFDocumentImpl::getEncoding(int nFontIndex)
724{
725 if (!m_pSuperstream)
726 {
727 auto it = m_aFontEncodings.find(nFontIndex);
728 if (it != m_aFontEncodings.end())
729 // We have a font encoding associated to this font.
730 return it->second;
731 if (m_aDefaultState.getCurrentEncoding() != rtl_getTextEncodingFromWindowsCharset(0))
732 // We have a default encoding.
733 return m_aDefaultState.getCurrentEncoding();
734 // Guess based on locale.
735 return msfilter::util::getBestTextEncodingFromLocale(
736 Application::GetSettings().GetLanguageTag().getLocale());
737 }
738
739 return m_pSuperstream->getEncoding(nFontIndex);
740}
741
742OUString RTFDocumentImpl::getFontName(int nIndex)
743{
744 if (!m_pSuperstream)
745 return m_aFontNames[nIndex];
746
747 return m_pSuperstream->getFontName(nIndex);
748}
749
750int RTFDocumentImpl::getFontIndex(int nIndex)
751{
752 if (!m_pSuperstream)
753 return std::find(m_aFontIndexes.begin(), m_aFontIndexes.end(), nIndex)
754 - m_aFontIndexes.begin();
755
756 return m_pSuperstream->getFontIndex(nIndex);
757}
758
759OUString RTFDocumentImpl::getStyleName(int nIndex)
760{
761 if (!m_pSuperstream)
762 {
763 OUString aRet;
764 if (m_aStyleNames.find(nIndex) != m_aStyleNames.end())
765 aRet = m_aStyleNames[nIndex];
766 return aRet;
767 }
768
769 return m_pSuperstream->getStyleName(nIndex);
770}
771
772Id RTFDocumentImpl::getStyleType(int nIndex)
773{
774 if (!m_pSuperstream)
775 {
776 Id nRet = 0;
777 if (m_aStyleTypes.find(nIndex) != m_aStyleTypes.end())
778 nRet = m_aStyleTypes[nIndex];
779 return nRet;
780 }
781
782 return m_pSuperstream->getStyleType(nIndex);
783}
784
785RTFParserState& RTFDocumentImpl::getDefaultState()
786{
787 if (!m_pSuperstream)
788 return m_aDefaultState;
789
790 return m_pSuperstream->getDefaultState();
791}
792
793oox::GraphicHelper& RTFDocumentImpl::getGraphicHelper() { return *m_pGraphicHelper; }
794
795bool RTFDocumentImpl::isStyleSheetImport()
796{
797 if (m_aStates.empty())
798 return false;
799 Destination eDestination = m_aStates.top().getDestination();
800 return eDestination == Destination::STYLESHEET || eDestination == Destination::STYLEENTRY;
801}
802
803void RTFDocumentImpl::resolve(Stream& rMapper)
804{
805 m_pMapperStream = &rMapper;
806 switch (m_pTokenizer->resolveParse())
807 {
808 case RTFError::OK:
809 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: finished without errors")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: finished without errors"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "809" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: finished without errors"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: finished without errors"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "809" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: finished without errors"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "809" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: finished without errors"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: finished without errors"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "809" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
810 break;
811 case RTFError::GROUP_UNDER:
812 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '}'")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: unmatched '}'"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "812" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: unmatched '}'"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: unmatched '}'"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "812" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: unmatched '}'") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "812" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: unmatched '}'"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: unmatched '}'"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "812" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
813 break;
814 case RTFError::GROUP_OVER:
815 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '{'")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: unmatched '{'"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "815" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: unmatched '{'"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: unmatched '{'"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "815" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: unmatched '{'") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "815" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: unmatched '{'"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: unmatched '{'"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "815" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
816 throw io::WrongFormatException(m_pTokenizer->getPosition());
817 break;
818 case RTFError::UNEXPECTED_EOF:
819 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unexpected end of file")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: unexpected end of file"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "819" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: unexpected end of file"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: unexpected end of file";
::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "819" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: unexpected end of file"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "819" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: unexpected end of file"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: unexpected end of file";
::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "819" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
820 throw io::WrongFormatException(m_pTokenizer->getPosition());
821 break;
822 case RTFError::HEX_INVALID:
823 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: invalid hex char")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: invalid hex char"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "823" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: invalid hex char"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: invalid hex char"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "823" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: invalid hex char") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "823" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: invalid hex char"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: invalid hex char"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "823" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
824 throw io::WrongFormatException(m_pTokenizer->getPosition());
825 break;
826 case RTFError::CHAR_OVER:
827 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: characters after last '}'")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: characters after last '}'"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "827" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: characters after last '}'"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: characters after last '}'"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "827" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: characters after last '}'"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "827" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: characters after last '}'"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: characters after last '}'"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "827" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
828 break;
829 case RTFError::CLASSIFICATION:
830 SAL_INFO("writerfilter.rtf",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: classification prevented paste"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: classification prevented paste"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: classification prevented paste"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: classification prevented paste"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: classification prevented paste"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: classification prevented paste"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
831 "RTFDocumentImpl::resolve: classification prevented paste")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolve: classification prevented paste"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: classification prevented paste"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: classification prevented paste"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolve: classification prevented paste"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "RTFDocumentImpl::resolve: classification prevented paste"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RTFDocumentImpl::resolve: classification prevented paste"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "831" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
832 break;
833 }
834}
835
836void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XShape> const& rShape)
837{
838 SvMemoryStream aStream;
839 SvStream* pStream = nullptr;
840 if (!m_pBinaryData)
841 {
842 pStream = &aStream;
843 int b = 0;
844 int count = 2;
845
846 // Feed the destination text to a stream.
847 OString aStr = OUStringToOString(m_aStates.top().getDestinationText().makeStringAndClear(),
848 RTL_TEXTENCODING_ASCII_US(((rtl_TextEncoding) 11)));
849 for (int i = 0; i < aStr.getLength(); ++i)
850 {
851 char ch = aStr[i];
852 if (ch != 0x0d && ch != 0x0a && ch != 0x20)
853 {
854 b = b << 4;
855 sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
856 if (parsed == -1)
857 return;
858 b += parsed;
859 count--;
860 if (!count)
861 {
862 aStream.WriteChar(static_cast<char>(b));
863 count = 2;
864 b = 0;
865 }
866 }
867 }
868 }
869 else
870 pStream = m_pBinaryData.get();
871
872 if (!pStream->Tell())
873 // No destination text? Then we'll get it later.
874 return;
875
876 SvMemoryStream aDIBStream;
877 if (m_aStates.top().getPicture().eStyle == RTFBmpStyle::DIBITMAP)
878 {
879 // Construct a BITMAPFILEHEADER structure before the real data.
880 SvStream& rBodyStream = *pStream;
881 aDIBStream.WriteChar('B');
882 aDIBStream.WriteChar('M');
883 // The size of the real data.
884 aDIBStream.WriteUInt32(rBodyStream.Tell());
885 // Reserved.
886 aDIBStream.WriteUInt32(0);
887 // The offset of the real data, i.e. the size of the header, including this number.
888 aDIBStream.WriteUInt32(14);
889 rBodyStream.Seek(0);
890 aDIBStream.WriteStream(rBodyStream);
891 pStream = &aDIBStream;
892 }
893
894 // Store, and get its URL.
895 pStream->Seek(0);
896 uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream));
897 WmfExternal aExtHeader;
898 aExtHeader.mapMode = m_aStates.top().getPicture().eWMetafile;
899 aExtHeader.xExt = sal_uInt16(
900 std::clamp<sal_Int32>(m_aStates.top().getPicture().nWidth, 0,
901 SAL_MAX_UINT16((sal_uInt16) 0xFFFF))); //TODO: better way to handle out-of-bounds values?
902 aExtHeader.yExt = sal_uInt16(
903 std::clamp<sal_Int32>(m_aStates.top().getPicture().nHeight, 0,
904 SAL_MAX_UINT16((sal_uInt16) 0xFFFF))); //TODO: better way to handle out-of-bounds values?
905 WmfExternal* pExtHeader = &aExtHeader;
906 uno::Reference<lang::XServiceInfo> xServiceInfo(m_aStates.top().getDrawingObject().getShape(),
907 uno::UNO_QUERY);
908 if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
909 pExtHeader = nullptr;
910
911 uno::Reference<graphic::XGraphic> xGraphic
912 = m_pGraphicHelper->importGraphic(xInputStream, pExtHeader);
913
914 if (m_aStates.top().getPicture().eStyle != RTFBmpStyle::NONE)
915 {
916 // In case of PNG/JPEG, the real size is known, don't use the values
917 // provided by picw and pich.
918
919 Graphic aGraphic(xGraphic);
920 Size aSize(aGraphic.GetPrefSize());
921 MapMode aMap(MapUnit::Map100thMM);
922 if (aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
923 aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMap);
924 else
925 aSize = OutputDevice::LogicToLogic(aSize, aGraphic.GetPrefMapMode(), aMap);
926 m_aStates.top().getPicture().nWidth = aSize.Width();
927 m_aStates.top().getPicture().nHeight = aSize.Height();
928 }
929
930 // Wrap it in an XShape.
931 uno::Reference<drawing::XShape> xShape(rShape);
932 if (xShape.is())
933 {
934 uno::Reference<lang::XServiceInfo> xSI(xShape, uno::UNO_QUERY_THROW);
935 if (!xSI->supportsService("com.sun.star.drawing.GraphicObjectShape"))
936 {
937 // it's sometimes an error to get here - but it's possible to have
938 // a \pict inside the \shptxt of a \shp of shapeType 202 "TextBox"
939 // and in that case xShape is the text frame; we actually need a
940 // new GraphicObject then (example: fdo37691-1.rtf)
941 SAL_INFO("writerfilter.rtf",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "cannot set graphic on existing shape, creating a new GraphicObjectShape"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "cannot set graphic on existing shape, creating a new GraphicObjectShape"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
942 "cannot set graphic on existing shape, creating a new GraphicObjectShape")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "cannot set graphic on existing shape, creating a new GraphicObjectShape"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "cannot set graphic on existing shape, creating a new GraphicObjectShape"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "cannot set graphic on existing shape, creating a new GraphicObjectShape"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "942" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
943 xShape.clear();
944 }
945 }
946 if (!xShape.is())
947 {
948 if (m_xModelFactory.is())
949 xShape.set(m_xModelFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
950 uno::UNO_QUERY);
951 uno::Reference<drawing::XDrawPageSupplier> const xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
952 if (xDrawSupplier.is())
953 {
954 uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
955 if (xShapes.is())
956 xShapes->add(xShape);
957 }
958 }
959
960 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
961
962 if (xPropertySet.is())
963 xPropertySet->setPropertyValue("Graphic", uno::Any(xGraphic));
964
965 // check if the picture is in an OLE object and if the \objdata element is used
966 // (see RTF_OBJECT in RTFDocumentImpl::dispatchDestination)
967 if (m_bObject)
968 {
969 // Set the object size
970 awt::Size aSize;
971 aSize.Width
972 = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
973 : m_aStates.top().getPicture().nWidth);
974 aSize.Height
975 = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
976 : m_aStates.top().getPicture().nHeight);
977 xShape->setSize(aSize);
978
979 // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert().
980 xPropertySet->setPropertyValue("AnchorType",
981 uno::makeAny(text::TextContentAnchorType_AS_CHARACTER));
982
983 auto pShapeValue = new RTFValue(xShape);
984 m_aObjectAttributes.set(NS_ooxml::LN_shape, pShapeValue);
985 return;
986 }
987
988 if (m_aStates.top().getInListpicture())
989 {
990 // Send the shape directly, no section is started, to additional properties will be ignored anyway.
991 Mapper().startShape(xShape);
992 Mapper().endShape();
993 return;
994 }
995
996 // Send it to the dmapper.
997 RTFSprms aSprms;
998 RTFSprms aAttributes;
999 // shape attribute
1000 RTFSprms aPicAttributes;
1001 auto pShapeValue = new RTFValue(xShape);
1002 aPicAttributes.set(NS_ooxml::LN_shape, pShapeValue);
1003 // pic sprm
1004 RTFSprms aGraphicDataAttributes;
1005 RTFSprms aGraphicDataSprms;
1006 auto pPicValue = new RTFValue(aPicAttributes);
1007 aGraphicDataSprms.set(NS_ooxml::LN_pic_pic, pPicValue);
1008 // graphicData sprm
1009 RTFSprms aGraphicAttributes;
1010 RTFSprms aGraphicSprms;
1011 auto pGraphicDataValue = new RTFValue(aGraphicDataAttributes, aGraphicDataSprms);
1012 aGraphicSprms.set(NS_ooxml::LN_CT_GraphicalObject_graphicData, pGraphicDataValue);
1013 // graphic sprm
1014 auto pGraphicValue = new RTFValue(aGraphicAttributes, aGraphicSprms);
1015 // extent sprm
1016 RTFSprms aExtentAttributes;
1017 int nXExt = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
1018 : m_aStates.top().getPicture().nWidth);
1019 int nYExt = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
1020 : m_aStates.top().getPicture().nHeight);
1021 if (m_aStates.top().getPicture().nScaleX != 100)
1022 nXExt = (static_cast<long>(m_aStates.top().getPicture().nScaleX)
1023 * (nXExt
1024 - (m_aStates.top().getPicture().nCropL + m_aStates.top().getPicture().nCropR)))
1025 / 100L;
1026 if (m_aStates.top().getPicture().nScaleY != 100)
1027 nYExt = (static_cast<long>(m_aStates.top().getPicture().nScaleY)
1028 * (nYExt
1029 - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB)))
1030 / 100L;
1031 if (m_aStates.top().getInShape())
1032 {
1033 // Picture in shape: it looks like pib picture, so we will stretch the picture to shape size (tdf#49893)
1034 nXExt = m_aStates.top().getShape().getRight() - m_aStates.top().getShape().getLeft();
1035 nYExt = m_aStates.top().getShape().getBottom() - m_aStates.top().getShape().getTop();
1036 }
1037 auto pXExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nXExt));
1038 auto pYExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nYExt));
1039 aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cx, pXExtValue);
1040 aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cy, pYExtValue);
1041 auto pExtentValue = new RTFValue(aExtentAttributes);
1042 // docpr sprm
1043 RTFSprms aDocprAttributes;
1044 for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
1045 if (rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_name
1046 || rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_descr)
1047 aDocprAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
1048 auto pDocprValue = new RTFValue(aDocprAttributes);
1049 if (bInline)
1050 {
1051 RTFSprms aInlineAttributes;
1052 aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distT, new RTFValue(0));
1053 aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distB, new RTFValue(0));
1054 aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distL, new RTFValue(0));
1055 aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distR, new RTFValue(0));
1056 RTFSprms aInlineSprms;
1057 aInlineSprms.set(NS_ooxml::LN_CT_Inline_extent, pExtentValue);
1058 aInlineSprms.set(NS_ooxml::LN_CT_Inline_docPr, pDocprValue);
1059 aInlineSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
1060 // inline sprm
1061 auto pValue = new RTFValue(aInlineAttributes, aInlineSprms);
1062 aSprms.set(NS_ooxml::LN_inline_inline, pValue);
1063 }
1064 else // anchored
1065 {
1066 // wrap sprm
1067 RTFSprms aAnchorWrapAttributes;
1068 m_aStates.top().getShape().getAnchorAttributes().set(
1069 NS_ooxml::LN_CT_Anchor_behindDoc,
1070 new RTFValue((m_aStates.top().getShape().getInBackground()) ? 1 : 0));
1071 RTFSprms aAnchorSprms;
1072 for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
1073 {
1074 if (rCharacterAttribute.first == NS_ooxml::LN_CT_WrapSquare_wrapText)
1075 aAnchorWrapAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
1076 }
1077 sal_Int32 nWrap = -1;
1078 for (auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
1079 {
1080 if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
1081 || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
1082 {
1083 nWrap = rCharacterSprm.first;
1084
1085 // If there is a wrap polygon prepared by RTFSdrImport, pick it up here.
1086 if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight
1087 && !m_aStates.top().getShape().getWrapPolygonSprms().empty())
1088 rCharacterSprm.second->getSprms().set(
1089 NS_ooxml::LN_CT_WrapTight_wrapPolygon,
1090 new RTFValue(RTFSprms(), m_aStates.top().getShape().getWrapPolygonSprms()));
1091
1092 aAnchorSprms.set(rCharacterSprm.first, rCharacterSprm.second);
1093 }
1094 }
1095
1096 if (m_aStates.top().getShape().getWrapSprm().first != 0)
1097 // Replay of a buffered shape, wrap sprm there has priority over
1098 // character sprms of the current state.
1099 aAnchorSprms.set(m_aStates.top().getShape().getWrapSprm().first,
1100 m_aStates.top().getShape().getWrapSprm().second);
1101
1102 aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_extent, pExtentValue);
1103 if (!aAnchorWrapAttributes.empty() && nWrap == -1)
1104 aAnchorSprms.set(NS_ooxml::LN_EG_WrapType_wrapSquare,
1105 new RTFValue(aAnchorWrapAttributes));
1106
1107 // See OOXMLFastContextHandler::positionOffset(), we can't just put offset values in an RTFValue.
1108 RTFSprms aPoshAttributes;
1109 RTFSprms aPoshSprms;
1110 if (m_aStates.top().getShape().getHoriOrientRelationToken() > 0)
1111 aPoshAttributes.set(
1112 NS_ooxml::LN_CT_PosH_relativeFrom,
1113 new RTFValue(m_aStates.top().getShape().getHoriOrientRelationToken()));
1114 if (m_aStates.top().getShape().getLeft() != 0)
1115 {
1116 Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
1117 m_aStates.top().getShape().getLeft())),
1118 /*bVertical=*/false);
1119 aPoshSprms.set(NS_ooxml::LN_CT_PosH_posOffset, new RTFValue());
1120 }
1121 aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionH,
1122 new RTFValue(aPoshAttributes, aPoshSprms));
1123
1124 RTFSprms aPosvAttributes;
1125 RTFSprms aPosvSprms;
1126 if (m_aStates.top().getShape().getVertOrientRelationToken() > 0)
1127 aPosvAttributes.set(
1128 NS_ooxml::LN_CT_PosV_relativeFrom,
1129 new RTFValue(m_aStates.top().getShape().getVertOrientRelationToken()));
1130 if (m_aStates.top().getShape().getTop() != 0)
1131 {
1132 Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
1133 m_aStates.top().getShape().getTop())),
1134 /*bVertical=*/true);
1135 aPosvSprms.set(NS_ooxml::LN_CT_PosV_posOffset, new RTFValue());
1136 }
1137 aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionV,
1138 new RTFValue(aPosvAttributes, aPosvSprms));
1139
1140 aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_docPr, pDocprValue);
1141 aAnchorSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
1142 // anchor sprm
1143 auto pValue = new RTFValue(m_aStates.top().getShape().getAnchorAttributes(), aAnchorSprms);
1144 aSprms.set(NS_ooxml::LN_anchor_anchor, pValue);
1145 }
1146 writerfilter::Reference<Properties>::Pointer_t pProperties
1147 = new RTFReferenceProperties(aAttributes, aSprms);
1148 checkFirstRun();
1149
1150 if (!m_aStates.top().getCurrentBuffer())
1151 {
1152 Mapper().props(pProperties);
1153 // Make sure we don't lose these properties with a too early reset.
1154 m_bHadPicture = true;
1155 }
1156 else
1157 {
1158 auto pValue = new RTFValue(aAttributes, aSprms);
1159 bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
1160 }
1161}
1162
1163RTFError RTFDocumentImpl::resolveChars(char ch)
1164{
1165 if (m_aStates.top().getInternalState() == RTFInternalState::BIN)
1166 {
1167 m_pBinaryData = std::make_shared<SvMemoryStream>();
1168 m_pBinaryData->WriteChar(ch);
1169 for (int i = 0; i < m_aStates.top().getBinaryToRead() - 1; ++i)
1170 {
1171 Strm().ReadChar(ch);
1172 m_pBinaryData->WriteChar(ch);
1173 }
1174 m_aStates.top().setInternalState(RTFInternalState::NORMAL);
1175 return RTFError::OK;
1176 }
1177
1178 OStringBuffer aBuf(512);
1179
1180 bool bUnicodeChecked = false;
1181 bool bSkipped = false;
1182
1183 while (!Strm().eof()
1184 && (m_aStates.top().getInternalState() == RTFInternalState::HEX
1185 || (ch != '{' && ch != '}' && ch != '\\')))
1186 {
1187 if (m_aStates.top().getInternalState() == RTFInternalState::HEX
1188 || (ch != 0x0d && ch != 0x0a))
1189 {
1190 if (m_aStates.top().getCharsToSkip() == 0)
1191 {
1192 if (!bUnicodeChecked)
1193 {
1194 checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
1195 bUnicodeChecked = true;
1196 }
1197 aBuf.append(ch);
1198 }
1199 else
1200 {
1201 bSkipped = true;
1202 m_aStates.top().getCharsToSkip()--;
1203 }
1204 }
1205
1206 // read a single char if we're in hex mode
1207 if (m_aStates.top().getInternalState() == RTFInternalState::HEX)
1208 break;
1209
1210 if (RTL_TEXTENCODING_MS_932(((rtl_TextEncoding) 60)) == m_aStates.top().getCurrentEncoding())
1211 {
1212 unsigned char uch = ch;
1213 if ((uch >= 0x80 && uch <= 0x9F) || uch >= 0xE0)
1214 {
1215 // read second byte of 2-byte Shift-JIS - may be \ { }
1216 Strm().ReadChar(ch);
1217 if (m_aStates.top().getCharsToSkip() == 0)
1218 {
1219 // fdo#79384: Word will reject Shift-JIS following \loch
1220 // but apparently OOo could read and (worse) write such documents
1221 SAL_INFO_IF(m_aStates.top().getRunType() != RTFParserState::RunType::DBCH,do { if (true && (m_aStates.top().getRunType() != RTFParserState
::RunType::DBCH)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "invalid Shift-JIS without DBCH"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid Shift-JIS without DBCH"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "invalid Shift-JIS without DBCH"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid Shift-JIS without DBCH") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid Shift-JIS without DBCH"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "invalid Shift-JIS without DBCH"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1222 "writerfilter.rtf", "invalid Shift-JIS without DBCH")do { if (true && (m_aStates.top().getRunType() != RTFParserState
::RunType::DBCH)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "invalid Shift-JIS without DBCH"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid Shift-JIS without DBCH"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "invalid Shift-JIS without DBCH"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid Shift-JIS without DBCH") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid Shift-JIS without DBCH"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "invalid Shift-JIS without DBCH"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1222" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1223 assert(bUnicodeChecked)(static_cast <bool> (bUnicodeChecked) ? void (0) : __assert_fail
("bUnicodeChecked", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 1223, __extension__ __PRETTY_FUNCTION__))
;
1224 aBuf.append(ch);
1225 }
1226 else
1227 {
1228 assert(bSkipped)(static_cast <bool> (bSkipped) ? void (0) : __assert_fail
("bSkipped", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 1228, __extension__ __PRETTY_FUNCTION__))
;
1229 // anybody who uses \ucN with Shift-JIS is insane
1230 m_aStates.top().getCharsToSkip()--;
1231 }
1232 }
1233 }
1234
1235 Strm().ReadChar(ch);
1236 }
1237 if (m_aStates.top().getInternalState() != RTFInternalState::HEX && !Strm().eof())
1238 Strm().SeekRel(-1);
1239
1240 if (m_aStates.top().getInternalState() == RTFInternalState::HEX
1241 && m_aStates.top().getDestination() != Destination::LEVELNUMBERS)
1242 {
1243 if (!bSkipped)
1244 {
1245 // note: apparently \'0d\'0a is interpreted as 2 breaks, not 1
1246 if ((ch == '\r' || ch == '\n')
1247 && m_aStates.top().getDestination() != Destination::DOCCOMM
1248 && m_aStates.top().getDestination() != Destination::LEVELNUMBERS
1249 && m_aStates.top().getDestination() != Destination::LEVELTEXT)
1250 {
1251 checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
1252 dispatchSymbol(RTF_PAR);
1253 }
1254 else
1255 {
1256 m_aHexBuffer.append(ch);
1257 }
1258 }
1259 return RTFError::OK;
1260 }
1261
1262 if (m_aStates.top().getDestination() == Destination::SKIP)
1263 return RTFError::OK;
1264 OString aStr = aBuf.makeStringAndClear();
1265 if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
1266 {
1267 if (aStr.toChar() != ';')
1268 m_aStates.top().getLevelNumbers().push_back(sal_Int32(ch));
1269 return RTFError::OK;
1270 }
1271
1272 SAL_INFO("writerfilter.rtf",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolveChars: collected '" <<
OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()
) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1273 "RTFDocumentImpl::resolveChars: collected '"do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolveChars: collected '" <<
OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()
) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1274 << OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()) << "'")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RTFDocumentImpl::resolveChars: collected '" <<
OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()
) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "RTFDocumentImpl::resolveChars: collected '"
<< OStringToOUString(aStr, m_aStates.top().getCurrentEncoding
()) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1274" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1275
1276 if (m_aStates.top().getDestination() == Destination::COLORTABLE)
1277 {
1278 // we hit a ';' at the end of each color entry
1279 m_aColorTable.push_back(m_aStates.top().getCurrentColor().GetColor());
1280 // set components back to zero
1281 m_aStates.top().getCurrentColor() = RTFColorTableEntry();
1282 }
1283 else if (!aStr.isEmpty())
1284 m_aHexBuffer.append(aStr);
1285
1286 checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
1287 return RTFError::OK;
1288}
1289
1290bool RTFFrame::inFrame() const { return m_nW > 0 || m_nH > 0 || m_nX > 0 || m_nY > 0; }
1291
1292void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
1293{
1294 sal_uInt8 sValue[] = { nValue };
1295 RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
1296
1297 if (!pCurrentBuffer)
1298 {
1299 Mapper().startCharacterGroup();
1300 // Should we send run properties?
1301 if (bRunProps)
1302 runProps();
1303 Mapper().text(sValue, 1);
1304 Mapper().endCharacterGroup();
1305 }
1306 else
1307 {
1308 pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, nullptr, nullptr));
1309 auto pValue = new RTFValue(*sValue);
1310 pCurrentBuffer->push_back(Buf_t(BUFFER_TEXT, pValue, nullptr));
1311 pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, nullptr, nullptr));
1312 }
1313}
1314
1315void RTFDocumentImpl::text(OUString& rString)
1316{
1317 if (rString.getLength() == 1 && m_aStates.top().getDestination() != Destination::DOCCOMM)
1
Assuming the condition is false
1318 {
1319 // No cheating! Tokenizer ignores bare \r and \n, their hex \'0d / \'0a form doesn't count, either.
1320 sal_Unicode ch = rString[0];
1321 if (ch == 0x0d || ch == 0x0a)
1322 return;
1323 }
1324
1325 bool bRet = true;
1326 switch (m_aStates.top().getDestination())
2
Control jumps to 'case REVISIONENTRY:' at line 1334
1327 {
1328 // Note: in fonttbl there may or may not be groups; in stylesheet
1329 // and revtbl groups are mandatory
1330 case Destination::FONTTABLE:
1331 case Destination::FONTENTRY:
1332 case Destination::STYLEENTRY:
1333 case Destination::LISTNAME:
1334 case Destination::REVISIONENTRY:
1335 {
1336 // ; is the end of the entry
1337 bool bEnd = false;
1338 if (rString.endsWith(";"))
3
Taking true branch
1339 {
1340 rString = rString.copy(0, rString.getLength() - 1);
1341 bEnd = true;
1342 }
1343 m_aStates.top().appendDestinationText(rString);
1344 if (bEnd
3.1
'bEnd' is true
3.1
'bEnd' is true
)
4
Taking true branch
1345 {
1346 // always clear, necessary in case of group-less fonttable
1347 OUString const aName
1348 = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
1349 switch (m_aStates.top().getDestination())
5
Control jumps to 'case STYLEENTRY:' at line 1379
1350 {
1351 case Destination::FONTTABLE:
1352 case Destination::FONTENTRY:
1353 {
1354 m_aFontNames[m_nCurrentFontIndex] = aName;
1355 if (m_nCurrentEncoding >= 0)
1356 {
1357 m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
1358 m_nCurrentEncoding = -1;
1359 }
1360 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
1361 new RTFValue(aName));
1362
1363 writerfilter::Reference<Properties>::Pointer_t const pProp(
1364 new RTFReferenceProperties(m_aStates.top().getTableAttributes(),
1365 m_aStates.top().getTableSprms()));
1366
1367 //See fdo#47347 initial invalid font entry properties are inserted first,
1368 //so when we attempt to insert the correct ones, there's already an
1369 //entry in the map for them, so the new ones aren't inserted.
1370 auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
1371 if (lb != m_aFontTableEntries.end()
1372 && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
1373 lb->second = pProp;
1374 else
1375 m_aFontTableEntries.insert(lb,
1376 std::make_pair(m_nCurrentFontIndex, pProp));
1377 }
1378 break;
1379 case Destination::STYLEENTRY:
1380 {
1381 RTFValue::Pointer_t pType
1382 = m_aStates.top().getTableAttributes().find(NS_ooxml::LN_CT_Style_type);
1383 if (pType)
6
Taking true branch
1384 {
1385 // Word strips whitespace around style names.
1386 m_aStyleNames[m_nCurrentStyleIndex] = aName.trim();
1387 m_aStyleTypes[m_nCurrentStyleIndex] = pType->getInt();
1388 auto pValue = new RTFValue(aName.trim());
7
Memory is allocated
1389 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_styleId,
1390 pValue);
8
Calling '~SvRef'
18
Returning from '~SvRef'
1391 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_name, pValue);
19
Use of memory after it is freed
1392
1393 writerfilter::Reference<Properties>::Pointer_t const pProp(
1394 createStyleProperties());
1395 m_aStyleTableEntries.insert(
1396 std::make_pair(m_nCurrentStyleIndex, pProp));
1397 }
1398 else
1399 SAL_INFO("writerfilter.rtf", "no RTF style type defined, ignoring")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "no RTF style type defined, ignoring"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1399" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no RTF style type defined, ignoring"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "no RTF style type defined, ignoring"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1399" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "no RTF style type defined, ignoring") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1399" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "no RTF style type defined, ignoring"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "no RTF style type defined, ignoring"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1399" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1400 break;
1401 }
1402 case Destination::LISTNAME:
1403 // TODO: what can be done with a list name?
1404 break;
1405 case Destination::REVISIONENTRY:
1406 m_aAuthors[m_aAuthors.size()] = aName;
1407 break;
1408 default:
1409 break;
1410 }
1411 resetAttributes();
1412 resetSprms();
1413 }
1414 }
1415 break;
1416 case Destination::LEVELTEXT:
1417 case Destination::SHAPEPROPERTYNAME:
1418 case Destination::SHAPEPROPERTYVALUE:
1419 case Destination::BOOKMARKEND:
1420 case Destination::PICT:
1421 case Destination::SHAPEPROPERTYVALUEPICT:
1422 case Destination::FORMFIELDNAME:
1423 case Destination::FORMFIELDLIST:
1424 case Destination::DATAFIELD:
1425 case Destination::AUTHOR:
1426 case Destination::KEYWORDS:
1427 case Destination::OPERATOR:
1428 case Destination::COMPANY:
1429 case Destination::COMMENT:
1430 case Destination::OBJDATA:
1431 case Destination::OBJCLASS:
1432 case Destination::ANNOTATIONDATE:
1433 case Destination::ANNOTATIONAUTHOR:
1434 case Destination::ANNOTATIONREFERENCE:
1435 case Destination::FALT:
1436 case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
1437 case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
1438 case Destination::TITLE:
1439 case Destination::SUBJECT:
1440 case Destination::DOCCOMM:
1441 case Destination::ATNID:
1442 case Destination::ANNOTATIONREFERENCESTART:
1443 case Destination::ANNOTATIONREFERENCEEND:
1444 case Destination::MR:
1445 case Destination::MCHR:
1446 case Destination::MPOS:
1447 case Destination::MVERTJC:
1448 case Destination::MSTRIKEH:
1449 case Destination::MDEGHIDE:
1450 case Destination::MBEGCHR:
1451 case Destination::MSEPCHR:
1452 case Destination::MENDCHR:
1453 case Destination::MSUBHIDE:
1454 case Destination::MSUPHIDE:
1455 case Destination::MTYPE:
1456 case Destination::MGROW:
1457 case Destination::INDEXENTRY:
1458 case Destination::TOCENTRY:
1459 case Destination::PROPNAME:
1460 case Destination::STATICVAL:
1461 m_aStates.top().appendDestinationText(rString);
1462 break;
1463 case Destination::GENERATOR:
1464 // don't enlarge space sequences, eg. it was saved in LibreOffice
1465 if (!rString.startsWithIgnoreAsciiCase("Microsoft"))
1466 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
1467 new RTFValue(0));
1468 break;
1469 default:
1470 bRet = false;
1471 break;
1472 }
1473 if (bRet)
1474 return;
1475
1476 if (!m_aIgnoreFirst.isEmpty() && m_aIgnoreFirst == rString)
1477 {
1478 m_aIgnoreFirst.clear();
1479 return;
1480 }
1481
1482 // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
1483 if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign)
1484 && m_nTopLevelCells == 0)
1485 {
1486 m_aTableBufferStack.back().emplace_back(
1487 Buf_t(BUFFER_UTEXT, new RTFValue(rString), nullptr));
1488 return;
1489 }
1490
1491 checkFirstRun();
1492 checkNeedPap();
1493
1494 // Don't return earlier, a bookmark start has to be in a paragraph group.
1495 if (m_aStates.top().getDestination() == Destination::BOOKMARKSTART)
1496 {
1497 m_aStates.top().appendDestinationText(rString);
1498 return;
1499 }
1500
1501 RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
1502
1503 if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
1504 Mapper().startCharacterGroup();
1505 else if (pCurrentBuffer)
1506 {
1507 RTFValue::Pointer_t pValue;
1508 pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, pValue, nullptr));
1509 }
1510
1511 if (m_aStates.top().getDestination() == Destination::NORMAL
1512 || m_aStates.top().getDestination() == Destination::FIELDRESULT
1513 || m_aStates.top().getDestination() == Destination::SHAPETEXT)
1514 runProps();
1515
1516 if (!pCurrentBuffer)
1517 Mapper().utext(reinterpret_cast<sal_uInt8 const*>(rString.getStr()), rString.getLength());
1518 else
1519 {
1520 auto pValue = new RTFValue(rString);
1521 pCurrentBuffer->push_back(Buf_t(BUFFER_UTEXT, pValue, nullptr));
1522 }
1523
1524 m_bNeedCr = true;
1525
1526 if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
1527 Mapper().endCharacterGroup();
1528 else if (pCurrentBuffer)
1529 {
1530 RTFValue::Pointer_t pValue;
1531 pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, pValue, nullptr));
1532 }
1533}
1534
1535void RTFDocumentImpl::prepareProperties(
1536 RTFParserState& rState, writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
1537 writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
1538 writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties, int const nCells,
1539 int const nCurrentCellX)
1540{
1541 o_rpParagraphProperties
1542 = getProperties(rState.getParagraphAttributes(), rState.getParagraphSprms(),
1543 NS_ooxml::LN_Value_ST_StyleType_paragraph);
1544
1545 if (rState.getFrame().hasProperties())
1546 {
1547 o_rpFrameProperties = new RTFReferenceProperties(RTFSprms(), rState.getFrame().getSprms());
1548 }
1549
1550 // Table width.
1551 RTFValue::Pointer_t const pTableWidthProps
1552 = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblW);
1553 if (!pTableWidthProps)
1554 {
1555 auto pUnitValue = new RTFValue(3);
1556 putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
1557 NS_ooxml::LN_CT_TblWidth_type, pUnitValue);
1558 auto pWValue = new RTFValue(nCurrentCellX);
1559 putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
1560 NS_ooxml::LN_CT_TblWidth_w, pWValue);
1561 }
1562
1563 if (nCells > 0)
1564 rState.getTableRowSprms().set(NS_ooxml::LN_tblRow, new RTFValue(1));
1565
1566 RTFValue::Pointer_t const pCellMar
1567 = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
1568 if (!pCellMar)
1569 {
1570 // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
1571 RTFSprms aAttributes;
1572 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1573 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1574 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(0));
1575 putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
1576 NS_ooxml::LN_CT_TblCellMar_left, new RTFValue(aAttributes));
1577 putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
1578 NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
1579 }
1580
1581 o_rpTableRowProperties
1582 = new RTFReferenceProperties(rState.getTableRowAttributes(), rState.getTableRowSprms());
1583}
1584
1585void RTFDocumentImpl::sendProperties(
1586 writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
1587 writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
1588 writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties)
1589{
1590 Mapper().props(pParagraphProperties);
1591
1592 if (pFrameProperties)
1593 {
1594 Mapper().props(pFrameProperties);
1595 }
1596
1597 Mapper().props(pTableRowProperties);
1598
1599 tableBreak();
1600}
1601
1602void RTFDocumentImpl::replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSrpms,
1603 ::std::deque<RTFSprms>& rCellsAttributes, int const nCells)
1604{
1605 for (int i = 0; i < nCells; ++i)
1606 {
1607 replayBuffer(rBuffer, &rCellsSrpms.front(), &rCellsAttributes.front());
1608 rCellsSrpms.pop_front();
1609 rCellsAttributes.pop_front();
1610 }
1611 for (Buf_t& i : rBuffer)
1612 {
1613 SAL_WARN_IF(BUFFER_CELLEND == std::get<0>(i), "writerfilter.rtf", "dropping table cell!")do { if (true && (BUFFER_CELLEND == std::get<0>
(i))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "dropping table cell!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1613" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "dropping table cell!"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"dropping table cell!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1613" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "dropping table cell!") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1613" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "dropping table cell!"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"dropping table cell!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1613" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1614 }
1615 assert(rCellsSrpms.empty())(static_cast <bool> (rCellsSrpms.empty()) ? void (0) : __assert_fail
("rCellsSrpms.empty()", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 1615, __extension__ __PRETTY_FUNCTION__))
;
1616 assert(rCellsAttributes.empty())(static_cast <bool> (rCellsAttributes.empty()) ? void (
0) : __assert_fail ("rCellsAttributes.empty()", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 1616, __extension__ __PRETTY_FUNCTION__))
;
1617}
1618
1619void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms,
1620 RTFSprms const* const pAttributes)
1621{
1622 while (!rBuffer.empty())
1623 {
1624 Buf_t aTuple(rBuffer.front());
1625 rBuffer.pop_front();
1626 if (std::get<0>(aTuple) == BUFFER_PROPS)
1627 {
1628 // Construct properties via getProperties() and not directly, to take care of deduplication.
1629 writerfilter::Reference<Properties>::Pointer_t const pProp(getProperties(
1630 std::get<1>(aTuple)->getAttributes(), std::get<1>(aTuple)->getSprms(), 0));
1631 Mapper().props(pProp);
1632 }
1633 else if (std::get<0>(aTuple) == BUFFER_NESTROW)
1634 {
1635 TableRowBuffer& rRowBuffer(*std::get<2>(aTuple));
1636
1637 replayRowBuffer(rRowBuffer.GetBuffer(), rRowBuffer.GetCellsSprms(),
1638 rRowBuffer.GetCellsAttributes(), rRowBuffer.GetCells());
1639
1640 sendProperties(rRowBuffer.GetParaProperties(), rRowBuffer.GetFrameProperties(),
1641 rRowBuffer.GetRowProperties());
1642 }
1643 else if (std::get<0>(aTuple) == BUFFER_CELLEND)
1644 {
1645 assert(pSprms && pAttributes)(static_cast <bool> (pSprms && pAttributes) ? void
(0) : __assert_fail ("pSprms && pAttributes", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 1645, __extension__ __PRETTY_FUNCTION__))
;
1646 auto pValue = new RTFValue(1);
1647 pSprms->set(NS_ooxml::LN_tblCell, pValue);
1648 writerfilter::Reference<Properties>::Pointer_t const pTableCellProperties(
1649 new RTFReferenceProperties(*pAttributes, *pSprms));
1650 Mapper().props(pTableCellProperties);
1651 tableBreak();
1652 break;
1653 }
1654 else if (std::get<0>(aTuple) == BUFFER_STARTRUN)
1655 Mapper().startCharacterGroup();
1656 else if (std::get<0>(aTuple) == BUFFER_TEXT)
1657 {
1658 sal_uInt8 const nValue = std::get<1>(aTuple)->getInt();
1659 Mapper().text(&nValue, 1);
1660 }
1661 else if (std::get<0>(aTuple) == BUFFER_UTEXT)
1662 {
1663 OUString const aString(std::get<1>(aTuple)->getString());
1664 Mapper().utext(reinterpret_cast<sal_uInt8 const*>(aString.getStr()),
1665 aString.getLength());
1666 }
1667 else if (std::get<0>(aTuple) == BUFFER_ENDRUN)
1668 Mapper().endCharacterGroup();
1669 else if (std::get<0>(aTuple) == BUFFER_PAR)
1670 parBreak();
1671 else if (std::get<0>(aTuple) == BUFFER_STARTSHAPE)
1672 m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), false, RTFSdrImport::SHAPE);
1673 else if (std::get<0>(aTuple) == BUFFER_RESOLVESHAPE)
1674 {
1675 // Make sure there is no current buffer while replaying the shape,
1676 // otherwise it gets re-buffered.
1677 RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
1678 m_aStates.top().setCurrentBuffer(nullptr);
1679
1680 // Set current shape during replay, needed by e.g. wrap in
1681 // background.
1682 m_aStates.top().getShape() = std::get<1>(aTuple)->getShape();
1683
1684 m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), true, RTFSdrImport::SHAPE);
1685 m_aStates.top().setCurrentBuffer(pCurrentBuffer);
1686 }
1687 else if (std::get<0>(aTuple) == BUFFER_ENDSHAPE)
1688 m_pSdrImport->close();
1689 else if (std::get<0>(aTuple) == BUFFER_RESOLVESUBSTREAM)
1690 {
1691 RTFSprms& rAttributes = std::get<1>(aTuple)->getAttributes();
1692 std::size_t nPos = rAttributes.find(0)->getInt();
1693 Id nId = rAttributes.find(1)->getInt();
1694 OUString aCustomMark = rAttributes.find(2)->getString();
1695 resolveSubstream(nPos, nId, aCustomMark);
1696 }
1697 else if (std::get<0>(aTuple) == BUFFER_PICTURE)
1698 m_aStates.top().getPicture() = std::get<1>(aTuple)->getPicture();
1699 else if (std::get<0>(aTuple) == BUFFER_SETSTYLE)
1700 {
1701 if (!m_aStates.empty())
1702 m_aStates.top().setCurrentStyleIndex(std::get<1>(aTuple)->getInt());
1703 }
1704 else
1705 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 1705, __extension__ __PRETTY_FUNCTION__))
;
1706 }
1707}
1708
1709bool findPropertyName(const std::vector<beans::PropertyValue>& rProperties, const OUString& rName)
1710{
1711 return std::any_of(
1712 rProperties.begin(), rProperties.end(),
1713 [&rName](const beans::PropertyValue& rProperty) { return rProperty.Name == rName; });
1714}
1715
1716void RTFDocumentImpl::backupTableRowProperties()
1717{
1718 if (m_nTopLevelCurrentCellX)
1719 {
1720 m_aBackupTableRowSprms = m_aStates.top().getTableRowSprms();
1721 m_aBackupTableRowAttributes = m_aStates.top().getTableRowAttributes();
1722 m_nBackupTopLevelCurrentCellX = m_nTopLevelCurrentCellX;
1723 }
1724}
1725
1726void RTFDocumentImpl::restoreTableRowProperties()
1727{
1728 m_aStates.top().getTableRowSprms() = m_aBackupTableRowSprms;
1729 m_aStates.top().getTableRowAttributes() = m_aBackupTableRowAttributes;
1730 m_nTopLevelCurrentCellX = m_nBackupTopLevelCurrentCellX;
1731}
1732
1733void RTFDocumentImpl::resetTableRowProperties()
1734{
1735 m_aStates.top().getTableRowSprms() = m_aDefaultState.getTableRowSprms();
1736 m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, new RTFValue(-1),
1737 RTFOverwrite::NO_APPEND);
1738 m_aStates.top().getTableRowAttributes() = m_aDefaultState.getTableRowAttributes();
1739 if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
1740 {
1741 m_nNestedTRLeft = 0;
1742 m_nNestedCurrentCellX = 0;
1743 }
1744 else
1745 {
1746 m_nTopLevelTRLeft = 0;
1747 m_nTopLevelCurrentCellX = 0;
1748 }
1749}
1750
1751RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam)
1752{
1753 setNeedSect(true);
1754 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
1755 RTFSkipDestination aSkip(*this);
1756 int nSprm = -1;
1757 tools::SvRef<RTFValue> pBoolValue(new RTFValue(int(!bParam || nParam != 0)));
1758
1759 // Underline toggles.
1760 switch (nKeyword)
1761 {
1762 case RTF_UL:
1763 nSprm = NS_ooxml::LN_Value_ST_Underline_single;
1764 break;
1765 case RTF_ULDASH:
1766 nSprm = NS_ooxml::LN_Value_ST_Underline_dash;
1767 break;
1768 case RTF_ULDASHD:
1769 nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash;
1770 break;
1771 case RTF_ULDASHDD:
1772 nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash;
1773 break;
1774 case RTF_ULDB:
1775 nSprm = NS_ooxml::LN_Value_ST_Underline_double;
1776 break;
1777 case RTF_ULHWAVE:
1778 nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy;
1779 break;
1780 case RTF_ULLDASH:
1781 nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong;
1782 break;
1783 case RTF_ULTH:
1784 nSprm = NS_ooxml::LN_Value_ST_Underline_thick;
1785 break;
1786 case RTF_ULTHD:
1787 nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy;
1788 break;
1789 case RTF_ULTHDASH:
1790 nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy;
1791 break;
1792 case RTF_ULTHDASHD:
1793 nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy;
1794 break;
1795 case RTF_ULTHDASHDD:
1796 nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy;
1797 break;
1798 case RTF_ULTHLDASH:
1799 nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy;
1800 break;
1801 case RTF_ULULDBWAVE:
1802 nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble;
1803 break;
1804 case RTF_ULWAVE:
1805 nSprm = NS_ooxml::LN_Value_ST_Underline_wave;
1806 break;
1807 default:
1808 break;
1809 }
1810 if (nSprm >= 0)
1811 {
1812 auto pValue
1813 = new RTFValue((!bParam || nParam != 0) ? nSprm : NS_ooxml::LN_Value_ST_Underline_none);
1814 m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
1815 return RTFError::OK;
1816 }
1817
1818 // Accent characters (over dot / over comma).
1819 switch (nKeyword)
1820 {
1821 case RTF_ACCNONE:
1822 nSprm = NS_ooxml::LN_Value_ST_Em_none;
1823 break;
1824 case RTF_ACCDOT:
1825 nSprm = NS_ooxml::LN_Value_ST_Em_dot;
1826 break;
1827 case RTF_ACCCOMMA:
1828 nSprm = NS_ooxml::LN_Value_ST_Em_comma;
1829 break;
1830 case RTF_ACCCIRCLE:
1831 nSprm = NS_ooxml::LN_Value_ST_Em_circle;
1832 break;
1833 case RTF_ACCUNDERDOT:
1834 nSprm = NS_ooxml::LN_Value_ST_Em_underDot;
1835 break;
1836 default:
1837 break;
1838 }
1839 if (nSprm >= 0)
1840 {
1841 auto pValue = new RTFValue((!bParam || nParam != 0) ? nSprm : 0);
1842 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_em, pValue);
1843 return RTFError::OK;
1844 }
1845
1846 // Trivial character sprms.
1847 switch (nKeyword)
1848 {
1849 case RTF_B:
1850 case RTF_AB:
1851 switch (m_aStates.top().getRunType())
1852 {
1853 case RTFParserState::RunType::HICH:
1854 case RTFParserState::RunType::RTLCH_LTRCH_1:
1855 case RTFParserState::RunType::LTRCH_RTLCH_2:
1856 case RTFParserState::RunType::DBCH:
1857 nSprm = NS_ooxml::LN_EG_RPrBase_bCs;
1858 break;
1859 case RTFParserState::RunType::NONE:
1860 case RTFParserState::RunType::LOCH:
1861 case RTFParserState::RunType::LTRCH_RTLCH_1:
1862 case RTFParserState::RunType::RTLCH_LTRCH_2:
1863 default:
1864 nSprm = NS_ooxml::LN_EG_RPrBase_b;
1865 break;
1866 }
1867 break;
1868 case RTF_I:
1869 case RTF_AI:
1870 switch (m_aStates.top().getRunType())
1871 {
1872 case RTFParserState::RunType::HICH:
1873 case RTFParserState::RunType::RTLCH_LTRCH_1:
1874 case RTFParserState::RunType::LTRCH_RTLCH_2:
1875 case RTFParserState::RunType::DBCH:
1876 nSprm = NS_ooxml::LN_EG_RPrBase_iCs;
1877 break;
1878 case RTFParserState::RunType::NONE:
1879 case RTFParserState::RunType::LOCH:
1880 case RTFParserState::RunType::LTRCH_RTLCH_1:
1881 case RTFParserState::RunType::RTLCH_LTRCH_2:
1882 default:
1883 nSprm = NS_ooxml::LN_EG_RPrBase_i;
1884 break;
1885 }
1886 break;
1887 case RTF_OUTL:
1888 nSprm = NS_ooxml::LN_EG_RPrBase_outline;
1889 break;
1890 case RTF_SHAD:
1891 nSprm = NS_ooxml::LN_EG_RPrBase_shadow;
1892 break;
1893 case RTF_V:
1894 nSprm = NS_ooxml::LN_EG_RPrBase_vanish;
1895 break;
1896 case RTF_STRIKE:
1897 nSprm = NS_ooxml::LN_EG_RPrBase_strike;
1898 break;
1899 case RTF_STRIKED:
1900 nSprm = NS_ooxml::LN_EG_RPrBase_dstrike;
1901 break;
1902 case RTF_SCAPS:
1903 nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps;
1904 break;
1905 case RTF_IMPR:
1906 nSprm = NS_ooxml::LN_EG_RPrBase_imprint;
1907 break;
1908 case RTF_CAPS:
1909 nSprm = NS_ooxml::LN_EG_RPrBase_caps;
1910 break;
1911 default:
1912 break;
1913 }
1914 if (nSprm >= 0)
1915 {
1916 m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
1917 return RTFError::OK;
1918 }
1919
1920 switch (nKeyword)
1921 {
1922 case RTF_ASPALPHA:
1923 m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE,
1924 pBoolValue);
1925 break;
1926 case RTF_DELETED:
1927 case RTF_REVISED:
1928 {
1929 auto pValue = new RTFValue(nKeyword == RTF_DELETED ? oox::XML_del : oox::XML_ins);
1930 putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
1931 NS_ooxml::LN_token, pValue);
1932 }
1933 break;
1934 case RTF_SBAUTO:
1935 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
1936 NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue);
1937 break;
1938 case RTF_SAAUTO:
1939 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
1940 NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue);
1941 break;
1942 case RTF_FACINGP:
1943 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue);
1944 break;
1945 case RTF_HYPHAUTO:
1946 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue);
1947 break;
1948 case RTF_HYPHPAR:
1949 m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens,
1950 new RTFValue(int(bParam && nParam == 0)));
1951 break;
1952 default:
1953 {
1954 SAL_INFO("writerfilter.rtf",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "TODO handle toggle '"
<< keywordToString(nKeyword) << "'") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "TODO handle toggle '" << keywordToString(nKeyword
) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1955 "TODO handle toggle '" << keywordToString(nKeyword) << "'")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "TODO handle toggle '"
<< keywordToString(nKeyword) << "'") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "TODO handle toggle '" << keywordToString(nKeyword
) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "TODO handle toggle '" << keywordToString
(nKeyword) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "1955" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1956 aSkip.setParsed(false);
1957 }
1958 break;
1959 }
1960 return RTFError::OK;
1961}
1962
1963RTFError RTFDocumentImpl::pushState()
1964{
1965 //SAL_INFO("writerfilter.rtf", __func__ << " before push: " << m_pTokenizer->getGroup());
1966
1967 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
1968 m_nGroupStartPos = Strm().Tell();
1969
1970 if (m_aStates.empty())
1971 m_aStates.push(m_aDefaultState);
1972 else
1973 {
1974 // fdo#85812 group resets run type of _current_ and new state (but not RTL)
1975 if (m_aStates.top().getRunType() != RTFParserState::RunType::LTRCH_RTLCH_2
1976 && m_aStates.top().getRunType() != RTFParserState::RunType::RTLCH_LTRCH_2)
1977 {
1978 m_aStates.top().setRunType(RTFParserState::RunType::NONE);
1979 }
1980
1981 if (m_aStates.top().getDestination() == Destination::MR)
1982 lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
1983 m_bMathNor);
1984 m_aStates.push(m_aStates.top());
1985 }
1986 m_aStates.top().getDestinationText().setLength(0); // was copied: always reset!
1987
1988 m_pTokenizer->pushGroup();
1989
1990 switch (m_aStates.top().getDestination())
1991 {
1992 case Destination::FONTTABLE:
1993 // this is a "faked" destination for the font entry
1994 m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
1995 m_aStates.top().setDestination(Destination::FONTENTRY);
1996 break;
1997 case Destination::STYLESHEET:
1998 // this is a "faked" destination for the style sheet entry
1999 m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
2000 m_aStates.top().setDestination(Destination::STYLEENTRY);
2001 {
2002 // the *default* is \s0 i.e. paragraph style default
2003 // this will be overwritten by \sN \csN \dsN \tsN
2004 m_nCurrentStyleIndex = 0;
2005 auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
2006 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, pValue);
2007 }
2008 break;
2009 case Destination::FIELDRESULT:
2010 case Destination::SHAPETEXT:
2011 case Destination::FORMFIELD:
2012 case Destination::FIELDINSTRUCTION:
2013 case Destination::PICT:
2014 m_aStates.top().setDestination(Destination::NORMAL);
2015 break;
2016 case Destination::MNUM:
2017 case Destination::MDEN:
2018 case Destination::ME:
2019 case Destination::MFNAME:
2020 case Destination::MLIM:
2021 case Destination::MSUB:
2022 case Destination::MSUP:
2023 case Destination::MDEG:
2024 case Destination::MOMATH:
2025 m_aStates.top().setDestination(Destination::MR);
2026 break;
2027 case Destination::REVISIONTABLE:
2028 // this is a "faked" destination for the revision table entry
2029 m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
2030 m_aStates.top().setDestination(Destination::REVISIONENTRY);
2031 break;
2032 default:
2033 break;
2034 }
2035
2036 // If this is true, then ooxml:endtrackchange will be generated. Make sure
2037 // we don't generate more ooxml:endtrackchange than ooxml:trackchange: new
2038 // state does not inherit this flag.
2039 m_aStates.top().setStartedTrackchange(false);
2040
2041 return RTFError::OK;
2042}
2043
2044writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStyleProperties()
2045{
2046 int nBasedOn = 0;
2047 RTFValue::Pointer_t pBasedOn
2048 = m_aStates.top().getTableSprms().find(NS_ooxml::LN_CT_Style_basedOn);
2049 if (pBasedOn)
2050 nBasedOn = pBasedOn->getInt();
2051 if (nBasedOn == 0)
2052 {
2053 // No parent style, then mimic what Word does: ignore attributes which
2054 // would set a margin as formatting, but with a default value.
2055 for (const auto& nId :
2056 { NS_ooxml::LN_CT_Ind_firstLine, NS_ooxml::LN_CT_Ind_left, NS_ooxml::LN_CT_Ind_right,
2057 NS_ooxml::LN_CT_Ind_start, NS_ooxml::LN_CT_Ind_end })
2058 {
2059 RTFValue::Pointer_t pValue = getNestedAttribute(m_aStates.top().getParagraphSprms(),
2060 NS_ooxml::LN_CT_PPrBase_ind, nId);
2061 if (pValue && pValue->getInt() == 0)
2062 eraseNestedAttribute(m_aStates.top().getParagraphSprms(),
2063 NS_ooxml::LN_CT_PPrBase_ind, nId);
2064 }
2065 }
2066
2067 RTFValue::Pointer_t pParaProps = new RTFValue(m_aStates.top().getParagraphAttributes(),
2068 m_aStates.top().getParagraphSprms());
2069 RTFValue::Pointer_t pCharProps = new RTFValue(m_aStates.top().getCharacterAttributes(),
2070 m_aStates.top().getCharacterSprms());
2071
2072 // resetSprms will clean up this modification
2073 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_pPr, pParaProps);
2074 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_rPr, pCharProps);
2075
2076 writerfilter::Reference<Properties>::Pointer_t pProps(new RTFReferenceProperties(
2077 m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
2078 return pProps;
2079}
2080
2081/** 2 different representations of the styles are needed:
2082
2083 1) flat content, as read from the input file:
2084 stored in m_aStyleTableEntries, used as reference input for
2085 deduplication both here and for hard formatting in getProperties()
2086
2087 2) real content, with proper override of sprms/attributes where it differs
2088 from parent style; this is produced here and sent to domain mapper
2089 */
2090RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
2091{
2092 RTFReferenceTable::Entries_t ret;
2093 for (auto const& it : m_aStyleTableEntries)
2094 {
2095 auto pStyle = it.second;
2096 ret[it.first] = pStyle;
2097 // ugly downcasts here, but can't easily replace the members with
2098 // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway
2099 RTFValue::Pointer_t const pBasedOn(
2100 static_cast<RTFReferenceProperties&>(*pStyle).getSprms().find(
2101 NS_ooxml::LN_CT_Style_basedOn));
2102 if (pBasedOn)
2103 {
2104 int const nBasedOn(pBasedOn->getInt());
2105 // don't deduplicate yourself - especially a potential problem for the default style.
2106 if (it.first == nBasedOn)
2107 continue;
2108
2109 auto const itParent(m_aStyleTableEntries.find(nBasedOn)); // definition as read!
2110 if (itParent != m_aStyleTableEntries.end())
2111 {
2112 auto const pStyleType(
2113 static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find(
2114 NS_ooxml::LN_CT_Style_type));
2115 assert(pStyleType)(static_cast <bool> (pStyleType) ? void (0) : __assert_fail
("pStyleType", "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 2115, __extension__ __PRETTY_FUNCTION__))
;
2116 int const nStyleType(pStyleType->getInt());
2117 RTFSprms const sprms(
2118 static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate(
2119 static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(),
2120 nStyleType));
2121 RTFSprms const attributes(
2122 static_cast<RTFReferenceProperties&>(*pStyle)
2123 .getAttributes()
2124 .cloneAndDeduplicate(
2125 static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(),
2126 nStyleType));
2127
2128 ret[it.first] = new RTFReferenceProperties(attributes, sprms);
2129 }
2130 else
2131 {
2132 SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "parent style not found: "
<< nBasedOn) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2132" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "parent style not found: " << nBasedOn
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "parent style not found: " << nBasedOn; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2132" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "parent style not found: " << nBasedOn) == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2132" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "parent style not found: " << nBasedOn
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "parent style not found: " << nBasedOn; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2132" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2133 }
2134 }
2135 }
2136 assert(ret.size() == m_aStyleTableEntries.size())(static_cast <bool> (ret.size() == m_aStyleTableEntries
.size()) ? void (0) : __assert_fail ("ret.size() == m_aStyleTableEntries.size()"
, "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
, 2136, __extension__ __PRETTY_FUNCTION__))
;
2137 return ret;
2138}
2139
2140void RTFDocumentImpl::resetSprms()
2141{
2142 m_aStates.top().getTableSprms().clear();
2143 m_aStates.top().getCharacterSprms().clear();
2144 m_aStates.top().getParagraphSprms().clear();
2145}
2146
2147void RTFDocumentImpl::resetAttributes()
2148{
2149 m_aStates.top().getTableAttributes().clear();
2150 m_aStates.top().getCharacterAttributes().clear();
2151 m_aStates.top().getParagraphAttributes().clear();
2152}
2153
2154static bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties,
2155 const OUString& rName)
2156{
2157 return std::any_of(rProperties.begin(), rProperties.end(),
2158 [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
2159}
2160
2161RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState)
2162{
2163 switch (rState.getDestination())
2164 {
2165 case Destination::FONTTABLE:
2166 {
2167 writerfilter::Reference<Table>::Pointer_t const pTable(
2168 new RTFReferenceTable(m_aFontTableEntries));
2169 Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
2170 if (m_nDefaultFontIndex >= 0)
2171 {
2172 auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
2173 putNestedAttribute(m_aDefaultState.getCharacterSprms(),
2174 NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
2175 pValue);
2176 }
2177 }
2178 break;
2179 case Destination::STYLESHEET:
2180 {
2181 RTFReferenceTable::Entries_t const pStyleTableDeduplicated(deduplicateStyleTable());
2182 writerfilter::Reference<Table>::Pointer_t const pTable(
2183 new RTFReferenceTable(pStyleTableDeduplicated));
2184 Mapper().table(NS_ooxml::LN_STYLESHEET, pTable);
2185 }
2186 break;
2187 case Destination::LISTOVERRIDETABLE:
2188 {
2189 RTFSprms aListTableAttributes;
2190 writerfilter::Reference<Properties>::Pointer_t pProp
2191 = new RTFReferenceProperties(aListTableAttributes, m_aListTableSprms);
2192 RTFReferenceTable::Entries_t aListTableEntries;
2193 aListTableEntries.insert(std::make_pair(0, pProp));
2194 writerfilter::Reference<Table>::Pointer_t const pTable(
2195 new RTFReferenceTable(aListTableEntries));
2196 Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
2197 }
2198 break;
2199 case Destination::LISTENTRY:
2200 for (const auto& rListLevelEntry : rState.getListLevelEntries())
2201 rState.getTableSprms().set(rListLevelEntry.first, rListLevelEntry.second,
2202 RTFOverwrite::NO_APPEND);
2203 break;
2204 case Destination::FIELDINSTRUCTION:
2205 {
2206 auto pValue = new RTFValue(m_aFormfieldAttributes, m_aFormfieldSprms);
2207 RTFSprms aFFAttributes;
2208 RTFSprms aFFSprms;
2209 aFFSprms.set(NS_ooxml::LN_ffdata, pValue);
2210 if (!m_aStates.top().getCurrentBuffer())
2211 {
2212 writerfilter::Reference<Properties>::Pointer_t pProperties
2213 = new RTFReferenceProperties(aFFAttributes, aFFSprms);
2214 Mapper().props(pProperties);
2215 }
2216 else
2217 {
2218 auto pFFValue = new RTFValue(aFFAttributes, aFFSprms);
2219 bufferProperties(*m_aStates.top().getCurrentBuffer(), pFFValue, nullptr);
2220 }
2221 m_aFormfieldAttributes.clear();
2222 m_aFormfieldSprms.clear();
2223 singleChar(cFieldSep);
2224 }
2225 break;
2226 case Destination::FIELDRESULT:
2227 singleChar(cFieldEnd);
2228
2229 if (!m_aPicturePath.isEmpty())
2230 {
2231 // Read the picture into m_aStates.top().aDestinationText.
2232 pushState();
2233 dispatchDestination(RTF_PICT);
2234 if (m_aPicturePath.endsWith(".png"))
2235 dispatchFlag(RTF_PNGBLIP);
2236 OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault(
2237 utl::MediaDescriptor::PROP_URL(), OUString());
2238 OUString aPictureURL;
2239 try
2240 {
2241 aPictureURL = rtl::Uri::convertRelToAbs(aFileURL, m_aPicturePath);
2242 }
2243 catch (const rtl::MalformedUriException& rException)
2244 {
2245 SAL_WARN("writerfilter.rtf",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage()) == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage()), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "rtl::Uri::convertRelToAbs() failed: " << rException
.getMessage()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage()), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
2246 "rtl::Uri::convertRelToAbs() failed: " << rException.getMessage())do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage()) == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage()), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "rtl::Uri::convertRelToAbs() failed: " << rException
.getMessage()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage()), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "rtl::Uri::convertRelToAbs() failed: "
<< rException.getMessage(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2246" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2247 }
2248
2249 if (!aPictureURL.isEmpty())
2250 {
2251 SvFileStream aStream(aPictureURL, StreamMode::READ);
2252 if (aStream.IsOpen())
2253 {
2254 OUStringBuffer aBuf;
2255 while (aStream.good())
2256 {
2257 unsigned char ch = 0;
2258 aStream.ReadUChar(ch);
2259 if (ch < 16)
2260 aBuf.append("0");
2261 aBuf.append(OUString::number(ch, 16));
2262 }
2263 m_aStates.top().getDestinationText() = aBuf;
2264 }
2265 }
2266 popState();
2267 m_aPicturePath.clear();
2268 }
2269
2270 break;
2271 case Destination::LEVELTEXT:
2272 {
2273 if (&m_aStates.top().getDestinationText()
2274 != m_aStates.top().getCurrentDestinationText())
2275 break; // not for nested group
2276 OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2277
2278 // The first character is the length of the string (the rest should be ignored).
2279 sal_Int32 nLength(aStr.toChar());
2280 OUString aValue;
2281 if (nLength < aStr.getLength())
2282 aValue = aStr.copy(1, nLength);
2283 else
2284 aValue = aStr;
2285 auto pValue = new RTFValue(aValue, true);
2286 rState.getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
2287 }
2288 break;
2289 case Destination::LEVELNUMBERS:
2290 {
2291 bool bNestedLevelNumbers = false;
2292 if (m_aStates.size() > 1)
2293 // Current destination is levelnumbers and parent destination is levelnumbers as well.
2294 bNestedLevelNumbers
2295 = m_aStates[m_aStates.size() - 2].getDestination() == Destination::LEVELNUMBERS;
2296 if (!bNestedLevelNumbers && rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText))
2297 {
2298 RTFSprms& rAttributes
2299 = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText)->getAttributes();
2300 RTFValue::Pointer_t pValue = rAttributes.find(NS_ooxml::LN_CT_LevelText_val);
2301 if (pValue && rState.getLevelNumbersValid())
2302 {
2303 OUString aOrig = pValue->getString();
2304
2305 OUStringBuffer aBuf(aOrig.getLength() * 2);
2306 sal_Int32 nReplaces = 1;
2307 for (int i = 0; i < aOrig.getLength(); i++)
2308 {
2309 if (std::find(rState.getLevelNumbers().begin(),
2310 rState.getLevelNumbers().end(), i + 1)
2311 != rState.getLevelNumbers().end())
2312 {
2313 aBuf.append('%');
2314 // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2.
2315 aBuf.append(sal_Int32(nReplaces++ + rState.getListLevelNum() + 1
2316 - rState.getLevelNumbers().size()));
2317 }
2318 else
2319 aBuf.append(aOrig[i]);
2320 }
2321
2322 pValue->setString(aBuf.makeStringAndClear());
2323 }
2324 else if (pValue)
2325 // Have a value, but levelnumbers is not valid -> ignore it.
2326 pValue->setString(OUString());
2327 }
2328 break;
2329 }
2330 case Destination::SHAPEPROPERTYNAME:
2331 if (&m_aStates.top().getDestinationText()
2332 != m_aStates.top().getCurrentDestinationText())
2333 break; // not for nested group
2334 rState.getShape().getProperties().emplace_back(
2335 m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), OUString());
2336 break;
2337 case Destination::SHAPEPROPERTYVALUE:
2338 if (!rState.getShape().getProperties().empty())
2339 {
2340 rState.getShape().getProperties().back().second
2341 = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2342 if (m_aStates.top().getHadShapeText())
2343 m_pSdrImport->append(rState.getShape().getProperties().back().first,
2344 rState.getShape().getProperties().back().second);
2345 else if (rState.getInShapeGroup() && !rState.getInShape()
2346 && rState.getShape().getProperties().back().first == "rotation")
2347 {
2348 // Rotation should be applied on the groupshape itself, not on each shape.
2349 rState.getShape().getGroupProperties().push_back(
2350 rState.getShape().getProperties().back());
2351 rState.getShape().getProperties().pop_back();
2352 }
2353 }
2354 break;
2355 case Destination::PICPROP:
2356 case Destination::SHAPEINSTRUCTION:
2357 if (m_aStates.size() > 1
2358 && m_aStates[m_aStates.size() - 2].getDestination()
2359 == Destination::SHAPEINSTRUCTION)
2360 {
2361 // Do not resolve shape if shape instruction destination is inside other shape instruction
2362 }
2363 else if (!m_bObject && !rState.getInListpicture() && !rState.getHadShapeText()
2364 && (!rState.getInShapeGroup() || rState.getInShape()))
2365 {
2366 // Don't trigger a shape import in case we're only leaving the \shpinst of the groupshape itself.
2367 RTFSdrImport::ShapeOrPict eType
2368 = (rState.getDestination() == Destination::SHAPEINSTRUCTION)
2369 ? RTFSdrImport::SHAPE
2370 : RTFSdrImport::PICT;
2371 if (!m_aStates.top().getCurrentBuffer() || eType != RTFSdrImport::SHAPE)
2372 m_pSdrImport->resolve(m_aStates.top().getShape(), true, eType);
2373 else
2374 {
2375 // Shape inside table: buffer the import to have correct anchor position.
2376 // Also buffer the RTFPicture of the state stack as it contains
2377 // the shape size.
2378 auto pPictureValue = new RTFValue(m_aStates.top().getPicture());
2379 m_aStates.top().getCurrentBuffer()->push_back(
2380 Buf_t(BUFFER_PICTURE, pPictureValue, nullptr));
2381 auto pValue = new RTFValue(m_aStates.top().getShape());
2382
2383 // Buffer wrap type.
2384 for (const auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
2385 {
2386 if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
2387 || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
2388 {
2389 m_aStates.top().getShape().getWrapSprm() = rCharacterSprm;
2390 break;
2391 }
2392 }
2393
2394 m_aStates.top().getCurrentBuffer()->push_back(
2395 Buf_t(BUFFER_RESOLVESHAPE, pValue, nullptr));
2396 }
2397 }
2398 else if (rState.getInShapeGroup() && !rState.getInShape())
2399 {
2400 // End of a groupshape, as we're in shapegroup, but not in a real shape.
2401 for (const auto& rGroupProperty : rState.getShape().getGroupProperties())
2402 m_pSdrImport->appendGroupProperty(rGroupProperty.first, rGroupProperty.second);
2403 rState.getShape().getGroupProperties().clear();
2404 }
2405 break;
2406 case Destination::BOOKMARKSTART:
2407 {
2408 if (&m_aStates.top().getDestinationText()
2409 != m_aStates.top().getCurrentDestinationText())
2410 break; // not for nested group
2411 OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2412 int nPos = m_aBookmarks.size();
2413 m_aBookmarks[aStr] = nPos;
2414 if (!m_aStates.top().getCurrentBuffer())
2415 Mapper().props(new RTFReferenceProperties(lcl_getBookmarkProperties(nPos, aStr)));
2416 else
2417 bufferProperties(*m_aStates.top().getCurrentBuffer(),
2418 new RTFValue(lcl_getBookmarkProperties(nPos, aStr)), nullptr);
2419 }
2420 break;
2421 case Destination::BOOKMARKEND:
2422 {
2423 if (&m_aStates.top().getDestinationText()
2424 != m_aStates.top().getCurrentDestinationText())
2425 break; // not for nested group
2426 OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2427 if (!m_aStates.top().getCurrentBuffer())
2428 Mapper().props(new RTFReferenceProperties(
2429 lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)));
2430 else
2431 bufferProperties(*m_aStates.top().getCurrentBuffer(),
2432 new RTFValue(lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)),
2433 nullptr);
2434 }
2435 break;
2436 case Destination::INDEXENTRY:
2437 case Destination::TOCENTRY:
2438 {
2439 if (&m_aStates.top().getDestinationText()
2440 != m_aStates.top().getCurrentDestinationText())
2441 break; // not for nested group
2442 OUString str(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2443 // dmapper expects this as a field, so let's fake something...
2444 auto const field((Destination::INDEXENTRY == rState.getDestination())
2445 ? OUStringLiteral(u"XE")
2446 : OUStringLiteral(u"TC"));
2447 str = field + " \"" + str.replaceAll("\"", "\\\"") + "\"";
2448 singleChar(cFieldStart);
2449 Mapper().utext(reinterpret_cast<sal_uInt8 const*>(str.getStr()), str.getLength());
2450 singleChar(cFieldSep);
2451 // no result
2452 singleChar(cFieldEnd);
2453 }
2454 break;
2455 case Destination::FORMFIELDNAME:
2456 {
2457 if (&m_aStates.top().getDestinationText()
2458 != m_aStates.top().getCurrentDestinationText())
2459 break; // not for nested group
2460 auto pValue
2461 = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2462 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pValue);
2463 }
2464 break;
2465 case Destination::FORMFIELDLIST:
2466 {
2467 if (&m_aStates.top().getDestinationText()
2468 != m_aStates.top().getCurrentDestinationText())
2469 break; // not for nested group
2470 auto pValue
2471 = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2472 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue);
2473 }
2474 break;
2475 case Destination::DATAFIELD:
2476 {
2477 if (m_bFormField)
2478 {
2479 if (&m_aStates.top().getDestinationText()
2480 != m_aStates.top().getCurrentDestinationText())
2481 break; // not for nested group
2482 OString aStr = OUStringToOString(
2483 m_aStates.top().getCurrentDestinationText()->makeStringAndClear(),
2484 rState.getCurrentEncoding());
2485 // decode hex dump
2486 OStringBuffer aBuf;
2487 int b = 0;
2488 int count = 2;
2489 for (int i = 0; i < aStr.getLength(); ++i)
2490 {
2491 char ch = aStr[i];
2492 if (ch != 0x0d && ch != 0x0a)
2493 {
2494 b = b << 4;
2495 sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
2496 if (parsed == -1)
2497 return RTFError::HEX_INVALID;
2498 b += parsed;
2499 count--;
2500 if (!count)
2501 {
2502 aBuf.append(static_cast<char>(b));
2503 count = 2;
2504 b = 0;
2505 }
2506 }
2507 }
2508 aStr = aBuf.makeStringAndClear();
2509
2510 // ignore the first bytes
2511 if (aStr.getLength() > 8)
2512 aStr = aStr.copy(8);
2513 // extract name
2514 sal_Int32 nLength = aStr.toChar();
2515 if (!aStr.isEmpty())
2516 aStr = aStr.copy(1);
2517 nLength = std::min(nLength, aStr.getLength());
2518 OString aName = aStr.copy(0, nLength);
2519 if (aStr.getLength() > nLength)
2520 aStr = aStr.copy(nLength + 1); // zero-terminated string
2521 else
2522 aStr.clear();
2523 // extract default text
2524 nLength = aStr.toChar();
2525 if (!aStr.isEmpty())
2526 aStr = aStr.copy(1);
2527 auto pNValue = new RTFValue(OStringToOUString(aName, rState.getCurrentEncoding()));
2528 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pNValue);
2529 if (nLength > 0)
2530 {
2531 OString aDefaultText = aStr.copy(0, std::min(nLength, aStr.getLength()));
2532 auto pDValue = new RTFValue(
2533 OStringToOUString(aDefaultText, rState.getCurrentEncoding()));
2534 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFTextInput_default, pDValue);
2535 }
2536
2537 m_bFormField = false;
2538 }
2539 }
2540 break;
2541 case Destination::CREATIONTIME:
2542 if (m_xDocumentProperties.is())
2543 m_xDocumentProperties->setCreationDate(lcl_getDateTime(rState));
2544 break;
2545 case Destination::REVISIONTIME:
2546 if (m_xDocumentProperties.is())
2547 m_xDocumentProperties->setModificationDate(lcl_getDateTime(rState));
2548 break;
2549 case Destination::PRINTTIME:
2550 if (m_xDocumentProperties.is())
2551 m_xDocumentProperties->setPrintDate(lcl_getDateTime(rState));
2552 break;
2553 case Destination::AUTHOR:
2554 if (&m_aStates.top().getDestinationText()
2555 != m_aStates.top().getCurrentDestinationText())
2556 break; // not for nested group
2557 if (m_xDocumentProperties.is())
2558 m_xDocumentProperties->setAuthor(
2559 m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2560 break;
2561 case Destination::KEYWORDS:
2562 if (&m_aStates.top().getDestinationText()
2563 != m_aStates.top().getCurrentDestinationText())
2564 break; // not for nested group
2565 if (m_xDocumentProperties.is())
2566 m_xDocumentProperties->setKeywords(comphelper::string::convertCommaSeparated(
2567 m_aStates.top().getCurrentDestinationText()->makeStringAndClear()));
2568 break;
2569 case Destination::COMMENT:
2570 if (&m_aStates.top().getDestinationText()
2571 != m_aStates.top().getCurrentDestinationText())
2572 break; // not for nested group
2573 if (m_xDocumentProperties.is())
2574 m_xDocumentProperties->setGenerator(
2575 m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2576 break;
2577 case Destination::SUBJECT:
2578 if (&m_aStates.top().getDestinationText()
2579 != m_aStates.top().getCurrentDestinationText())
2580 break; // not for nested group
2581 if (m_xDocumentProperties.is())
2582 m_xDocumentProperties->setSubject(
2583 m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2584 break;
2585 case Destination::TITLE:
2586 {
2587 if (&m_aStates.top().getDestinationText()
2588 != m_aStates.top().getCurrentDestinationText())
2589 break; // not for nested group
2590 if (m_xDocumentProperties.is())
2591 m_xDocumentProperties->setTitle(
2592 rState.getCurrentDestinationText()->makeStringAndClear());
2593 }
2594 break;
2595
2596 case Destination::DOCCOMM:
2597 if (&m_aStates.top().getDestinationText()
2598 != m_aStates.top().getCurrentDestinationText())
2599 break; // not for nested group
2600 if (m_xDocumentProperties.is())
2601 m_xDocumentProperties->setDescription(
2602 m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2603 break;
2604 case Destination::OPERATOR:
2605 case Destination::COMPANY:
2606 {
2607 if (&m_aStates.top().getDestinationText()
2608 != m_aStates.top().getCurrentDestinationText())
2609 break; // not for nested group
2610 OUString aName = rState.getDestination() == Destination::OPERATOR ? OUString("Operator")
2611 : OUString("Company");
2612 uno::Any aValue
2613 = uno::makeAny(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2614 if (m_xDocumentProperties.is())
2615 {
2616 uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
2617 = m_xDocumentProperties->getUserDefinedProperties();
2618 uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
2619 uno::UNO_QUERY);
2620 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo
2621 = xPropertySet->getPropertySetInfo();
2622 if (xPropertySetInfo->hasPropertyByName(aName))
2623 xPropertySet->setPropertyValue(aName, aValue);
2624 else
2625 xUserDefinedProperties->addProperty(aName, beans::PropertyAttribute::REMOVABLE,
2626 aValue);
2627 }
2628 }
2629 break;
2630 case Destination::OBJDATA:
2631 {
2632 if (&m_aStates.top().getDestinationText()
2633 != m_aStates.top().getCurrentDestinationText())
2634 break; // not for nested group
2635
2636 RTFError eError = handleEmbeddedObject();
2637 if (eError != RTFError::OK)
2638 return eError;
2639 }
2640 break;
2641 case Destination::OBJCLASS:
2642 {
2643 auto pValue
2644 = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2645 m_aOLEAttributes.set(NS_ooxml::LN_CT_OLEObject_ProgID, pValue);
2646 break;
2647 }
2648 case Destination::OBJECT:
2649 {
2650 if (!m_bObject)
2651 {
2652 // if the object is in a special container we will use the \result
2653 // element instead of the \objdata
2654 // (see RTF_OBJECT in RTFDocumentImpl::dispatchDestination)
2655 break;
2656 }
2657
2658 RTFSprms aObjectSprms;
2659 auto pOLEValue = new RTFValue(m_aOLEAttributes);
2660 aObjectSprms.set(NS_ooxml::LN_OLEObject_OLEObject, pOLEValue);
2661
2662 RTFSprms aObjAttributes;
2663 RTFSprms aObjSprms;
2664 auto pValue = new RTFValue(m_aObjectAttributes, aObjectSprms);
2665 aObjSprms.set(NS_ooxml::LN_object, pValue);
2666 writerfilter::Reference<Properties>::Pointer_t pProperties
2667 = new RTFReferenceProperties(aObjAttributes, aObjSprms);
2668 uno::Reference<drawing::XShape> xShape;
2669 RTFValue::Pointer_t pShape = m_aObjectAttributes.find(NS_ooxml::LN_shape);
2670 OSL_ASSERT(pShape)do { if (true && (!(pShape))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "2670" ": "), "OSL_ASSERT: %s", "pShape"); } } while (false
)
;
2671 if (pShape)
2672 pShape->getAny() >>= xShape;
2673 if (xShape.is())
2674 {
2675 Mapper().startShape(xShape);
2676 Mapper().props(pProperties);
2677 Mapper().endShape();
2678 }
2679 m_aObjectAttributes.clear();
2680 m_aOLEAttributes.clear();
2681 m_bObject = false;
2682 }
2683 break;
2684 case Destination::ANNOTATIONDATE:
2685 {
2686 if (&m_aStates.top().getDestinationText()
2687 != m_aStates.top().getCurrentDestinationText())
2688 break; // not for nested group
2689 OUString aStr(OStringToOUString(
2690 DTTM22OString(
2691 m_aStates.top().getCurrentDestinationText()->makeStringAndClear().toInt32()),
2692 rState.getCurrentEncoding()));
2693 auto pValue = new RTFValue(aStr);
2694 RTFSprms aAnnAttributes;
2695 aAnnAttributes.set(NS_ooxml::LN_CT_TrackChange_date, pValue);
2696 writerfilter::Reference<Properties>::Pointer_t pProperties
2697 = new RTFReferenceProperties(aAnnAttributes);
2698 Mapper().props(pProperties);
2699 }
2700 break;
2701 case Destination::ANNOTATIONAUTHOR:
2702 if (&m_aStates.top().getDestinationText()
2703 != m_aStates.top().getCurrentDestinationText())
2704 break; // not for nested group
2705 m_aAuthor = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2706 break;
2707 case Destination::ATNID:
2708 if (&m_aStates.top().getDestinationText()
2709 != m_aStates.top().getCurrentDestinationText())
2710 break; // not for nested group
2711 m_aAuthorInitials = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2712 break;
2713 case Destination::ANNOTATIONREFERENCESTART:
2714 case Destination::ANNOTATIONREFERENCEEND:
2715 {
2716 if (&m_aStates.top().getDestinationText()
2717 != m_aStates.top().getCurrentDestinationText())
2718 break; // not for nested group
2719 OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2720 auto pValue = new RTFValue(aStr.toInt32());
2721 RTFSprms aAttributes;
2722 if (rState.getDestination() == Destination::ANNOTATIONREFERENCESTART)
2723 aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart, pValue);
2724 else
2725 aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd, pValue);
2726 writerfilter::Reference<Properties>::Pointer_t pProperties
2727 = new RTFReferenceProperties(aAttributes);
2728 if (!m_aStates.top().getCurrentBuffer())
2729 {
2730 Mapper().props(pProperties);
2731 }
2732 else
2733 {
2734 auto const pValue2 = new RTFValue(aAttributes, RTFSprms());
2735 bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue2, nullptr);
2736 }
2737 }
2738 break;
2739 case Destination::ANNOTATIONREFERENCE:
2740 {
2741 if (&m_aStates.top().getDestinationText()
2742 != m_aStates.top().getCurrentDestinationText())
2743 break; // not for nested group
2744 OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2745 RTFSprms aAnnAttributes;
2746 aAnnAttributes.set(NS_ooxml::LN_CT_Markup_id, new RTFValue(aStr.toInt32()));
2747 Mapper().props(new RTFReferenceProperties(aAnnAttributes));
2748 }
2749 break;
2750 case Destination::FALT:
2751 {
2752 if (&m_aStates.top().getDestinationText()
2753 != m_aStates.top().getCurrentDestinationText())
2754 break; // not for nested group
2755 OUString aStr(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
2756 auto pValue = new RTFValue(aStr);
2757 rState.getTableSprms().set(NS_ooxml::LN_CT_Font_altName, pValue);
2758 }
2759 break;
2760 case Destination::DRAWINGOBJECT:
2761 if (m_aStates.top().getDrawingObject().getShape().is())
2762 {
2763 RTFDrawingObject& rDrawing = m_aStates.top().getDrawingObject();
2764 const uno::Reference<drawing::XShape>& xShape(rDrawing.getShape());
2765 const uno::Reference<beans::XPropertySet>& xPropertySet(rDrawing.getPropertySet());
2766
2767 uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
2768 bool bTextFrame = xServiceInfo->supportsService("com.sun.star.text.TextFrame");
2769
2770 // The default is certainly not inline, but then what Word supports is just at-character.
2771 xPropertySet->setPropertyValue(
2772 "AnchorType", uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
2773
2774 if (bTextFrame)
2775 {
2776 xPropertySet->setPropertyValue("HoriOrientPosition",
2777 uno::makeAny(rDrawing.getLeft()));
2778 xPropertySet->setPropertyValue("VertOrientPosition",
2779 uno::makeAny(rDrawing.getTop()));
2780 }
2781 else
2782 {
2783 xShape->setPosition(awt::Point(rDrawing.getLeft(), rDrawing.getTop()));
2784 }
2785 xShape->setSize(awt::Size(rDrawing.getRight(), rDrawing.getBottom()));
2786
2787 if (rDrawing.getHasLineColor())
2788 {
2789 uno::Any aLineColor = uno::makeAny(sal_uInt32((rDrawing.getLineColorR() << 16)
2790 + (rDrawing.getLineColorG() << 8)
2791 + rDrawing.getLineColorB()));
2792 uno::Any aLineWidth;
2793 RTFSdrImport::resolveLineColorAndWidth(bTextFrame, xPropertySet, aLineColor,
2794 aLineWidth);
2795 }
2796 if (rDrawing.getHasFillColor())
2797 xPropertySet->setPropertyValue(
2798 "FillColor", uno::makeAny(sal_uInt32((rDrawing.getFillColorR() << 16)
2799 + (rDrawing.getFillColorG() << 8)
2800 + rDrawing.getFillColorB())));
2801 else if (!bTextFrame)
2802 // If there is no fill, the Word default is 100% transparency.
2803 xPropertySet->setPropertyValue("FillTransparence",
2804 uno::makeAny(sal_Int32(100)));
2805
2806 RTFSdrImport::resolveFLine(xPropertySet, rDrawing.getFLine());
2807
2808 if (!m_aStates.top().getDrawingObject().getHadShapeText())
2809 {
2810 Mapper().startShape(xShape);
2811 }
2812 Mapper().endShape();
2813 }
2814 break;
2815 case Destination::PICT:
2816 // fdo#79319 ignore picture data if it's really a shape
2817 if (!m_pSdrImport->isFakePict())
2818 {
2819 resolvePict(true, m_pSdrImport->getCurrentShape());
2820 }
2821 m_bNeedFinalPar = true;
2822 break;
2823 case Destination::SHAPE:
2824 m_bNeedFinalPar = true;
2825 m_bNeedCr = m_bNeedCrOrig;
2826 if (rState.getFrame().inFrame())
2827 {
2828 // parBreak() modifies m_aStates.top() so we can't apply resetFrame() directly on aState
2829 resetFrame();
2830 parBreak();
2831 // Save this state for later use, so we only reset frame status only for the first shape inside a frame.
2832 rState = m_aStates.top();
2833 m_bNeedPap = true;
2834 }
2835 break;
2836 case Destination::MOMATH:
2837 {
2838 m_aMathBuffer.appendClosingTag(M_TOKEN(oMath)(::oox::NMSP_officeMath | ::oox::XML_oMath));
2839
2840 SvGlobalName aGlobalName(SO3_SM_CLASSID0x078B7ABA, 0x54FC, 0x457F, 0x85, 0x51, 0x61, 0x47, 0xE7, 0x76
, 0xA9, 0x97
);
2841 comphelper::EmbeddedObjectContainer aContainer;
2842 OUString aName;
2843 uno::Reference<embed::XEmbeddedObject> xObject
2844 = aContainer.CreateEmbeddedObject(aGlobalName.GetByteSequence(), aName);
2845 if (xObject) // rhbz#1766990 starmath might not be available
2846 {
2847 uno::Reference<util::XCloseable> xComponent(xObject->getComponent(),
2848 uno::UNO_SET_THROW);
2849 // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
2850 // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
2851 // to RTLD_GLOBAL, so most probably a gcc bug.
2852 auto& rImport = dynamic_cast<oox::FormulaImportBase&>(
2853 dynamic_cast<SfxBaseModel&>(*xComponent));
2854 rImport.readFormulaOoxml(m_aMathBuffer);
2855
2856 auto pValue = new RTFValue(xObject);
2857 RTFSprms aMathAttributes;
2858 aMathAttributes.set(NS_ooxml::LN_starmath, pValue);
2859 writerfilter::Reference<Properties>::Pointer_t pProperties
2860 = new RTFReferenceProperties(aMathAttributes);
2861 Mapper().props(pProperties);
2862 }
2863
2864 m_aMathBuffer = oox::formulaimport::XmlStreamBuilder();
2865 }
2866 break;
2867 case Destination::MR:
2868 lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
2869 m_bMathNor);
2870 break;
2871 case Destination::MF:
2872 m_aMathBuffer.appendClosingTag(M_TOKEN(f)(::oox::NMSP_officeMath | ::oox::XML_f));
2873 break;
2874 case Destination::MFPR:
2875 m_aMathBuffer.appendClosingTag(M_TOKEN(fPr)(::oox::NMSP_officeMath | ::oox::XML_fPr));
2876 break;
2877 case Destination::MCTRLPR:
2878 m_aMathBuffer.appendClosingTag(M_TOKEN(ctrlPr)(::oox::NMSP_officeMath | ::oox::XML_ctrlPr));
2879 break;
2880 case Destination::MNUM:
2881 m_aMathBuffer.appendClosingTag(M_TOKEN(num)(::oox::NMSP_officeMath | ::oox::XML_num));
2882 break;
2883 case Destination::MDEN:
2884 m_aMathBuffer.appendClosingTag(M_TOKEN(den)(::oox::NMSP_officeMath | ::oox::XML_den));
2885 break;
2886 case Destination::MACC:
2887 m_aMathBuffer.appendClosingTag(M_TOKEN(acc)(::oox::NMSP_officeMath | ::oox::XML_acc));
2888 break;
2889 case Destination::MACCPR:
2890 m_aMathBuffer.appendClosingTag(M_TOKEN(accPr)(::oox::NMSP_officeMath | ::oox::XML_accPr));
2891 break;
2892 case Destination::MCHR:
2893 case Destination::MPOS:
2894 case Destination::MVERTJC:
2895 case Destination::MSTRIKEH:
2896 case Destination::MDEGHIDE:
2897 case Destination::MBEGCHR:
2898 case Destination::MSEPCHR:
2899 case Destination::MENDCHR:
2900 case Destination::MSUBHIDE:
2901 case Destination::MSUPHIDE:
2902 case Destination::MTYPE:
2903 case Destination::MGROW:
2904 {
2905 sal_Int32 nMathToken = 0;
2906 switch (rState.getDestination())
2907 {
2908 case Destination::MCHR:
2909 nMathToken = M_TOKEN(chr)(::oox::NMSP_officeMath | ::oox::XML_chr);
2910 break;
2911 case Destination::MPOS:
2912 nMathToken = M_TOKEN(pos)(::oox::NMSP_officeMath | ::oox::XML_pos);
2913 break;
2914 case Destination::MVERTJC:
2915 nMathToken = M_TOKEN(vertJc)(::oox::NMSP_officeMath | ::oox::XML_vertJc);
2916 break;
2917 case Destination::MSTRIKEH:
2918 nMathToken = M_TOKEN(strikeH)(::oox::NMSP_officeMath | ::oox::XML_strikeH);
2919 break;
2920 case Destination::MDEGHIDE:
2921 nMathToken = M_TOKEN(degHide)(::oox::NMSP_officeMath | ::oox::XML_degHide);
2922 break;
2923 case Destination::MBEGCHR:
2924 nMathToken = M_TOKEN(begChr)(::oox::NMSP_officeMath | ::oox::XML_begChr);
2925 break;
2926 case Destination::MSEPCHR:
2927 nMathToken = M_TOKEN(sepChr)(::oox::NMSP_officeMath | ::oox::XML_sepChr);
2928 break;
2929 case Destination::MENDCHR:
2930 nMathToken = M_TOKEN(endChr)(::oox::NMSP_officeMath | ::oox::XML_endChr);
2931 break;
2932 case Destination::MSUBHIDE:
2933 nMathToken = M_TOKEN(subHide)(::oox::NMSP_officeMath | ::oox::XML_subHide);
2934 break;
2935 case Destination::MSUPHIDE:
2936 nMathToken = M_TOKEN(supHide)(::oox::NMSP_officeMath | ::oox::XML_supHide);
2937 break;
2938 case Destination::MTYPE:
2939 nMathToken = M_TOKEN(type)(::oox::NMSP_officeMath | ::oox::XML_type);
2940 break;
2941 case Destination::MGROW:
2942 nMathToken = M_TOKEN(grow)(::oox::NMSP_officeMath | ::oox::XML_grow);
2943 break;
2944 default:
2945 break;
2946 }
2947
2948 oox::formulaimport::XmlStream::AttributeList aAttribs;
2949 aAttribs[M_TOKEN(val)(::oox::NMSP_officeMath | ::oox::XML_val)]
2950 = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
2951 m_aMathBuffer.appendOpeningTag(nMathToken, aAttribs);
2952 m_aMathBuffer.appendClosingTag(nMathToken);
2953 }
2954 break;
2955 case Destination::ME:
2956 m_aMathBuffer.appendClosingTag(M_TOKEN(e)(::oox::NMSP_officeMath | ::oox::XML_e));
2957 break;
2958 case Destination::MBAR:
2959 m_aMathBuffer.appendClosingTag(M_TOKEN(bar)(::oox::NMSP_officeMath | ::oox::XML_bar));
2960 break;
2961 case Destination::MBARPR:
2962 m_aMathBuffer.appendClosingTag(M_TOKEN(barPr)(::oox::NMSP_officeMath | ::oox::XML_barPr));
2963 break;
2964 case Destination::MD:
2965 m_aMathBuffer.appendClosingTag(M_TOKEN(d)(::oox::NMSP_officeMath | ::oox::XML_d));
2966 break;
2967 case Destination::MDPR:
2968 m_aMathBuffer.appendClosingTag(M_TOKEN(dPr)(::oox::NMSP_officeMath | ::oox::XML_dPr));
2969 break;
2970 case Destination::MFUNC:
2971 m_aMathBuffer.appendClosingTag(M_TOKEN(func)(::oox::NMSP_officeMath | ::oox::XML_func));
2972 break;
2973 case Destination::MFUNCPR:
2974 m_aMathBuffer.appendClosingTag(M_TOKEN(funcPr)(::oox::NMSP_officeMath | ::oox::XML_funcPr));
2975 break;
2976 case Destination::MFNAME:
2977 m_aMathBuffer.appendClosingTag(M_TOKEN(fName)(::oox::NMSP_officeMath | ::oox::XML_fName));
2978 break;
2979 case Destination::MLIMLOW:
2980 m_aMathBuffer.appendClosingTag(M_TOKEN(limLow)(::oox::NMSP_officeMath | ::oox::XML_limLow));
2981 break;
2982 case Destination::MLIMLOWPR:
2983 m_aMathBuffer.appendClosingTag(M_TOKEN(limLowPr)(::oox::NMSP_officeMath | ::oox::XML_limLowPr));
2984 break;
2985 case Destination::MLIM:
2986 m_aMathBuffer.appendClosingTag(M_TOKEN(lim)(::oox::NMSP_officeMath | ::oox::XML_lim));
2987 break;
2988 case Destination::MM:
2989 m_aMathBuffer.appendClosingTag(M_TOKEN(m)(::oox::NMSP_officeMath | ::oox::XML_m));
2990 break;
2991 case Destination::MMPR:
2992 m_aMathBuffer.appendClosingTag(M_TOKEN(mPr)(::oox::NMSP_officeMath | ::oox::XML_mPr));
2993 break;
2994 case Destination::MMR:
2995 m_aMathBuffer.appendClosingTag(M_TOKEN(mr)(::oox::NMSP_officeMath | ::oox::XML_mr));
2996 break;
2997 case Destination::MNARY:
2998 m_aMathBuffer.appendClosingTag(M_TOKEN(nary)(::oox::NMSP_officeMath | ::oox::XML_nary));
2999 break;
3000 case Destination::MNARYPR:
3001 m_aMathBuffer.appendClosingTag(M_TOKEN(naryPr)(::oox::NMSP_officeMath | ::oox::XML_naryPr));
3002 break;
3003 case Destination::MSUB:
3004 m_aMathBuffer.appendClosingTag(M_TOKEN(sub)(::oox::NMSP_officeMath | ::oox::XML_sub));
3005 break;
3006 case Destination::MSUP:
3007 m_aMathBuffer.appendClosingTag(M_TOKEN(sup)(::oox::NMSP_officeMath | ::oox::XML_sup));
3008 break;
3009 case Destination::MLIMUPP:
3010 m_aMathBuffer.appendClosingTag(M_TOKEN(limUpp)(::oox::NMSP_officeMath | ::oox::XML_limUpp));
3011 break;
3012 case Destination::MLIMUPPPR:
3013 m_aMathBuffer.appendClosingTag(M_TOKEN(limUppPr)(::oox::NMSP_officeMath | ::oox::XML_limUppPr));
3014 break;
3015 case Destination::MGROUPCHR:
3016 m_aMathBuffer.appendClosingTag(M_TOKEN(groupChr)(::oox::NMSP_officeMath | ::oox::XML_groupChr));
3017 break;
3018 case Destination::MGROUPCHRPR:
3019 m_aMathBuffer.appendClosingTag(M_TOKEN(groupChrPr)(::oox::NMSP_officeMath | ::oox::XML_groupChrPr));
3020 break;
3021 case Destination::MBORDERBOX:
3022 m_aMathBuffer.appendClosingTag(M_TOKEN(borderBox)(::oox::NMSP_officeMath | ::oox::XML_borderBox));
3023 break;
3024 case Destination::MBORDERBOXPR:
3025 m_aMathBuffer.appendClosingTag(M_TOKEN(borderBoxPr)(::oox::NMSP_officeMath | ::oox::XML_borderBoxPr));
3026 break;
3027 case Destination::MRAD:
3028 m_aMathBuffer.appendClosingTag(M_TOKEN(rad)(::oox::NMSP_officeMath | ::oox::XML_rad));
3029 break;
3030 case Destination::MRADPR:
3031 m_aMathBuffer.appendClosingTag(M_TOKEN(radPr)(::oox::NMSP_officeMath | ::oox::XML_radPr));
3032 break;
3033 case Destination::MDEG:
3034 m_aMathBuffer.appendClosingTag(M_TOKEN(deg)(::oox::NMSP_officeMath | ::oox::XML_deg));
3035 break;
3036 case Destination::MSSUB:
3037 m_aMathBuffer.appendClosingTag(M_TOKEN(sSub)(::oox::NMSP_officeMath | ::oox::XML_sSub));
3038 break;
3039 case Destination::MSSUBPR:
3040 m_aMathBuffer.appendClosingTag(M_TOKEN(sSubPr)(::oox::NMSP_officeMath | ::oox::XML_sSubPr));
3041 break;
3042 case Destination::MSSUP:
3043 m_aMathBuffer.appendClosingTag(M_TOKEN(sSup)(::oox::NMSP_officeMath | ::oox::XML_sSup));
3044 break;
3045 case Destination::MSSUPPR:
3046 m_aMathBuffer.appendClosingTag(M_TOKEN(sSupPr)(::oox::NMSP_officeMath | ::oox::XML_sSupPr));
3047 break;
3048 case Destination::MSSUBSUP:
3049 m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSup)(::oox::NMSP_officeMath | ::oox::XML_sSubSup));
3050 break;
3051 case Destination::MSSUBSUPPR:
3052 m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSupPr)(::oox::NMSP_officeMath | ::oox::XML_sSubSupPr));
3053 break;
3054 case Destination::MSPRE:
3055 m_aMathBuffer.appendClosingTag(M_TOKEN(sPre)(::oox::NMSP_officeMath | ::oox::XML_sPre));
3056 break;
3057 case Destination::MSPREPR:
3058 m_aMathBuffer.appendClosingTag(M_TOKEN(sPrePr)(::oox::NMSP_officeMath | ::oox::XML_sPrePr));
3059 break;
3060 case Destination::MBOX:
3061 m_aMathBuffer.appendClosingTag(M_TOKEN(box)(::oox::NMSP_officeMath | ::oox::XML_box));
3062 break;
3063 case Destination::MEQARR:
3064 m_aMathBuffer.appendClosingTag(M_TOKEN(eqArr)(::oox::NMSP_officeMath | ::oox::XML_eqArr));
3065 break;
3066 case Destination::SHAPEGROUP:
3067 if (rState.getCreatedShapeGroup())
3068 m_pSdrImport->popParent();
3069 break;
3070 case Destination::PROPNAME:
3071 if (&m_aStates.top().getDestinationText()
3072 != m_aStates.top().getCurrentDestinationText())
3073 break; // not for nested group
3074 rState.setPropName(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
3075 break;
3076 case Destination::STATICVAL:
3077 if (&m_aStates.top().getDestinationText()
3078 != m_aStates.top().getCurrentDestinationText())
3079 break; // not for nested group
3080 if (m_xDocumentProperties.is())
3081 {
3082 // Find out what is the key, value type and value we want to set.
3083 uno::Reference<beans::XPropertyContainer> xPropertyContainer
3084 = m_xDocumentProperties->getUserDefinedProperties();
3085 const OUString& rKey = m_aStates.top().getPropName();
3086 OUString aStaticVal
3087 = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
3088 uno::Any aAny;
3089 if (m_aStates.top().getPropType() == cppu::UnoType<OUString>::get())
3090 aAny <<= aStaticVal;
3091 else if (m_aStates.top().getPropType() == cppu::UnoType<sal_Int32>::get())
3092 aAny <<= aStaticVal.toInt32();
3093 else if (m_aStates.top().getPropType() == cppu::UnoType<bool>::get())
3094 aAny <<= aStaticVal.toBoolean();
3095 else if (m_aStates.top().getPropType() == cppu::UnoType<util::DateTime>::get())
3096 aAny <<= getDateTimeFromUserProp(aStaticVal);
3097 else if (m_aStates.top().getPropType() == cppu::UnoType<double>::get())
3098 aAny <<= aStaticVal.toDouble();
3099
3100 xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
3101 }
3102 break;
3103 case Destination::USERPROPS:
3104 {
3105 // These are the imported properties.
3106 uno::Reference<document::XDocumentProperties> xDocumentProperties
3107 = m_xDocumentProperties;
3108
3109 // These are the real document properties.
3110 uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
3111 m_xDstDoc, uno::UNO_QUERY);
3112 if (xDocumentPropertiesSupplier.is())
3113 m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
3114
3115 if (m_xDocumentProperties.is())
3116 {
3117 if (!m_bIsNewDoc)
3118 {
3119 // Check classification.
3120 if (!SfxClassificationHelper::ShowPasteInfo(SfxClassificationHelper::CheckPaste(
3121 xDocumentProperties, m_xDocumentProperties)))
3122 return RTFError::CLASSIFICATION;
3123 }
3124
3125 uno::Reference<beans::XPropertyContainer> xClipboardPropertyContainer
3126 = xDocumentProperties->getUserDefinedProperties();
3127 uno::Reference<beans::XPropertyContainer> xDocumentPropertyContainer
3128 = m_xDocumentProperties->getUserDefinedProperties();
3129 uno::Reference<beans::XPropertySet> xClipboardPropertySet(
3130 xClipboardPropertyContainer, uno::UNO_QUERY);
3131 uno::Reference<beans::XPropertySet> xDocumentPropertySet(xDocumentPropertyContainer,
3132 uno::UNO_QUERY);
3133 const uno::Sequence<beans::Property> aClipboardProperties
3134 = xClipboardPropertySet->getPropertySetInfo()->getProperties();
3135 uno::Sequence<beans::Property> aDocumentProperties
3136 = xDocumentPropertySet->getPropertySetInfo()->getProperties();
3137
3138 for (const beans::Property& rProperty : aClipboardProperties)
3139 {
3140 const OUString& rKey = rProperty.Name;
3141 uno::Any aValue = xClipboardPropertySet->getPropertyValue(rKey);
3142
3143 try
3144 {
3145 if (lcl_containsProperty(aDocumentProperties, rKey))
3146 {
3147 // When pasting, don't update existing properties.
3148 if (!m_bIsNewDoc)
3149 xDocumentPropertySet->setPropertyValue(rKey, aValue);
3150 }
3151 else
3152 xDocumentPropertyContainer->addProperty(
3153 rKey, beans::PropertyAttribute::REMOVABLE, aValue);
3154 }
3155 catch (const uno::Exception&)
3156 {
3157 TOOLS_WARN_EXCEPTION("writerfilter.rtf", "failed to set property " << rKey)do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "failed to set property "
<< rKey << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3157" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "failed to set property " << rKey
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "failed to set property " << rKey << " "
<< exceptionToString(tools_warn_exception); ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3157" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "failed to set property " << rKey << " "
<< exceptionToString(tools_warn_exception)) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3157" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "failed to set property " << rKey
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "failed to set property " << rKey << " "
<< exceptionToString(tools_warn_exception); ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.rtf"), (
"/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3157" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3158 }
3159 }
3160 }
3161 }
3162 break;
3163 default:
3164 break;
3165 }
3166
3167 return RTFError::OK;
3168}
3169
3170void RTFDocumentImpl::afterPopState(RTFParserState& rState)
3171{
3172 // list table
3173 switch (rState.getDestination())
3174 {
3175 case Destination::LISTENTRY:
3176 {
3177 auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
3178 m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pValue,
3179 RTFOverwrite::NO_APPEND);
3180 m_aListTable[rState.getCurrentListIndex()] = pValue;
3181 m_nListLevel = -1;
3182 m_aInvalidListTableFirstIndents[rState.getCurrentListIndex()]
3183 = m_aInvalidListLevelFirstIndents;
3184 m_aInvalidListLevelFirstIndents.clear();
3185 }
3186 break;
3187 case Destination::PARAGRAPHNUMBERING:
3188 {
3189 RTFValue::Pointer_t pIdValue
3190 = rState.getTableAttributes().find(NS_ooxml::LN_CT_AbstractNum_nsid);
3191 if (pIdValue && !m_aStates.empty())
3192 {
3193 // Abstract numbering
3194 RTFSprms aLeveltextAttributes;
3195 OUString aTextValue;
3196 RTFValue::Pointer_t pTextBefore
3197 = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelText_val);
3198 if (pTextBefore)
3199 aTextValue += pTextBefore->getString();
3200 aTextValue += "%1";
3201 RTFValue::Pointer_t pTextAfter
3202 = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelSuffix_val);
3203 if (pTextAfter)
3204 aTextValue += pTextAfter->getString();
3205 auto pTextValue = new RTFValue(aTextValue);
3206 aLeveltextAttributes.set(NS_ooxml::LN_CT_LevelText_val, pTextValue);
3207
3208 RTFSprms aLevelAttributes;
3209 RTFSprms aLevelSprms;
3210 auto pIlvlValue = new RTFValue(0);
3211 aLevelAttributes.set(NS_ooxml::LN_CT_Lvl_ilvl, pIlvlValue);
3212
3213 RTFValue::Pointer_t pFmtValue
3214 = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_numFmt);
3215 if (pFmtValue)
3216 aLevelSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, pFmtValue);
3217
3218 RTFValue::Pointer_t pStartatValue
3219 = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_start);
3220 if (pStartatValue)
3221 aLevelSprms.set(NS_ooxml::LN_CT_Lvl_start, pStartatValue);
3222
3223 auto pLeveltextValue = new RTFValue(aLeveltextAttributes);
3224 aLevelSprms.set(NS_ooxml::LN_CT_Lvl_lvlText, pLeveltextValue);
3225 RTFValue::Pointer_t pRunProps
3226 = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_rPr);
3227 if (pRunProps)
3228 aLevelSprms.set(NS_ooxml::LN_CT_Lvl_rPr, pRunProps);
3229
3230 RTFSprms aAbstractAttributes;
3231 RTFSprms aAbstractSprms;
3232 aAbstractAttributes.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, pIdValue);
3233 auto pLevelValue = new RTFValue(aLevelAttributes, aLevelSprms);
3234 aAbstractSprms.set(NS_ooxml::LN_CT_AbstractNum_lvl, pLevelValue,
3235 RTFOverwrite::NO_APPEND);
3236
3237 RTFSprms aListTableSprms;
3238 auto pAbstractValue = new RTFValue(aAbstractAttributes, aAbstractSprms);
3239 // It's important that Numbering_abstractNum and Numbering_num never overwrites previous values.
3240 aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pAbstractValue,
3241 RTFOverwrite::NO_APPEND);
3242
3243 // Numbering
3244 RTFSprms aNumberingAttributes;
3245 RTFSprms aNumberingSprms;
3246 aNumberingAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pIdValue);
3247 aNumberingSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIdValue);
3248 auto pNumberingValue = new RTFValue(aNumberingAttributes, aNumberingSprms);
3249 aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pNumberingValue,
3250 RTFOverwrite::NO_APPEND);
3251
3252 // Table
3253 RTFSprms aListTableAttributes;
3254 writerfilter::Reference<Properties>::Pointer_t pProp
3255 = new RTFReferenceProperties(aListTableAttributes, aListTableSprms);
3256
3257 RTFReferenceTable::Entries_t aListTableEntries;
3258 aListTableEntries.insert(std::make_pair(0, pProp));
3259 writerfilter::Reference<Table>::Pointer_t const pTable(
3260 new RTFReferenceTable(aListTableEntries));
3261 Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
3262
3263 // Use it
3264 putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
3265 NS_ooxml::LN_CT_NumPr_ilvl, pIlvlValue);
3266 putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
3267 NS_ooxml::LN_CT_NumPr_numId, pIdValue);
3268 }
3269 }
3270 break;
3271 case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
3272 if (!m_aStates.empty())
3273 {
3274 // FIXME: don't use pDestinationText, points to popped state
3275 auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
3276 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelSuffix_val, pValue);
3277 }
3278 break;
3279 case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
3280 if (!m_aStates.empty())
3281 {
3282 // FIXME: don't use pDestinationText, points to popped state
3283 auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
3284 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
3285 }
3286 break;
3287 case Destination::LISTNAME:
3288 break;
3289 case Destination::LISTLEVEL:
3290 if (!m_aStates.empty())
3291 {
3292 auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
3293 rState.getTableAttributes().set(NS_ooxml::LN_CT_Lvl_ilvl, pInnerValue);
3294
3295 auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
3296 if (m_aStates.top().getDestination() != Destination::LFOLEVEL)
3297 m_aStates.top().getListLevelEntries().set(NS_ooxml::LN_CT_AbstractNum_lvl,
3298 pValue, RTFOverwrite::NO_APPEND);
3299 else
3300 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_NumLvl_lvl, pValue);
3301 }
3302 break;
3303 case Destination::LFOLEVEL:
3304 if (!m_aStates.empty())
3305 {
3306 auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
3307 rState.getTableAttributes().set(NS_ooxml::LN_CT_NumLvl_ilvl, pInnerValue);
3308
3309 auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
3310 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_lvlOverride, pValue,
3311 RTFOverwrite::NO_APPEND);
3312 }
3313 break;
3314 // list override table
3315 case Destination::LISTOVERRIDEENTRY:
3316 if (!m_aStates.empty())
3317 {
3318 if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
3319 {
3320 // copy properties upwards so upper popState() inserts it
3321 m_aStates.top().getTableAttributes() = rState.getTableAttributes();
3322 m_aStates.top().getTableSprms() = rState.getTableSprms();
3323 }
3324 else
3325 {
3326 auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
3327 m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pValue,
3328 RTFOverwrite::NO_APPEND);
3329 m_aListOverrideTable[rState.getCurrentListOverrideIndex()]
3330 = rState.getCurrentListIndex();
3331 }
3332 }
3333 break;
3334 case Destination::LEVELTEXT:
3335 if (!m_aStates.empty())
3336 {
3337 auto pValue = new RTFValue(rState.getTableAttributes());
3338 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_lvlText, pValue);
3339 }
3340 break;
3341 case Destination::LEVELNUMBERS:
3342 if (!m_aStates.empty())
3343 {
3344 m_aStates.top().getTableSprms() = rState.getTableSprms();
3345 if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS
3346 || m_aStates.top().getDestination() == Destination::LISTLEVEL)
3347 // Parent state is level number or list level, current state is
3348 // level numbers: mark parent as invalid as well if necessary.
3349 m_aStates.top().setLevelNumbersValid(rState.getLevelNumbersValid());
3350 }
3351 break;
3352 case Destination::FIELDINSTRUCTION:
3353 if (!m_aStates.empty())
3354 m_aStates.top().setFieldStatus(RTFFieldStatus::INSTRUCTION);
3355 break;
3356 case Destination::FIELDRESULT:
3357 if (!m_aStates.empty())
3358 m_aStates.top().setFieldStatus(RTFFieldStatus::RESULT);
3359 break;
3360 case Destination::FIELD:
3361 if (rState.getFieldStatus() == RTFFieldStatus::INSTRUCTION)
3362 singleChar(cFieldEnd);
3363 break;
3364 case Destination::SHAPEPROPERTYVALUEPICT:
3365 if (!m_aStates.empty())
3366 {
3367 m_aStates.top().getPicture() = rState.getPicture();
3368 // both \sp and \sv are destinations, copy the text up-ward for later
3369 m_aStates.top().getDestinationText() = rState.getDestinationText();
3370 }
3371 break;
3372 case Destination::FALT:
3373 if (!m_aStates.empty())
3374 m_aStates.top().getTableSprms() = rState.getTableSprms();
3375 break;
3376 case Destination::SHAPEPROPERTYNAME:
3377 case Destination::SHAPEPROPERTYVALUE:
3378 case Destination::SHAPEPROPERTY:
3379 if (!m_aStates.empty())
3380 {
3381 m_aStates.top().getShape() = rState.getShape();
3382 m_aStates.top().getPicture() = rState.getPicture();
3383 m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
3384 }
3385 break;
3386 case Destination::SHAPEINSTRUCTION:
3387 if (!m_aStates.empty()
3388 && m_aStates.top().getDestination() == Destination::SHAPEINSTRUCTION)
3389 {
3390 // Shape instruction inside other shape instruction: just copy new shape settings:
3391 // it will be resolved on end of topmost shape instruction destination
3392 m_aStates.top().getShape() = rState.getShape();
3393 m_aStates.top().getPicture() = rState.getPicture();
3394 m_aStates.top().getCharacterSprms() = rState.getCharacterSprms();
3395 m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
3396 }
3397 break;
3398 case Destination::FLYMAINCONTENT:
3399 case Destination::SHPPICT:
3400 case Destination::SHAPE:
3401 if (!m_aStates.empty())
3402 {
3403 m_aStates.top().getFrame() = rState.getFrame();
3404 if (rState.getDestination() == Destination::SHPPICT
3405 && m_aStates.top().getDestination() == Destination::LISTPICTURE)
3406 {
3407 RTFSprms aAttributes;
3408 aAttributes.set(NS_ooxml::LN_CT_NumPicBullet_numPicBulletId,
3409 new RTFValue(m_nListPictureId++));
3410 RTFSprms aSprms;
3411 // Dummy value, real picture is already sent to dmapper.
3412 aSprms.set(NS_ooxml::LN_CT_NumPicBullet_pict, new RTFValue(0));
3413 auto pValue = new RTFValue(aAttributes, aSprms);
3414 m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_numPicBullet, pValue,
3415 RTFOverwrite::NO_APPEND);
3416 }
3417 }
3418 break;
3419 case Destination::SHAPETEXT:
3420 if (!m_aStates.empty())
3421 {
3422 // If we're leaving the shapetext group (it may have nested ones) and this is a shape, not an old drawingobject.
3423 if (m_aStates.top().getDestination() != Destination::SHAPETEXT
3424 && !m_aStates.top().getDrawingObject().getHadShapeText())
3425 {
3426 m_aStates.top().setHadShapeText(true);
3427 if (!m_aStates.top().getCurrentBuffer())
3428 m_pSdrImport->close();
3429 else
3430 m_aStates.top().getCurrentBuffer()->push_back(
3431 Buf_t(BUFFER_ENDSHAPE, nullptr, nullptr));
3432 }
3433
3434 // It's allowed to declare these inside the shape text, and they
3435 // are expected to have an effect for the whole shape.
3436 if (rState.getDrawingObject().getLeft())
3437 m_aStates.top().getDrawingObject().setLeft(rState.getDrawingObject().getLeft());
3438 if (rState.getDrawingObject().getTop())
3439 m_aStates.top().getDrawingObject().setTop(rState.getDrawingObject().getTop());
3440 if (rState.getDrawingObject().getRight())
3441 m_aStates.top().getDrawingObject().setRight(
3442 rState.getDrawingObject().getRight());
3443 if (rState.getDrawingObject().getBottom())
3444 m_aStates.top().getDrawingObject().setBottom(
3445 rState.getDrawingObject().getBottom());
3446 }
3447 break;
3448 case Destination::PROPNAME:
3449 if (m_aStates.top().getDestination() == Destination::USERPROPS)
3450 m_aStates.top().setPropName(rState.getPropName());
3451 break;
3452 default:
3453 {
3454 if (!m_aStates.empty() && m_aStates.top().getDestination() == Destination::PICT)
3455 m_aStates.top().getPicture() = rState.getPicture();
3456 }
3457 break;
3458 }
3459}
3460
3461RTFError RTFDocumentImpl::popState()
3462{
3463 //SAL_INFO("writerfilter", __func__ << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
3464 // ", dest state: " << m_aStates.top().eDestination);
3465
3466 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
3467 RTFParserState aState(m_aStates.top());
3468 m_bWasInFrame = aState.getFrame().inFrame();
3469
3470 // dmapper expects some content in header/footer, so if there would be nothing, add an empty paragraph.
3471 if (m_pTokenizer->getGroup() == 1 && m_bFirstRun)
3472 {
3473 switch (m_nStreamType)
3474 {
3475 case NS_ooxml::LN_headerl:
3476 case NS_ooxml::LN_headerr:
3477 case NS_ooxml::LN_headerf:
3478 case NS_ooxml::LN_footerl:
3479 case NS_ooxml::LN_footerr:
3480 case NS_ooxml::LN_footerf:
3481 dispatchSymbol(RTF_PAR);
3482 break;
3483 }
3484 }
3485
3486 RTFError eError = beforePopState(aState);
3487 if (eError != RTFError::OK)
3488 return eError;
3489
3490 // See if we need to end a track change
3491 if (aState.getStartedTrackchange())
3492 {
3493 RTFSprms aTCSprms;
3494 auto pValue = new RTFValue(0);
3495 aTCSprms.set(NS_ooxml::LN_endtrackchange, pValue);
3496 if (!m_aStates.top().getCurrentBuffer())
3497 Mapper().props(new RTFReferenceProperties(RTFSprms(), aTCSprms));
3498 else
3499 bufferProperties(*m_aStates.top().getCurrentBuffer(),
3500 new RTFValue(RTFSprms(), aTCSprms), nullptr);
3501 }
3502
3503 // This is the end of the doc, see if we need to close the last section.
3504 if (m_pTokenizer->getGroup() == 1 && !m_bFirstRun)
3505 {
3506 // \par means an empty paragraph at the end of footnotes/endnotes, but
3507 // not in case of other substreams, like headers.
3508 if (m_bNeedCr && m_nStreamType != NS_ooxml::LN_footnote
3509 && m_nStreamType != NS_ooxml::LN_endnote && m_bIsNewDoc)
3510 dispatchSymbol(RTF_PAR);
3511 if (m_bNeedSect) // may be set by dispatchSymbol above!
3512 sectBreak(true);
3513 }
3514
3515 m_aStates.pop();
3516
3517 m_pTokenizer->popGroup();
3518
3519 afterPopState(aState);
3520
3521 if (aState.getCurrentBuffer() == &m_aSuperBuffer)
3522 {
3523 OSL_ASSERT(!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr)do { if (true && (!(!m_aStates.empty() && m_aStates
.top().getCurrentBuffer() == nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3523" ": "), "OSL_ASSERT: %s", "!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr"
); } } while (false)
;
3524
3525 if (!m_aSuperBuffer.empty())
3526 replayBuffer(m_aSuperBuffer, nullptr, nullptr);
3527 }
3528
3529 if (!m_aStates.empty() && m_aStates.top().getTableRowWidthAfter() > 0
3530 && aState.getTableRowWidthAfter() == 0)
3531 // An RTF_ROW in the inner group already parsed nTableRowWidthAfter,
3532 // don't do it again in the outer state later.
3533 m_aStates.top().setTableRowWidthAfter(0);
3534
3535 if (m_nResetBreakOnSectBreak != RTF_invalid && !m_aStates.empty())
3536 {
3537 // Section break type created for \page still has an effect in the
3538 // outer state as well.
3539 RTFValue::Pointer_t pType
3540 = aState.getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
3541 if (pType)
3542 m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pType);
3543 }
3544
3545 return RTFError::OK;
3546}
3547
3548RTFError RTFDocumentImpl::handleEmbeddedObject()
3549{
3550 OString aStr
3551 = OUStringToOString(m_aStates.top().getCurrentDestinationText()->makeStringAndClear(),
3552 RTL_TEXTENCODING_ASCII_US(((rtl_TextEncoding) 11)));
3553 std::unique_ptr<SvStream> pStream(new SvMemoryStream());
3554 if (!msfilter::rtfutil::ExtractOLE2FromObjdata(aStr, *pStream))
3555 return RTFError::HEX_INVALID;
3556
3557 uno::Reference<io::XInputStream> xInputStream(
3558 new utl::OSeekableInputStreamWrapper(pStream.release(), /*_bOwner=*/true));
3559 auto pStreamValue = new RTFValue(xInputStream);
3560 m_aOLEAttributes.set(NS_ooxml::LN_inputstream, pStreamValue);
3561
3562 return RTFError::OK;
3563}
3564
3565bool RTFDocumentImpl::isInBackground() { return m_aStates.top().getInBackground(); }
3566
3567RTFInternalState RTFDocumentImpl::getInternalState() { return m_aStates.top().getInternalState(); }
3568
3569void RTFDocumentImpl::setInternalState(RTFInternalState nInternalState)
3570{
3571 m_aStates.top().setInternalState(nInternalState);
3572}
3573
3574Destination RTFDocumentImpl::getDestination() { return m_aStates.top().getDestination(); }
3575
3576void RTFDocumentImpl::setDestination(Destination eDestination)
3577{
3578 m_aStates.top().setDestination(eDestination);
3579}
3580
3581// this is a questionably named method that is used only in a very special
3582// situation where it looks like the "current" buffer is needed?
3583void RTFDocumentImpl::setDestinationText(OUString const& rString)
3584{
3585 m_aStates.top().getDestinationText().setLength(0);
3586 m_aStates.top().getDestinationText().append(rString);
3587}
3588
3589bool RTFDocumentImpl::getSkipUnknown() { return m_bSkipUnknown; }
3590
3591void RTFDocumentImpl::setSkipUnknown(bool bSkipUnknown) { m_bSkipUnknown = bSkipUnknown; }
3592
3593static auto FilterControlChars(Destination const destination, OUString const& rString) -> OUString
3594{
3595 if (destination == Destination::LEVELNUMBERS || destination == Destination::LEVELTEXT)
3596 { // control characters are magic here!
3597 return rString;
3598 }
3599 OUStringBuffer buf(rString.getLength());
3600 for (sal_Int32 i = 0; i < rString.getLength(); ++i)
3601 {
3602 sal_Unicode const ch(rString[i]);
3603 if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
3604 {
3605 buf.append(ch);
3606 }
3607 else
3608 {
3609 SAL_INFO("writerfilter.rtf", "filtering control character")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "writerfilter.rtf")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "filtering control character"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"
), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3609" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "filtering control character"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "filtering control character"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3609" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "filtering control character") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3609" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "filtering control character"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "filtering control character"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter.rtf"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdocumentimpl.cxx"
":" "3609" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3610 }
3611 }
3612 return buf.makeStringAndClear();
3613}
3614
3615void RTFDocumentImpl::checkUnicode(bool bUnicode, bool bHex)
3616{
3617 if (bUnicode && !m_aUnicodeBuffer.isEmpty())
3618 {
3619 OUString aString = m_aUnicodeBuffer.toString();
3620 m_aUnicodeBuffer.setLength(0);
3621 aString = FilterControlChars(m_aStates.top().getDestination(), aString);
3622 text(aString);
3623 }
3624 if (bHex && !m_aHexBuffer.isEmpty())
3625 {
3626 rtl_TextEncoding nEncoding = m_aStates.top().getCurrentEncoding();
3627 if (m_aStates.top().getDestination() == Destination::FONTENTRY
3628 && m_aStates.top().getCurrentEncoding() == RTL_TEXTENCODING_SYMBOL(((rtl_TextEncoding) 10)))
3629 nEncoding = RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1));
3630 OUString aString = OStringToOUString(m_aHexBuffer.toString(), nEncoding);
3631 m_aHexBuffer.setLength(0);
3632 aString = FilterControlChars(m_aStates.top().getDestination(), aString);
3633 text(aString);
3634 }
3635}
3636
3637RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl)
3638 : m_pDocumentImpl(pDocumentImpl)
3639 , m_nInternalState(RTFInternalState::NORMAL)
3640 , m_eDestination(Destination::NORMAL)
3641 , m_eFieldStatus(RTFFieldStatus::NONE)
3642 , m_nBorderState(RTFBorderState::NONE)
3643 , m_nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0))
3644 , m_nUc(1)
3645 , m_nCharsToSkip(0)
3646 , m_nBinaryToRead(0)
3647 , m_nListLevelNum(0)
3648 , m_bLevelNumbersValid(true)
3649 , m_aFrame(this)
3650 , m_eRunType(RunType::NONE)
3651 , m_nYear(0)
3652 , m_nMonth(0)
3653 , m_nDay(0)
3654 , m_nHour(0)
3655 , m_nMinute(0)
3656 , m_pCurrentDestinationText(nullptr)
3657 , m_nCurrentStyleIndex(-1)
3658 , m_nCurrentCharacterStyleIndex(-1)
3659 , m_pCurrentBuffer(nullptr)
3660 , m_bInListpicture(false)
3661 , m_bInBackground(false)
3662 , m_bHadShapeText(false)
3663 , m_bInShapeGroup(false)
3664 , m_bInShape(false)
3665 , m_bCreatedShapeGroup(false)
3666 , m_bStartedTrackchange(false)
3667 , m_nTableRowWidthAfter(0)
3668{
3669}
3670
3671void RTFDocumentImpl::resetFrame() { m_aStates.top().getFrame() = RTFFrame(&m_aStates.top()); }
3672
3673void RTFDocumentImpl::bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
3674 const tools::SvRef<TableRowBuffer>& pTableProperties)
3675{
3676 rBuffer.emplace_back(
3677 Buf_t(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()), nullptr));
3678 rBuffer.emplace_back(Buf_t(BUFFER_PROPS, pValue, pTableProperties));
3679}
3680
3681RTFShape::RTFShape() = default;
3682
3683RTFDrawingObject::RTFDrawingObject() = default;
3684
3685RTFFrame::RTFFrame(RTFParserState* pParserState)
3686 : m_pDocumentImpl(pParserState->getDocumentImpl())
3687 , m_nX(0)
3688 , m_nY(0)
3689 , m_nW(0)
3690 , m_nH(0)
3691 , m_nHoriPadding(0)
3692 , m_nVertPadding(0)
3693 , m_nHoriAlign(0)
3694 , m_nHoriAnchor(0)
3695 , m_nVertAlign(0)
3696 , m_nVertAnchor(0)
3697 , m_nHRule(NS_ooxml::LN_Value_doc_ST_HeightRule_auto)
3698{
3699}
3700
3701void RTFFrame::setSprm(Id nId, Id nValue)
3702{
3703 if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport())
3704 {
3705 m_pDocumentImpl->checkFirstRun();
3706 m_pDocumentImpl->setNeedPar(false);
3707 }
3708 switch (nId)
3709 {
3710 case NS_ooxml::LN_CT_FramePr_w:
3711 m_nW = nValue;
3712 break;
3713 case NS_ooxml::LN_CT_FramePr_h:
3714 m_nH = nValue;
3715 break;
3716 case NS_ooxml::LN_CT_FramePr_x:
3717 m_nX = nValue;
3718 break;
3719 case NS_ooxml::LN_CT_FramePr_y:
3720 m_nY = nValue;
3721 break;
3722 case NS_ooxml::LN_CT_FramePr_hSpace:
3723 m_nHoriPadding = nValue;
3724 break;
3725 case NS_ooxml::LN_CT_FramePr_vSpace:
3726 m_nVertPadding = nValue;
3727 break;
3728 case NS_ooxml::LN_CT_FramePr_xAlign:
3729 m_nHoriAlign = nValue;
3730 break;
3731 case NS_ooxml::LN_CT_FramePr_hAnchor:
3732 m_nHoriAnchor = nValue;
3733 break;
3734 case NS_ooxml::LN_CT_FramePr_yAlign:
3735 m_nVertAlign = nValue;
3736 break;
3737 case NS_ooxml::LN_CT_FramePr_vAnchor:
3738 m_nVertAnchor = nValue;
3739 break;
3740 case NS_ooxml::LN_CT_FramePr_wrap:
3741 m_oWrap = nValue;
3742 break;
3743 default:
3744 break;
3745 }
3746}
3747
3748RTFSprms RTFFrame::getSprms()
3749{
3750 RTFSprms sprms;
3751
3752 static const Id pNames[]
3753 = { NS_ooxml::LN_CT_FramePr_x, NS_ooxml::LN_CT_FramePr_y,
3754 NS_ooxml::LN_CT_FramePr_hRule, // Make sure nHRule is processed before nH
3755 NS_ooxml::LN_CT_FramePr_h, NS_ooxml::LN_CT_FramePr_w,
3756 NS_ooxml::LN_CT_FramePr_hSpace, NS_ooxml::LN_CT_FramePr_vSpace,
3757 NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_CT_FramePr_vAnchor,
3758 NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_CT_FramePr_yAlign,
3759 NS_ooxml::LN_CT_FramePr_wrap, NS_ooxml::LN_CT_FramePr_dropCap,
3760 NS_ooxml::LN_CT_FramePr_lines };
3761
3762 for (Id nId : pNames)
3763 {
3764 RTFValue::Pointer_t pValue;
3765
3766 switch (nId)
3767 {
3768 case NS_ooxml::LN_CT_FramePr_x:
3769 if (m_nX != 0)
3770 pValue = new RTFValue(m_nX);
3771 break;
3772 case NS_ooxml::LN_CT_FramePr_y:
3773 if (m_nY != 0)
3774 pValue = new RTFValue(m_nY);
3775 break;
3776 case NS_ooxml::LN_CT_FramePr_h:
3777 if (m_nH != 0)
3778 {
3779 if (m_nHRule == NS_ooxml::LN_Value_doc_ST_HeightRule_exact)
3780 pValue = new RTFValue(-m_nH); // The negative value just sets nHRule
3781 else
3782 pValue = new RTFValue(m_nH);
3783 }
3784 break;
3785 case NS_ooxml::LN_CT_FramePr_w:
3786 if (m_nW != 0)
3787 pValue = new RTFValue(m_nW);
3788 break;
3789 case NS_ooxml::LN_CT_FramePr_hSpace:
3790 if (m_nHoriPadding != 0)
3791 pValue = new RTFValue(m_nHoriPadding);
3792 break;
3793 case NS_ooxml::LN_CT_FramePr_vSpace:
3794 if (m_nVertPadding != 0)
3795 pValue = new RTFValue(m_nVertPadding);
3796 break;
3797 case NS_ooxml::LN_CT_FramePr_hAnchor:
3798 {
3799 if (m_nHoriAnchor == 0)
3800 m_nHoriAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin;
3801 pValue = new RTFValue(m_nHoriAnchor);
3802 }
3803 break;
3804 case NS_ooxml::LN_CT_FramePr_vAnchor:
3805 {
3806 if (m_nVertAnchor == 0)
3807 m_nVertAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
3808 pValue = new RTFValue(m_nVertAnchor);
3809 }
3810 break;
3811 case NS_ooxml::LN_CT_FramePr_xAlign:
3812 pValue = new RTFValue(m_nHoriAlign);
3813 break;
3814 case NS_ooxml::LN_CT_FramePr_yAlign:
3815 pValue = new RTFValue(m_nVertAlign);
3816 break;
3817 case NS_ooxml::LN_CT_FramePr_hRule:
3818 {
3819 if (m_nH < 0)
3820 m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_exact;
3821 else if (m_nH > 0)
3822 m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_atLeast;
3823 pValue = new RTFValue(m_nHRule);
3824 }
3825 break;
3826 case NS_ooxml::LN_CT_FramePr_wrap:
3827 if (m_oWrap)
3828 pValue = new RTFValue(*m_oWrap);
3829 break;
3830 default:
3831 break;
3832 }
3833
3834 if (pValue)
3835 sprms.set(nId, pValue);
3836 }
3837
3838 RTFSprms frameprSprms;
3839 frameprSprms.set(NS_ooxml::LN_CT_PPrBase_framePr, new RTFValue(sprms));
3840 return frameprSprms;
3841}
3842
3843bool RTFFrame::hasProperties() const
3844{
3845 return m_nX != 0 || m_nY != 0 || m_nW != 0 || m_nH != 0 || m_nHoriPadding != 0
3846 || m_nVertPadding != 0 || m_nHoriAlign != 0 || m_nHoriAnchor != 0 || m_nVertAlign != 0
3847 || m_nVertAnchor != 0;
3848}
3849
3850} // namespace writerfilter
3851
3852/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

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#ifndef INCLUDED_TOOLS_REF_HXX
20#define INCLUDED_TOOLS_REF_HXX
21
22#include <sal/config.h>
23#include <cassert>
24#include <tools/toolsdllapi.h>
25#include <utility>
26
27/**
28 This implements similar functionality to boost::intrusive_ptr
29*/
30
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
36 SvRef(): pObj(nullptr) {}
37
38 SvRef(SvRef&& rObj) noexcept
39 {
40 pObj = rObj.pObj;
41 rObj.pObj = nullptr;
42 }
43
44 SvRef(SvRef const & rObj): pObj(rObj.pObj)
45 {
46 if (pObj != nullptr) pObj->AddNextRef();
47 }
48
49 SvRef(T * pObjP): pObj(pObjP)
50 {
51 if (pObj != nullptr) pObj->AddFirstRef();
52 }
53
54 ~SvRef()
55 {
56 if (pObj != nullptr) pObj->ReleaseRef();
9
Taking true branch
10
Calling 'SvRefBase::ReleaseRef'
17
Returning; memory was released
57 }
58
59 void clear()
60 {
61 if (pObj != nullptr) {
62 T * pRefObj = pObj;
63 pObj = nullptr;
64 pRefObj->ReleaseRef();
65 }
66 }
67
68 SvRef & operator =(SvRef const & rObj)
69 {
70 if (rObj.pObj != nullptr) {
71 rObj.pObj->AddNextRef();
72 }
73 T * pRefObj = pObj;
74 pObj = rObj.pObj;
75 if (pRefObj != nullptr) {
76 pRefObj->ReleaseRef();
77 }
78 return *this;
79 }
80
81 SvRef & operator =(SvRef && rObj)
82 {
83 if (pObj != nullptr) {
84 pObj->ReleaseRef();
85 }
86 pObj = rObj.pObj;
87 rObj.pObj = nullptr;
88 return *this;
89 }
90
91 bool is() const { return pObj != nullptr; }
92
93 explicit operator bool() const { return is(); }
94
95 T * get() const { return pObj; }
96
97 T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 97, __extension__ __PRETTY_FUNCTION__))
; return pObj; }
98
99 T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
; return *pObj; }
100
101 bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; }
102 bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); }
103
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<T> make_ref(Args&& ... args)
113{
114 return SvRef<T>(new T(std::forward<Args>(args)...));
115}
116
117}
118
119/** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */
120class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase
121{
122 // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
123 // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
124 unsigned int nRefCount : 31;
125 // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
126 unsigned int bNoDelete : 1;
127
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
132 SvRefBase() : nRefCount(0), bNoDelete(1) {}
133 SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {}
134
135 SvRefBase & operator=(const SvRefBase &) { return *this; }
136
137 void RestoreNoDelete()
138 { bNoDelete = 1; }
139
140 void AddNextRef()
141 {
142 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
142, __extension__ __PRETTY_FUNCTION__))
;
143 ++nRefCount;
144 }
145
146 void AddFirstRef()
147 {
148 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
148, __extension__ __PRETTY_FUNCTION__))
;
149 if( bNoDelete )
150 bNoDelete = 0;
151 ++nRefCount;
152 }
153
154 void ReleaseRef()
155 {
156 assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail
("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 156, __extension__ __PRETTY_FUNCTION__))
;
11
Assuming field 'nRefCount' is >= 1
12
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete)
13
Assuming the condition is true
14
Assuming field 'bNoDelete' is 0
15
Taking true branch
158 {
159 // I'm not sure about the original purpose of this line, but right now
160 // it serves the purpose that anything that attempts to do an AddRef()
161 // after an object is deleted will trip an assert.
162 nRefCount = 1 << 30;
163 delete this;
16
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
185 void ResetWeakBase( ) { _pObj = nullptr; }
186 T* GetObj() { return _pObj; }
187};
188
189/** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame.
190 Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted.
191*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
198 /** Does not use initializer due to compiler warnings,
199 because the lifetime of the _xHdl object can exceed the lifetime of this class.
200 */
201 SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); }
202
203 ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); }
204
205 SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); }
206};
207
208/** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak.
209*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
215 SvCompatWeakRef( ) {}
216 SvCompatWeakRef( T* pObj )
217 { if( pObj ) _xHdl = pObj->GetHdl(); }
218#if defined(__COVERITY__)
219 ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {}
220#endif
221 SvCompatWeakRef& operator = ( T * pObj )
222 { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; }
223 bool is() const
224 { return _xHdl.is() && _xHdl->GetObj(); }
225 explicit operator bool() const { return is(); }
226 T* operator -> () const
227 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
228 operator T* () const
229 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
230};
231
232#endif
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */