1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "rtfdocumentimpl.hxx"
13 #include <string_view>
14 #include <com/sun/star/embed/XEmbeddedObject.hpp>
15 #include <com/sun/star/beans/PropertyAttribute.hpp>
16 #include <com/sun/star/io/WrongFormatException.hpp>
17 #include <com/sun/star/lang/XServiceInfo.hpp>
18 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
19 #include <com/sun/star/text/WrapTextMode.hpp>
20 #include <com/sun/star/text/TextContentAnchorType.hpp>
21 #include <i18nlangtag/languagetag.hxx>
22 #include <unotools/ucbstreamhelper.hxx>
23 #include <unotools/streamwrap.hxx>
24 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
25 #include <filter/msfilter/util.hxx>
26 #include <filter/msfilter/rtfutil.hxx>
27 #include <comphelper/string.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <tools/globname.hxx>
30 #include <tools/datetimeutils.hxx>
31 #include <comphelper/classids.hxx>
32 #include <comphelper/embeddedobjectcontainer.hxx>
33 #include <svl/lngmisc.hxx>
34 #include <sfx2/sfxbasemodel.hxx>
35 #include <sfx2/classificationhelper.hxx>
36 #include <oox/mathml/import.hxx>
37 #include <ooxml/resourceids.hxx>
38 #include <oox/token/namespaces.hxx>
39 #include <oox/drawingml/drawingmltypes.hxx>
40 #include <rtl/uri.hxx>
41 #include <rtl/tencinfo.h>
42 #include <sal/log.hxx>
43 #include <osl/diagnose.h>
44 #include <oox/helper/graphichelper.hxx>
45 #include <vcl/wmfexternal.hxx>
46 #include <vcl/graph.hxx>
47 #include <vcl/settings.hxx>
48 #include <vcl/svapp.hxx>
49 #include "rtfsdrimport.hxx"
50 #include "rtfreferenceproperties.hxx"
51 #include "rtfskipdestination.hxx"
52 #include "rtftokenizer.hxx"
53 #include "rtflookahead.hxx"
55 using namespace com::sun::star
;
59 /// Returns an util::DateTime from a 'YYYY. MM. DD.' string.
60 util::DateTime
getDateTimeFromUserProp(const OUString
& rString
)
63 sal_Int32 nLen
= rString
.getLength();
66 aRet
.Year
= rString
.copy(0, 4).toInt32();
68 if (nLen
>= 8 && rString
.match(". ", 4))
70 aRet
.Month
= rString
.copy(6, 2).toInt32();
72 if (nLen
>= 12 && rString
.match(". ", 8))
73 aRet
.Day
= rString
.copy(10, 2).toInt32();
78 } // anonymous namespace
80 namespace writerfilter
84 Id
getParagraphBorder(sal_uInt32 nIndex
)
86 static const Id aBorderIds
[] = { NS_ooxml::LN_CT_PBdr_top
, NS_ooxml::LN_CT_PBdr_left
,
87 NS_ooxml::LN_CT_PBdr_bottom
, NS_ooxml::LN_CT_PBdr_right
};
89 return aBorderIds
[nIndex
];
92 void putNestedAttribute(RTFSprms
& rSprms
, Id nParent
, Id nId
, const RTFValue::Pointer_t
& pValue
,
93 RTFOverwrite eOverwrite
, bool bAttribute
)
95 RTFValue::Pointer_t pParent
= rSprms
.find(nParent
, /*bFirst=*/true, /*bForWrite=*/true);
99 if (nParent
== NS_ooxml::LN_CT_TcPrBase_shd
)
101 // RTF default is 'auto', see writerfilter::dmapper::CellColorHandler
102 aAttributes
.set(NS_ooxml::LN_CT_Shd_color
, new RTFValue(sal_uInt32(COL_AUTO
)));
103 aAttributes
.set(NS_ooxml::LN_CT_Shd_fill
, new RTFValue(sal_uInt32(COL_AUTO
)));
105 auto pParentValue
= new RTFValue(aAttributes
);
106 rSprms
.set(nParent
, pParentValue
, eOverwrite
);
107 pParent
= pParentValue
;
109 RTFSprms
& rAttributes
= (bAttribute
? pParent
->getAttributes() : pParent
->getSprms());
110 rAttributes
.set(nId
, pValue
, eOverwrite
);
113 void putNestedSprm(RTFSprms
& rSprms
, Id nParent
, Id nId
, const RTFValue::Pointer_t
& pValue
,
114 RTFOverwrite eOverwrite
)
116 putNestedAttribute(rSprms
, nParent
, nId
, pValue
, eOverwrite
, false);
119 RTFValue::Pointer_t
getNestedAttribute(RTFSprms
& rSprms
, Id nParent
, Id nId
)
121 RTFValue::Pointer_t pParent
= rSprms
.find(nParent
);
123 return RTFValue::Pointer_t();
124 RTFSprms
& rAttributes
= pParent
->getAttributes();
125 return rAttributes
.find(nId
);
128 RTFValue::Pointer_t
getNestedSprm(RTFSprms
& rSprms
, Id nParent
, Id nId
)
130 RTFValue::Pointer_t pParent
= rSprms
.find(nParent
);
132 return RTFValue::Pointer_t();
133 RTFSprms
& rInner
= pParent
->getSprms();
134 return rInner
.find(nId
);
137 bool eraseNestedAttribute(RTFSprms
& rSprms
, Id nParent
, Id nId
)
139 RTFValue::Pointer_t pParent
= rSprms
.find(nParent
);
141 // It doesn't even have a parent, we're done.
143 RTFSprms
& rAttributes
= pParent
->getAttributes();
144 return rAttributes
.erase(nId
);
147 RTFSprms
& getLastAttributes(RTFSprms
& rSprms
, Id nId
)
149 RTFValue::Pointer_t p
= rSprms
.find(nId
);
150 if (p
.get() && !p
->getSprms().empty())
151 return p
->getSprms().back().second
->getAttributes();
153 SAL_WARN("writerfilter.rtf", "trying to set property when no type is defined");
157 void putBorderProperty(RTFStack
& aStates
, Id nId
, const RTFValue::Pointer_t
& pValue
)
159 RTFSprms
* pAttributes
= nullptr;
160 if (aStates
.top().getBorderState() == RTFBorderState::PARAGRAPH_BOX
)
161 for (int i
= 0; i
< 4; i
++)
163 RTFValue::Pointer_t p
= aStates
.top().getParagraphSprms().find(getParagraphBorder(i
));
166 RTFSprms
& rAttributes
= p
->getAttributes();
167 rAttributes
.set(nId
, pValue
);
170 else if (aStates
.top().getBorderState() == RTFBorderState::CHARACTER
)
172 RTFValue::Pointer_t pPointer
173 = aStates
.top().getCharacterSprms().find(NS_ooxml::LN_EG_RPrBase_bdr
);
176 RTFSprms
& rAttributes
= pPointer
->getAttributes();
177 rAttributes
.set(nId
, pValue
);
180 // Attributes of the last border type
181 else if (aStates
.top().getBorderState() == RTFBorderState::PARAGRAPH
)
183 = &getLastAttributes(aStates
.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr
);
184 else if (aStates
.top().getBorderState() == RTFBorderState::CELL
)
185 pAttributes
= &getLastAttributes(aStates
.top().getTableCellSprms(),
186 NS_ooxml::LN_CT_TcPrBase_tcBorders
);
187 else if (aStates
.top().getBorderState() == RTFBorderState::PAGE
)
188 pAttributes
= &getLastAttributes(aStates
.top().getSectionSprms(),
189 NS_ooxml::LN_EG_SectPrContents_pgBorders
);
191 pAttributes
->set(nId
, pValue
);
194 OString
DTTM22OString(long nDTTM
)
196 return DateTimeToOString(msfilter::util::DTTM2DateTime(nDTTM
));
199 static RTFSprms
lcl_getBookmarkProperties(int nPos
, const OUString
& rString
)
201 RTFSprms aAttributes
;
202 auto pPos
= new RTFValue(nPos
);
203 if (!rString
.isEmpty())
205 // If present, this should be sent first.
206 auto pString
= new RTFValue(rString
);
207 aAttributes
.set(NS_ooxml::LN_CT_Bookmark_name
, pString
);
209 aAttributes
.set(NS_ooxml::LN_CT_MarkupRangeBookmark_id
, pPos
);
213 const char* keywordToString(RTFKeyword nKeyword
)
215 for (int i
= 0; i
< nRTFControlWords
; i
++)
217 if (nKeyword
== aRTFControlWords
[i
].GetIndex())
218 return aRTFControlWords
[i
].GetKeyword();
223 static util::DateTime
lcl_getDateTime(RTFParserState
const& aState
)
225 return { 0 /*100sec*/,
231 static_cast<sal_Int16
>(aState
.getYear()),
235 static void lcl_DestinationToMath(OUStringBuffer
* pDestinationText
,
236 oox::formulaimport::XmlStreamBuilder
& rMathBuffer
, bool& rMathNor
)
238 if (!pDestinationText
)
240 OUString aStr
= pDestinationText
->makeStringAndClear();
243 rMathBuffer
.appendOpeningTag(M_TOKEN(r
));
246 rMathBuffer
.appendOpeningTag(M_TOKEN(rPr
));
247 // Same as M_TOKEN(lit)
248 rMathBuffer
.appendOpeningTag(M_TOKEN(nor
));
249 rMathBuffer
.appendClosingTag(M_TOKEN(nor
));
250 rMathBuffer
.appendClosingTag(M_TOKEN(rPr
));
253 rMathBuffer
.appendOpeningTag(M_TOKEN(t
));
254 rMathBuffer
.appendCharacters(aStr
);
255 rMathBuffer
.appendClosingTag(M_TOKEN(t
));
256 rMathBuffer
.appendClosingTag(M_TOKEN(r
));
259 RTFDocumentImpl::RTFDocumentImpl(uno::Reference
<uno::XComponentContext
> const& xContext
,
260 uno::Reference
<io::XInputStream
> const& xInputStream
,
261 uno::Reference
<lang::XComponent
> const& xDstDoc
,
262 uno::Reference
<frame::XFrame
> const& xFrame
,
263 uno::Reference
<task::XStatusIndicator
> const& xStatusIndicator
,
264 const utl::MediaDescriptor
& rMediaDescriptor
)
265 : m_xContext(xContext
)
266 , m_xInputStream(xInputStream
)
269 , m_xStatusIndicator(xStatusIndicator
)
270 , m_pMapperStream(nullptr)
271 , m_aDefaultState(this)
272 , m_bSkipUnknown(false)
274 , m_bFirstRunException(false)
277 , m_bNeedCrOrig(false)
279 , m_bNeedFinalPar(false)
281 , m_nTopLevelCells(0)
282 , m_nInheritingCells(0)
284 , m_nTopLevelTRLeft(0)
285 , m_nNestedCurrentCellX(0)
286 , m_nTopLevelCurrentCellX(0)
287 , m_nBackupTopLevelCurrentCellX(0)
288 , m_aTableBufferStack(1) // create top-level buffer already
289 , m_pSuperstream(nullptr)
291 , m_nGroupStartPos(0)
292 , m_nFormFieldType(RTFFormFieldType::NONE
)
294 , m_nCurrentFontIndex(0)
295 , m_nCurrentEncoding(-1)
296 , m_nDefaultFontIndex(-1)
297 , m_nCurrentStyleIndex(0)
298 , m_bFormField(false)
300 , m_bIgnoreNextContSectBreak(false)
301 , m_nResetBreakOnSectBreak(RTF_invalid
)
302 , m_bNeedSect(false) // done by checkFirstRun
303 , m_bWasInFrame(false)
304 , m_bHadPicture(false)
307 , m_nListPictureId(0)
308 , m_bIsNewDoc(!rMediaDescriptor
.getUnpackedValueOrDefault("InsertMode", false))
309 , m_rMediaDescriptor(rMediaDescriptor
)
310 , m_hasRHeader(false)
311 , m_hasFHeader(false)
312 , m_hasRFooter(false)
313 , m_hasFFooter(false)
314 , m_bAfterCellBeforeRow(false)
316 OSL_ASSERT(xInputStream
.is());
317 m_pInStream
= utl::UcbStreamHelper::CreateStream(xInputStream
, true);
319 m_xModelFactory
.set(m_xDstDoc
, uno::UNO_QUERY
);
321 uno::Reference
<document::XDocumentPropertiesSupplier
> xDocumentPropertiesSupplier(
322 m_xDstDoc
, uno::UNO_QUERY
);
323 if (xDocumentPropertiesSupplier
.is())
324 m_xDocumentProperties
= xDocumentPropertiesSupplier
->getDocumentProperties();
326 m_pGraphicHelper
.reset(new oox::GraphicHelper(m_xContext
, xFrame
, oox::StorageRef()));
328 m_pTokenizer
= new RTFTokenizer(*this, m_pInStream
.get(), m_xStatusIndicator
);
329 m_pSdrImport
= new RTFSdrImport(*this, m_xDstDoc
);
332 RTFDocumentImpl::~RTFDocumentImpl() = default;
334 SvStream
& RTFDocumentImpl::Strm() { return *m_pInStream
; }
336 void RTFDocumentImpl::setSuperstream(RTFDocumentImpl
* pSuperstream
)
338 m_pSuperstream
= pSuperstream
;
341 bool RTFDocumentImpl::isSubstream() const { return m_pSuperstream
!= nullptr; }
343 void RTFDocumentImpl::finishSubstream() { checkUnicode(/*bUnicode =*/true, /*bHex =*/true); }
345 void RTFDocumentImpl::resolveSubstream(std::size_t nPos
, Id nId
)
347 resolveSubstream(nPos
, nId
, OUString());
349 void RTFDocumentImpl::resolveSubstream(std::size_t nPos
, Id nId
, OUString
const& rIgnoreFirst
)
351 sal_uInt64
const nCurrent
= Strm().Tell();
352 // Seek to header position, parse, then seek back.
353 auto pImpl
= new RTFDocumentImpl(m_xContext
, m_xInputStream
, m_xDstDoc
, m_xFrame
,
354 m_xStatusIndicator
, m_rMediaDescriptor
);
355 pImpl
->setSuperstream(this);
356 pImpl
->m_nStreamType
= nId
;
357 pImpl
->m_aIgnoreFirst
= rIgnoreFirst
;
358 if (!m_aAuthor
.isEmpty())
360 pImpl
->m_aAuthor
= m_aAuthor
;
363 if (!m_aAuthorInitials
.isEmpty())
365 pImpl
->m_aAuthorInitials
= m_aAuthorInitials
;
366 m_aAuthorInitials
.clear();
368 pImpl
->m_nDefaultFontIndex
= m_nDefaultFontIndex
;
369 pImpl
->Strm().Seek(nPos
);
370 SAL_INFO("writerfilter.rtf", "substream start");
371 Mapper().substream(nId
, pImpl
);
372 SAL_INFO("writerfilter.rtf", "substream end");
373 Strm().Seek(nCurrent
);
376 void RTFDocumentImpl::outputSettingsTable()
378 writerfilter::Reference
<Properties
>::Pointer_t pProp
379 = new RTFReferenceProperties(m_aSettingsTableAttributes
, m_aSettingsTableSprms
);
380 RTFReferenceTable::Entries_t aSettingsTableEntries
;
381 aSettingsTableEntries
.insert(std::make_pair(0, pProp
));
382 writerfilter::Reference
<Table
>::Pointer_t pTable
= new RTFReferenceTable(aSettingsTableEntries
);
383 Mapper().table(NS_ooxml::LN_settings_settings
, pTable
);
386 void RTFDocumentImpl::checkFirstRun()
390 outputSettingsTable();
391 // start initial paragraph
393 assert(!m_bNeedSect
|| m_bFirstRunException
);
394 setNeedSect(true); // first call that succeeds
396 // set the requested default font, if there are none
397 RTFValue::Pointer_t pFont
398 = getNestedAttribute(m_aDefaultState
.getCharacterSprms(),
399 NS_ooxml::LN_EG_RPrBase_rFonts
, NS_ooxml::LN_CT_Fonts_ascii
);
400 RTFValue::Pointer_t pCurrentFont
401 = getNestedAttribute(m_aStates
.top().getCharacterSprms(),
402 NS_ooxml::LN_EG_RPrBase_rFonts
, NS_ooxml::LN_CT_Fonts_ascii
);
403 if (pFont
&& !pCurrentFont
)
404 putNestedAttribute(m_aStates
.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts
,
405 NS_ooxml::LN_CT_Fonts_ascii
, pFont
);
409 void RTFDocumentImpl::setNeedPar(bool bNeedPar
) { m_bNeedPar
= bNeedPar
; }
411 void RTFDocumentImpl::setNeedSect(bool bNeedSect
)
413 if (!m_bNeedSect
&& bNeedSect
&& m_bFirstRun
)
415 RTFLookahead
aLookahead(Strm(), m_pTokenizer
->getGroupStart());
416 if (aLookahead
.hasTable() && aLookahead
.hasColumns())
418 m_bFirstRunException
= true;
422 // ignore setting before checkFirstRun - every keyword calls setNeedSect!
423 // except the case of a table in a multicolumn section
424 if (!m_bNeedSect
&& bNeedSect
&& (!m_bFirstRun
|| m_bFirstRunException
))
426 if (!m_pSuperstream
) // no sections in header/footer!
428 Mapper().startSectionGroup();
430 // set flag in substream too - otherwise multiple startParagraphGroup
431 m_bNeedSect
= bNeedSect
;
432 Mapper().startParagraphGroup();
435 else if (m_bNeedSect
&& !bNeedSect
)
437 m_bNeedSect
= bNeedSect
;
441 /// Copy rProps to rStyleAttributes and rStyleSprms, but in case of nested sprms, copy their children as toplevel sprms/attributes.
442 static void lcl_copyFlatten(RTFReferenceProperties
& rProps
, RTFSprms
& rStyleAttributes
,
443 RTFSprms
& rStyleSprms
)
445 for (auto& rSprm
: rProps
.getSprms())
447 // createStyleProperties() puts properties to rPr, but here we need a flat list.
448 if (rSprm
.first
== NS_ooxml::LN_CT_Style_rPr
)
450 // rPr can have both attributes and SPRMs, copy over both types.
451 RTFSprms
& rRPrSprms
= rSprm
.second
->getSprms();
452 for (const auto& rRPrSprm
: rRPrSprms
)
453 rStyleSprms
.set(rRPrSprm
.first
, rRPrSprm
.second
);
455 RTFSprms
& rRPrAttributes
= rSprm
.second
->getAttributes();
456 for (const auto& rRPrAttribute
: rRPrAttributes
)
457 rStyleAttributes
.set(rRPrAttribute
.first
, rRPrAttribute
.second
);
460 rStyleSprms
.set(rSprm
.first
, rSprm
.second
);
463 RTFSprms
& rAttributes
= rProps
.getAttributes();
464 for (const auto& rAttribute
: rAttributes
)
465 rStyleAttributes
.set(rAttribute
.first
, rAttribute
.second
);
468 writerfilter::Reference
<Properties
>::Pointer_t
469 RTFDocumentImpl::getProperties(const RTFSprms
& rAttributes
, RTFSprms
const& rSprms
, Id nStyleType
)
471 RTFSprms
aSprms(rSprms
);
472 RTFValue::Pointer_t pAbstractList
;
473 int nAbstractListId
= -1;
474 RTFValue::Pointer_t pNumId
475 = getNestedSprm(aSprms
, NS_ooxml::LN_CT_PPrBase_numPr
, NS_ooxml::LN_CT_NumPr_numId
);
478 // We have a numbering, look up the abstract list for property
479 // deduplication and duplication.
480 auto itNumId
= m_aListOverrideTable
.find(pNumId
->getInt());
481 if (itNumId
!= m_aListOverrideTable
.end())
483 nAbstractListId
= itNumId
->second
;
484 auto itAbstract
= m_aListTable
.find(nAbstractListId
);
485 if (itAbstract
!= m_aListTable
.end())
486 pAbstractList
= itAbstract
->second
;
492 auto it
= m_aInvalidListTableFirstIndents
.find(nAbstractListId
);
493 if (it
!= m_aInvalidListTableFirstIndents
.end())
494 aSprms
.deduplicateList(it
->second
);
498 if (!m_aStates
.empty())
499 nStyle
= m_aStates
.top().getCurrentStyleIndex();
500 auto it
= m_aStyleTableEntries
.find(nStyle
);
501 if (it
!= m_aStyleTableEntries
.end())
503 // cloneAndDeduplicate() wants to know about only a single "style", so
504 // let's merge paragraph and character style properties here.
505 auto itChar
= m_aStyleTableEntries
.end();
506 if (!m_aStates
.empty())
508 int nCharStyle
= m_aStates
.top().getCurrentCharacterStyleIndex();
509 itChar
= m_aStyleTableEntries
.find(nCharStyle
);
512 RTFSprms aStyleSprms
;
513 RTFSprms aStyleAttributes
;
514 // Ensure the paragraph style is a flat list.
515 // Take paragraph style into account for character properties as well,
516 // as paragraph style may contain character properties.
517 RTFReferenceProperties
& rProps
= *static_cast<RTFReferenceProperties
*>(it
->second
.get());
518 lcl_copyFlatten(rProps
, aStyleAttributes
, aStyleSprms
);
520 if (itChar
!= m_aStyleTableEntries
.end())
522 // Found active character style, then update aStyleSprms/Attributes.
523 if (!nStyleType
|| nStyleType
== NS_ooxml::LN_Value_ST_StyleType_character
)
525 RTFReferenceProperties
& rCharProps
526 = *static_cast<RTFReferenceProperties
*>(itChar
->second
.get());
527 lcl_copyFlatten(rCharProps
, aStyleAttributes
, aStyleSprms
);
531 // Get rid of direct formatting what is already in the style.
532 RTFSprms
const sprms(aSprms
.cloneAndDeduplicate(aStyleSprms
, nStyleType
, true));
533 RTFSprms
const attributes(
534 rAttributes
.cloneAndDeduplicate(aStyleAttributes
, nStyleType
, true));
535 return new RTFReferenceProperties(attributes
, sprms
);
539 aSprms
.duplicateList(pAbstractList
);
540 writerfilter::Reference
<Properties
>::Pointer_t pRet
541 = new RTFReferenceProperties(rAttributes
, aSprms
);
545 void RTFDocumentImpl::checkNeedPap()
549 m_bNeedPap
= false; // reset early, so we can avoid recursion when calling ourselves
551 if (m_aStates
.empty())
554 if (!m_aStates
.top().getCurrentBuffer())
556 writerfilter::Reference
<Properties
>::Pointer_t
const pParagraphProperties(getProperties(
557 m_aStates
.top().getParagraphAttributes(), m_aStates
.top().getParagraphSprms(),
558 NS_ooxml::LN_Value_ST_StyleType_paragraph
));
560 // Writer will ignore a page break before a text frame, so guard it with empty paragraphs
561 bool hasBreakBeforeFrame
= m_aStates
.top().getFrame().hasProperties()
564 .find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore
)
566 if (hasBreakBeforeFrame
)
568 dispatchSymbol(RTF_PAR
);
571 Mapper().props(pParagraphProperties
);
572 if (hasBreakBeforeFrame
)
573 dispatchSymbol(RTF_PAR
);
575 if (m_aStates
.top().getFrame().hasProperties())
577 writerfilter::Reference
<Properties
>::Pointer_t
const pFrameProperties(
578 new RTFReferenceProperties(RTFSprms(), m_aStates
.top().getFrame().getSprms()));
579 Mapper().props(pFrameProperties
);
584 auto pValue
= new RTFValue(m_aStates
.top().getParagraphAttributes(),
585 m_aStates
.top().getParagraphSprms());
586 bufferProperties(*m_aStates
.top().getCurrentBuffer(), pValue
, nullptr);
591 void RTFDocumentImpl::runProps()
593 if (!m_aStates
.top().getCurrentBuffer())
595 Reference
<Properties
>::Pointer_t
const pProperties
= getProperties(
596 m_aStates
.top().getCharacterAttributes(), m_aStates
.top().getCharacterSprms(),
597 NS_ooxml::LN_Value_ST_StyleType_character
);
598 Mapper().props(pProperties
);
602 auto pValue
= new RTFValue(m_aStates
.top().getCharacterAttributes(),
603 m_aStates
.top().getCharacterSprms());
604 bufferProperties(*m_aStates
.top().getCurrentBuffer(), pValue
, nullptr);
607 // Delete the sprm, so the trackchange range will be started only once.
608 // OTOH set a boolean flag, so we'll know we need to end the range later.
609 RTFValue::Pointer_t pTrackchange
610 = m_aStates
.top().getCharacterSprms().find(NS_ooxml::LN_trackchange
);
613 m_aStates
.top().setStartedTrackchange(true);
614 m_aStates
.top().getCharacterSprms().erase(NS_ooxml::LN_trackchange
);
618 void RTFDocumentImpl::runBreak()
620 sal_uInt8
const sBreak
[] = { 0xd };
621 Mapper().text(sBreak
, 1);
625 void RTFDocumentImpl::tableBreak()
628 Mapper().endParagraphGroup();
629 Mapper().startParagraphGroup();
632 void RTFDocumentImpl::parBreak()
636 // end previous paragraph
637 Mapper().startCharacterGroup();
639 Mapper().endCharacterGroup();
640 Mapper().endParagraphGroup();
642 m_bHadPicture
= false;
645 Mapper().startParagraphGroup();
648 void RTFDocumentImpl::sectBreak(bool bFinal
)
650 SAL_INFO("writerfilter.rtf",
651 OSL_THIS_FUNC
<< ": final? " << bFinal
<< ", needed? " << m_bNeedSect
);
652 bool bNeedSect
= m_bNeedSect
;
653 RTFValue::Pointer_t pBreak
654 = m_aStates
.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type
);
658 == static_cast<sal_Int32
>(NS_ooxml::LN_Value_ST_SectionMark_continuous
);
659 // If there is no paragraph in this section, then insert a dummy one, as required by Writer,
660 // unless this is the end of the doc, we had nothing since the last section break and this is not a continuous one.
661 // Also, when pasting, it's fine to not have any paragraph inside the document at all.
662 if (m_bNeedPar
&& !(bFinal
&& !m_bNeedSect
&& !bContinuous
) && !isSubstream() && m_bIsNewDoc
)
663 dispatchSymbol(RTF_PAR
);
664 // It's allowed to not have a non-table paragraph at the end of an RTF doc, add it now if required.
665 if (m_bNeedFinalPar
&& bFinal
)
667 dispatchFlag(RTF_PARD
);
668 dispatchSymbol(RTF_PAR
);
669 m_bNeedSect
= bNeedSect
;
671 while (!m_nHeaderFooterPositions
.empty())
673 std::pair
<Id
, std::size_t> aPair
= m_nHeaderFooterPositions
.front();
674 m_nHeaderFooterPositions
.pop();
675 resolveSubstream(aPair
.second
, aPair
.first
);
678 // Normally a section break at the end of the doc is necessary. Unless the
679 // last control word in the document is a section break itself.
680 if (!bNeedSect
|| !m_bHadSect
)
682 // In case the last section is a continuous one, we don't need to output a section break.
683 if (bFinal
&& bContinuous
)
684 m_aStates
.top().getSectionSprms().erase(NS_ooxml::LN_EG_SectPrContents_type
);
687 // Section properties are a paragraph sprm.
689 = new RTFValue(m_aStates
.top().getSectionAttributes(), m_aStates
.top().getSectionSprms());
690 RTFSprms aAttributes
;
692 aSprms
.set(NS_ooxml::LN_CT_PPr_sectPr
, pValue
);
693 writerfilter::Reference
<Properties
>::Pointer_t pProperties
694 = new RTFReferenceProperties(aAttributes
, aSprms
);
696 if (bFinal
&& !m_pSuperstream
)
697 // This is the end of the document, not just the end of e.g. a header.
698 // This makes sure that dmapper can set DontBalanceTextColumns=true for this section if necessary.
699 Mapper().markLastSectionGroup();
701 // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects.
702 Mapper().props(pProperties
);
703 Mapper().endParagraphGroup();
708 m_hasFHeader
= false;
709 m_hasRHeader
= false;
710 m_hasRFooter
= false;
711 m_hasFFooter
= false;
712 Mapper().endSectionGroup();
718 Color
RTFDocumentImpl::getColorTable(sal_uInt32 nIndex
)
722 if (nIndex
< m_aColorTable
.size())
723 return m_aColorTable
[nIndex
];
727 return m_pSuperstream
->getColorTable(nIndex
);
730 rtl_TextEncoding
RTFDocumentImpl::getEncoding(int nFontIndex
)
734 auto it
= m_aFontEncodings
.find(nFontIndex
);
735 if (it
!= m_aFontEncodings
.end())
736 // We have a font encoding associated to this font.
738 if (m_aDefaultState
.getCurrentEncoding() != rtl_getTextEncodingFromWindowsCharset(0))
739 // We have a default encoding.
740 return m_aDefaultState
.getCurrentEncoding();
741 // Guess based on locale.
742 return msfilter::util::getBestTextEncodingFromLocale(
743 Application::GetSettings().GetLanguageTag().getLocale());
746 return m_pSuperstream
->getEncoding(nFontIndex
);
749 OUString
RTFDocumentImpl::getFontName(int nIndex
)
752 return m_aFontNames
[nIndex
];
754 return m_pSuperstream
->getFontName(nIndex
);
757 int RTFDocumentImpl::getFontIndex(int nIndex
)
760 return std::find(m_aFontIndexes
.begin(), m_aFontIndexes
.end(), nIndex
)
761 - m_aFontIndexes
.begin();
763 return m_pSuperstream
->getFontIndex(nIndex
);
766 OUString
RTFDocumentImpl::getStyleName(int nIndex
)
771 if (m_aStyleNames
.find(nIndex
) != m_aStyleNames
.end())
772 aRet
= m_aStyleNames
[nIndex
];
776 return m_pSuperstream
->getStyleName(nIndex
);
779 Id
RTFDocumentImpl::getStyleType(int nIndex
)
784 if (m_aStyleTypes
.find(nIndex
) != m_aStyleTypes
.end())
785 nRet
= m_aStyleTypes
[nIndex
];
789 return m_pSuperstream
->getStyleType(nIndex
);
792 RTFParserState
& RTFDocumentImpl::getDefaultState()
795 return m_aDefaultState
;
797 return m_pSuperstream
->getDefaultState();
800 oox::GraphicHelper
& RTFDocumentImpl::getGraphicHelper() { return *m_pGraphicHelper
; }
802 bool RTFDocumentImpl::isStyleSheetImport()
804 if (m_aStates
.empty())
806 Destination eDestination
= m_aStates
.top().getDestination();
807 return eDestination
== Destination::STYLESHEET
|| eDestination
== Destination::STYLEENTRY
;
810 void RTFDocumentImpl::resolve(Stream
& rMapper
)
812 m_pMapperStream
= &rMapper
;
813 switch (m_pTokenizer
->resolveParse())
816 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: finished without errors");
818 case RTFError::GROUP_UNDER
:
819 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '}'");
821 case RTFError::GROUP_OVER
:
822 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '{'");
823 throw io::WrongFormatException(m_pTokenizer
->getPosition());
825 case RTFError::UNEXPECTED_EOF
:
826 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unexpected end of file");
827 throw io::WrongFormatException(m_pTokenizer
->getPosition());
829 case RTFError::HEX_INVALID
:
830 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: invalid hex char");
831 throw io::WrongFormatException(m_pTokenizer
->getPosition());
833 case RTFError::CHAR_OVER
:
834 SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: characters after last '}'");
836 case RTFError::CLASSIFICATION
:
837 SAL_INFO("writerfilter.rtf",
838 "RTFDocumentImpl::resolve: classification prevented paste");
843 void RTFDocumentImpl::resolvePict(bool const bInline
, uno::Reference
<drawing::XShape
> const& rShape
)
845 SvMemoryStream aStream
;
846 SvStream
* pStream
= nullptr;
847 if (!m_pBinaryData
.get())
853 // Feed the destination text to a stream.
854 OString aStr
= OUStringToOString(m_aStates
.top().getDestinationText().makeStringAndClear(),
855 RTL_TEXTENCODING_ASCII_US
);
856 for (int i
= 0; i
< aStr
.getLength(); ++i
)
859 if (ch
!= 0x0d && ch
!= 0x0a && ch
!= 0x20)
862 sal_Int8 parsed
= msfilter::rtfutil::AsHex(ch
);
869 aStream
.WriteChar(static_cast<char>(b
));
877 pStream
= m_pBinaryData
.get();
879 if (!pStream
->Tell())
880 // No destination text? Then we'll get it later.
883 SvMemoryStream aDIBStream
;
884 if (m_aStates
.top().getPicture().eStyle
== RTFBmpStyle::DIBITMAP
)
886 // Construct a BITMAPFILEHEADER structure before the real data.
887 SvStream
& rBodyStream
= *pStream
;
888 aDIBStream
.WriteChar('B');
889 aDIBStream
.WriteChar('M');
890 // The size of the real data.
891 aDIBStream
.WriteUInt32(rBodyStream
.Tell());
893 aDIBStream
.WriteUInt32(0);
894 // The offset of the real data, i.e. the size of the header, including this number.
895 aDIBStream
.WriteUInt32(14);
897 aDIBStream
.WriteStream(rBodyStream
);
898 pStream
= &aDIBStream
;
901 // Store, and get its URL.
903 uno::Reference
<io::XInputStream
> xInputStream(new utl::OInputStreamWrapper(pStream
));
904 WmfExternal aExtHeader
;
905 aExtHeader
.mapMode
= m_aStates
.top().getPicture().eWMetafile
;
906 aExtHeader
.xExt
= sal_uInt16(
907 std::clamp
<sal_Int32
>(m_aStates
.top().getPicture().nWidth
, 0,
908 SAL_MAX_UINT16
)); //TODO: better way to handle out-of-bounds values?
909 aExtHeader
.yExt
= sal_uInt16(
910 std::clamp
<sal_Int32
>(m_aStates
.top().getPicture().nHeight
, 0,
911 SAL_MAX_UINT16
)); //TODO: better way to handle out-of-bounds values?
912 WmfExternal
* pExtHeader
= &aExtHeader
;
913 uno::Reference
<lang::XServiceInfo
> xServiceInfo(m_aStates
.top().getDrawingObject().getShape(),
915 if (xServiceInfo
.is() && xServiceInfo
->supportsService("com.sun.star.text.TextFrame"))
916 pExtHeader
= nullptr;
918 uno::Reference
<graphic::XGraphic
> xGraphic
919 = m_pGraphicHelper
->importGraphic(xInputStream
, pExtHeader
);
921 if (m_aStates
.top().getPicture().eStyle
!= RTFBmpStyle::NONE
)
923 // In case of PNG/JPEG, the real size is known, don't use the values
924 // provided by picw and pich.
926 Graphic
aGraphic(xGraphic
);
927 Size
aSize(aGraphic
.GetPrefSize());
928 MapMode
aMap(MapUnit::Map100thMM
);
929 if (aGraphic
.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel
)
930 aSize
= Application::GetDefaultDevice()->PixelToLogic(aSize
, aMap
);
932 aSize
= OutputDevice::LogicToLogic(aSize
, aGraphic
.GetPrefMapMode(), aMap
);
933 m_aStates
.top().getPicture().nWidth
= aSize
.Width();
934 m_aStates
.top().getPicture().nHeight
= aSize
.Height();
937 // Wrap it in an XShape.
938 uno::Reference
<drawing::XShape
> xShape(rShape
);
941 uno::Reference
<lang::XServiceInfo
> xSI(xShape
, uno::UNO_QUERY_THROW
);
942 if (!xSI
->supportsService("com.sun.star.drawing.GraphicObjectShape"))
944 // it's sometimes an error to get here - but it's possible to have
945 // a \pict inside the \shptxt of a \shp of shapeType 202 "TextBox"
946 // and in that case xShape is the text frame; we actually need a
947 // new GraphicObject then (example: fdo37691-1.rtf)
948 SAL_INFO("writerfilter.rtf",
949 "cannot set graphic on existing shape, creating a new GraphicObjectShape");
955 if (m_xModelFactory
.is())
956 xShape
.set(m_xModelFactory
->createInstance("com.sun.star.drawing.GraphicObjectShape"),
958 uno::Reference
<drawing::XDrawPageSupplier
> const xDrawSupplier(m_xDstDoc
, uno::UNO_QUERY
);
959 if (xDrawSupplier
.is())
961 uno::Reference
<drawing::XShapes
> xShapes
= xDrawSupplier
->getDrawPage();
963 xShapes
->add(xShape
);
967 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, uno::UNO_QUERY
);
969 if (xPropertySet
.is())
970 xPropertySet
->setPropertyValue("Graphic", uno::Any(xGraphic
));
972 // check if the picture is in an OLE object and if the \objdata element is used
973 // (see RTF_OBJECT in RTFDocumentImpl::dispatchDestination)
976 // Set the object size
979 = (m_aStates
.top().getPicture().nGoalWidth
? m_aStates
.top().getPicture().nGoalWidth
980 : m_aStates
.top().getPicture().nWidth
);
982 = (m_aStates
.top().getPicture().nGoalHeight
? m_aStates
.top().getPicture().nGoalHeight
983 : m_aStates
.top().getPicture().nHeight
);
984 xShape
->setSize(aSize
);
986 // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert().
987 xPropertySet
->setPropertyValue("AnchorType",
988 uno::makeAny(text::TextContentAnchorType_AS_CHARACTER
));
990 auto pShapeValue
= new RTFValue(xShape
);
991 m_aObjectAttributes
.set(NS_ooxml::LN_shape
, pShapeValue
);
995 if (m_aStates
.top().getInListpicture())
997 // Send the shape directly, no section is started, to additional properties will be ignored anyway.
998 Mapper().startShape(xShape
);
1003 // Send it to the dmapper.
1005 RTFSprms aAttributes
;
1007 RTFSprms aPicAttributes
;
1008 auto pShapeValue
= new RTFValue(xShape
);
1009 aPicAttributes
.set(NS_ooxml::LN_shape
, pShapeValue
);
1011 RTFSprms aGraphicDataAttributes
;
1012 RTFSprms aGraphicDataSprms
;
1013 auto pPicValue
= new RTFValue(aPicAttributes
);
1014 aGraphicDataSprms
.set(NS_ooxml::LN_pic_pic
, pPicValue
);
1016 RTFSprms aGraphicAttributes
;
1017 RTFSprms aGraphicSprms
;
1018 auto pGraphicDataValue
= new RTFValue(aGraphicDataAttributes
, aGraphicDataSprms
);
1019 aGraphicSprms
.set(NS_ooxml::LN_CT_GraphicalObject_graphicData
, pGraphicDataValue
);
1021 auto pGraphicValue
= new RTFValue(aGraphicAttributes
, aGraphicSprms
);
1023 RTFSprms aExtentAttributes
;
1024 int nXExt
= (m_aStates
.top().getPicture().nGoalWidth
? m_aStates
.top().getPicture().nGoalWidth
1025 : m_aStates
.top().getPicture().nWidth
);
1026 int nYExt
= (m_aStates
.top().getPicture().nGoalHeight
? m_aStates
.top().getPicture().nGoalHeight
1027 : m_aStates
.top().getPicture().nHeight
);
1028 if (m_aStates
.top().getPicture().nScaleX
!= 100)
1029 nXExt
= (static_cast<long>(m_aStates
.top().getPicture().nScaleX
)
1031 - (m_aStates
.top().getPicture().nCropL
+ m_aStates
.top().getPicture().nCropR
)))
1033 if (m_aStates
.top().getPicture().nScaleY
!= 100)
1034 nYExt
= (static_cast<long>(m_aStates
.top().getPicture().nScaleY
)
1036 - (m_aStates
.top().getPicture().nCropT
+ m_aStates
.top().getPicture().nCropB
)))
1038 if (m_aStates
.top().getInShape())
1040 // Picture in shape: it looks like pib picture, so we will stretch the picture to shape size (tdf#49893)
1041 nXExt
= m_aStates
.top().getShape().getRight() - m_aStates
.top().getShape().getLeft();
1042 nYExt
= m_aStates
.top().getShape().getBottom() - m_aStates
.top().getShape().getTop();
1044 auto pXExtValue
= new RTFValue(oox::drawingml::convertHmmToEmu(nXExt
));
1045 auto pYExtValue
= new RTFValue(oox::drawingml::convertHmmToEmu(nYExt
));
1046 aExtentAttributes
.set(NS_ooxml::LN_CT_PositiveSize2D_cx
, pXExtValue
);
1047 aExtentAttributes
.set(NS_ooxml::LN_CT_PositiveSize2D_cy
, pYExtValue
);
1048 auto pExtentValue
= new RTFValue(aExtentAttributes
);
1050 RTFSprms aDocprAttributes
;
1051 for (const auto& rCharacterAttribute
: m_aStates
.top().getCharacterAttributes())
1052 if (rCharacterAttribute
.first
== NS_ooxml::LN_CT_NonVisualDrawingProps_name
1053 || rCharacterAttribute
.first
== NS_ooxml::LN_CT_NonVisualDrawingProps_descr
)
1054 aDocprAttributes
.set(rCharacterAttribute
.first
, rCharacterAttribute
.second
);
1055 auto pDocprValue
= new RTFValue(aDocprAttributes
);
1058 RTFSprms aInlineAttributes
;
1059 aInlineAttributes
.set(NS_ooxml::LN_CT_Inline_distT
, new RTFValue(0));
1060 aInlineAttributes
.set(NS_ooxml::LN_CT_Inline_distB
, new RTFValue(0));
1061 aInlineAttributes
.set(NS_ooxml::LN_CT_Inline_distL
, new RTFValue(0));
1062 aInlineAttributes
.set(NS_ooxml::LN_CT_Inline_distR
, new RTFValue(0));
1063 RTFSprms aInlineSprms
;
1064 aInlineSprms
.set(NS_ooxml::LN_CT_Inline_extent
, pExtentValue
);
1065 aInlineSprms
.set(NS_ooxml::LN_CT_Inline_docPr
, pDocprValue
);
1066 aInlineSprms
.set(NS_ooxml::LN_graphic_graphic
, pGraphicValue
);
1068 auto pValue
= new RTFValue(aInlineAttributes
, aInlineSprms
);
1069 aSprms
.set(NS_ooxml::LN_inline_inline
, pValue
);
1074 RTFSprms aAnchorWrapAttributes
;
1075 m_aStates
.top().getShape().getAnchorAttributes().set(
1076 NS_ooxml::LN_CT_Anchor_behindDoc
,
1077 new RTFValue((m_aStates
.top().getShape().getInBackground()) ? 1 : 0));
1078 RTFSprms aAnchorSprms
;
1079 for (const auto& rCharacterAttribute
: m_aStates
.top().getCharacterAttributes())
1081 if (rCharacterAttribute
.first
== NS_ooxml::LN_CT_WrapSquare_wrapText
)
1082 aAnchorWrapAttributes
.set(rCharacterAttribute
.first
, rCharacterAttribute
.second
);
1084 sal_Int32 nWrap
= -1;
1085 for (auto& rCharacterSprm
: m_aStates
.top().getCharacterSprms())
1087 if (rCharacterSprm
.first
== NS_ooxml::LN_EG_WrapType_wrapNone
1088 || rCharacterSprm
.first
== NS_ooxml::LN_EG_WrapType_wrapTight
)
1090 nWrap
= rCharacterSprm
.first
;
1092 // If there is a wrap polygon prepared by RTFSdrImport, pick it up here.
1093 if (rCharacterSprm
.first
== NS_ooxml::LN_EG_WrapType_wrapTight
1094 && !m_aStates
.top().getShape().getWrapPolygonSprms().empty())
1095 rCharacterSprm
.second
->getSprms().set(
1096 NS_ooxml::LN_CT_WrapTight_wrapPolygon
,
1097 new RTFValue(RTFSprms(), m_aStates
.top().getShape().getWrapPolygonSprms()));
1099 aAnchorSprms
.set(rCharacterSprm
.first
, rCharacterSprm
.second
);
1103 if (m_aStates
.top().getShape().getWrapSprm().first
!= 0)
1104 // Replay of a buffered shape, wrap sprm there has priority over
1105 // character sprms of the current state.
1106 aAnchorSprms
.set(m_aStates
.top().getShape().getWrapSprm().first
,
1107 m_aStates
.top().getShape().getWrapSprm().second
);
1109 aAnchorSprms
.set(NS_ooxml::LN_CT_Anchor_extent
, pExtentValue
);
1110 if (!aAnchorWrapAttributes
.empty() && nWrap
== -1)
1111 aAnchorSprms
.set(NS_ooxml::LN_EG_WrapType_wrapSquare
,
1112 new RTFValue(aAnchorWrapAttributes
));
1114 // See OOXMLFastContextHandler::positionOffset(), we can't just put offset values in an RTFValue.
1115 RTFSprms aPoshAttributes
;
1116 RTFSprms aPoshSprms
;
1117 if (m_aStates
.top().getShape().getHoriOrientRelationToken() > 0)
1118 aPoshAttributes
.set(
1119 NS_ooxml::LN_CT_PosH_relativeFrom
,
1120 new RTFValue(m_aStates
.top().getShape().getHoriOrientRelationToken()));
1121 if (m_aStates
.top().getShape().getLeft() != 0)
1123 Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
1124 m_aStates
.top().getShape().getLeft())),
1125 /*bVertical=*/false);
1126 aPoshSprms
.set(NS_ooxml::LN_CT_PosH_posOffset
, new RTFValue());
1128 aAnchorSprms
.set(NS_ooxml::LN_CT_Anchor_positionH
,
1129 new RTFValue(aPoshAttributes
, aPoshSprms
));
1131 RTFSprms aPosvAttributes
;
1132 RTFSprms aPosvSprms
;
1133 if (m_aStates
.top().getShape().getVertOrientRelationToken() > 0)
1134 aPosvAttributes
.set(
1135 NS_ooxml::LN_CT_PosV_relativeFrom
,
1136 new RTFValue(m_aStates
.top().getShape().getVertOrientRelationToken()));
1137 if (m_aStates
.top().getShape().getTop() != 0)
1139 Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
1140 m_aStates
.top().getShape().getTop())),
1141 /*bVertical=*/true);
1142 aPosvSprms
.set(NS_ooxml::LN_CT_PosV_posOffset
, new RTFValue());
1144 aAnchorSprms
.set(NS_ooxml::LN_CT_Anchor_positionV
,
1145 new RTFValue(aPosvAttributes
, aPosvSprms
));
1147 aAnchorSprms
.set(NS_ooxml::LN_CT_Anchor_docPr
, pDocprValue
);
1148 aAnchorSprms
.set(NS_ooxml::LN_graphic_graphic
, pGraphicValue
);
1150 auto pValue
= new RTFValue(m_aStates
.top().getShape().getAnchorAttributes(), aAnchorSprms
);
1151 aSprms
.set(NS_ooxml::LN_anchor_anchor
, pValue
);
1153 writerfilter::Reference
<Properties
>::Pointer_t pProperties
1154 = new RTFReferenceProperties(aAttributes
, aSprms
);
1157 if (!m_aStates
.top().getCurrentBuffer())
1159 Mapper().props(pProperties
);
1160 // Make sure we don't lose these properties with a too early reset.
1161 m_bHadPicture
= true;
1165 auto pValue
= new RTFValue(aAttributes
, aSprms
);
1166 bufferProperties(*m_aStates
.top().getCurrentBuffer(), pValue
, nullptr);
1170 RTFError
RTFDocumentImpl::resolveChars(char ch
)
1172 if (m_aStates
.top().getInternalState() == RTFInternalState::BIN
)
1174 m_pBinaryData
.reset(new SvMemoryStream());
1175 m_pBinaryData
->WriteChar(ch
);
1176 for (int i
= 0; i
< m_aStates
.top().getBinaryToRead() - 1; ++i
)
1178 Strm().ReadChar(ch
);
1179 m_pBinaryData
->WriteChar(ch
);
1181 m_aStates
.top().setInternalState(RTFInternalState::NORMAL
);
1182 return RTFError::OK
;
1185 OStringBuffer
aBuf(512);
1187 bool bUnicodeChecked
= false;
1188 bool bSkipped
= false;
1190 while (!Strm().eof()
1191 && (m_aStates
.top().getInternalState() == RTFInternalState::HEX
1192 || (ch
!= '{' && ch
!= '}' && ch
!= '\\')))
1194 if (m_aStates
.top().getInternalState() == RTFInternalState::HEX
1195 || (ch
!= 0x0d && ch
!= 0x0a))
1197 if (m_aStates
.top().getCharsToSkip() == 0)
1199 if (!bUnicodeChecked
)
1201 checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
1202 bUnicodeChecked
= true;
1209 m_aStates
.top().getCharsToSkip()--;
1213 // read a single char if we're in hex mode
1214 if (m_aStates
.top().getInternalState() == RTFInternalState::HEX
)
1217 if (RTL_TEXTENCODING_MS_932
== m_aStates
.top().getCurrentEncoding())
1219 unsigned char uch
= ch
;
1220 if ((uch
>= 0x80 && uch
<= 0x9F) || uch
>= 0xE0)
1222 // read second byte of 2-byte Shift-JIS - may be \ { }
1223 Strm().ReadChar(ch
);
1224 if (m_aStates
.top().getCharsToSkip() == 0)
1226 // fdo#79384: Word will reject Shift-JIS following \loch
1227 // but apparently OOo could read and (worse) write such documents
1228 SAL_INFO_IF(m_aStates
.top().getRunType() != RTFParserState::RunType::DBCH
,
1229 "writerfilter.rtf", "invalid Shift-JIS without DBCH");
1230 assert(bUnicodeChecked
);
1236 // anybody who uses \ucN with Shift-JIS is insane
1237 m_aStates
.top().getCharsToSkip()--;
1242 Strm().ReadChar(ch
);
1244 if (m_aStates
.top().getInternalState() != RTFInternalState::HEX
&& !Strm().eof())
1247 if (m_aStates
.top().getInternalState() == RTFInternalState::HEX
1248 && m_aStates
.top().getDestination() != Destination::LEVELNUMBERS
)
1252 // note: apparently \'0d\'0a is interpreted as 2 breaks, not 1
1253 if ((ch
== '\r' || ch
== '\n')
1254 && m_aStates
.top().getDestination() != Destination::DOCCOMM
1255 && m_aStates
.top().getDestination() != Destination::LEVELNUMBERS
1256 && m_aStates
.top().getDestination() != Destination::LEVELTEXT
)
1258 checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
1259 dispatchSymbol(RTF_PAR
);
1263 m_aHexBuffer
.append(ch
);
1266 return RTFError::OK
;
1269 if (m_aStates
.top().getDestination() == Destination::SKIP
)
1270 return RTFError::OK
;
1271 OString aStr
= aBuf
.makeStringAndClear();
1272 if (m_aStates
.top().getDestination() == Destination::LEVELNUMBERS
)
1274 if (aStr
.toChar() != ';')
1275 m_aStates
.top().getLevelNumbers().push_back(sal_Int32(ch
));
1276 return RTFError::OK
;
1279 SAL_INFO("writerfilter.rtf",
1280 "RTFDocumentImpl::resolveChars: collected '"
1281 << OStringToOUString(aStr
, m_aStates
.top().getCurrentEncoding()) << "'");
1283 if (m_aStates
.top().getDestination() == Destination::COLORTABLE
)
1285 // we hit a ';' at the end of each color entry
1286 m_aColorTable
.push_back(m_aStates
.top().getCurrentColor().GetColor());
1287 // set components back to zero
1288 m_aStates
.top().getCurrentColor() = RTFColorTableEntry();
1290 else if (!aStr
.isEmpty())
1291 m_aHexBuffer
.append(aStr
);
1293 checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
1294 return RTFError::OK
;
1297 bool RTFFrame::inFrame() { return m_nW
> 0 || m_nH
> 0 || m_nX
> 0 || m_nY
> 0; }
1299 void RTFDocumentImpl::singleChar(sal_uInt8 nValue
, bool bRunProps
)
1301 sal_uInt8 sValue
[] = { nValue
};
1302 RTFBuffer_t
* pCurrentBuffer
= m_aStates
.top().getCurrentBuffer();
1304 if (!pCurrentBuffer
)
1306 Mapper().startCharacterGroup();
1307 // Should we send run properties?
1310 Mapper().text(sValue
, 1);
1311 Mapper().endCharacterGroup();
1315 pCurrentBuffer
->push_back(Buf_t(BUFFER_STARTRUN
, nullptr, nullptr));
1316 auto pValue
= new RTFValue(*sValue
);
1317 pCurrentBuffer
->push_back(Buf_t(BUFFER_TEXT
, pValue
, nullptr));
1318 pCurrentBuffer
->push_back(Buf_t(BUFFER_ENDRUN
, nullptr, nullptr));
1322 void RTFDocumentImpl::text(OUString
& rString
)
1324 if (rString
.getLength() == 1 && m_aStates
.top().getDestination() != Destination::DOCCOMM
)
1326 // No cheating! Tokenizer ignores bare \r and \n, their hex \'0d / \'0a form doesn't count, either.
1327 sal_Unicode ch
= rString
[0];
1328 if (ch
== 0x0d || ch
== 0x0a)
1333 switch (m_aStates
.top().getDestination())
1335 // Note: in fonttbl there may or may not be groups; in stylesheet
1336 // and revtbl groups are mandatory
1337 case Destination::FONTTABLE
:
1338 case Destination::FONTENTRY
:
1339 case Destination::STYLEENTRY
:
1340 case Destination::LISTNAME
:
1341 case Destination::REVISIONENTRY
:
1343 // ; is the end of the entry
1345 if (rString
.endsWith(";"))
1347 rString
= rString
.copy(0, rString
.getLength() - 1);
1350 m_aStates
.top().appendDestinationText(rString
);
1353 // always clear, necessary in case of group-less fonttable
1354 OUString
const aName
1355 = m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
1356 switch (m_aStates
.top().getDestination())
1358 case Destination::FONTTABLE
:
1359 case Destination::FONTENTRY
:
1361 m_aFontNames
[m_nCurrentFontIndex
] = aName
;
1362 if (m_nCurrentEncoding
>= 0)
1364 m_aFontEncodings
[m_nCurrentFontIndex
] = m_nCurrentEncoding
;
1365 m_nCurrentEncoding
= -1;
1367 m_aStates
.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name
,
1368 new RTFValue(aName
));
1370 writerfilter::Reference
<Properties
>::Pointer_t
const pProp(
1371 new RTFReferenceProperties(m_aStates
.top().getTableAttributes(),
1372 m_aStates
.top().getTableSprms()));
1374 //See fdo#47347 initial invalid font entry properties are inserted first,
1375 //so when we attempt to insert the correct ones, there's already an
1376 //entry in the map for them, so the new ones aren't inserted.
1377 auto lb
= m_aFontTableEntries
.lower_bound(m_nCurrentFontIndex
);
1378 if (lb
!= m_aFontTableEntries
.end()
1379 && !(m_aFontTableEntries
.key_comp()(m_nCurrentFontIndex
, lb
->first
)))
1382 m_aFontTableEntries
.insert(lb
,
1383 std::make_pair(m_nCurrentFontIndex
, pProp
));
1386 case Destination::STYLEENTRY
:
1388 RTFValue::Pointer_t pType
1389 = m_aStates
.top().getTableAttributes().find(NS_ooxml::LN_CT_Style_type
);
1392 // Word strips whitespace around style names.
1393 m_aStyleNames
[m_nCurrentStyleIndex
] = aName
.trim();
1394 m_aStyleTypes
[m_nCurrentStyleIndex
] = pType
->getInt();
1395 auto pValue
= new RTFValue(aName
.trim());
1396 m_aStates
.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_styleId
,
1398 m_aStates
.top().getTableSprms().set(NS_ooxml::LN_CT_Style_name
, pValue
);
1400 writerfilter::Reference
<Properties
>::Pointer_t
const pProp(
1401 createStyleProperties());
1402 m_aStyleTableEntries
.insert(
1403 std::make_pair(m_nCurrentStyleIndex
, pProp
));
1406 SAL_INFO("writerfilter.rtf", "no RTF style type defined, ignoring");
1409 case Destination::LISTNAME
:
1410 // TODO: what can be done with a list name?
1412 case Destination::REVISIONENTRY
:
1413 m_aAuthors
[m_aAuthors
.size()] = aName
;
1423 case Destination::LEVELTEXT
:
1424 case Destination::SHAPEPROPERTYNAME
:
1425 case Destination::SHAPEPROPERTYVALUE
:
1426 case Destination::BOOKMARKEND
:
1427 case Destination::PICT
:
1428 case Destination::SHAPEPROPERTYVALUEPICT
:
1429 case Destination::FORMFIELDNAME
:
1430 case Destination::FORMFIELDLIST
:
1431 case Destination::DATAFIELD
:
1432 case Destination::AUTHOR
:
1433 case Destination::KEYWORDS
:
1434 case Destination::OPERATOR
:
1435 case Destination::COMPANY
:
1436 case Destination::COMMENT
:
1437 case Destination::OBJDATA
:
1438 case Destination::OBJCLASS
:
1439 case Destination::ANNOTATIONDATE
:
1440 case Destination::ANNOTATIONAUTHOR
:
1441 case Destination::ANNOTATIONREFERENCE
:
1442 case Destination::FALT
:
1443 case Destination::PARAGRAPHNUMBERING_TEXTAFTER
:
1444 case Destination::PARAGRAPHNUMBERING_TEXTBEFORE
:
1445 case Destination::TITLE
:
1446 case Destination::SUBJECT
:
1447 case Destination::DOCCOMM
:
1448 case Destination::ATNID
:
1449 case Destination::ANNOTATIONREFERENCESTART
:
1450 case Destination::ANNOTATIONREFERENCEEND
:
1451 case Destination::MR
:
1452 case Destination::MCHR
:
1453 case Destination::MPOS
:
1454 case Destination::MVERTJC
:
1455 case Destination::MSTRIKEH
:
1456 case Destination::MDEGHIDE
:
1457 case Destination::MBEGCHR
:
1458 case Destination::MSEPCHR
:
1459 case Destination::MENDCHR
:
1460 case Destination::MSUBHIDE
:
1461 case Destination::MSUPHIDE
:
1462 case Destination::MTYPE
:
1463 case Destination::MGROW
:
1464 case Destination::INDEXENTRY
:
1465 case Destination::TOCENTRY
:
1466 case Destination::PROPNAME
:
1467 case Destination::STATICVAL
:
1468 m_aStates
.top().appendDestinationText(rString
);
1470 case Destination::GENERATOR
:
1471 // don't enlarge space sequences, eg. it was saved in LibreOffice
1472 if (!rString
.startsWithIgnoreAsciiCase("Microsoft"))
1473 m_aSettingsTableSprms
.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence
,
1483 if (!m_aIgnoreFirst
.isEmpty() && m_aIgnoreFirst
== rString
)
1485 m_aIgnoreFirst
.clear();
1489 // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
1490 if (m_aStates
.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign
).get()
1491 && m_nTopLevelCells
== 0)
1493 m_aTableBufferStack
.back().emplace_back(
1494 Buf_t(BUFFER_UTEXT
, new RTFValue(rString
), nullptr));
1501 // Don't return earlier, a bookmark start has to be in a paragraph group.
1502 if (m_aStates
.top().getDestination() == Destination::BOOKMARKSTART
)
1504 m_aStates
.top().appendDestinationText(rString
);
1508 RTFBuffer_t
* pCurrentBuffer
= m_aStates
.top().getCurrentBuffer();
1510 if (!pCurrentBuffer
&& m_aStates
.top().getDestination() != Destination::FOOTNOTE
)
1511 Mapper().startCharacterGroup();
1512 else if (pCurrentBuffer
)
1514 RTFValue::Pointer_t pValue
;
1515 pCurrentBuffer
->push_back(Buf_t(BUFFER_STARTRUN
, pValue
, nullptr));
1518 if (m_aStates
.top().getDestination() == Destination::NORMAL
1519 || m_aStates
.top().getDestination() == Destination::FIELDRESULT
1520 || m_aStates
.top().getDestination() == Destination::SHAPETEXT
)
1523 if (!pCurrentBuffer
)
1524 Mapper().utext(reinterpret_cast<sal_uInt8
const*>(rString
.getStr()), rString
.getLength());
1527 auto pValue
= new RTFValue(rString
);
1528 pCurrentBuffer
->push_back(Buf_t(BUFFER_UTEXT
, pValue
, nullptr));
1533 if (!pCurrentBuffer
&& m_aStates
.top().getDestination() != Destination::FOOTNOTE
)
1534 Mapper().endCharacterGroup();
1535 else if (pCurrentBuffer
)
1537 RTFValue::Pointer_t pValue
;
1538 pCurrentBuffer
->push_back(Buf_t(BUFFER_ENDRUN
, pValue
, nullptr));
1542 void RTFDocumentImpl::prepareProperties(
1543 RTFParserState
& rState
, writerfilter::Reference
<Properties
>::Pointer_t
& o_rpParagraphProperties
,
1544 writerfilter::Reference
<Properties
>::Pointer_t
& o_rpFrameProperties
,
1545 writerfilter::Reference
<Properties
>::Pointer_t
& o_rpTableRowProperties
, int const nCells
,
1546 int const nCurrentCellX
)
1548 o_rpParagraphProperties
1549 = getProperties(rState
.getParagraphAttributes(), rState
.getParagraphSprms(),
1550 NS_ooxml::LN_Value_ST_StyleType_paragraph
);
1552 if (rState
.getFrame().hasProperties())
1554 o_rpFrameProperties
= new RTFReferenceProperties(RTFSprms(), rState
.getFrame().getSprms());
1558 RTFValue::Pointer_t
const pTableWidthProps
1559 = rState
.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblW
);
1560 if (!pTableWidthProps
.get())
1562 auto pUnitValue
= new RTFValue(3);
1563 putNestedAttribute(rState
.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW
,
1564 NS_ooxml::LN_CT_TblWidth_type
, pUnitValue
);
1565 auto pWValue
= new RTFValue(nCurrentCellX
);
1566 putNestedAttribute(rState
.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW
,
1567 NS_ooxml::LN_CT_TblWidth_w
, pWValue
);
1571 rState
.getTableRowSprms().set(NS_ooxml::LN_tblRow
, new RTFValue(1));
1573 RTFValue::Pointer_t
const pCellMar
1574 = rState
.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblCellMar
);
1575 if (!pCellMar
.get())
1577 // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
1578 RTFSprms aAttributes
;
1579 aAttributes
.set(NS_ooxml::LN_CT_TblWidth_type
,
1580 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa
));
1581 aAttributes
.set(NS_ooxml::LN_CT_TblWidth_w
, new RTFValue(0));
1582 putNestedSprm(rState
.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar
,
1583 NS_ooxml::LN_CT_TblCellMar_left
, new RTFValue(aAttributes
));
1584 putNestedSprm(rState
.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar
,
1585 NS_ooxml::LN_CT_TblCellMar_right
, new RTFValue(aAttributes
));
1588 o_rpTableRowProperties
1589 = new RTFReferenceProperties(rState
.getTableRowAttributes(), rState
.getTableRowSprms());
1592 void RTFDocumentImpl::sendProperties(
1593 writerfilter::Reference
<Properties
>::Pointer_t
const& pParagraphProperties
,
1594 writerfilter::Reference
<Properties
>::Pointer_t
const& pFrameProperties
,
1595 writerfilter::Reference
<Properties
>::Pointer_t
const& pTableRowProperties
)
1597 Mapper().props(pParagraphProperties
);
1599 if (pFrameProperties
)
1601 Mapper().props(pFrameProperties
);
1604 Mapper().props(pTableRowProperties
);
1609 void RTFDocumentImpl::replayRowBuffer(RTFBuffer_t
& rBuffer
, ::std::deque
<RTFSprms
>& rCellsSrpms
,
1610 ::std::deque
<RTFSprms
>& rCellsAttributes
, int const nCells
)
1612 for (int i
= 0; i
< nCells
; ++i
)
1614 replayBuffer(rBuffer
, &rCellsSrpms
.front(), &rCellsAttributes
.front());
1615 rCellsSrpms
.pop_front();
1616 rCellsAttributes
.pop_front();
1618 for (Buf_t
& i
: rBuffer
)
1620 SAL_WARN_IF(BUFFER_CELLEND
== std::get
<0>(i
), "writerfilter.rtf", "dropping table cell!");
1622 assert(rCellsSrpms
.empty());
1623 assert(rCellsAttributes
.empty());
1626 void RTFDocumentImpl::replayBuffer(RTFBuffer_t
& rBuffer
, RTFSprms
* const pSprms
,
1627 RTFSprms
const* const pAttributes
)
1629 while (!rBuffer
.empty())
1631 Buf_t
aTuple(rBuffer
.front());
1632 rBuffer
.pop_front();
1633 if (std::get
<0>(aTuple
) == BUFFER_PROPS
)
1635 // Construct properties via getProperties() and not directly, to take care of deduplication.
1636 writerfilter::Reference
<Properties
>::Pointer_t
const pProp(getProperties(
1637 std::get
<1>(aTuple
)->getAttributes(), std::get
<1>(aTuple
)->getSprms(), 0));
1638 Mapper().props(pProp
);
1640 else if (std::get
<0>(aTuple
) == BUFFER_NESTROW
)
1642 TableRowBuffer
& rRowBuffer(*std::get
<2>(aTuple
));
1644 replayRowBuffer(rRowBuffer
.GetBuffer(), rRowBuffer
.GetCellsSprms(),
1645 rRowBuffer
.GetCellsAttributes(), rRowBuffer
.GetCells());
1647 sendProperties(rRowBuffer
.GetParaProperties(), rRowBuffer
.GetFrameProperties(),
1648 rRowBuffer
.GetRowProperties());
1650 else if (std::get
<0>(aTuple
) == BUFFER_CELLEND
)
1652 assert(pSprms
&& pAttributes
);
1653 auto pValue
= new RTFValue(1);
1654 pSprms
->set(NS_ooxml::LN_tblCell
, pValue
);
1655 writerfilter::Reference
<Properties
>::Pointer_t
const pTableCellProperties(
1656 new RTFReferenceProperties(*pAttributes
, *pSprms
));
1657 Mapper().props(pTableCellProperties
);
1661 else if (std::get
<0>(aTuple
) == BUFFER_STARTRUN
)
1662 Mapper().startCharacterGroup();
1663 else if (std::get
<0>(aTuple
) == BUFFER_TEXT
)
1665 sal_uInt8
const nValue
= std::get
<1>(aTuple
)->getInt();
1666 Mapper().text(&nValue
, 1);
1668 else if (std::get
<0>(aTuple
) == BUFFER_UTEXT
)
1670 OUString
const aString(std::get
<1>(aTuple
)->getString());
1671 Mapper().utext(reinterpret_cast<sal_uInt8
const*>(aString
.getStr()),
1672 aString
.getLength());
1674 else if (std::get
<0>(aTuple
) == BUFFER_ENDRUN
)
1675 Mapper().endCharacterGroup();
1676 else if (std::get
<0>(aTuple
) == BUFFER_PAR
)
1678 else if (std::get
<0>(aTuple
) == BUFFER_STARTSHAPE
)
1679 m_pSdrImport
->resolve(std::get
<1>(aTuple
)->getShape(), false, RTFSdrImport::SHAPE
);
1680 else if (std::get
<0>(aTuple
) == BUFFER_RESOLVESHAPE
)
1682 // Make sure there is no current buffer while replaying the shape,
1683 // otherwise it gets re-buffered.
1684 RTFBuffer_t
* pCurrentBuffer
= m_aStates
.top().getCurrentBuffer();
1685 m_aStates
.top().setCurrentBuffer(nullptr);
1687 // Set current shape during replay, needed by e.g. wrap in
1689 m_aStates
.top().getShape() = std::get
<1>(aTuple
)->getShape();
1691 m_pSdrImport
->resolve(std::get
<1>(aTuple
)->getShape(), true, RTFSdrImport::SHAPE
);
1692 m_aStates
.top().setCurrentBuffer(pCurrentBuffer
);
1694 else if (std::get
<0>(aTuple
) == BUFFER_ENDSHAPE
)
1695 m_pSdrImport
->close();
1696 else if (std::get
<0>(aTuple
) == BUFFER_RESOLVESUBSTREAM
)
1698 RTFSprms
& rAttributes
= std::get
<1>(aTuple
)->getAttributes();
1699 std::size_t nPos
= rAttributes
.find(0)->getInt();
1700 Id nId
= rAttributes
.find(1)->getInt();
1701 OUString aCustomMark
= rAttributes
.find(2)->getString();
1702 resolveSubstream(nPos
, nId
, aCustomMark
);
1704 else if (std::get
<0>(aTuple
) == BUFFER_PICTURE
)
1705 m_aStates
.top().getPicture() = std::get
<1>(aTuple
)->getPicture();
1706 else if (std::get
<0>(aTuple
) == BUFFER_SETSTYLE
)
1708 if (!m_aStates
.empty())
1709 m_aStates
.top().setCurrentStyleIndex(std::get
<1>(aTuple
)->getInt());
1716 bool findPropertyName(const std::vector
<beans::PropertyValue
>& rProperties
, const OUString
& rName
)
1718 for (auto& rProperty
: rProperties
)
1720 if (rProperty
.Name
== rName
)
1726 void RTFDocumentImpl::backupTableRowProperties()
1728 if (m_nTopLevelCurrentCellX
)
1730 m_aBackupTableRowSprms
= m_aStates
.top().getTableRowSprms();
1731 m_aBackupTableRowAttributes
= m_aStates
.top().getTableRowAttributes();
1732 m_nBackupTopLevelCurrentCellX
= m_nTopLevelCurrentCellX
;
1736 void RTFDocumentImpl::restoreTableRowProperties()
1738 m_aStates
.top().getTableRowSprms() = m_aBackupTableRowSprms
;
1739 m_aStates
.top().getTableRowAttributes() = m_aBackupTableRowAttributes
;
1740 m_nTopLevelCurrentCellX
= m_nBackupTopLevelCurrentCellX
;
1743 void RTFDocumentImpl::resetTableRowProperties()
1745 m_aStates
.top().getTableRowSprms() = m_aDefaultState
.getTableRowSprms();
1746 m_aStates
.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol
, new RTFValue(-1),
1747 RTFOverwrite::NO_APPEND
);
1748 m_aStates
.top().getTableRowAttributes() = m_aDefaultState
.getTableRowAttributes();
1749 if (Destination::NESTEDTABLEPROPERTIES
== m_aStates
.top().getDestination())
1751 m_nNestedTRLeft
= 0;
1752 m_nNestedCurrentCellX
= 0;
1756 m_nTopLevelTRLeft
= 0;
1757 m_nTopLevelCurrentCellX
= 0;
1761 RTFError
RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword
, bool bParam
, int nParam
)
1764 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
1765 RTFSkipDestination
aSkip(*this);
1767 tools::SvRef
<RTFValue
> pBoolValue(new RTFValue(int(!bParam
|| nParam
!= 0)));
1769 // Underline toggles.
1773 nSprm
= NS_ooxml::LN_Value_ST_Underline_single
;
1776 nSprm
= NS_ooxml::LN_Value_ST_Underline_dash
;
1779 nSprm
= NS_ooxml::LN_Value_ST_Underline_dotDash
;
1782 nSprm
= NS_ooxml::LN_Value_ST_Underline_dotDotDash
;
1785 nSprm
= NS_ooxml::LN_Value_ST_Underline_double
;
1788 nSprm
= NS_ooxml::LN_Value_ST_Underline_wavyHeavy
;
1791 nSprm
= NS_ooxml::LN_Value_ST_Underline_dashLong
;
1794 nSprm
= NS_ooxml::LN_Value_ST_Underline_thick
;
1797 nSprm
= NS_ooxml::LN_Value_ST_Underline_dottedHeavy
;
1800 nSprm
= NS_ooxml::LN_Value_ST_Underline_dashedHeavy
;
1803 nSprm
= NS_ooxml::LN_Value_ST_Underline_dashDotHeavy
;
1805 case RTF_ULTHDASHDD
:
1806 nSprm
= NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy
;
1809 nSprm
= NS_ooxml::LN_Value_ST_Underline_dashLongHeavy
;
1811 case RTF_ULULDBWAVE
:
1812 nSprm
= NS_ooxml::LN_Value_ST_Underline_wavyDouble
;
1815 nSprm
= NS_ooxml::LN_Value_ST_Underline_wave
;
1823 = new RTFValue((!bParam
|| nParam
!= 0) ? nSprm
: NS_ooxml::LN_Value_ST_Underline_none
);
1824 m_aStates
.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val
, pValue
);
1825 return RTFError::OK
;
1828 // Accent characters (over dot / over comma).
1832 nSprm
= NS_ooxml::LN_Value_ST_Em_none
;
1835 nSprm
= NS_ooxml::LN_Value_ST_Em_dot
;
1838 nSprm
= NS_ooxml::LN_Value_ST_Em_comma
;
1841 nSprm
= NS_ooxml::LN_Value_ST_Em_circle
;
1843 case RTF_ACCUNDERDOT
:
1844 nSprm
= NS_ooxml::LN_Value_ST_Em_underDot
;
1851 auto pValue
= new RTFValue((!bParam
|| nParam
!= 0) ? nSprm
: 0);
1852 m_aStates
.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_em
, pValue
);
1853 return RTFError::OK
;
1856 // Trivial character sprms.
1861 switch (m_aStates
.top().getRunType())
1863 case RTFParserState::RunType::HICH
:
1864 case RTFParserState::RunType::RTLCH_LTRCH_1
:
1865 case RTFParserState::RunType::LTRCH_RTLCH_2
:
1866 case RTFParserState::RunType::DBCH
:
1867 nSprm
= NS_ooxml::LN_EG_RPrBase_bCs
;
1869 case RTFParserState::RunType::NONE
:
1870 case RTFParserState::RunType::LOCH
:
1871 case RTFParserState::RunType::LTRCH_RTLCH_1
:
1872 case RTFParserState::RunType::RTLCH_LTRCH_2
:
1874 nSprm
= NS_ooxml::LN_EG_RPrBase_b
;
1880 switch (m_aStates
.top().getRunType())
1882 case RTFParserState::RunType::HICH
:
1883 case RTFParserState::RunType::RTLCH_LTRCH_1
:
1884 case RTFParserState::RunType::LTRCH_RTLCH_2
:
1885 case RTFParserState::RunType::DBCH
:
1886 nSprm
= NS_ooxml::LN_EG_RPrBase_iCs
;
1888 case RTFParserState::RunType::NONE
:
1889 case RTFParserState::RunType::LOCH
:
1890 case RTFParserState::RunType::LTRCH_RTLCH_1
:
1891 case RTFParserState::RunType::RTLCH_LTRCH_2
:
1893 nSprm
= NS_ooxml::LN_EG_RPrBase_i
;
1898 nSprm
= NS_ooxml::LN_EG_RPrBase_outline
;
1901 nSprm
= NS_ooxml::LN_EG_RPrBase_shadow
;
1904 nSprm
= NS_ooxml::LN_EG_RPrBase_vanish
;
1907 nSprm
= NS_ooxml::LN_EG_RPrBase_strike
;
1910 nSprm
= NS_ooxml::LN_EG_RPrBase_dstrike
;
1913 nSprm
= NS_ooxml::LN_EG_RPrBase_smallCaps
;
1916 nSprm
= NS_ooxml::LN_EG_RPrBase_imprint
;
1919 nSprm
= NS_ooxml::LN_EG_RPrBase_caps
;
1926 m_aStates
.top().getCharacterSprms().set(nSprm
, pBoolValue
);
1927 return RTFError::OK
;
1933 m_aStates
.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE
,
1939 auto pValue
= new RTFValue(nKeyword
== RTF_DELETED
? oox::XML_del
: oox::XML_ins
);
1940 putNestedAttribute(m_aStates
.top().getCharacterSprms(), NS_ooxml::LN_trackchange
,
1941 NS_ooxml::LN_token
, pValue
);
1945 putNestedAttribute(m_aStates
.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing
,
1946 NS_ooxml::LN_CT_Spacing_beforeAutospacing
, pBoolValue
);
1949 putNestedAttribute(m_aStates
.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing
,
1950 NS_ooxml::LN_CT_Spacing_afterAutospacing
, pBoolValue
);
1953 m_aSettingsTableSprms
.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders
, pBoolValue
);
1956 m_aSettingsTableSprms
.set(NS_ooxml::LN_CT_Settings_autoHyphenation
, pBoolValue
);
1959 m_aStates
.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens
,
1960 new RTFValue(int(bParam
&& nParam
== 0)));
1964 SAL_INFO("writerfilter.rtf",
1965 "TODO handle toggle '" << keywordToString(nKeyword
) << "'");
1966 aSkip
.setParsed(false);
1970 return RTFError::OK
;
1973 RTFError
RTFDocumentImpl::pushState()
1975 //SAL_INFO("writerfilter.rtf", OSL_THIS_FUNC << " before push: " << m_pTokenizer->getGroup());
1977 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
1978 m_nGroupStartPos
= Strm().Tell();
1980 if (m_aStates
.empty())
1981 m_aStates
.push(m_aDefaultState
);
1984 // fdo#85812 group resets run type of _current_ and new state (but not RTL)
1985 if (m_aStates
.top().getRunType() != RTFParserState::RunType::LTRCH_RTLCH_2
1986 && m_aStates
.top().getRunType() != RTFParserState::RunType::RTLCH_LTRCH_2
)
1988 m_aStates
.top().setRunType(RTFParserState::RunType::NONE
);
1991 if (m_aStates
.top().getDestination() == Destination::MR
)
1992 lcl_DestinationToMath(m_aStates
.top().getCurrentDestinationText(), m_aMathBuffer
,
1994 m_aStates
.push(m_aStates
.top());
1996 m_aStates
.top().getDestinationText().setLength(0); // was copied: always reset!
1998 m_pTokenizer
->pushGroup();
2000 switch (m_aStates
.top().getDestination())
2002 case Destination::FONTTABLE
:
2003 // this is a "faked" destination for the font entry
2004 m_aStates
.top().setCurrentDestinationText(&m_aStates
.top().getDestinationText());
2005 m_aStates
.top().setDestination(Destination::FONTENTRY
);
2007 case Destination::STYLESHEET
:
2008 // this is a "faked" destination for the style sheet entry
2009 m_aStates
.top().setCurrentDestinationText(&m_aStates
.top().getDestinationText());
2010 m_aStates
.top().setDestination(Destination::STYLEENTRY
);
2012 // the *default* is \s0 i.e. paragraph style default
2013 // this will be overwritten by \sN \csN \dsN \tsN
2014 m_nCurrentStyleIndex
= 0;
2015 auto pValue
= new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph
);
2016 m_aStates
.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type
, pValue
);
2019 case Destination::FIELDRESULT
:
2020 case Destination::SHAPETEXT
:
2021 case Destination::FORMFIELD
:
2022 case Destination::FIELDINSTRUCTION
:
2023 case Destination::PICT
:
2024 m_aStates
.top().setDestination(Destination::NORMAL
);
2026 case Destination::MNUM
:
2027 case Destination::MDEN
:
2028 case Destination::ME
:
2029 case Destination::MFNAME
:
2030 case Destination::MLIM
:
2031 case Destination::MSUB
:
2032 case Destination::MSUP
:
2033 case Destination::MDEG
:
2034 case Destination::MOMATH
:
2035 m_aStates
.top().setDestination(Destination::MR
);
2037 case Destination::REVISIONTABLE
:
2038 // this is a "faked" destination for the revision table entry
2039 m_aStates
.top().setCurrentDestinationText(&m_aStates
.top().getDestinationText());
2040 m_aStates
.top().setDestination(Destination::REVISIONENTRY
);
2046 // If this is true, then ooxml:endtrackchange will be generated. Make sure
2047 // we don't generate more ooxml:endtrackchange than ooxml:trackchange: new
2048 // state does not inherit this flag.
2049 m_aStates
.top().setStartedTrackchange(false);
2051 return RTFError::OK
;
2054 writerfilter::Reference
<Properties
>::Pointer_t
RTFDocumentImpl::createStyleProperties()
2057 RTFValue::Pointer_t pBasedOn
2058 = m_aStates
.top().getTableSprms().find(NS_ooxml::LN_CT_Style_basedOn
);
2060 nBasedOn
= pBasedOn
->getInt();
2063 // No parent style, then mimic what Word does: ignore attributes which
2064 // would set a margin as formatting, but with a default value.
2065 for (const auto& nId
:
2066 { NS_ooxml::LN_CT_Ind_firstLine
, NS_ooxml::LN_CT_Ind_left
, NS_ooxml::LN_CT_Ind_right
,
2067 NS_ooxml::LN_CT_Ind_start
, NS_ooxml::LN_CT_Ind_end
})
2069 RTFValue::Pointer_t pValue
= getNestedAttribute(m_aStates
.top().getParagraphSprms(),
2070 NS_ooxml::LN_CT_PPrBase_ind
, nId
);
2071 if (pValue
&& pValue
->getInt() == 0)
2072 eraseNestedAttribute(m_aStates
.top().getParagraphSprms(),
2073 NS_ooxml::LN_CT_PPrBase_ind
, nId
);
2077 RTFValue::Pointer_t pParaProps
= new RTFValue(m_aStates
.top().getParagraphAttributes(),
2078 m_aStates
.top().getParagraphSprms());
2079 RTFValue::Pointer_t pCharProps
= new RTFValue(m_aStates
.top().getCharacterAttributes(),
2080 m_aStates
.top().getCharacterSprms());
2082 // resetSprms will clean up this modification
2083 m_aStates
.top().getTableSprms().set(NS_ooxml::LN_CT_Style_pPr
, pParaProps
);
2084 m_aStates
.top().getTableSprms().set(NS_ooxml::LN_CT_Style_rPr
, pCharProps
);
2086 writerfilter::Reference
<Properties
>::Pointer_t
const pProps(new RTFReferenceProperties(
2087 m_aStates
.top().getTableAttributes(), m_aStates
.top().getTableSprms()));
2091 /** 2 different representations of the styles are needed:
2093 1) flat content, as read from the input file:
2094 stored in m_aStyleTableEntries, used as reference input for
2095 deduplication both here and for hard formatting in getProperties()
2097 2) real content, with proper override of sprms/attributes where it differs
2098 from parent style; this is produced here and sent to domain mapper
2100 RTFReferenceTable::Entries_t
RTFDocumentImpl::deduplicateStyleTable()
2102 RTFReferenceTable::Entries_t ret
;
2103 for (auto const& it
: m_aStyleTableEntries
)
2105 auto pStyle
= it
.second
;
2106 // ugly downcasts here, but can't easily replace the members with
2107 // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway
2108 RTFValue::Pointer_t
const pBasedOn(
2109 static_cast<RTFReferenceProperties
&>(*pStyle
).getSprms().find(
2110 NS_ooxml::LN_CT_Style_basedOn
));
2113 int const nBasedOn(pBasedOn
->getInt());
2114 auto const itParent(m_aStyleTableEntries
.find(nBasedOn
)); // definition as read!
2115 if (itParent
!= m_aStyleTableEntries
.end())
2117 auto const pStyleType(
2118 static_cast<RTFReferenceProperties
&>(*pStyle
).getAttributes().find(
2119 NS_ooxml::LN_CT_Style_type
));
2121 int const nStyleType(pStyleType
->getInt());
2122 RTFSprms
const sprms(
2123 static_cast<RTFReferenceProperties
&>(*pStyle
).getSprms().cloneAndDeduplicate(
2124 static_cast<RTFReferenceProperties
&>(*itParent
->second
).getSprms(),
2126 RTFSprms
const attributes(
2127 static_cast<RTFReferenceProperties
&>(*pStyle
)
2129 .cloneAndDeduplicate(
2130 static_cast<RTFReferenceProperties
&>(*itParent
->second
).getAttributes(),
2133 pStyle
= new RTFReferenceProperties(attributes
, sprms
);
2137 SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn
);
2140 ret
[it
.first
] = pStyle
;
2142 assert(ret
.size() == m_aStyleTableEntries
.size());
2146 void RTFDocumentImpl::resetSprms()
2148 m_aStates
.top().getTableSprms().clear();
2149 m_aStates
.top().getCharacterSprms().clear();
2150 m_aStates
.top().getParagraphSprms().clear();
2153 void RTFDocumentImpl::resetAttributes()
2155 m_aStates
.top().getTableAttributes().clear();
2156 m_aStates
.top().getCharacterAttributes().clear();
2157 m_aStates
.top().getParagraphAttributes().clear();
2160 static bool lcl_containsProperty(const uno::Sequence
<beans::Property
>& rProperties
,
2161 const OUString
& rName
)
2163 return std::any_of(rProperties
.begin(), rProperties
.end(),
2164 [&](const beans::Property
& rProperty
) { return rProperty
.Name
== rName
; });
2167 RTFError
RTFDocumentImpl::popState()
2169 //SAL_INFO("writerfilter", OSL_THIS_FUNC << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
2170 // ", dest state: " << m_aStates.top().eDestination);
2172 checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
2173 RTFParserState
aState(m_aStates
.top());
2174 m_bWasInFrame
= aState
.getFrame().inFrame();
2176 // dmapper expects some content in header/footer, so if there would be nothing, add an empty paragraph.
2177 if (m_pTokenizer
->getGroup() == 1 && m_bFirstRun
)
2179 switch (m_nStreamType
)
2181 case NS_ooxml::LN_headerl
:
2182 case NS_ooxml::LN_headerr
:
2183 case NS_ooxml::LN_headerf
:
2184 case NS_ooxml::LN_footerl
:
2185 case NS_ooxml::LN_footerr
:
2186 case NS_ooxml::LN_footerf
:
2187 dispatchSymbol(RTF_PAR
);
2192 switch (aState
.getDestination())
2194 case Destination::FONTTABLE
:
2196 writerfilter::Reference
<Table
>::Pointer_t
const pTable(
2197 new RTFReferenceTable(m_aFontTableEntries
));
2198 Mapper().table(NS_ooxml::LN_FONTTABLE
, pTable
);
2199 if (m_nDefaultFontIndex
>= 0)
2201 auto pValue
= new RTFValue(m_aFontNames
[getFontIndex(m_nDefaultFontIndex
)]);
2202 putNestedAttribute(m_aDefaultState
.getCharacterSprms(),
2203 NS_ooxml::LN_EG_RPrBase_rFonts
, NS_ooxml::LN_CT_Fonts_ascii
,
2208 case Destination::STYLESHEET
:
2210 RTFReferenceTable::Entries_t
const pStyleTableDeduplicated(deduplicateStyleTable());
2211 writerfilter::Reference
<Table
>::Pointer_t
const pTable(
2212 new RTFReferenceTable(pStyleTableDeduplicated
));
2213 Mapper().table(NS_ooxml::LN_STYLESHEET
, pTable
);
2216 case Destination::LISTOVERRIDETABLE
:
2218 RTFSprms aListTableAttributes
;
2219 writerfilter::Reference
<Properties
>::Pointer_t pProp
2220 = new RTFReferenceProperties(aListTableAttributes
, m_aListTableSprms
);
2221 RTFReferenceTable::Entries_t aListTableEntries
;
2222 aListTableEntries
.insert(std::make_pair(0, pProp
));
2223 writerfilter::Reference
<Table
>::Pointer_t
const pTable(
2224 new RTFReferenceTable(aListTableEntries
));
2225 Mapper().table(NS_ooxml::LN_NUMBERING
, pTable
);
2228 case Destination::LISTENTRY
:
2229 for (const auto& rListLevelEntry
: aState
.getListLevelEntries())
2230 aState
.getTableSprms().set(rListLevelEntry
.first
, rListLevelEntry
.second
,
2231 RTFOverwrite::NO_APPEND
);
2233 case Destination::FIELDINSTRUCTION
:
2235 auto pValue
= new RTFValue(m_aFormfieldAttributes
, m_aFormfieldSprms
);
2236 RTFSprms aFFAttributes
;
2238 aFFSprms
.set(NS_ooxml::LN_ffdata
, pValue
);
2239 if (!m_aStates
.top().getCurrentBuffer())
2241 writerfilter::Reference
<Properties
>::Pointer_t pProperties
2242 = new RTFReferenceProperties(aFFAttributes
, aFFSprms
);
2243 Mapper().props(pProperties
);
2247 auto pFFValue
= new RTFValue(aFFAttributes
, aFFSprms
);
2248 bufferProperties(*m_aStates
.top().getCurrentBuffer(), pFFValue
, nullptr);
2250 m_aFormfieldAttributes
.clear();
2251 m_aFormfieldSprms
.clear();
2252 singleChar(cFieldSep
);
2255 case Destination::FIELDRESULT
:
2256 singleChar(cFieldEnd
);
2258 if (!m_aPicturePath
.isEmpty())
2260 // Read the picture into m_aStates.top().aDestinationText.
2262 dispatchDestination(RTF_PICT
);
2263 if (m_aPicturePath
.endsWith(".png"))
2264 dispatchFlag(RTF_PNGBLIP
);
2265 OUString aFileURL
= m_rMediaDescriptor
.getUnpackedValueOrDefault(
2266 utl::MediaDescriptor::PROP_URL(), OUString());
2267 OUString aPictureURL
;
2270 aPictureURL
= rtl::Uri::convertRelToAbs(aFileURL
, m_aPicturePath
);
2272 catch (const rtl::MalformedUriException
& rException
)
2274 SAL_WARN("writerfilter.rtf",
2275 "rtl::Uri::convertRelToAbs() failed: " << rException
.getMessage());
2278 if (!aPictureURL
.isEmpty())
2280 SvFileStream
aStream(aPictureURL
, StreamMode::READ
);
2281 if (aStream
.IsOpen())
2283 OUStringBuffer aBuf
;
2284 while (aStream
.good())
2286 unsigned char ch
= 0;
2287 aStream
.ReadUChar(ch
);
2290 aBuf
.append(OUString::number(ch
, 16));
2292 m_aStates
.top().getDestinationText() = aBuf
;
2296 m_aPicturePath
.clear();
2300 case Destination::LEVELTEXT
:
2302 if (&m_aStates
.top().getDestinationText()
2303 != m_aStates
.top().getCurrentDestinationText())
2304 break; // not for nested group
2305 OUString aStr
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2307 // The first character is the length of the string (the rest should be ignored).
2308 sal_Int32
nLength(aStr
.toChar());
2310 if (nLength
< aStr
.getLength())
2311 aValue
= aStr
.copy(1, nLength
);
2314 auto pValue
= new RTFValue(aValue
, true);
2315 aState
.getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val
, pValue
);
2318 case Destination::LEVELNUMBERS
:
2320 bool bNestedLevelNumbers
= false;
2321 if (m_aStates
.size() > 1)
2322 // Current destination is levelnumbers and parent destination is levelnumbers as well.
2324 = m_aStates
[m_aStates
.size() - 2].getDestination() == Destination::LEVELNUMBERS
;
2325 if (!bNestedLevelNumbers
&& aState
.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText
))
2327 RTFSprms
& rAttributes
2328 = aState
.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText
)->getAttributes();
2329 RTFValue::Pointer_t pValue
= rAttributes
.find(NS_ooxml::LN_CT_LevelText_val
);
2330 if (pValue
&& aState
.getLevelNumbersValid())
2332 OUString aOrig
= pValue
->getString();
2334 OUStringBuffer
aBuf(aOrig
.getLength() * 2);
2335 sal_Int32 nReplaces
= 1;
2336 for (int i
= 0; i
< aOrig
.getLength(); i
++)
2338 if (std::find(aState
.getLevelNumbers().begin(),
2339 aState
.getLevelNumbers().end(), i
+ 1)
2340 != aState
.getLevelNumbers().end())
2343 // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2.
2344 aBuf
.append(sal_Int32(nReplaces
++ + aState
.getListLevelNum() + 1
2345 - aState
.getLevelNumbers().size()));
2348 aBuf
.append(aOrig
[i
]);
2351 pValue
->setString(aBuf
.makeStringAndClear());
2354 // Have a value, but levelnumbers is not valid -> ignore it.
2355 pValue
->setString(OUString());
2359 case Destination::SHAPEPROPERTYNAME
:
2360 if (&m_aStates
.top().getDestinationText()
2361 != m_aStates
.top().getCurrentDestinationText())
2362 break; // not for nested group
2363 aState
.getShape().getProperties().emplace_back(
2364 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear(), OUString());
2366 case Destination::SHAPEPROPERTYVALUE
:
2367 if (!aState
.getShape().getProperties().empty())
2369 aState
.getShape().getProperties().back().second
2370 = m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2371 if (m_aStates
.top().getHadShapeText())
2372 m_pSdrImport
->append(aState
.getShape().getProperties().back().first
,
2373 aState
.getShape().getProperties().back().second
);
2374 else if (aState
.getInShapeGroup() && !aState
.getInShape()
2375 && aState
.getShape().getProperties().back().first
== "rotation")
2377 // Rotation should be applied on the groupshape itself, not on each shape.
2378 aState
.getShape().getGroupProperties().push_back(
2379 aState
.getShape().getProperties().back());
2380 aState
.getShape().getProperties().pop_back();
2384 case Destination::PICPROP
:
2385 case Destination::SHAPEINSTRUCTION
:
2386 if (m_aStates
.size() > 1
2387 && m_aStates
[m_aStates
.size() - 2].getDestination()
2388 == Destination::SHAPEINSTRUCTION
)
2390 // Do not resolve shape if shape instruction destination is inside other shape instruction
2392 else if (!m_bObject
&& !aState
.getInListpicture() && !aState
.getHadShapeText()
2393 && !(aState
.getInShapeGroup() && !aState
.getInShape()))
2395 // Don't trigger a shape import in case we're only leaving the \shpinst of the groupshape itself.
2396 RTFSdrImport::ShapeOrPict eType
2397 = (aState
.getDestination() == Destination::SHAPEINSTRUCTION
)
2398 ? RTFSdrImport::SHAPE
2399 : RTFSdrImport::PICT
;
2400 if (!m_aStates
.top().getCurrentBuffer() || eType
!= RTFSdrImport::SHAPE
)
2401 m_pSdrImport
->resolve(m_aStates
.top().getShape(), true, eType
);
2404 // Shape inside table: buffer the import to have correct anchor position.
2405 // Also buffer the RTFPicture of the state stack as it contains
2407 auto pPictureValue
= new RTFValue(m_aStates
.top().getPicture());
2408 m_aStates
.top().getCurrentBuffer()->push_back(
2409 Buf_t(BUFFER_PICTURE
, pPictureValue
, nullptr));
2410 auto pValue
= new RTFValue(m_aStates
.top().getShape());
2412 // Buffer wrap type.
2413 for (const auto& rCharacterSprm
: m_aStates
.top().getCharacterSprms())
2415 if (rCharacterSprm
.first
== NS_ooxml::LN_EG_WrapType_wrapNone
2416 || rCharacterSprm
.first
== NS_ooxml::LN_EG_WrapType_wrapTight
)
2418 m_aStates
.top().getShape().getWrapSprm() = rCharacterSprm
;
2423 m_aStates
.top().getCurrentBuffer()->push_back(
2424 Buf_t(BUFFER_RESOLVESHAPE
, pValue
, nullptr));
2427 else if (aState
.getInShapeGroup() && !aState
.getInShape())
2429 // End of a groupshape, as we're in shapegroup, but not in a real shape.
2430 for (const auto& rGroupProperty
: aState
.getShape().getGroupProperties())
2431 m_pSdrImport
->appendGroupProperty(rGroupProperty
.first
, rGroupProperty
.second
);
2432 aState
.getShape().getGroupProperties().clear();
2435 case Destination::BOOKMARKSTART
:
2437 if (&m_aStates
.top().getDestinationText()
2438 != m_aStates
.top().getCurrentDestinationText())
2439 break; // not for nested group
2440 OUString aStr
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2441 int nPos
= m_aBookmarks
.size();
2442 m_aBookmarks
[aStr
] = nPos
;
2443 if (!m_aStates
.top().getCurrentBuffer())
2444 Mapper().props(new RTFReferenceProperties(lcl_getBookmarkProperties(nPos
, aStr
)));
2446 bufferProperties(*m_aStates
.top().getCurrentBuffer(),
2447 new RTFValue(lcl_getBookmarkProperties(nPos
, aStr
)), nullptr);
2450 case Destination::BOOKMARKEND
:
2452 if (&m_aStates
.top().getDestinationText()
2453 != m_aStates
.top().getCurrentDestinationText())
2454 break; // not for nested group
2455 OUString aStr
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2456 if (!m_aStates
.top().getCurrentBuffer())
2457 Mapper().props(new RTFReferenceProperties(
2458 lcl_getBookmarkProperties(m_aBookmarks
[aStr
], aStr
)));
2460 bufferProperties(*m_aStates
.top().getCurrentBuffer(),
2461 new RTFValue(lcl_getBookmarkProperties(m_aBookmarks
[aStr
], aStr
)),
2465 case Destination::INDEXENTRY
:
2466 case Destination::TOCENTRY
:
2468 if (&m_aStates
.top().getDestinationText()
2469 != m_aStates
.top().getCurrentDestinationText())
2470 break; // not for nested group
2471 OUString
str(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2472 // dmapper expects this as a field, so let's fake something...
2473 OUString
const field((Destination::INDEXENTRY
== aState
.getDestination())
2474 ? OUStringLiteral("XE")
2475 : OUStringLiteral("TC"));
2476 str
= field
+ " \"" + str
.replaceAll("\"", "\\\"") + "\"";
2477 singleChar(cFieldStart
);
2478 Mapper().utext(reinterpret_cast<sal_uInt8
const*>(str
.getStr()), str
.getLength());
2479 singleChar(cFieldSep
);
2481 singleChar(cFieldEnd
);
2484 case Destination::FORMFIELDNAME
:
2486 if (&m_aStates
.top().getDestinationText()
2487 != m_aStates
.top().getCurrentDestinationText())
2488 break; // not for nested group
2490 = new RTFValue(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2491 m_aFormfieldSprms
.set(NS_ooxml::LN_CT_FFData_name
, pValue
);
2494 case Destination::FORMFIELDLIST
:
2496 if (&m_aStates
.top().getDestinationText()
2497 != m_aStates
.top().getCurrentDestinationText())
2498 break; // not for nested group
2500 = new RTFValue(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2501 m_aFormfieldSprms
.set(NS_ooxml::LN_CT_FFDDList_listEntry
, pValue
);
2504 case Destination::DATAFIELD
:
2508 if (&m_aStates
.top().getDestinationText()
2509 != m_aStates
.top().getCurrentDestinationText())
2510 break; // not for nested group
2511 OString aStr
= OUStringToOString(
2512 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear(),
2513 aState
.getCurrentEncoding());
2518 for (int i
= 0; i
< aStr
.getLength(); ++i
)
2521 if (ch
!= 0x0d && ch
!= 0x0a)
2524 sal_Int8 parsed
= msfilter::rtfutil::AsHex(ch
);
2526 return RTFError::HEX_INVALID
;
2531 aBuf
.append(static_cast<char>(b
));
2537 aStr
= aBuf
.makeStringAndClear();
2539 // ignore the first bytes
2540 if (aStr
.getLength() > 8)
2541 aStr
= aStr
.copy(8);
2543 sal_Int32 nLength
= aStr
.toChar();
2544 if (!aStr
.isEmpty())
2545 aStr
= aStr
.copy(1);
2546 nLength
= std::min(nLength
, aStr
.getLength());
2547 OString aName
= aStr
.copy(0, nLength
);
2548 if (aStr
.getLength() > nLength
)
2549 aStr
= aStr
.copy(nLength
+ 1); // zero-terminated string
2552 // extract default text
2553 nLength
= aStr
.toChar();
2554 if (!aStr
.isEmpty())
2555 aStr
= aStr
.copy(1);
2556 auto pNValue
= new RTFValue(OStringToOUString(aName
, aState
.getCurrentEncoding()));
2557 m_aFormfieldSprms
.set(NS_ooxml::LN_CT_FFData_name
, pNValue
);
2560 OString aDefaultText
= aStr
.copy(0, std::min(nLength
, aStr
.getLength()));
2561 auto pDValue
= new RTFValue(
2562 OStringToOUString(aDefaultText
, aState
.getCurrentEncoding()));
2563 m_aFormfieldSprms
.set(NS_ooxml::LN_CT_FFTextInput_default
, pDValue
);
2566 m_bFormField
= false;
2570 case Destination::CREATIONTIME
:
2571 if (m_xDocumentProperties
.is())
2572 m_xDocumentProperties
->setCreationDate(lcl_getDateTime(aState
));
2574 case Destination::REVISIONTIME
:
2575 if (m_xDocumentProperties
.is())
2576 m_xDocumentProperties
->setModificationDate(lcl_getDateTime(aState
));
2578 case Destination::PRINTTIME
:
2579 if (m_xDocumentProperties
.is())
2580 m_xDocumentProperties
->setPrintDate(lcl_getDateTime(aState
));
2582 case Destination::AUTHOR
:
2583 if (&m_aStates
.top().getDestinationText()
2584 != m_aStates
.top().getCurrentDestinationText())
2585 break; // not for nested group
2586 if (m_xDocumentProperties
.is())
2587 m_xDocumentProperties
->setAuthor(
2588 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2590 case Destination::KEYWORDS
:
2591 if (&m_aStates
.top().getDestinationText()
2592 != m_aStates
.top().getCurrentDestinationText())
2593 break; // not for nested group
2594 if (m_xDocumentProperties
.is())
2595 m_xDocumentProperties
->setKeywords(comphelper::string::convertCommaSeparated(
2596 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear()));
2598 case Destination::COMMENT
:
2599 if (&m_aStates
.top().getDestinationText()
2600 != m_aStates
.top().getCurrentDestinationText())
2601 break; // not for nested group
2602 if (m_xDocumentProperties
.is())
2603 m_xDocumentProperties
->setGenerator(
2604 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2606 case Destination::SUBJECT
:
2607 if (&m_aStates
.top().getDestinationText()
2608 != m_aStates
.top().getCurrentDestinationText())
2609 break; // not for nested group
2610 if (m_xDocumentProperties
.is())
2611 m_xDocumentProperties
->setSubject(
2612 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2614 case Destination::TITLE
:
2616 if (&m_aStates
.top().getDestinationText()
2617 != m_aStates
.top().getCurrentDestinationText())
2618 break; // not for nested group
2619 if (m_xDocumentProperties
.is())
2620 m_xDocumentProperties
->setTitle(
2621 aState
.getCurrentDestinationText()->makeStringAndClear());
2625 case Destination::DOCCOMM
:
2626 if (&m_aStates
.top().getDestinationText()
2627 != m_aStates
.top().getCurrentDestinationText())
2628 break; // not for nested group
2629 if (m_xDocumentProperties
.is())
2630 m_xDocumentProperties
->setDescription(
2631 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2633 case Destination::OPERATOR
:
2634 case Destination::COMPANY
:
2636 if (&m_aStates
.top().getDestinationText()
2637 != m_aStates
.top().getCurrentDestinationText())
2638 break; // not for nested group
2639 OUString aName
= aState
.getDestination() == Destination::OPERATOR
? OUString("Operator")
2640 : OUString("Company");
2642 = uno::makeAny(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2643 if (m_xDocumentProperties
.is())
2645 uno::Reference
<beans::XPropertyContainer
> xUserDefinedProperties
2646 = m_xDocumentProperties
->getUserDefinedProperties();
2647 uno::Reference
<beans::XPropertySet
> xPropertySet(xUserDefinedProperties
,
2649 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
2650 = xPropertySet
->getPropertySetInfo();
2651 if (xPropertySetInfo
->hasPropertyByName(aName
))
2652 xPropertySet
->setPropertyValue(aName
, aValue
);
2654 xUserDefinedProperties
->addProperty(aName
, beans::PropertyAttribute::REMOVABLE
,
2659 case Destination::OBJDATA
:
2661 if (&m_aStates
.top().getDestinationText()
2662 != m_aStates
.top().getCurrentDestinationText())
2663 break; // not for nested group
2665 RTFError eError
= handleEmbeddedObject();
2666 if (eError
!= RTFError::OK
)
2670 case Destination::OBJCLASS
:
2673 = new RTFValue(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2674 m_aOLEAttributes
.set(NS_ooxml::LN_CT_OLEObject_ProgID
, pValue
);
2677 case Destination::OBJECT
:
2681 // if the object is in a special container we will use the \result
2682 // element instead of the \objdata
2683 // (see RTF_OBJECT in RTFDocumentImpl::dispatchDestination)
2687 RTFSprms aObjectSprms
;
2688 auto pOLEValue
= new RTFValue(m_aOLEAttributes
);
2689 aObjectSprms
.set(NS_ooxml::LN_OLEObject_OLEObject
, pOLEValue
);
2691 RTFSprms aObjAttributes
;
2693 auto pValue
= new RTFValue(m_aObjectAttributes
, aObjectSprms
);
2694 aObjSprms
.set(NS_ooxml::LN_object
, pValue
);
2695 writerfilter::Reference
<Properties
>::Pointer_t pProperties
2696 = new RTFReferenceProperties(aObjAttributes
, aObjSprms
);
2697 uno::Reference
<drawing::XShape
> xShape
;
2698 RTFValue::Pointer_t pShape
= m_aObjectAttributes
.find(NS_ooxml::LN_shape
);
2699 OSL_ASSERT(pShape
.get());
2701 pShape
->getAny() >>= xShape
;
2704 Mapper().startShape(xShape
);
2705 Mapper().props(pProperties
);
2706 Mapper().endShape();
2708 m_aObjectAttributes
.clear();
2709 m_aOLEAttributes
.clear();
2713 case Destination::ANNOTATIONDATE
:
2715 if (&m_aStates
.top().getDestinationText()
2716 != m_aStates
.top().getCurrentDestinationText())
2717 break; // not for nested group
2718 OUString
aStr(OStringToOUString(
2720 m_aStates
.top().getCurrentDestinationText()->makeStringAndClear().toInt32()),
2721 aState
.getCurrentEncoding()));
2722 auto pValue
= new RTFValue(aStr
);
2723 RTFSprms aAnnAttributes
;
2724 aAnnAttributes
.set(NS_ooxml::LN_CT_TrackChange_date
, pValue
);
2725 writerfilter::Reference
<Properties
>::Pointer_t pProperties
2726 = new RTFReferenceProperties(aAnnAttributes
);
2727 Mapper().props(pProperties
);
2730 case Destination::ANNOTATIONAUTHOR
:
2731 if (&m_aStates
.top().getDestinationText()
2732 != m_aStates
.top().getCurrentDestinationText())
2733 break; // not for nested group
2734 m_aAuthor
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2736 case Destination::ATNID
:
2737 if (&m_aStates
.top().getDestinationText()
2738 != m_aStates
.top().getCurrentDestinationText())
2739 break; // not for nested group
2740 m_aAuthorInitials
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2742 case Destination::ANNOTATIONREFERENCESTART
:
2743 case Destination::ANNOTATIONREFERENCEEND
:
2745 if (&m_aStates
.top().getDestinationText()
2746 != m_aStates
.top().getCurrentDestinationText())
2747 break; // not for nested group
2748 OUString aStr
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2749 auto pValue
= new RTFValue(aStr
.toInt32());
2750 RTFSprms aAttributes
;
2751 if (aState
.getDestination() == Destination::ANNOTATIONREFERENCESTART
)
2752 aAttributes
.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart
, pValue
);
2754 aAttributes
.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd
, pValue
);
2755 writerfilter::Reference
<Properties
>::Pointer_t pProperties
2756 = new RTFReferenceProperties(aAttributes
);
2757 Mapper().props(pProperties
);
2760 case Destination::ANNOTATIONREFERENCE
:
2762 if (&m_aStates
.top().getDestinationText()
2763 != m_aStates
.top().getCurrentDestinationText())
2764 break; // not for nested group
2765 OUString aStr
= m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2766 RTFSprms aAnnAttributes
;
2767 aAnnAttributes
.set(NS_ooxml::LN_CT_Markup_id
, new RTFValue(aStr
.toInt32()));
2768 Mapper().props(new RTFReferenceProperties(aAnnAttributes
));
2771 case Destination::FALT
:
2773 if (&m_aStates
.top().getDestinationText()
2774 != m_aStates
.top().getCurrentDestinationText())
2775 break; // not for nested group
2776 OUString
aStr(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
2777 auto pValue
= new RTFValue(aStr
);
2778 aState
.getTableSprms().set(NS_ooxml::LN_CT_Font_altName
, pValue
);
2781 case Destination::DRAWINGOBJECT
:
2782 if (m_aStates
.top().getDrawingObject().getShape().is())
2784 RTFDrawingObject
& rDrawing
= m_aStates
.top().getDrawingObject();
2785 const uno::Reference
<drawing::XShape
>& xShape(rDrawing
.getShape());
2786 const uno::Reference
<beans::XPropertySet
>& xPropertySet(rDrawing
.getPropertySet());
2788 uno::Reference
<lang::XServiceInfo
> xServiceInfo(xShape
, uno::UNO_QUERY
);
2789 bool bTextFrame
= xServiceInfo
->supportsService("com.sun.star.text.TextFrame");
2791 // The default is certainly not inline, but then what Word supports is just at-character.
2792 xPropertySet
->setPropertyValue(
2793 "AnchorType", uno::makeAny(text::TextContentAnchorType_AT_CHARACTER
));
2797 xPropertySet
->setPropertyValue("HoriOrientPosition",
2798 uno::makeAny(rDrawing
.getLeft()));
2799 xPropertySet
->setPropertyValue("VertOrientPosition",
2800 uno::makeAny(rDrawing
.getTop()));
2804 xShape
->setPosition(awt::Point(rDrawing
.getLeft(), rDrawing
.getTop()));
2806 xShape
->setSize(awt::Size(rDrawing
.getRight(), rDrawing
.getBottom()));
2808 if (rDrawing
.getHasLineColor())
2810 uno::Any aLineColor
= uno::makeAny(sal_uInt32((rDrawing
.getLineColorR() << 16)
2811 + (rDrawing
.getLineColorG() << 8)
2812 + rDrawing
.getLineColorB()));
2813 uno::Any aLineWidth
;
2814 RTFSdrImport::resolveLineColorAndWidth(bTextFrame
, xPropertySet
, aLineColor
,
2817 if (rDrawing
.getHasFillColor())
2818 xPropertySet
->setPropertyValue(
2819 "FillColor", uno::makeAny(sal_uInt32((rDrawing
.getFillColorR() << 16)
2820 + (rDrawing
.getFillColorG() << 8)
2821 + rDrawing
.getFillColorB())));
2822 else if (!bTextFrame
)
2823 // If there is no fill, the Word default is 100% transparency.
2824 xPropertySet
->setPropertyValue("FillTransparence",
2825 uno::makeAny(sal_Int32(100)));
2827 RTFSdrImport::resolveFLine(xPropertySet
, rDrawing
.getFLine());
2829 if (!m_aStates
.top().getDrawingObject().getHadShapeText())
2831 Mapper().startShape(xShape
);
2833 Mapper().endShape();
2836 case Destination::PICT
:
2837 // fdo#79319 ignore picture data if it's really a shape
2838 if (!m_pSdrImport
->isFakePict())
2840 resolvePict(true, m_pSdrImport
->getCurrentShape());
2842 m_bNeedFinalPar
= true;
2844 case Destination::SHAPE
:
2845 m_bNeedFinalPar
= true;
2846 m_bNeedCr
= m_bNeedCrOrig
;
2847 if (aState
.getFrame().inFrame())
2849 // parBreak() modifies m_aStates.top() so we can't apply resetFrame() directly on aState
2852 // Save this state for later use, so we only reset frame status only for the first shape inside a frame.
2853 aState
= m_aStates
.top();
2857 case Destination::MOMATH
:
2859 m_aMathBuffer
.appendClosingTag(M_TOKEN(oMath
));
2861 SvGlobalName
aGlobalName(SO3_SM_CLASSID
);
2862 comphelper::EmbeddedObjectContainer aContainer
;
2864 uno::Reference
<embed::XEmbeddedObject
> xObject
2865 = aContainer
.CreateEmbeddedObject(aGlobalName
.GetByteSequence(), aName
);
2866 if (xObject
) // rhbz#1766990 starmath might not be available
2868 uno::Reference
<util::XCloseable
> xComponent(xObject
->getComponent(),
2869 uno::UNO_SET_THROW
);
2870 // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
2871 // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
2872 // to RTLD_GLOBAL, so most probably a gcc bug.
2873 auto& rImport
= dynamic_cast<oox::FormulaImportBase
&>(
2874 dynamic_cast<SfxBaseModel
&>(*xComponent
));
2875 rImport
.readFormulaOoxml(m_aMathBuffer
);
2877 auto pValue
= new RTFValue(xObject
);
2878 RTFSprms aMathAttributes
;
2879 aMathAttributes
.set(NS_ooxml::LN_starmath
, pValue
);
2880 writerfilter::Reference
<Properties
>::Pointer_t pProperties
2881 = new RTFReferenceProperties(aMathAttributes
);
2882 Mapper().props(pProperties
);
2885 m_aMathBuffer
= oox::formulaimport::XmlStreamBuilder();
2888 case Destination::MR
:
2889 lcl_DestinationToMath(m_aStates
.top().getCurrentDestinationText(), m_aMathBuffer
,
2892 case Destination::MF
:
2893 m_aMathBuffer
.appendClosingTag(M_TOKEN(f
));
2895 case Destination::MFPR
:
2896 m_aMathBuffer
.appendClosingTag(M_TOKEN(fPr
));
2898 case Destination::MCTRLPR
:
2899 m_aMathBuffer
.appendClosingTag(M_TOKEN(ctrlPr
));
2901 case Destination::MNUM
:
2902 m_aMathBuffer
.appendClosingTag(M_TOKEN(num
));
2904 case Destination::MDEN
:
2905 m_aMathBuffer
.appendClosingTag(M_TOKEN(den
));
2907 case Destination::MACC
:
2908 m_aMathBuffer
.appendClosingTag(M_TOKEN(acc
));
2910 case Destination::MACCPR
:
2911 m_aMathBuffer
.appendClosingTag(M_TOKEN(accPr
));
2913 case Destination::MCHR
:
2914 case Destination::MPOS
:
2915 case Destination::MVERTJC
:
2916 case Destination::MSTRIKEH
:
2917 case Destination::MDEGHIDE
:
2918 case Destination::MBEGCHR
:
2919 case Destination::MSEPCHR
:
2920 case Destination::MENDCHR
:
2921 case Destination::MSUBHIDE
:
2922 case Destination::MSUPHIDE
:
2923 case Destination::MTYPE
:
2924 case Destination::MGROW
:
2926 sal_Int32 nMathToken
= 0;
2927 switch (aState
.getDestination())
2929 case Destination::MCHR
:
2930 nMathToken
= M_TOKEN(chr
);
2932 case Destination::MPOS
:
2933 nMathToken
= M_TOKEN(pos
);
2935 case Destination::MVERTJC
:
2936 nMathToken
= M_TOKEN(vertJc
);
2938 case Destination::MSTRIKEH
:
2939 nMathToken
= M_TOKEN(strikeH
);
2941 case Destination::MDEGHIDE
:
2942 nMathToken
= M_TOKEN(degHide
);
2944 case Destination::MBEGCHR
:
2945 nMathToken
= M_TOKEN(begChr
);
2947 case Destination::MSEPCHR
:
2948 nMathToken
= M_TOKEN(sepChr
);
2950 case Destination::MENDCHR
:
2951 nMathToken
= M_TOKEN(endChr
);
2953 case Destination::MSUBHIDE
:
2954 nMathToken
= M_TOKEN(subHide
);
2956 case Destination::MSUPHIDE
:
2957 nMathToken
= M_TOKEN(supHide
);
2959 case Destination::MTYPE
:
2960 nMathToken
= M_TOKEN(type
);
2962 case Destination::MGROW
:
2963 nMathToken
= M_TOKEN(grow
);
2969 oox::formulaimport::XmlStream::AttributeList aAttribs
;
2970 aAttribs
[M_TOKEN(val
)]
2971 = m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
2972 m_aMathBuffer
.appendOpeningTag(nMathToken
, aAttribs
);
2973 m_aMathBuffer
.appendClosingTag(nMathToken
);
2976 case Destination::ME
:
2977 m_aMathBuffer
.appendClosingTag(M_TOKEN(e
));
2979 case Destination::MBAR
:
2980 m_aMathBuffer
.appendClosingTag(M_TOKEN(bar
));
2982 case Destination::MBARPR
:
2983 m_aMathBuffer
.appendClosingTag(M_TOKEN(barPr
));
2985 case Destination::MD
:
2986 m_aMathBuffer
.appendClosingTag(M_TOKEN(d
));
2988 case Destination::MDPR
:
2989 m_aMathBuffer
.appendClosingTag(M_TOKEN(dPr
));
2991 case Destination::MFUNC
:
2992 m_aMathBuffer
.appendClosingTag(M_TOKEN(func
));
2994 case Destination::MFUNCPR
:
2995 m_aMathBuffer
.appendClosingTag(M_TOKEN(funcPr
));
2997 case Destination::MFNAME
:
2998 m_aMathBuffer
.appendClosingTag(M_TOKEN(fName
));
3000 case Destination::MLIMLOW
:
3001 m_aMathBuffer
.appendClosingTag(M_TOKEN(limLow
));
3003 case Destination::MLIMLOWPR
:
3004 m_aMathBuffer
.appendClosingTag(M_TOKEN(limLowPr
));
3006 case Destination::MLIM
:
3007 m_aMathBuffer
.appendClosingTag(M_TOKEN(lim
));
3009 case Destination::MM
:
3010 m_aMathBuffer
.appendClosingTag(M_TOKEN(m
));
3012 case Destination::MMPR
:
3013 m_aMathBuffer
.appendClosingTag(M_TOKEN(mPr
));
3015 case Destination::MMR
:
3016 m_aMathBuffer
.appendClosingTag(M_TOKEN(mr
));
3018 case Destination::MNARY
:
3019 m_aMathBuffer
.appendClosingTag(M_TOKEN(nary
));
3021 case Destination::MNARYPR
:
3022 m_aMathBuffer
.appendClosingTag(M_TOKEN(naryPr
));
3024 case Destination::MSUB
:
3025 m_aMathBuffer
.appendClosingTag(M_TOKEN(sub
));
3027 case Destination::MSUP
:
3028 m_aMathBuffer
.appendClosingTag(M_TOKEN(sup
));
3030 case Destination::MLIMUPP
:
3031 m_aMathBuffer
.appendClosingTag(M_TOKEN(limUpp
));
3033 case Destination::MLIMUPPPR
:
3034 m_aMathBuffer
.appendClosingTag(M_TOKEN(limUppPr
));
3036 case Destination::MGROUPCHR
:
3037 m_aMathBuffer
.appendClosingTag(M_TOKEN(groupChr
));
3039 case Destination::MGROUPCHRPR
:
3040 m_aMathBuffer
.appendClosingTag(M_TOKEN(groupChrPr
));
3042 case Destination::MBORDERBOX
:
3043 m_aMathBuffer
.appendClosingTag(M_TOKEN(borderBox
));
3045 case Destination::MBORDERBOXPR
:
3046 m_aMathBuffer
.appendClosingTag(M_TOKEN(borderBoxPr
));
3048 case Destination::MRAD
:
3049 m_aMathBuffer
.appendClosingTag(M_TOKEN(rad
));
3051 case Destination::MRADPR
:
3052 m_aMathBuffer
.appendClosingTag(M_TOKEN(radPr
));
3054 case Destination::MDEG
:
3055 m_aMathBuffer
.appendClosingTag(M_TOKEN(deg
));
3057 case Destination::MSSUB
:
3058 m_aMathBuffer
.appendClosingTag(M_TOKEN(sSub
));
3060 case Destination::MSSUBPR
:
3061 m_aMathBuffer
.appendClosingTag(M_TOKEN(sSubPr
));
3063 case Destination::MSSUP
:
3064 m_aMathBuffer
.appendClosingTag(M_TOKEN(sSup
));
3066 case Destination::MSSUPPR
:
3067 m_aMathBuffer
.appendClosingTag(M_TOKEN(sSupPr
));
3069 case Destination::MSSUBSUP
:
3070 m_aMathBuffer
.appendClosingTag(M_TOKEN(sSubSup
));
3072 case Destination::MSSUBSUPPR
:
3073 m_aMathBuffer
.appendClosingTag(M_TOKEN(sSubSupPr
));
3075 case Destination::MSPRE
:
3076 m_aMathBuffer
.appendClosingTag(M_TOKEN(sPre
));
3078 case Destination::MSPREPR
:
3079 m_aMathBuffer
.appendClosingTag(M_TOKEN(sPrePr
));
3081 case Destination::MBOX
:
3082 m_aMathBuffer
.appendClosingTag(M_TOKEN(box
));
3084 case Destination::MEQARR
:
3085 m_aMathBuffer
.appendClosingTag(M_TOKEN(eqArr
));
3087 case Destination::SHAPEGROUP
:
3088 if (aState
.getCreatedShapeGroup())
3089 m_pSdrImport
->popParent();
3091 case Destination::PROPNAME
:
3092 if (&m_aStates
.top().getDestinationText()
3093 != m_aStates
.top().getCurrentDestinationText())
3094 break; // not for nested group
3095 aState
.setPropName(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear());
3097 case Destination::STATICVAL
:
3098 if (&m_aStates
.top().getDestinationText()
3099 != m_aStates
.top().getCurrentDestinationText())
3100 break; // not for nested group
3101 if (m_xDocumentProperties
.is())
3103 // Find out what is the key, value type and value we want to set.
3104 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
3105 = m_xDocumentProperties
->getUserDefinedProperties();
3106 const OUString
& rKey
= m_aStates
.top().getPropName();
3108 = m_aStates
.top().getCurrentDestinationText()->makeStringAndClear();
3110 if (m_aStates
.top().getPropType() == cppu::UnoType
<OUString
>::get())
3111 aAny
<<= aStaticVal
;
3112 else if (m_aStates
.top().getPropType() == cppu::UnoType
<sal_Int32
>::get())
3113 aAny
<<= aStaticVal
.toInt32();
3114 else if (m_aStates
.top().getPropType() == cppu::UnoType
<bool>::get())
3115 aAny
<<= aStaticVal
.toBoolean();
3116 else if (m_aStates
.top().getPropType() == cppu::UnoType
<util::DateTime
>::get())
3117 aAny
<<= getDateTimeFromUserProp(aStaticVal
);
3118 else if (m_aStates
.top().getPropType() == cppu::UnoType
<double>::get())
3119 aAny
<<= aStaticVal
.toDouble();
3121 xPropertyContainer
->addProperty(rKey
, beans::PropertyAttribute::REMOVABLE
, aAny
);
3124 case Destination::USERPROPS
:
3126 // These are the imported properties.
3127 uno::Reference
<document::XDocumentProperties
> xDocumentProperties
3128 = m_xDocumentProperties
;
3130 // These are the real document properties.
3131 uno::Reference
<document::XDocumentPropertiesSupplier
> xDocumentPropertiesSupplier(
3132 m_xDstDoc
, uno::UNO_QUERY
);
3133 if (xDocumentPropertiesSupplier
.is())
3134 m_xDocumentProperties
= xDocumentPropertiesSupplier
->getDocumentProperties();
3136 if (m_xDocumentProperties
.is())
3140 // Check classification.
3141 if (!SfxClassificationHelper::ShowPasteInfo(SfxClassificationHelper::CheckPaste(
3142 xDocumentProperties
, m_xDocumentProperties
)))
3143 return RTFError::CLASSIFICATION
;
3146 uno::Reference
<beans::XPropertyContainer
> xClipboardPropertyContainer
3147 = xDocumentProperties
->getUserDefinedProperties();
3148 uno::Reference
<beans::XPropertyContainer
> xDocumentPropertyContainer
3149 = m_xDocumentProperties
->getUserDefinedProperties();
3150 uno::Reference
<beans::XPropertySet
> xClipboardPropertySet(
3151 xClipboardPropertyContainer
, uno::UNO_QUERY
);
3152 uno::Reference
<beans::XPropertySet
> xDocumentPropertySet(xDocumentPropertyContainer
,
3154 const uno::Sequence
<beans::Property
> aClipboardProperties
3155 = xClipboardPropertySet
->getPropertySetInfo()->getProperties();
3156 uno::Sequence
<beans::Property
> aDocumentProperties
3157 = xDocumentPropertySet
->getPropertySetInfo()->getProperties();
3159 for (const beans::Property
& rProperty
: aClipboardProperties
)
3161 const OUString
& rKey
= rProperty
.Name
;
3162 uno::Any aValue
= xClipboardPropertySet
->getPropertyValue(rKey
);
3166 if (lcl_containsProperty(aDocumentProperties
, rKey
))
3168 // When pasting, don't update existing properties.
3170 xDocumentPropertySet
->setPropertyValue(rKey
, aValue
);
3173 xDocumentPropertyContainer
->addProperty(
3174 rKey
, beans::PropertyAttribute::REMOVABLE
, aValue
);
3176 catch (const uno::Exception
&)
3178 TOOLS_WARN_EXCEPTION("writerfilter.rtf", "failed to set property " << rKey
);
3188 // See if we need to end a track change
3189 if (aState
.getStartedTrackchange())
3192 auto pValue
= new RTFValue(0);
3193 aTCSprms
.set(NS_ooxml::LN_endtrackchange
, pValue
);
3194 if (!m_aStates
.top().getCurrentBuffer())
3195 Mapper().props(new RTFReferenceProperties(RTFSprms(), aTCSprms
));
3197 bufferProperties(*m_aStates
.top().getCurrentBuffer(),
3198 new RTFValue(RTFSprms(), aTCSprms
), nullptr);
3201 // This is the end of the doc, see if we need to close the last section.
3202 if (m_pTokenizer
->getGroup() == 1 && !m_bFirstRun
)
3204 // \par means an empty paragraph at the end of footnotes/endnotes, but
3205 // not in case of other substreams, like headers.
3207 && !(m_nStreamType
== NS_ooxml::LN_footnote
|| m_nStreamType
== NS_ooxml::LN_endnote
)
3209 dispatchSymbol(RTF_PAR
);
3210 if (m_bNeedSect
) // may be set by dispatchSymbol above!
3216 m_pTokenizer
->popGroup();
3219 switch (aState
.getDestination())
3221 case Destination::LISTENTRY
:
3223 auto pValue
= new RTFValue(aState
.getTableAttributes(), aState
.getTableSprms());
3224 m_aListTableSprms
.set(NS_ooxml::LN_CT_Numbering_abstractNum
, pValue
,
3225 RTFOverwrite::NO_APPEND
);
3226 m_aListTable
[aState
.getCurrentListIndex()] = pValue
;
3228 m_aInvalidListTableFirstIndents
[aState
.getCurrentListIndex()]
3229 = m_aInvalidListLevelFirstIndents
;
3230 m_aInvalidListLevelFirstIndents
.clear();
3233 case Destination::PARAGRAPHNUMBERING
:
3235 RTFValue::Pointer_t pIdValue
3236 = aState
.getTableAttributes().find(NS_ooxml::LN_CT_AbstractNum_nsid
);
3237 if (pIdValue
.get() && !m_aStates
.empty())
3239 // Abstract numbering
3240 RTFSprms aLeveltextAttributes
;
3241 OUString aTextValue
;
3242 RTFValue::Pointer_t pTextBefore
3243 = aState
.getTableAttributes().find(NS_ooxml::LN_CT_LevelText_val
);
3245 aTextValue
+= pTextBefore
->getString();
3247 RTFValue::Pointer_t pTextAfter
3248 = aState
.getTableAttributes().find(NS_ooxml::LN_CT_LevelSuffix_val
);
3250 aTextValue
+= pTextAfter
->getString();
3251 auto pTextValue
= new RTFValue(aTextValue
);
3252 aLeveltextAttributes
.set(NS_ooxml::LN_CT_LevelText_val
, pTextValue
);
3254 RTFSprms aLevelAttributes
;
3255 RTFSprms aLevelSprms
;
3256 auto pIlvlValue
= new RTFValue(0);
3257 aLevelAttributes
.set(NS_ooxml::LN_CT_Lvl_ilvl
, pIlvlValue
);
3259 RTFValue::Pointer_t pFmtValue
3260 = aState
.getTableSprms().find(NS_ooxml::LN_CT_Lvl_numFmt
);
3262 aLevelSprms
.set(NS_ooxml::LN_CT_Lvl_numFmt
, pFmtValue
);
3264 RTFValue::Pointer_t pStartatValue
3265 = aState
.getTableSprms().find(NS_ooxml::LN_CT_Lvl_start
);
3267 aLevelSprms
.set(NS_ooxml::LN_CT_Lvl_start
, pStartatValue
);
3269 auto pLeveltextValue
= new RTFValue(aLeveltextAttributes
);
3270 aLevelSprms
.set(NS_ooxml::LN_CT_Lvl_lvlText
, pLeveltextValue
);
3271 RTFValue::Pointer_t pRunProps
3272 = aState
.getTableSprms().find(NS_ooxml::LN_CT_Lvl_rPr
);
3274 aLevelSprms
.set(NS_ooxml::LN_CT_Lvl_rPr
, pRunProps
);
3276 RTFSprms aAbstractAttributes
;
3277 RTFSprms aAbstractSprms
;
3278 aAbstractAttributes
.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId
, pIdValue
);
3279 auto pLevelValue
= new RTFValue(aLevelAttributes
, aLevelSprms
);
3280 aAbstractSprms
.set(NS_ooxml::LN_CT_AbstractNum_lvl
, pLevelValue
,
3281 RTFOverwrite::NO_APPEND
);
3283 RTFSprms aListTableSprms
;
3284 auto pAbstractValue
= new RTFValue(aAbstractAttributes
, aAbstractSprms
);
3285 // It's important that Numbering_abstractNum and Numbering_num never overwrites previous values.
3286 aListTableSprms
.set(NS_ooxml::LN_CT_Numbering_abstractNum
, pAbstractValue
,
3287 RTFOverwrite::NO_APPEND
);
3290 RTFSprms aNumberingAttributes
;
3291 RTFSprms aNumberingSprms
;
3292 aNumberingAttributes
.set(NS_ooxml::LN_CT_AbstractNum_nsid
, pIdValue
);
3293 aNumberingSprms
.set(NS_ooxml::LN_CT_Num_abstractNumId
, pIdValue
);
3294 auto pNumberingValue
= new RTFValue(aNumberingAttributes
, aNumberingSprms
);
3295 aListTableSprms
.set(NS_ooxml::LN_CT_Numbering_num
, pNumberingValue
,
3296 RTFOverwrite::NO_APPEND
);
3299 RTFSprms aListTableAttributes
;
3300 writerfilter::Reference
<Properties
>::Pointer_t pProp
3301 = new RTFReferenceProperties(aListTableAttributes
, aListTableSprms
);
3303 RTFReferenceTable::Entries_t aListTableEntries
;
3304 aListTableEntries
.insert(std::make_pair(0, pProp
));
3305 writerfilter::Reference
<Table
>::Pointer_t
const pTable(
3306 new RTFReferenceTable(aListTableEntries
));
3307 Mapper().table(NS_ooxml::LN_NUMBERING
, pTable
);
3310 putNestedSprm(m_aStates
.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr
,
3311 NS_ooxml::LN_CT_NumPr_ilvl
, pIlvlValue
);
3312 putNestedSprm(m_aStates
.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr
,
3313 NS_ooxml::LN_CT_NumPr_numId
, pIdValue
);
3317 case Destination::PARAGRAPHNUMBERING_TEXTAFTER
:
3318 if (!m_aStates
.empty())
3320 // FIXME: don't use pDestinationText, points to popped state
3321 auto pValue
= new RTFValue(aState
.getDestinationText().makeStringAndClear(), true);
3322 m_aStates
.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelSuffix_val
, pValue
);
3325 case Destination::PARAGRAPHNUMBERING_TEXTBEFORE
:
3326 if (!m_aStates
.empty())
3328 // FIXME: don't use pDestinationText, points to popped state
3329 auto pValue
= new RTFValue(aState
.getDestinationText().makeStringAndClear(), true);
3330 m_aStates
.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val
, pValue
);
3333 case Destination::LISTNAME
:
3335 case Destination::LISTLEVEL
:
3336 if (!m_aStates
.empty())
3338 auto pInnerValue
= new RTFValue(m_aStates
.top().getListLevelNum()++);
3339 aState
.getTableAttributes().set(NS_ooxml::LN_CT_Lvl_ilvl
, pInnerValue
);
3341 auto pValue
= new RTFValue(aState
.getTableAttributes(), aState
.getTableSprms());
3342 if (m_aStates
.top().getDestination() != Destination::LFOLEVEL
)
3343 m_aStates
.top().getListLevelEntries().set(NS_ooxml::LN_CT_AbstractNum_lvl
,
3344 pValue
, RTFOverwrite::NO_APPEND
);
3346 m_aStates
.top().getTableSprms().set(NS_ooxml::LN_CT_NumLvl_lvl
, pValue
);
3349 case Destination::LFOLEVEL
:
3350 if (!m_aStates
.empty())
3352 auto pInnerValue
= new RTFValue(m_aStates
.top().getListLevelNum()++);
3353 aState
.getTableAttributes().set(NS_ooxml::LN_CT_NumLvl_ilvl
, pInnerValue
);
3355 auto pValue
= new RTFValue(aState
.getTableAttributes(), aState
.getTableSprms());
3356 m_aStates
.top().getTableSprms().set(NS_ooxml::LN_CT_Num_lvlOverride
, pValue
,
3357 RTFOverwrite::NO_APPEND
);
3360 // list override table
3361 case Destination::LISTOVERRIDEENTRY
:
3362 if (!m_aStates
.empty())
3364 if (m_aStates
.top().getDestination() == Destination::LISTOVERRIDEENTRY
)
3366 // copy properties upwards so upper popState() inserts it
3367 m_aStates
.top().getTableAttributes() = aState
.getTableAttributes();
3368 m_aStates
.top().getTableSprms() = aState
.getTableSprms();
3372 auto pValue
= new RTFValue(aState
.getTableAttributes(), aState
.getTableSprms());
3373 m_aListTableSprms
.set(NS_ooxml::LN_CT_Numbering_num
, pValue
,
3374 RTFOverwrite::NO_APPEND
);
3375 m_aListOverrideTable
[aState
.getCurrentListOverrideIndex()]
3376 = aState
.getCurrentListIndex();
3380 case Destination::LEVELTEXT
:
3381 if (!m_aStates
.empty())
3383 auto pValue
= new RTFValue(aState
.getTableAttributes());
3384 m_aStates
.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_lvlText
, pValue
);
3387 case Destination::LEVELNUMBERS
:
3388 if (!m_aStates
.empty())
3390 m_aStates
.top().getTableSprms() = aState
.getTableSprms();
3391 if (m_aStates
.top().getDestination() == Destination::LEVELNUMBERS
3392 || m_aStates
.top().getDestination() == Destination::LISTLEVEL
)
3393 // Parent state is level number or list level, current state is
3394 // level numbers: mark parent as invalid as well if necessary.
3395 m_aStates
.top().setLevelNumbersValid(aState
.getLevelNumbersValid());
3398 case Destination::FIELDINSTRUCTION
:
3399 if (!m_aStates
.empty())
3400 m_aStates
.top().setFieldStatus(RTFFieldStatus::INSTRUCTION
);
3402 case Destination::FIELDRESULT
:
3403 if (!m_aStates
.empty())
3404 m_aStates
.top().setFieldStatus(RTFFieldStatus::RESULT
);
3406 case Destination::FIELD
:
3407 if (aState
.getFieldStatus() == RTFFieldStatus::INSTRUCTION
)
3408 singleChar(cFieldEnd
);
3410 case Destination::SHAPEPROPERTYVALUEPICT
:
3411 if (!m_aStates
.empty())
3413 m_aStates
.top().getPicture() = aState
.getPicture();
3414 // both \sp and \sv are destinations, copy the text up-ward for later
3415 m_aStates
.top().getDestinationText() = aState
.getDestinationText();
3418 case Destination::FALT
:
3419 if (!m_aStates
.empty())
3420 m_aStates
.top().getTableSprms() = aState
.getTableSprms();
3422 case Destination::SHAPEPROPERTYNAME
:
3423 case Destination::SHAPEPROPERTYVALUE
:
3424 case Destination::SHAPEPROPERTY
:
3425 if (!m_aStates
.empty())
3427 m_aStates
.top().getShape() = aState
.getShape();
3428 m_aStates
.top().getPicture() = aState
.getPicture();
3429 m_aStates
.top().getCharacterAttributes() = aState
.getCharacterAttributes();
3432 case Destination::SHAPEINSTRUCTION
:
3433 if (!m_aStates
.empty()
3434 && m_aStates
.top().getDestination() == Destination::SHAPEINSTRUCTION
)
3436 // Shape instruction inside other shape instruction: just copy new shape settings:
3437 // it will be resolved on end of topmost shape instruction destination
3438 m_aStates
.top().getShape() = aState
.getShape();
3439 m_aStates
.top().getPicture() = aState
.getPicture();
3440 m_aStates
.top().getCharacterSprms() = aState
.getCharacterSprms();
3441 m_aStates
.top().getCharacterAttributes() = aState
.getCharacterAttributes();
3444 case Destination::FLYMAINCONTENT
:
3445 case Destination::SHPPICT
:
3446 case Destination::SHAPE
:
3447 if (!m_aStates
.empty())
3449 m_aStates
.top().getFrame() = aState
.getFrame();
3450 if (aState
.getDestination() == Destination::SHPPICT
3451 && m_aStates
.top().getDestination() == Destination::LISTPICTURE
)
3453 RTFSprms aAttributes
;
3454 aAttributes
.set(NS_ooxml::LN_CT_NumPicBullet_numPicBulletId
,
3455 new RTFValue(m_nListPictureId
++));
3457 // Dummy value, real picture is already sent to dmapper.
3458 aSprms
.set(NS_ooxml::LN_CT_NumPicBullet_pict
, new RTFValue(0));
3459 auto pValue
= new RTFValue(aAttributes
, aSprms
);
3460 m_aListTableSprms
.set(NS_ooxml::LN_CT_Numbering_numPicBullet
, pValue
,
3461 RTFOverwrite::NO_APPEND
);
3465 case Destination::SHAPETEXT
:
3466 if (!m_aStates
.empty())
3468 // If we're leaving the shapetext group (it may have nested ones) and this is a shape, not an old drawingobject.
3469 if (m_aStates
.top().getDestination() != Destination::SHAPETEXT
3470 && !m_aStates
.top().getDrawingObject().getHadShapeText())
3472 m_aStates
.top().setHadShapeText(true);
3473 if (!m_aStates
.top().getCurrentBuffer())
3474 m_pSdrImport
->close();
3476 m_aStates
.top().getCurrentBuffer()->push_back(
3477 Buf_t(BUFFER_ENDSHAPE
, nullptr, nullptr));
3480 // It's allowed to declare these inside the shape text, and they
3481 // are expected to have an effect for the whole shape.
3482 if (aState
.getDrawingObject().getLeft())
3483 m_aStates
.top().getDrawingObject().setLeft(aState
.getDrawingObject().getLeft());
3484 if (aState
.getDrawingObject().getTop())
3485 m_aStates
.top().getDrawingObject().setTop(aState
.getDrawingObject().getTop());
3486 if (aState
.getDrawingObject().getRight())
3487 m_aStates
.top().getDrawingObject().setRight(
3488 aState
.getDrawingObject().getRight());
3489 if (aState
.getDrawingObject().getBottom())
3490 m_aStates
.top().getDrawingObject().setBottom(
3491 aState
.getDrawingObject().getBottom());
3494 case Destination::PROPNAME
:
3495 if (m_aStates
.top().getDestination() == Destination::USERPROPS
)
3496 m_aStates
.top().setPropName(aState
.getPropName());
3500 if (!m_aStates
.empty() && m_aStates
.top().getDestination() == Destination::PICT
)
3501 m_aStates
.top().getPicture() = aState
.getPicture();
3506 if (aState
.getCurrentBuffer() == &m_aSuperBuffer
)
3508 OSL_ASSERT(!m_aStates
.empty() && m_aStates
.top().getCurrentBuffer() == nullptr);
3510 if (!m_aSuperBuffer
.empty())
3511 replayBuffer(m_aSuperBuffer
, nullptr, nullptr);
3514 if (!m_aStates
.empty() && m_aStates
.top().getTableRowWidthAfter() > 0
3515 && aState
.getTableRowWidthAfter() == 0)
3516 // An RTF_ROW in the inner group already parsed nTableRowWidthAfter,
3517 // don't do it again in the outer state later.
3518 m_aStates
.top().setTableRowWidthAfter(0);
3520 if (m_nResetBreakOnSectBreak
!= RTF_invalid
&& !m_aStates
.empty())
3522 // Section break type created for \page still has an effect in the
3523 // outer state as well.
3524 RTFValue::Pointer_t pType
3525 = aState
.getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type
);
3527 m_aStates
.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type
, pType
);
3530 return RTFError::OK
;
3533 RTFError
RTFDocumentImpl::handleEmbeddedObject()
3536 = OUStringToOString(m_aStates
.top().getCurrentDestinationText()->makeStringAndClear(),
3537 RTL_TEXTENCODING_ASCII_US
);
3538 std::unique_ptr
<SvStream
> pStream(new SvMemoryStream());
3539 if (!msfilter::rtfutil::ExtractOLE2FromObjdata(aStr
, *pStream
))
3540 return RTFError::HEX_INVALID
;
3542 uno::Reference
<io::XInputStream
> xInputStream(
3543 new utl::OSeekableInputStreamWrapper(pStream
.release(), /*_bOwner=*/true));
3544 auto pStreamValue
= new RTFValue(xInputStream
);
3545 m_aOLEAttributes
.set(NS_ooxml::LN_inputstream
, pStreamValue
);
3547 return RTFError::OK
;
3550 bool RTFDocumentImpl::isInBackground() { return m_aStates
.top().getInBackground(); }
3552 RTFInternalState
RTFDocumentImpl::getInternalState() { return m_aStates
.top().getInternalState(); }
3554 void RTFDocumentImpl::setInternalState(RTFInternalState nInternalState
)
3556 m_aStates
.top().setInternalState(nInternalState
);
3559 Destination
RTFDocumentImpl::getDestination() { return m_aStates
.top().getDestination(); }
3561 void RTFDocumentImpl::setDestination(Destination eDestination
)
3563 m_aStates
.top().setDestination(eDestination
);
3566 // this is a questionably named method that is used only in a very special
3567 // situation where it looks like the "current" buffer is needed?
3568 void RTFDocumentImpl::setDestinationText(OUString
const& rString
)
3570 m_aStates
.top().getDestinationText().setLength(0);
3571 m_aStates
.top().getDestinationText().append(rString
);
3574 bool RTFDocumentImpl::getSkipUnknown() { return m_bSkipUnknown
; }
3576 void RTFDocumentImpl::setSkipUnknown(bool bSkipUnknown
) { m_bSkipUnknown
= bSkipUnknown
; }
3578 static auto FilterControlChars(Destination
const destination
, OUString
const& rString
) -> OUString
3580 if (destination
== Destination::LEVELNUMBERS
|| destination
== Destination::LEVELTEXT
)
3581 { // control characters are magic here!
3584 OUStringBuffer
buf(rString
.getLength());
3585 for (sal_Int32 i
= 0; i
< rString
.getLength(); ++i
)
3587 sal_Unicode
const ch(rString
[i
]);
3588 if (!linguistic::IsControlChar(ch
) || ch
== '\r' || ch
== '\n' || ch
== '\t')
3594 SAL_INFO("writerfilter.rtf", "filtering control character");
3597 return buf
.makeStringAndClear();
3600 void RTFDocumentImpl::checkUnicode(bool bUnicode
, bool bHex
)
3602 if (bUnicode
&& !m_aUnicodeBuffer
.isEmpty())
3604 OUString aString
= m_aUnicodeBuffer
.toString();
3605 m_aUnicodeBuffer
.setLength(0);
3606 aString
= FilterControlChars(m_aStates
.top().getDestination(), aString
);
3609 if (bHex
&& !m_aHexBuffer
.isEmpty())
3611 rtl_TextEncoding nEncoding
= m_aStates
.top().getCurrentEncoding();
3612 if (m_aStates
.top().getDestination() == Destination::FONTENTRY
3613 && m_aStates
.top().getCurrentEncoding() == RTL_TEXTENCODING_SYMBOL
)
3614 nEncoding
= RTL_TEXTENCODING_MS_1252
;
3615 OUString aString
= OStringToOUString(m_aHexBuffer
.toString(), nEncoding
);
3616 m_aHexBuffer
.setLength(0);
3617 aString
= FilterControlChars(m_aStates
.top().getDestination(), aString
);
3622 RTFParserState::RTFParserState(RTFDocumentImpl
* pDocumentImpl
)
3623 : m_pDocumentImpl(pDocumentImpl
)
3624 , m_nInternalState(RTFInternalState::NORMAL
)
3625 , m_eDestination(Destination::NORMAL
)
3626 , m_eFieldStatus(RTFFieldStatus::NONE
)
3627 , m_nBorderState(RTFBorderState::NONE
)
3628 , m_nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0))
3631 , m_nBinaryToRead(0)
3632 , m_nListLevelNum(0)
3633 , m_bLevelNumbersValid(true)
3635 , m_eRunType(RunType::NONE
)
3641 , m_pCurrentDestinationText(nullptr)
3642 , m_nCurrentStyleIndex(-1)
3643 , m_nCurrentCharacterStyleIndex(-1)
3644 , m_pCurrentBuffer(nullptr)
3645 , m_bInListpicture(false)
3646 , m_bInBackground(false)
3647 , m_bHadShapeText(false)
3648 , m_bInShapeGroup(false)
3650 , m_bCreatedShapeGroup(false)
3651 , m_bStartedTrackchange(false)
3652 , m_nTableRowWidthAfter(0)
3656 void RTFDocumentImpl::resetFrame() { m_aStates
.top().getFrame() = RTFFrame(&m_aStates
.top()); }
3658 void RTFDocumentImpl::bufferProperties(RTFBuffer_t
& rBuffer
, const RTFValue::Pointer_t
& pValue
,
3659 const tools::SvRef
<TableRowBuffer
>& pTableProperties
)
3661 rBuffer
.emplace_back(
3662 Buf_t(BUFFER_SETSTYLE
, new RTFValue(m_aStates
.top().getCurrentStyleIndex()), nullptr));
3663 rBuffer
.emplace_back(Buf_t(BUFFER_PROPS
, pValue
, pTableProperties
));
3666 RTFShape::RTFShape() = default;
3668 RTFDrawingObject::RTFDrawingObject() = default;
3670 RTFFrame::RTFFrame(RTFParserState
* pParserState
)
3671 : m_pDocumentImpl(pParserState
->getDocumentImpl())
3682 , m_nHRule(NS_ooxml::LN_Value_doc_ST_HeightRule_auto
)
3686 void RTFFrame::setSprm(Id nId
, Id nValue
)
3688 if (m_pDocumentImpl
->getFirstRun() && !m_pDocumentImpl
->isStyleSheetImport())
3690 m_pDocumentImpl
->checkFirstRun();
3691 m_pDocumentImpl
->setNeedPar(false);
3695 case NS_ooxml::LN_CT_FramePr_w
:
3698 case NS_ooxml::LN_CT_FramePr_h
:
3701 case NS_ooxml::LN_CT_FramePr_x
:
3704 case NS_ooxml::LN_CT_FramePr_y
:
3707 case NS_ooxml::LN_CT_FramePr_hSpace
:
3708 m_nHoriPadding
= nValue
;
3710 case NS_ooxml::LN_CT_FramePr_vSpace
:
3711 m_nVertPadding
= nValue
;
3713 case NS_ooxml::LN_CT_FramePr_xAlign
:
3714 m_nHoriAlign
= nValue
;
3716 case NS_ooxml::LN_CT_FramePr_hAnchor
:
3717 m_nHoriAnchor
= nValue
;
3719 case NS_ooxml::LN_CT_FramePr_yAlign
:
3720 m_nVertAlign
= nValue
;
3722 case NS_ooxml::LN_CT_FramePr_vAnchor
:
3723 m_nVertAnchor
= nValue
;
3725 case NS_ooxml::LN_CT_FramePr_wrap
:
3733 RTFSprms
RTFFrame::getSprms()
3737 static const Id pNames
[]
3738 = { NS_ooxml::LN_CT_FramePr_x
, NS_ooxml::LN_CT_FramePr_y
,
3739 NS_ooxml::LN_CT_FramePr_hRule
, // Make sure nHRule is processed before nH
3740 NS_ooxml::LN_CT_FramePr_h
, NS_ooxml::LN_CT_FramePr_w
,
3741 NS_ooxml::LN_CT_FramePr_hSpace
, NS_ooxml::LN_CT_FramePr_vSpace
,
3742 NS_ooxml::LN_CT_FramePr_hAnchor
, NS_ooxml::LN_CT_FramePr_vAnchor
,
3743 NS_ooxml::LN_CT_FramePr_xAlign
, NS_ooxml::LN_CT_FramePr_yAlign
,
3744 NS_ooxml::LN_CT_FramePr_wrap
, NS_ooxml::LN_CT_FramePr_dropCap
,
3745 NS_ooxml::LN_CT_FramePr_lines
};
3747 for (Id nId
: pNames
)
3749 RTFValue::Pointer_t pValue
;
3753 case NS_ooxml::LN_CT_FramePr_x
:
3755 pValue
= new RTFValue(m_nX
);
3757 case NS_ooxml::LN_CT_FramePr_y
:
3759 pValue
= new RTFValue(m_nY
);
3761 case NS_ooxml::LN_CT_FramePr_h
:
3764 if (m_nHRule
== NS_ooxml::LN_Value_doc_ST_HeightRule_exact
)
3765 pValue
= new RTFValue(-m_nH
); // The negative value just sets nHRule
3767 pValue
= new RTFValue(m_nH
);
3770 case NS_ooxml::LN_CT_FramePr_w
:
3772 pValue
= new RTFValue(m_nW
);
3774 case NS_ooxml::LN_CT_FramePr_hSpace
:
3775 if (m_nHoriPadding
!= 0)
3776 pValue
= new RTFValue(m_nHoriPadding
);
3778 case NS_ooxml::LN_CT_FramePr_vSpace
:
3779 if (m_nVertPadding
!= 0)
3780 pValue
= new RTFValue(m_nVertPadding
);
3782 case NS_ooxml::LN_CT_FramePr_hAnchor
:
3784 if (m_nHoriAnchor
== 0)
3785 m_nHoriAnchor
= NS_ooxml::LN_Value_doc_ST_HAnchor_margin
;
3786 pValue
= new RTFValue(m_nHoriAnchor
);
3789 case NS_ooxml::LN_CT_FramePr_vAnchor
:
3791 if (m_nVertAnchor
== 0)
3792 m_nVertAnchor
= NS_ooxml::LN_Value_doc_ST_VAnchor_margin
;
3793 pValue
= new RTFValue(m_nVertAnchor
);
3796 case NS_ooxml::LN_CT_FramePr_xAlign
:
3797 pValue
= new RTFValue(m_nHoriAlign
);
3799 case NS_ooxml::LN_CT_FramePr_yAlign
:
3800 pValue
= new RTFValue(m_nVertAlign
);
3802 case NS_ooxml::LN_CT_FramePr_hRule
:
3805 m_nHRule
= NS_ooxml::LN_Value_doc_ST_HeightRule_exact
;
3807 m_nHRule
= NS_ooxml::LN_Value_doc_ST_HeightRule_atLeast
;
3808 pValue
= new RTFValue(m_nHRule
);
3811 case NS_ooxml::LN_CT_FramePr_wrap
:
3813 pValue
= new RTFValue(*m_oWrap
);
3820 sprms
.set(nId
, pValue
);
3823 RTFSprms frameprSprms
;
3824 frameprSprms
.set(NS_ooxml::LN_CT_PPrBase_framePr
, new RTFValue(sprms
));
3825 return frameprSprms
;
3828 bool RTFFrame::hasProperties() const
3830 return m_nX
!= 0 || m_nY
!= 0 || m_nW
!= 0 || m_nH
!= 0 || m_nHoriPadding
!= 0
3831 || m_nVertPadding
!= 0 || m_nHoriAlign
!= 0 || m_nHoriAnchor
!= 0 || m_nVertAlign
!= 0
3832 || m_nVertAnchor
!= 0;
3835 } // namespace rtftok
3836 } // namespace writerfilter
3838 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */