summaryrefslogtreecommitdiff
path: root/writerfilter/source/rtftok/rtfdocumentimpl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'writerfilter/source/rtftok/rtfdocumentimpl.cxx')
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.cxx4062
1 files changed, 0 insertions, 4062 deletions
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
deleted file mode 100644
index ab700ff0dc14..000000000000
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ /dev/null
@@ -1,4062 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#include "rtfdocumentimpl.hxx"
-
-#include <algorithm>
-#include <memory>
-#include <string_view>
-
-#include <com/sun/star/embed/XEmbeddedObject.hpp>
-#include <com/sun/star/beans/PropertyAttribute.hpp>
-#include <com/sun/star/io/WrongFormatException.hpp>
-#include <com/sun/star/lang/XServiceInfo.hpp>
-#include <com/sun/star/lang/XMultiServiceFactory.hpp>
-#include <com/sun/star/text/TextContentAnchorType.hpp>
-#include <com/sun/star/text/XDependentTextField.hpp>
-#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
-
-#include <i18nlangtag/languagetag.hxx>
-#include <unotools/ucbstreamhelper.hxx>
-#include <unotools/streamwrap.hxx>
-#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
-#include <filter/msfilter/util.hxx>
-#include <filter/msfilter/rtfutil.hxx>
-#include <comphelper/string.hxx>
-#include <comphelper/diagnose_ex.hxx>
-#include <tools/globname.hxx>
-#include <tools/datetimeutils.hxx>
-#include <comphelper/classids.hxx>
-#include <comphelper/embeddedobjectcontainer.hxx>
-#include <svl/lngmisc.hxx>
-#include <sfx2/classificationhelper.hxx>
-#include <oox/mathml/imexport.hxx>
-#include <ooxml/resourceids.hxx>
-#include <oox/token/namespaces.hxx>
-#include <oox/drawingml/drawingmltypes.hxx>
-#include <rtl/uri.hxx>
-#include <rtl/tencinfo.h>
-#include <sal/log.hxx>
-#include <osl/diagnose.h>
-#include <oox/helper/graphichelper.hxx>
-#include <vcl/wmfexternal.hxx>
-#include <vcl/graph.hxx>
-#include <vcl/settings.hxx>
-#include <vcl/svapp.hxx>
-#include "rtfsdrimport.hxx"
-#include "rtfreferenceproperties.hxx"
-#include "rtfskipdestination.hxx"
-#include "rtftokenizer.hxx"
-#include "rtflookahead.hxx"
-#include "rtfcharsets.hxx"
-
-using namespace com::sun::star;
-
-namespace
-{
-/// Returns an util::DateTime from a 'YYYY. MM. DD.' string.
-util::DateTime getDateTimeFromUserProp(std::u16string_view rString)
-{
- util::DateTime aRet;
- size_t nLen = rString.size();
- if (nLen >= 4)
- {
- aRet.Year = o3tl::toInt32(rString.substr(0, 4));
-
- if (nLen >= 8 && o3tl::starts_with(rString.substr(4), u". "))
- {
- aRet.Month = o3tl::toInt32(rString.substr(6, 2));
-
- if (nLen >= 12 && o3tl::starts_with(rString.substr(8), u". "))
- aRet.Day = o3tl::toInt32(rString.substr(10, 2));
- }
- }
- return aRet;
-}
-} // anonymous namespace
-
-namespace writerfilter::rtftok
-{
-Id getParagraphBorder(sal_uInt32 nIndex)
-{
- static const Id aBorderIds[]
- = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left, NS_ooxml::LN_CT_PBdr_bottom,
- NS_ooxml::LN_CT_PBdr_right, NS_ooxml::LN_CT_PBdr_between };
-
- return aBorderIds[nIndex];
-}
-
-void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
- RTFOverwrite eOverwrite, bool bAttribute)
-{
- RTFValue::Pointer_t pParent = rSprms.find(nParent, /*bFirst=*/true, /*bForWrite=*/true);
- if (!pParent)
- {
- RTFSprms aAttributes;
- if (nParent == NS_ooxml::LN_CT_TcPrBase_shd)
- {
- // RTF default is 'auto', see writerfilter::dmapper::CellColorHandler
- aAttributes.set(NS_ooxml::LN_CT_Shd_color, new RTFValue(sal_uInt32(COL_AUTO)));
- aAttributes.set(NS_ooxml::LN_CT_Shd_fill, new RTFValue(sal_uInt32(COL_AUTO)));
- }
- auto pParentValue = new RTFValue(aAttributes);
- rSprms.set(nParent, pParentValue, eOverwrite);
- pParent = pParentValue;
- }
- RTFSprms& rAttributes = (bAttribute ? pParent->getAttributes() : pParent->getSprms());
- rAttributes.set(nId, pValue, eOverwrite);
-}
-
-void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
- RTFOverwrite eOverwrite)
-{
- putNestedAttribute(rSprms, nParent, nId, pValue, eOverwrite, false);
-}
-
-RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
-{
- RTFValue::Pointer_t pParent = rSprms.find(nParent);
- if (!pParent)
- return RTFValue::Pointer_t();
- RTFSprms& rAttributes = pParent->getAttributes();
- return rAttributes.find(nId);
-}
-
-RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId)
-{
- RTFValue::Pointer_t pParent = rSprms.find(nParent);
- if (!pParent)
- return RTFValue::Pointer_t();
- RTFSprms& rInner = pParent->getSprms();
- return rInner.find(nId);
-}
-
-bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
-{
- RTFValue::Pointer_t pParent = rSprms.find(nParent);
- if (!pParent)
- // It doesn't even have a parent, we're done.
- return false;
- RTFSprms& rAttributes = pParent->getAttributes();
- return rAttributes.erase(nId);
-}
-
-RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId)
-{
- RTFValue::Pointer_t p = rSprms.find(nId);
- if (p && !p->getSprms().empty())
- return p->getSprms().back().second->getAttributes();
-
- SAL_WARN("writerfilter.rtf", "trying to set property when no type is defined");
- return rSprms;
-}
-
-void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue)
-{
- RTFSprms* pAttributes = nullptr;
- if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH_BOX)
- for (int i = 0; i < 4; i++)
- {
- RTFValue::Pointer_t p = aStates.top().getParagraphSprms().find(getParagraphBorder(i));
- if (p)
- {
- RTFSprms& rAttributes = p->getAttributes();
- rAttributes.set(nId, pValue);
- }
- }
- else if (aStates.top().getBorderState() == RTFBorderState::CHARACTER)
- {
- RTFValue::Pointer_t pPointer
- = aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_RPrBase_bdr);
- if (pPointer)
- {
- RTFSprms& rAttributes = pPointer->getAttributes();
- rAttributes.set(nId, pValue);
- }
- }
- // Attributes of the last border type
- else if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH)
- pAttributes
- = &getLastAttributes(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr);
- else if (aStates.top().getBorderState() == RTFBorderState::CELL)
- pAttributes = &getLastAttributes(aStates.top().getTableCellSprms(),
- NS_ooxml::LN_CT_TcPrBase_tcBorders);
- else if (aStates.top().getBorderState() == RTFBorderState::PAGE)
- pAttributes = &getLastAttributes(aStates.top().getSectionSprms(),
- NS_ooxml::LN_EG_SectPrContents_pgBorders);
- else if (aStates.top().getBorderState() == RTFBorderState::NONE)
- {
- // this is invalid, but Word apparently clears or overrides all paragraph borders now
- for (int i = 0; i < 4; ++i)
- {
- auto const nBorder = getParagraphBorder(i);
- RTFSprms aAttributes;
- RTFSprms aSprms;
- aAttributes.set(NS_ooxml::LN_CT_Border_val,
- new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
- putNestedSprm(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nBorder,
- new RTFValue(aAttributes, aSprms), RTFOverwrite::YES);
- }
- }
-
- if (pAttributes)
- pAttributes->set(nId, pValue);
-}
-
-OString DTTM22OString(tools::Long nDTTM)
-{
- return DateTimeToOString(msfilter::util::DTTM2DateTime(nDTTM));
-}
-
-static RTFSprms lcl_getBookmarkProperties(int nPos, const OUString& rString)
-{
- RTFSprms aAttributes;
- auto pPos = new RTFValue(nPos);
- if (!rString.isEmpty())
- {
- // If present, this should be sent first.
- auto pString = new RTFValue(rString);
- aAttributes.set(NS_ooxml::LN_CT_Bookmark_name, pString);
- }
- aAttributes.set(NS_ooxml::LN_CT_MarkupRangeBookmark_id, pPos);
- return aAttributes;
-}
-
-const char* keywordToString(RTFKeyword nKeyword)
-{
- for (int i = 0; i < nRTFControlWords; i++)
- {
- if (nKeyword == aRTFControlWords[i].GetIndex())
- return aRTFControlWords[i].GetKeyword();
- }
- return nullptr;
-}
-
-static util::DateTime lcl_getDateTime(RTFParserState const& aState)
-{
- return { 0 /*100sec*/,
- 0 /*sec*/,
- aState.getMinute(),
- aState.getHour(),
- aState.getDay(),
- aState.getMonth(),
- static_cast<sal_Int16>(aState.getYear()),
- false };
-}
-
-static void lcl_DestinationToMath(OUStringBuffer* pDestinationText,
- oox::formulaimport::XmlStreamBuilder& rMathBuffer, bool& rMathNor)
-{
- if (!pDestinationText)
- return;
- OUString aStr = pDestinationText->makeStringAndClear();
- if (aStr.isEmpty())
- return;
- rMathBuffer.appendOpeningTag(M_TOKEN(r));
- if (rMathNor)
- {
- rMathBuffer.appendOpeningTag(M_TOKEN(rPr));
- // Same as M_TOKEN(lit)
- rMathBuffer.appendOpeningTag(M_TOKEN(nor));
- rMathBuffer.appendClosingTag(M_TOKEN(nor));
- rMathBuffer.appendClosingTag(M_TOKEN(rPr));
- rMathNor = false;
- }
- rMathBuffer.appendOpeningTag(M_TOKEN(t));
- rMathBuffer.appendCharacters(aStr);
- rMathBuffer.appendClosingTag(M_TOKEN(t));
- rMathBuffer.appendClosingTag(M_TOKEN(r));
-}
-
-RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& xContext,
- uno::Reference<io::XInputStream> const& xInputStream,
- uno::Reference<lang::XComponent> const& xDstDoc,
- uno::Reference<frame::XFrame> const& xFrame,
- uno::Reference<task::XStatusIndicator> const& xStatusIndicator,
- const utl::MediaDescriptor& rMediaDescriptor)
- : m_xContext(xContext)
- , m_xInputStream(xInputStream)
- , m_xDstDoc(xDstDoc)
- , m_xFrame(xFrame)
- , m_xStatusIndicator(xStatusIndicator)
- , m_pMapperStream(nullptr)
- , m_aDefaultState(this)
- , m_bSkipUnknown(false)
- , m_bFirstRun(true)
- , m_bFirstRunException(false)
- , m_bNeedPap(true)
- , m_bNeedCr(false)
- , m_bNeedCrOrig(false)
- , m_bNeedPar(true)
- , m_bNeedFinalPar(false)
- , m_nNestedCells(0)
- , m_nTopLevelCells(0)
- , m_nInheritingCells(0)
- , m_nNestedTRLeft(0)
- , m_nTopLevelTRLeft(0)
- , m_nNestedCurrentCellX(0)
- , m_nTopLevelCurrentCellX(0)
- , m_nBackupTopLevelCurrentCellX(0)
- , m_aTableBufferStack(1) // create top-level buffer already
- , m_pSuperstream(nullptr)
- , m_nStreamType(0)
- , m_nGroupStartPos(0)
- , m_nFormFieldType(RTFFormFieldType::NONE)
- , m_bObject(false)
- , m_nCurrentFontIndex(0)
- , m_nCurrentEncoding(-1)
- , m_nDefaultFontIndex(-1)
- , m_pStyleTableEntries(new RTFReferenceTable::Entries_t)
- , m_nCurrentStyleIndex(0)
- , m_bFormField(false)
- , m_bMathNor(false)
- , m_bIgnoreNextContSectBreak(false)
- , m_nResetBreakOnSectBreak(RTFKeyword::invalid)
- , m_bNeedSect(false) // done by checkFirstRun
- , m_bWasInFrame(false)
- , m_bHadPicture(false)
- , m_bHadSect(false)
- , m_nCellxMax(0)
- , m_nListPictureId(0)
- , m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault("InsertMode", false))
- , m_rMediaDescriptor(rMediaDescriptor)
- , m_hasRHeader(false)
- , m_hasFHeader(false)
- , m_hasRFooter(false)
- , m_hasFFooter(false)
-{
- OSL_ASSERT(xInputStream.is());
- m_pInStream = utl::UcbStreamHelper::CreateStream(xInputStream, true);
-
- m_xModelFactory.set(m_xDstDoc, uno::UNO_QUERY);
-
- uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
- m_xDstDoc, uno::UNO_QUERY);
- if (xDocumentPropertiesSupplier.is())
- m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
-
- m_pGraphicHelper = std::make_shared<oox::GraphicHelper>(m_xContext, xFrame, oox::StorageRef());
-
- m_pTokenizer = new RTFTokenizer(*this, m_pInStream.get(), m_xStatusIndicator);
- m_pSdrImport = new RTFSdrImport(*this, m_xDstDoc);
-
- // unlike OOXML, this is enabled by default
- m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_splitPgBreakAndParaMark, new RTFValue(1));
-}
-
-RTFDocumentImpl::~RTFDocumentImpl() = default;
-
-SvStream& RTFDocumentImpl::Strm() { return *m_pInStream; }
-
-void RTFDocumentImpl::setSuperstream(RTFDocumentImpl* pSuperstream)
-{
- m_pSuperstream = pSuperstream;
-}
-
-bool RTFDocumentImpl::isSubstream() const { return m_pSuperstream != nullptr; }
-
-void RTFDocumentImpl::finishSubstream() { checkUnicode(/*bUnicode =*/true, /*bHex =*/true); }
-
-void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId)
-{
- resolveSubstream(nPos, nId, OUString());
-}
-void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst)
-{
- sal_uInt64 const nCurrent = Strm().Tell();
- // Seek to header position, parse, then seek back.
- auto pImpl = new RTFDocumentImpl(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame,
- m_xStatusIndicator, m_rMediaDescriptor);
- pImpl->setSuperstream(this);
- pImpl->m_nStreamType = nId;
- pImpl->m_aIgnoreFirst = rIgnoreFirst;
- if (!m_aAuthor.isEmpty())
- {
- pImpl->m_aAuthor = m_aAuthor;
- m_aAuthor.clear();
- }
- if (!m_aAuthorInitials.isEmpty())
- {
- pImpl->m_aAuthorInitials = m_aAuthorInitials;
- m_aAuthorInitials.clear();
- }
- pImpl->m_nDefaultFontIndex = m_nDefaultFontIndex;
- pImpl->m_pStyleTableEntries = m_pStyleTableEntries;
- pImpl->Strm().Seek(nPos);
- SAL_INFO("writerfilter.rtf", "substream start");
- Mapper().substream(nId, pImpl);
- SAL_INFO("writerfilter.rtf", "substream end");
- Strm().Seek(nCurrent);
-}
-
-void RTFDocumentImpl::outputSettingsTable()
-{
- // tdf#136740: do not change target document settings when pasting
- if (!m_bIsNewDoc || isSubstream())
- return;
- writerfilter::Reference<Properties>::Pointer_t pProp
- = new RTFReferenceProperties(m_aSettingsTableAttributes, m_aSettingsTableSprms);
- RTFReferenceTable::Entries_t aSettingsTableEntries;
- aSettingsTableEntries.insert(std::make_pair(0, pProp));
- writerfilter::Reference<Table>::Pointer_t pTable
- = new RTFReferenceTable(std::move(aSettingsTableEntries));
- Mapper().table(NS_ooxml::LN_settings_settings, pTable);
-}
-
-void RTFDocumentImpl::checkFirstRun()
-{
- if (!m_bFirstRun)
- return;
-
- outputSettingsTable();
- // start initial paragraph
- m_bFirstRun = false;
- assert(!m_bNeedSect || m_bFirstRunException);
- setNeedSect(true); // first call that succeeds
-
- // set the requested default font, if there are none for each state in stack
- RTFValue::Pointer_t pFont
- = getNestedAttribute(m_aDefaultState.getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
- NS_ooxml::LN_CT_Fonts_ascii);
- if (!pFont)
- return;
-
- for (size_t i = 0; i < m_aStates.size(); i++)
- {
- RTFValue::Pointer_t pCurrentFont
- = getNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
- NS_ooxml::LN_CT_Fonts_ascii);
- if (!pCurrentFont)
- putNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
- NS_ooxml::LN_CT_Fonts_ascii, pFont);
- }
-}
-
-void RTFDocumentImpl::setNeedPar(bool bNeedPar) { m_bNeedPar = bNeedPar; }
-
-void RTFDocumentImpl::setNeedSect(bool bNeedSect)
-{
- if (!m_bNeedSect && bNeedSect && m_bFirstRun)
- {
- RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
- if (aLookahead.hasTable() && aLookahead.hasColumns())
- {
- m_bFirstRunException = true;
- }
- }
-
- // ignore setting before checkFirstRun - every keyword calls setNeedSect!
- // except the case of a table in a multicolumn section
- if (!m_bNeedSect && bNeedSect && (!m_bFirstRun || m_bFirstRunException))
- {
- if (!m_pSuperstream) // no sections in header/footer!
- {
- Mapper().startSectionGroup();
- }
- // set flag in substream too - otherwise multiple startParagraphGroup
- m_bNeedSect = bNeedSect;
- Mapper().startParagraphGroup();
- setNeedPar(true);
- }
- else if (m_bNeedSect && !bNeedSect)
- {
- m_bNeedSect = bNeedSect;
- }
-}
-
-/// Copy rProps to rStyleAttributes and rStyleSprms, but in case of nested sprms, copy their children as toplevel sprms/attributes.
-static void lcl_copyFlatten(RTFReferenceProperties& rProps, RTFSprms& rStyleAttributes,
- RTFSprms& rStyleSprms)
-{
- for (auto& rSprm : rProps.getSprms())
- {
- // createStyleProperties() puts properties to rPr, but here we need a flat list.
- if (rSprm.first == NS_ooxml::LN_CT_Style_rPr)
- {
- // rPr can have both attributes and SPRMs, copy over both types.
- RTFSprms& rRPrSprms = rSprm.second->getSprms();
- for (const auto& rRPrSprm : rRPrSprms)
- rStyleSprms.set(rRPrSprm.first, rRPrSprm.second);
-
- RTFSprms& rRPrAttributes = rSprm.second->getAttributes();
- for (const auto& rRPrAttribute : rRPrAttributes)
- rStyleAttributes.set(rRPrAttribute.first, rRPrAttribute.second);
- }
- else
- rStyleSprms.set(rSprm.first, rSprm.second);
- }
-
- RTFSprms& rAttributes = rProps.getAttributes();
- for (const auto& rAttribute : rAttributes)
- rStyleAttributes.set(rAttribute.first, rAttribute.second);
-}
-
-writerfilter::Reference<Properties>::Pointer_t
-RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType)
-{
- RTFSprms aSprms(rSprms);
- RTFValue::Pointer_t pAbstractList;
- int nAbstractListId = -1;
- RTFValue::Pointer_t pNumId
- = getNestedSprm(aSprms, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_numId);
- if (pNumId)
- {
- // We have a numbering, look up the abstract list for property
- // deduplication and duplication.
- auto itNumId = m_aListOverrideTable.find(pNumId->getInt());
- if (itNumId != m_aListOverrideTable.end())
- {
- nAbstractListId = itNumId->second;
- auto itAbstract = m_aListTable.find(nAbstractListId);
- if (itAbstract != m_aListTable.end())
- pAbstractList = itAbstract->second;
- }
- }
-
- if (pAbstractList)
- {
- auto it = m_aInvalidListTableFirstIndents.find(nAbstractListId);
- if (it != m_aInvalidListTableFirstIndents.end())
- aSprms.deduplicateList(it->second);
- }
-
- int nStyle = 0;
- if (!m_aStates.empty())
- nStyle = m_aStates.top().getCurrentStyleIndex();
- auto it = m_pStyleTableEntries->find(nStyle);
- if (it != m_pStyleTableEntries->end())
- {
- // cloneAndDeduplicate() wants to know about only a single "style", so
- // let's merge paragraph and character style properties here.
- auto itChar = m_pStyleTableEntries->end();
- if (!m_aStates.empty())
- {
- int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex();
- itChar = m_pStyleTableEntries->find(nCharStyle);
- }
-
- RTFSprms aStyleSprms;
- RTFSprms aStyleAttributes;
- // Ensure the paragraph style is a flat list.
- // Take paragraph style into account for character properties as well,
- // as paragraph style may contain character properties.
- RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get());
- lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms);
-
- if (itChar != m_pStyleTableEntries->end())
- {
- // Found active character style, then update aStyleSprms/Attributes.
- if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
- {
- RTFReferenceProperties& rCharProps
- = *static_cast<RTFReferenceProperties*>(itChar->second.get());
- lcl_copyFlatten(rCharProps, aStyleAttributes, aStyleSprms);
- }
- }
-
- RTFSprms sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true, &aSprms));
- RTFSprms attributes(rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true));
- return new RTFReferenceProperties(std::move(attributes), std::move(sprms));
- }
-
- if (pAbstractList)
- aSprms.duplicateList(pAbstractList);
- writerfilter::Reference<Properties>::Pointer_t pRet
- = new RTFReferenceProperties(rAttributes, std::move(aSprms));
- return pRet;
-}
-
-void RTFDocumentImpl::checkNeedPap()
-{
- if (!m_bNeedPap)
- return;
-
- m_bNeedPap = false; // reset early, so we can avoid recursion when calling ourselves
-
- if (m_aStates.empty())
- return;
-
- if (!m_aStates.top().getCurrentBuffer())
- {
- writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties(getProperties(
- m_aStates.top().getParagraphAttributes(), m_aStates.top().getParagraphSprms(),
- NS_ooxml::LN_Value_ST_StyleType_paragraph));
-
- // Writer will ignore a page break before a text frame, so guard it with empty paragraphs
- const bool bIsInFrame = m_aStates.top().getFrame().hasProperties();
- bool hasBreakBeforeFrame
- = bIsInFrame
- && m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore);
- if (hasBreakBeforeFrame)
- {
- dispatchSymbol(RTFKeyword::PAR);
- m_bNeedPap = false;
- }
- Mapper().props(pParagraphProperties);
- if (hasBreakBeforeFrame)
- dispatchSymbol(RTFKeyword::PAR);
-
- if (bIsInFrame)
- {
- writerfilter::Reference<Properties>::Pointer_t const pFrameProperties(
- new RTFReferenceProperties(RTFSprms(), m_aStates.top().getFrame().getSprms()));
- Mapper().props(pFrameProperties);
- }
- }
- else
- {
- auto pValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
- m_aStates.top().getParagraphSprms());
- bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
- }
-}
-
-void RTFDocumentImpl::runProps()
-{
- if (!m_aStates.top().getCurrentBuffer())
- {
- Reference<Properties>::Pointer_t const pProperties = getProperties(
- m_aStates.top().getCharacterAttributes(), m_aStates.top().getCharacterSprms(),
- NS_ooxml::LN_Value_ST_StyleType_character);
- Mapper().props(pProperties);
- }
- else
- {
- auto pValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
- m_aStates.top().getCharacterSprms());
- bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr,
- NS_ooxml::LN_Value_ST_StyleType_character);
- }
-
- // Delete the sprm, so the trackchange range will be started only once.
- // OTOH set a boolean flag, so we'll know we need to end the range later.
- RTFValue::Pointer_t pTrackchange
- = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_trackchange);
- if (pTrackchange)
- {
- m_aStates.top().setStartedTrackchange(true);
- m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_trackchange);
- }
-}
-
-void RTFDocumentImpl::runBreak()
-{
- sal_Unicode const sBreak[] = { 0x0d };
- Mapper().utext(sBreak, 1);
- m_bNeedCr = false;
-}
-
-void RTFDocumentImpl::tableBreak()
-{
- checkFirstRun(); // ooo113308-1.rtf has a header at offset 151084 that doesn't startParagraphGroup() without this
- runBreak();
- Mapper().endParagraphGroup();
- Mapper().startParagraphGroup();
-}
-
-void RTFDocumentImpl::parBreak()
-{
- checkFirstRun();
- checkNeedPap();
- // end previous paragraph
- Mapper().startCharacterGroup();
- runBreak();
- Mapper().endCharacterGroup();
- Mapper().endParagraphGroup();
-
- m_bHadPicture = false;
-
- // start new one
- if (!m_bParAtEndOfSection)
- {
- Mapper().startParagraphGroup();
- }
-}
-
-void RTFDocumentImpl::sectBreak(bool bFinal)
-{
- SAL_INFO("writerfilter.rtf", __func__ << ": final? " << bFinal << ", needed? " << m_bNeedSect);
- bool bNeedSect = m_bNeedSect;
- RTFValue::Pointer_t pBreak
- = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
- bool bContinuous = pBreak && pBreak->getInt() == NS_ooxml::LN_Value_ST_SectionMark_continuous;
- // If there is no paragraph in this section, then insert a dummy one, as required by Writer,
- // unless this is the end of the doc, we had nothing since the last section break and this is not a continuous one.
- // Also, when pasting, it's fine to not have any paragraph inside the document at all.
- if (m_bNeedPar && (!bFinal || m_bNeedSect || bContinuous) && !isSubstream() && m_bIsNewDoc)
- {
- m_bParAtEndOfSection = true;
- dispatchSymbol(RTFKeyword::PAR);
- }
- // It's allowed to not have a non-table paragraph at the end of an RTF doc, add it now if required.
- if (m_bNeedFinalPar && bFinal)
- {
- dispatchFlag(RTFKeyword::PARD);
- m_bParAtEndOfSection = true;
- dispatchSymbol(RTFKeyword::PAR);
- m_bNeedSect = bNeedSect;
- }
- // testTdf148515, if RTF ends with \row, endParagraphGroup() must be called!
- if (!m_bParAtEndOfSection || m_aStates.top().getCurrentBuffer())
- {
- Mapper().endParagraphGroup(); // < top para context dies with page break
- }
- m_bParAtEndOfSection = false;
- // paragraph properties are *done* now - only section properties following
-
- while (!m_nHeaderFooterPositions.empty())
- {
- std::pair<Id, std::size_t> aPair = m_nHeaderFooterPositions.front();
- m_nHeaderFooterPositions.pop();
- resolveSubstream(aPair.second, aPair.first);
- }
-
- // Normally a section break at the end of the doc is necessary. Unless the
- // last control word in the document is a section break itself.
- if (!bNeedSect || !m_bHadSect)
- {
- // In case the last section is a continuous one, we don't need to output a section break.
- if (bFinal && bContinuous)
- m_aStates.top().getSectionSprms().erase(NS_ooxml::LN_EG_SectPrContents_type);
- }
-
- // Section properties are a paragraph sprm.
- auto pValue
- = new RTFValue(m_aStates.top().getSectionAttributes(), m_aStates.top().getSectionSprms());
- RTFSprms aAttributes;
- RTFSprms aSprms;
- aSprms.set(NS_ooxml::LN_CT_PPr_sectPr, pValue);
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
-
- if (bFinal && !m_pSuperstream)
- // This is the end of the document, not just the end of e.g. a header.
- // This makes sure that dmapper can set DontBalanceTextColumns=true for this section if necessary.
- Mapper().markLastSectionGroup();
-
- // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects.
- Mapper().props(pProperties);
-
- // End Section
- if (!m_pSuperstream)
- {
- m_hasFHeader = false;
- m_hasRHeader = false;
- m_hasRFooter = false;
- m_hasFFooter = false;
- Mapper().endSectionGroup();
- }
- m_bNeedPar = false;
- m_bNeedSect = false;
-}
-
-Color RTFDocumentImpl::getColorTable(sal_uInt32 nIndex)
-{
- if (!m_pSuperstream)
- {
- if (nIndex < m_aColorTable.size())
- return m_aColorTable[nIndex];
- return 0;
- }
-
- return m_pSuperstream->getColorTable(nIndex);
-}
-
-rtl_TextEncoding RTFDocumentImpl::getEncoding(int nFontIndex)
-{
- if (!m_pSuperstream)
- {
- auto it = m_aFontEncodings.find(nFontIndex);
- if (it != m_aFontEncodings.end())
- // We have a font encoding associated to this font.
- return it->second;
- if (m_aDefaultState.getCurrentEncoding() != rtl_getTextEncodingFromWindowsCharset(0))
- // We have a default encoding.
- return m_aDefaultState.getCurrentEncoding();
- // Guess based on locale.
- return msfilter::util::getBestTextEncodingFromLocale(
- Application::GetSettings().GetLanguageTag().getLocale());
- }
-
- return m_pSuperstream->getEncoding(nFontIndex);
-}
-
-OUString RTFDocumentImpl::getFontName(int nIndex)
-{
- if (!m_pSuperstream)
- return m_aFontNames[nIndex];
-
- return m_pSuperstream->getFontName(nIndex);
-}
-
-int RTFDocumentImpl::getFontIndex(int nIndex)
-{
- if (!m_pSuperstream)
- return std::find(m_aFontIndexes.begin(), m_aFontIndexes.end(), nIndex)
- - m_aFontIndexes.begin();
-
- return m_pSuperstream->getFontIndex(nIndex);
-}
-
-OUString RTFDocumentImpl::getStyleName(int nIndex)
-{
- if (!m_pSuperstream)
- {
- OUString aRet;
- auto it = m_aStyleNames.find(nIndex);
- if (it != m_aStyleNames.end())
- aRet = it->second;
- return aRet;
- }
-
- return m_pSuperstream->getStyleName(nIndex);
-}
-
-Id RTFDocumentImpl::getStyleType(int nIndex)
-{
- if (!m_pSuperstream)
- {
- Id nRet = 0;
- auto it = m_aStyleTypes.find(nIndex);
- if (it != m_aStyleTypes.end())
- nRet = it->second;
- return nRet;
- }
-
- return m_pSuperstream->getStyleType(nIndex);
-}
-
-RTFParserState& RTFDocumentImpl::getDefaultState()
-{
- if (!m_pSuperstream)
- return m_aDefaultState;
-
- return m_pSuperstream->getDefaultState();
-}
-
-oox::GraphicHelper& RTFDocumentImpl::getGraphicHelper() { return *m_pGraphicHelper; }
-
-bool RTFDocumentImpl::isStyleSheetImport()
-{
- if (m_aStates.empty())
- return false;
- Destination eDestination = m_aStates.top().getDestination();
- return eDestination == Destination::STYLESHEET || eDestination == Destination::STYLEENTRY;
-}
-
-void RTFDocumentImpl::resolve(Stream& rMapper)
-{
- m_pMapperStream = &rMapper;
- switch (m_pTokenizer->resolveParse())
- {
- case RTFError::OK:
- SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: finished without errors");
- break;
- case RTFError::GROUP_UNDER:
- SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '}'");
- break;
- case RTFError::GROUP_OVER:
- SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '{'");
- throw io::WrongFormatException(m_pTokenizer->getPosition());
- break;
- case RTFError::UNEXPECTED_EOF:
- SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unexpected end of file");
- throw io::WrongFormatException(m_pTokenizer->getPosition());
- break;
- case RTFError::HEX_INVALID:
- SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: invalid hex char");
- throw io::WrongFormatException(m_pTokenizer->getPosition());
- break;
- case RTFError::CHAR_OVER:
- SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: characters after last '}'");
- break;
- case RTFError::CLASSIFICATION:
- SAL_INFO("writerfilter.rtf",
- "RTFDocumentImpl::resolve: classification prevented paste");
- break;
- }
-}
-
-void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XShape> const& rShape)
-{
- SvMemoryStream aStream;
- SvStream* pStream = nullptr;
- if (!m_pBinaryData)
- {
- pStream = &aStream;
- int b = 0;
- int count = 2;
-
- // Feed the destination text to a stream.
- auto& rDestinationTextBuffer = m_aStates.top().getDestinationText();
- OString aStr = OUStringToOString(rDestinationTextBuffer, RTL_TEXTENCODING_ASCII_US);
- rDestinationTextBuffer.setLength(0);
- for (int i = 0; i < aStr.getLength(); ++i)
- {
- char ch = aStr[i];
- if (ch != 0x0d && ch != 0x0a && ch != 0x20)
- {
- b = b << 4;
- sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
- if (parsed == -1)
- return;
- b += parsed;
- count--;
- if (!count)
- {
- aStream.WriteChar(static_cast<char>(b));
- count = 2;
- b = 0;
- }
- }
- }
- }
- else
- pStream = m_pBinaryData.get();
-
- if (!pStream->Tell())
- // No destination text? Then we'll get it later.
- return;
-
- SvMemoryStream aDIBStream;
- if (m_aStates.top().getPicture().eStyle == RTFBmpStyle::DIBITMAP)
- {
- // Construct a BITMAPFILEHEADER structure before the real data.
- SvStream& rBodyStream = *pStream;
- aDIBStream.WriteChar('B');
- aDIBStream.WriteChar('M');
- // The size of the real data.
- aDIBStream.WriteUInt32(rBodyStream.Tell());
- // Reserved.
- aDIBStream.WriteUInt32(0);
- // The offset of the real data, i.e. the size of the header, including this number.
- aDIBStream.WriteUInt32(14);
- rBodyStream.Seek(0);
- aDIBStream.WriteStream(rBodyStream);
- pStream = &aDIBStream;
- }
-
- // Store, and get its URL.
- pStream->Seek(0);
- uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream));
- WmfExternal aExtHeader;
- aExtHeader.mapMode = m_aStates.top().getPicture().eWMetafile;
- if (m_aStates.top().getPicture().nGoalWidth == 0
- || m_aStates.top().getPicture().nGoalHeight == 0)
- {
- // Don't use the values provided by picw and pich if the desired size is provided.
-
- aExtHeader.xExt = sal_uInt16(std::clamp<sal_Int32>(
- m_aStates.top().getPicture().nWidth, 0,
- SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
- aExtHeader.yExt = sal_uInt16(std::clamp<sal_Int32>(
- m_aStates.top().getPicture().nHeight, 0,
- SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
- }
- WmfExternal* pExtHeader = &aExtHeader;
- uno::Reference<lang::XServiceInfo> xServiceInfo(m_aStates.top().getDrawingObject().getShape(),
- uno::UNO_QUERY);
- if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
- pExtHeader = nullptr;
-
- uno::Reference<graphic::XGraphic> xGraphic
- = m_pGraphicHelper->importGraphic(xInputStream, pExtHeader);
-
- if (m_aStates.top().getPicture().eStyle != RTFBmpStyle::NONE)
- {
- // In case of PNG/JPEG, the real size is known, don't use the values
- // provided by picw and pich.
-
- Graphic aGraphic(xGraphic);
- Size aSize(aGraphic.GetPrefSize());
- MapMode aMap(MapUnit::Map100thMM);
- if (aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
- aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMap);
- else
- aSize = OutputDevice::LogicToLogic(aSize, aGraphic.GetPrefMapMode(), aMap);
- m_aStates.top().getPicture().nWidth = aSize.Width();
- m_aStates.top().getPicture().nHeight = aSize.Height();
- }
-
- uno::Reference<drawing::XShape> xShape(rShape);
- if (m_aStates.top().getInShape() && xShape.is())
- {
- awt::Size aSize = xShape->getSize();
- if (aSize.Width || aSize.Height)
- {
- // resolvePict() is processing pib structure inside shape
- // So if shape has dimensions we should use them instead of
- // \picwN, \pichN, \picscalexN, \picscaleyN given with picture
- m_aStates.top().getPicture().nGoalWidth = aSize.Width;
- m_aStates.top().getPicture().nGoalHeight = aSize.Height;
- m_aStates.top().getPicture().nScaleX = 100;
- m_aStates.top().getPicture().nScaleY = 100;
- }
- }
-
- // Wrap it in an XShape.
- if (xShape.is())
- {
- uno::Reference<lang::XServiceInfo> xSI(xShape, uno::UNO_QUERY_THROW);
- if (!xSI->supportsService("com.sun.star.drawing.GraphicObjectShape"))
- {
- // it's sometimes an error to get here - but it's possible to have
- // a \pict inside the \shptxt of a \shp of shapeType 202 "TextBox"
- // and in that case xShape is the text frame; we actually need a
- // new GraphicObject then (example: fdo37691-1.rtf)
- SAL_INFO("writerfilter.rtf",
- "cannot set graphic on existing shape, creating a new GraphicObjectShape");
- xShape.clear();
- }
- }
- if (!xShape.is())
- {
- if (m_xModelFactory.is())
- xShape.set(m_xModelFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
- uno::UNO_QUERY);
- uno::Reference<drawing::XDrawPageSupplier> const xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
- if (xDrawSupplier.is())
- {
- uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
- if (xShapes.is())
- xShapes->add(xShape);
- }
- }
-
- uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
-
- if (xPropertySet.is())
- xPropertySet->setPropertyValue("Graphic", uno::Any(xGraphic));
-
- // check if the picture is in an OLE object and if the \objdata element is used
- // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
- if (m_bObject)
- {
- // Set the object size
- awt::Size aSize;
- aSize.Width
- = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
- : m_aStates.top().getPicture().nWidth);
- aSize.Height
- = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
- : m_aStates.top().getPicture().nHeight);
- xShape->setSize(aSize);
-
- // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert().
- xPropertySet->setPropertyValue("AnchorType",
- uno::Any(text::TextContentAnchorType_AS_CHARACTER));
-
- auto pShapeValue = new RTFValue(xShape);
- m_aObjectAttributes.set(NS_ooxml::LN_shape, pShapeValue);
- return;
- }
-
- if (m_aStates.top().getInListpicture())
- {
- // Send the shape directly, no section is started, to additional properties will be ignored anyway.
- Mapper().startShape(xShape);
- Mapper().endShape();
- return;
- }
-
- // Send it to the dmapper.
- RTFSprms aSprms;
- RTFSprms aAttributes;
- // shape attribute
- RTFSprms aPicAttributes;
- if (m_aStates.top().getPicture().nCropT != 0 || m_aStates.top().getPicture().nCropB != 0
- || m_aStates.top().getPicture().nCropL != 0 || m_aStates.top().getPicture().nCropR != 0)
- {
- text::GraphicCrop const crop{ m_aStates.top().getPicture().nCropT,
- m_aStates.top().getPicture().nCropB,
- m_aStates.top().getPicture().nCropL,
- m_aStates.top().getPicture().nCropR };
- auto const pCrop = new RTFValue(crop);
- aPicAttributes.set(NS_ooxml::LN_CT_BlipFillProperties_srcRect, pCrop);
- }
- auto pShapeValue = new RTFValue(xShape);
- aPicAttributes.set(NS_ooxml::LN_shape, pShapeValue);
- // pic sprm
- RTFSprms aGraphicDataAttributes;
- RTFSprms aGraphicDataSprms;
- auto pPicValue = new RTFValue(aPicAttributes);
- aGraphicDataSprms.set(NS_ooxml::LN_pic_pic, pPicValue);
- // graphicData sprm
- RTFSprms aGraphicAttributes;
- RTFSprms aGraphicSprms;
- auto pGraphicDataValue = new RTFValue(aGraphicDataAttributes, aGraphicDataSprms);
- aGraphicSprms.set(NS_ooxml::LN_CT_GraphicalObject_graphicData, pGraphicDataValue);
- // graphic sprm
- auto pGraphicValue = new RTFValue(aGraphicAttributes, aGraphicSprms);
- // extent sprm
- RTFSprms aExtentAttributes;
- int nXExt = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
- : m_aStates.top().getPicture().nWidth);
- int nYExt = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
- : m_aStates.top().getPicture().nHeight);
- if (m_aStates.top().getPicture().nScaleX != 100)
- nXExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleX)
- * (nXExt
- - (m_aStates.top().getPicture().nCropL + m_aStates.top().getPicture().nCropR)))
- / 100L;
- if (m_aStates.top().getPicture().nScaleY != 100)
- nYExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleY)
- * (nYExt
- - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB)))
- / 100L;
- auto pXExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nXExt));
- auto pYExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nYExt));
- aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cx, pXExtValue);
- aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cy, pYExtValue);
- auto pExtentValue = new RTFValue(aExtentAttributes);
- // docpr sprm
- RTFSprms aDocprAttributes;
- for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
- if (rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_name
- || rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_descr)
- aDocprAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
- auto pDocprValue = new RTFValue(aDocprAttributes);
- if (bInline)
- {
- RTFSprms aInlineAttributes;
- aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distT, new RTFValue(0));
- aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distB, new RTFValue(0));
- aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distL, new RTFValue(0));
- aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distR, new RTFValue(0));
- RTFSprms aInlineSprms;
- aInlineSprms.set(NS_ooxml::LN_CT_Inline_extent, pExtentValue);
- aInlineSprms.set(NS_ooxml::LN_CT_Inline_docPr, pDocprValue);
- aInlineSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
- // inline sprm
- auto pValue = new RTFValue(aInlineAttributes, aInlineSprms);
- aSprms.set(NS_ooxml::LN_inline_inline, pValue);
- }
- else // anchored
- {
- // wrap sprm
- RTFSprms aAnchorWrapAttributes;
- m_aStates.top().getShape().getAnchorAttributes().set(
- NS_ooxml::LN_CT_Anchor_behindDoc,
- new RTFValue((m_aStates.top().getShape().getInBackground()) ? 1 : 0));
- RTFSprms aAnchorSprms;
- for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
- {
- if (rCharacterAttribute.first == NS_ooxml::LN_CT_WrapSquare_wrapText)
- aAnchorWrapAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
- }
- sal_Int32 nWrap = -1;
- for (auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
- {
- if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
- || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
- {
- nWrap = rCharacterSprm.first;
-
- // If there is a wrap polygon prepared by RTFSdrImport, pick it up here.
- if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight
- && !m_aStates.top().getShape().getWrapPolygonSprms().empty())
- rCharacterSprm.second->getSprms().set(
- NS_ooxml::LN_CT_WrapTight_wrapPolygon,
- new RTFValue(RTFSprms(), m_aStates.top().getShape().getWrapPolygonSprms()));
-
- aAnchorSprms.set(rCharacterSprm.first, rCharacterSprm.second);
- }
- }
-
- if (m_aStates.top().getShape().getWrapSprm().first != 0)
- // Replay of a buffered shape, wrap sprm there has priority over
- // character sprms of the current state.
- aAnchorSprms.set(m_aStates.top().getShape().getWrapSprm().first,
- m_aStates.top().getShape().getWrapSprm().second);
-
- aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_extent, pExtentValue);
- if (!aAnchorWrapAttributes.empty() && nWrap == -1)
- aAnchorSprms.set(NS_ooxml::LN_EG_WrapType_wrapSquare,
- new RTFValue(aAnchorWrapAttributes));
-
- // See OOXMLFastContextHandler::positionOffset(), we can't just put offset values in an RTFValue.
- RTFSprms aPoshAttributes;
- RTFSprms aPoshSprms;
- if (m_aStates.top().getShape().getHoriOrientRelationToken() > 0)
- aPoshAttributes.set(
- NS_ooxml::LN_CT_PosH_relativeFrom,
- new RTFValue(m_aStates.top().getShape().getHoriOrientRelationToken()));
- if (m_aStates.top().getShape().getLeft() != 0)
- {
- Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
- m_aStates.top().getShape().getLeft())),
- /*bVertical=*/false);
- aPoshSprms.set(NS_ooxml::LN_CT_PosH_posOffset, new RTFValue());
- }
- aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionH,
- new RTFValue(aPoshAttributes, aPoshSprms));
-
- RTFSprms aPosvAttributes;
- RTFSprms aPosvSprms;
- if (m_aStates.top().getShape().getVertOrientRelationToken() > 0)
- aPosvAttributes.set(
- NS_ooxml::LN_CT_PosV_relativeFrom,
- new RTFValue(m_aStates.top().getShape().getVertOrientRelationToken()));
- if (m_aStates.top().getShape().getTop() != 0)
- {
- Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
- m_aStates.top().getShape().getTop())),
- /*bVertical=*/true);
- aPosvSprms.set(NS_ooxml::LN_CT_PosV_posOffset, new RTFValue());
- }
- aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionV,
- new RTFValue(aPosvAttributes, aPosvSprms));
-
- aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_docPr, pDocprValue);
- aAnchorSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
- // anchor sprm
- auto pValue = new RTFValue(m_aStates.top().getShape().getAnchorAttributes(), aAnchorSprms);
- aSprms.set(NS_ooxml::LN_anchor_anchor, pValue);
- }
- checkFirstRun();
-
- if (!m_aStates.top().getCurrentBuffer())
- {
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
- Mapper().props(pProperties);
- // Make sure we don't lose these properties with a too early reset.
- m_bHadPicture = true;
- }
- else
- {
- auto pValue = new RTFValue(aAttributes, aSprms);
- bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
- }
-}
-
-RTFError RTFDocumentImpl::resolveChars(char ch)
-{
- if (m_aStates.top().getInternalState() == RTFInternalState::BIN)
- {
- m_pBinaryData = std::make_shared<SvMemoryStream>();
- m_pBinaryData->WriteChar(ch);
- for (int i = 0; i < m_aStates.top().getBinaryToRead() - 1; ++i)
- {
- Strm().ReadChar(ch);
- m_pBinaryData->WriteChar(ch);
- }
- m_aStates.top().setInternalState(RTFInternalState::NORMAL);
- return RTFError::OK;
- }
-
- OStringBuffer aBuf(512);
-
- bool bUnicodeChecked = false;
- bool bSkipped = false;
-
- while (!Strm().eof()
- && (m_aStates.top().getInternalState() == RTFInternalState::HEX
- || (ch != '{' && ch != '}' && ch != '\\')))
- {
- if (m_aStates.top().getInternalState() == RTFInternalState::HEX
- || (ch != 0x0d && ch != 0x0a))
- {
- if (m_aStates.top().getCharsToSkip() == 0)
- {
- if (!bUnicodeChecked)
- {
- checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
- bUnicodeChecked = true;
- }
- aBuf.append(ch);
- }
- else
- {
- bSkipped = true;
- m_aStates.top().getCharsToSkip()--;
- }
- }
-
- // read a single char if we're in hex mode
- if (m_aStates.top().getInternalState() == RTFInternalState::HEX)
- break;
-
- if (RTL_TEXTENCODING_MS_932 == m_aStates.top().getCurrentEncoding())
- {
- unsigned char uch = ch;
- if ((uch >= 0x80 && uch <= 0x9F) || uch >= 0xE0)
- {
- // read second byte of 2-byte Shift-JIS - may be \ { }
- Strm().ReadChar(ch);
- if (m_aStates.top().getCharsToSkip() == 0)
- {
- // fdo#79384: Word will reject Shift-JIS following \loch
- // but apparently OOo could read and (worse) write such documents
- SAL_INFO_IF(m_aStates.top().getRunType() != RTFParserState::RunType::DBCH,
- "writerfilter.rtf", "invalid Shift-JIS without DBCH");
- assert(bUnicodeChecked);
- aBuf.append(ch);
- }
- else
- {
- assert(bSkipped);
- // anybody who uses \ucN with Shift-JIS is insane
- m_aStates.top().getCharsToSkip()--;
- }
- }
- }
-
- Strm().ReadChar(ch);
- }
- if (m_aStates.top().getInternalState() != RTFInternalState::HEX && !Strm().eof())
- Strm().SeekRel(-1);
-
- if (m_aStates.top().getInternalState() == RTFInternalState::HEX
- && m_aStates.top().getDestination() != Destination::LEVELNUMBERS)
- {
- if (!bSkipped)
- {
- // note: apparently \'0d\'0a is interpreted as 2 breaks, not 1
- if ((ch == '\r' || ch == '\n')
- && m_aStates.top().getDestination() != Destination::DOCCOMM
- && m_aStates.top().getDestination() != Destination::LEVELNUMBERS
- && m_aStates.top().getDestination() != Destination::LEVELTEXT)
- {
- checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
- dispatchSymbol(RTFKeyword::PAR);
- }
- else
- {
- m_aHexBuffer.append(ch);
- }
- }
- return RTFError::OK;
- }
-
- if (m_aStates.top().getDestination() == Destination::SKIP)
- return RTFError::OK;
- OString aStr = aBuf.makeStringAndClear();
- if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
- {
- if (aStr.toChar() != ';')
- m_aStates.top().getLevelNumbers().push_back(sal_Int32(ch));
- return RTFError::OK;
- }
-
- SAL_INFO("writerfilter.rtf",
- "RTFDocumentImpl::resolveChars: collected '"
- << OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()) << "'");
-
- if (m_aStates.top().getDestination() == Destination::COLORTABLE)
- {
- // we hit a ';' at the end of each color entry
- m_aColorTable.push_back(m_aStates.top().getCurrentColor().GetColor());
- // set components back to zero
- m_aStates.top().getCurrentColor() = RTFColorTableEntry();
- }
- else if (!aStr.isEmpty())
- m_aHexBuffer.append(aStr);
-
- checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
- return RTFError::OK;
-}
-
-void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
-{
- sal_uInt8 sValue[] = { nValue };
- RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
-
- if (!pCurrentBuffer)
- {
- Mapper().startCharacterGroup();
- }
- else
- {
- pCurrentBuffer->emplace_back(BUFFER_STARTRUN, nullptr, nullptr);
- }
-
- // Should we send run properties?
- if (bRunProps)
- runProps();
-
- if (!pCurrentBuffer)
- {
- Mapper().text(sValue, 1);
- Mapper().endCharacterGroup();
- }
- else
- {
- auto pValue = new RTFValue(*sValue);
- pCurrentBuffer->emplace_back(BUFFER_TEXT, pValue, nullptr);
- pCurrentBuffer->emplace_back(BUFFER_ENDRUN, nullptr, nullptr);
- }
-}
-
-void RTFDocumentImpl::handleFontTableEntry()
-{
- OUString aName = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
-
- if (aName.isEmpty())
- return;
-
- if (aName.endsWith(";"))
- {
- aName = aName.copy(0, aName.getLength() - 1);
- }
-
- // Old documents can contain no encoding information in fontinfo,
- // but there can be font name suffixes: Arial CE is not a special
- // font, it is ordinal Arial, but with used cp 1250 encoding.
- // Moreover these suffixes have priority over \cpgN and \fcharsetN
- // in MS Word.
- OUString aFontSuffix;
- OUString aNameNoSuffix(aName);
- sal_Int32 nLastSpace = aName.lastIndexOf(' ');
- if (nLastSpace >= 0)
- {
- aFontSuffix = aName.copy(nLastSpace + 1);
- aNameNoSuffix = aName.copy(0, nLastSpace);
- sal_Int32 nEncoding = RTL_TEXTENCODING_DONTKNOW;
- for (int i = 0; aRTFFontNameSuffixes[i].codepage != RTL_TEXTENCODING_DONTKNOW; i++)
- {
- if (aFontSuffix.equalsAscii(aRTFFontNameSuffixes[i].suffix))
- {
- nEncoding = aRTFFontNameSuffixes[i].codepage;
- break;
- }
- }
- if (nEncoding > RTL_TEXTENCODING_DONTKNOW)
- {
- m_nCurrentEncoding = nEncoding;
- m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
- }
- else
- {
- // Unknown suffix: looks like it is just a part of font name, restore it
- aNameNoSuffix = aName;
- }
- }
-
- m_aFontNames[m_nCurrentFontIndex] = aNameNoSuffix;
- if (m_nCurrentEncoding >= 0)
- {
- m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
- m_nCurrentEncoding = -1;
- }
- m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
- new RTFValue(aNameNoSuffix));
-
- writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(
- m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
-
- //See fdo#47347 initial invalid font entry properties are inserted first,
- //so when we attempt to insert the correct ones, there's already an
- //entry in the map for them, so the new ones aren't inserted.
- auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
- if (lb != m_aFontTableEntries.end()
- && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
- lb->second = pProp;
- else
- m_aFontTableEntries.insert(lb, std::make_pair(m_nCurrentFontIndex, pProp));
-}
-
-void RTFDocumentImpl::text(OUString& rString)
-{
- if (rString.getLength() == 1 && m_aStates.top().getDestination() != Destination::DOCCOMM)
- {
- // No cheating! Tokenizer ignores bare \r and \n, their hex \'0d / \'0a form doesn't count, either.
- sal_Unicode ch = rString[0];
- if (ch == 0x0d || ch == 0x0a)
- return;
- }
-
- bool bRet = true;
- switch (m_aStates.top().getDestination())
- {
- // Note: in stylesheet and revtbl groups are mandatory
- case Destination::STYLEENTRY:
- case Destination::LISTNAME:
- case Destination::REVISIONENTRY:
- {
- // ; is the end of the entry
- bool bEnd = false;
- if (rString.endsWith(";"))
- {
- rString = rString.copy(0, rString.getLength() - 1);
- bEnd = true;
- }
- m_aStates.top().appendDestinationText(rString);
- if (bEnd)
- {
- // always clear, necessary in case of group-less fonttable
- OUString const aName
- = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- switch (m_aStates.top().getDestination())
- {
- case Destination::STYLEENTRY:
- {
- RTFValue::Pointer_t pType
- = m_aStates.top().getTableAttributes().find(NS_ooxml::LN_CT_Style_type);
- if (pType)
- {
- // Word strips whitespace around style names.
- m_aStyleNames[m_nCurrentStyleIndex] = aName.trim();
- m_aStyleTypes[m_nCurrentStyleIndex] = pType->getInt();
- auto pValue = new RTFValue(aName.trim());
- m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_styleId,
- pValue);
- m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_name, pValue);
-
- writerfilter::Reference<Properties>::Pointer_t const pProp(
- createStyleProperties());
- m_pStyleTableEntries->insert(
- std::make_pair(m_nCurrentStyleIndex, pProp));
- }
- else
- SAL_INFO("writerfilter.rtf", "no RTF style type defined, ignoring");
- break;
- }
- case Destination::LISTNAME:
- // TODO: what can be done with a list name?
- break;
- case Destination::REVISIONENTRY:
- m_aAuthors[m_aAuthors.size()] = aName;
- break;
- default:
- break;
- }
- resetAttributes();
- resetSprms();
- }
- }
- break;
- case Destination::DOCVAR:
- {
- m_aStates.top().appendDocVar(rString);
- }
- break;
- case Destination::FONTTABLE:
- case Destination::FONTENTRY:
- case Destination::LEVELTEXT:
- case Destination::SHAPEPROPERTYNAME:
- case Destination::SHAPEPROPERTYVALUE:
- case Destination::BOOKMARKEND:
- case Destination::PICT:
- case Destination::SHAPEPROPERTYVALUEPICT:
- case Destination::FORMFIELDNAME:
- case Destination::FORMFIELDLIST:
- case Destination::DATAFIELD:
- case Destination::AUTHOR:
- case Destination::KEYWORDS:
- case Destination::OPERATOR:
- case Destination::COMPANY:
- case Destination::COMMENT:
- case Destination::OBJDATA:
- case Destination::OBJCLASS:
- case Destination::ANNOTATIONDATE:
- case Destination::ANNOTATIONAUTHOR:
- case Destination::ANNOTATIONREFERENCE:
- case Destination::FALT:
- case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
- case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
- case Destination::TITLE:
- case Destination::SUBJECT:
- case Destination::DOCCOMM:
- case Destination::ATNID:
- case Destination::ANNOTATIONREFERENCESTART:
- case Destination::ANNOTATIONREFERENCEEND:
- case Destination::MR:
- case Destination::MCHR:
- case Destination::MPOS:
- case Destination::MVERTJC:
- case Destination::MSTRIKEH:
- case Destination::MDEGHIDE:
- case Destination::MBEGCHR:
- case Destination::MSEPCHR:
- case Destination::MENDCHR:
- case Destination::MSUBHIDE:
- case Destination::MSUPHIDE:
- case Destination::MTYPE:
- case Destination::MGROW:
- case Destination::INDEXENTRY:
- case Destination::TOCENTRY:
- case Destination::PROPNAME:
- case Destination::STATICVAL:
- m_aStates.top().appendDestinationText(rString);
- break;
- case Destination::GENERATOR:
- // don't enlarge space sequences, eg. it was saved in LibreOffice
- if (!rString.startsWithIgnoreAsciiCase("Microsoft"))
- m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
- new RTFValue(0));
- break;
- default:
- bRet = false;
- break;
- }
- if (bRet)
- return;
-
- if (!m_aIgnoreFirst.isEmpty() && m_aIgnoreFirst == rString)
- {
- m_aIgnoreFirst.clear();
- return;
- }
-
- // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
- if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign)
- && m_nTopLevelCells == 0)
- {
- m_aTableBufferStack.back().emplace_back(BUFFER_UTEXT, new RTFValue(rString), nullptr);
- return;
- }
-
- checkFirstRun();
- checkNeedPap();
-
- // Don't return earlier, a bookmark start has to be in a paragraph group.
- if (m_aStates.top().getDestination() == Destination::BOOKMARKSTART)
- {
- m_aStates.top().appendDestinationText(rString);
- return;
- }
-
- RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
-
- if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
- Mapper().startCharacterGroup();
- else if (pCurrentBuffer)
- {
- RTFValue::Pointer_t pValue;
- pCurrentBuffer->emplace_back(BUFFER_STARTRUN, pValue, nullptr);
- }
-
- if (m_aStates.top().getDestination() == Destination::NORMAL
- || m_aStates.top().getDestination() == Destination::FIELDRESULT
- || m_aStates.top().getDestination() == Destination::SHAPETEXT)
- runProps();
-
- if (!pCurrentBuffer)
- Mapper().utext(rString.getStr(), rString.getLength());
- else
- {
- auto pValue = new RTFValue(rString);
- pCurrentBuffer->emplace_back(BUFFER_UTEXT, pValue, nullptr);
- }
-
- m_bNeedCr = true;
-
- if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
- Mapper().endCharacterGroup();
- else if (pCurrentBuffer)
- {
- RTFValue::Pointer_t pValue;
- pCurrentBuffer->emplace_back(BUFFER_ENDRUN, pValue, nullptr);
- }
-}
-
-void RTFDocumentImpl::prepareProperties(
- RTFParserState& rState, writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
- writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
- writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties, int const nCells,
- int const nCurrentCellX)
-{
- o_rpParagraphProperties
- = getProperties(rState.getParagraphAttributes(), rState.getParagraphSprms(),
- NS_ooxml::LN_Value_ST_StyleType_paragraph);
-
- if (rState.getFrame().hasProperties())
- {
- o_rpFrameProperties = new RTFReferenceProperties(RTFSprms(), rState.getFrame().getSprms());
- }
-
- // Table width.
- RTFValue::Pointer_t const pTableWidthProps
- = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblW);
- if (!pTableWidthProps)
- {
- auto pUnitValue = new RTFValue(3);
- putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
- NS_ooxml::LN_CT_TblWidth_type, pUnitValue);
- auto pWValue = new RTFValue(nCurrentCellX);
- putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
- NS_ooxml::LN_CT_TblWidth_w, pWValue);
- }
-
- if (nCells > 0)
- rState.getTableRowSprms().set(NS_ooxml::LN_tblRow, new RTFValue(1));
-
- RTFValue::Pointer_t const pCellMar
- = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
- if (!pCellMar)
- {
- // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
- RTFSprms aAttributes;
- aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
- new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
- aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(0));
- putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
- NS_ooxml::LN_CT_TblCellMar_left, new RTFValue(aAttributes));
- putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
- NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
- }
-
- o_rpTableRowProperties
- = new RTFReferenceProperties(rState.getTableRowAttributes(), rState.getTableRowSprms());
-}
-
-void RTFDocumentImpl::sendProperties(
- writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
- writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
- writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties)
-{
- Mapper().props(pParagraphProperties);
-
- if (pFrameProperties)
- {
- Mapper().props(pFrameProperties);
- }
-
- Mapper().props(pTableRowProperties);
-
- tableBreak();
-}
-
-void RTFDocumentImpl::replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSprms,
- ::std::deque<RTFSprms>& rCellsAttributes, int const nCells)
-{
- for (int i = 0; i < nCells; ++i)
- {
- replayBuffer(rBuffer, &rCellsSprms.front(), &rCellsAttributes.front());
- rCellsSprms.pop_front();
- rCellsAttributes.pop_front();
- }
- for (Buf_t& i : rBuffer)
- {
- SAL_WARN_IF(BUFFER_CELLEND == std::get<0>(i), "writerfilter.rtf", "dropping table cell!");
- }
- assert(rCellsSprms.empty());
- assert(rCellsAttributes.empty());
-}
-
-void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms,
- RTFSprms const* const pAttributes)
-{
- while (!rBuffer.empty())
- {
- Buf_t aTuple(rBuffer.front());
- rBuffer.pop_front();
- if (std::get<0>(aTuple) == BUFFER_PROPS || std::get<0>(aTuple) == BUFFER_PROPS_CHAR)
- {
- // Construct properties via getProperties() and not directly, to take care of deduplication.
- writerfilter::Reference<Properties>::Pointer_t const pProp(getProperties(
- std::get<1>(aTuple)->getAttributes(), std::get<1>(aTuple)->getSprms(),
- std::get<0>(aTuple) == BUFFER_PROPS_CHAR ? NS_ooxml::LN_Value_ST_StyleType_character
- : 0));
- Mapper().props(pProp);
- }
- else if (std::get<0>(aTuple) == BUFFER_NESTROW)
- {
- TableRowBuffer& rRowBuffer(*std::get<2>(aTuple));
-
- replayRowBuffer(rRowBuffer.GetBuffer(), rRowBuffer.GetCellsSprms(),
- rRowBuffer.GetCellsAttributes(), rRowBuffer.GetCells());
-
- sendProperties(rRowBuffer.GetParaProperties(), rRowBuffer.GetFrameProperties(),
- rRowBuffer.GetRowProperties());
- }
- else if (std::get<0>(aTuple) == BUFFER_CELLEND)
- {
- assert(pSprms && pAttributes);
- auto pValue = new RTFValue(1);
- pSprms->set(NS_ooxml::LN_tblCell, pValue);
- writerfilter::Reference<Properties>::Pointer_t const pTableCellProperties(
- new RTFReferenceProperties(*pAttributes, *pSprms));
- Mapper().props(pTableCellProperties);
- tableBreak();
- break;
- }
- else if (std::get<0>(aTuple) == BUFFER_STARTRUN)
- Mapper().startCharacterGroup();
- else if (std::get<0>(aTuple) == BUFFER_TEXT)
- {
- sal_uInt8 const nValue = std::get<1>(aTuple)->getInt();
- Mapper().text(&nValue, 1);
- }
- else if (std::get<0>(aTuple) == BUFFER_UTEXT)
- {
- OUString const aString(std::get<1>(aTuple)->getString());
- Mapper().utext(aString.getStr(), aString.getLength());
- }
- else if (std::get<0>(aTuple) == BUFFER_ENDRUN)
- Mapper().endCharacterGroup();
- else if (std::get<0>(aTuple) == BUFFER_PAR)
- parBreak();
- else if (std::get<0>(aTuple) == BUFFER_STARTSHAPE)
- m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), false, RTFSdrImport::SHAPE);
- else if (std::get<0>(aTuple) == BUFFER_RESOLVESHAPE)
- {
- // Make sure there is no current buffer while replaying the shape,
- // otherwise it gets re-buffered.
- RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
- m_aStates.top().setCurrentBuffer(nullptr);
-
- // Set current shape during replay, needed by e.g. wrap in
- // background.
- RTFShape aShape = m_aStates.top().getShape();
- m_aStates.top().getShape() = std::get<1>(aTuple)->getShape();
-
- m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), true, RTFSdrImport::SHAPE);
- m_aStates.top().getShape() = std::move(aShape);
- m_aStates.top().setCurrentBuffer(pCurrentBuffer);
- }
- else if (std::get<0>(aTuple) == BUFFER_ENDSHAPE)
- m_pSdrImport->close();
- else if (std::get<0>(aTuple) == BUFFER_RESOLVESUBSTREAM)
- {
- RTFSprms& rAttributes = std::get<1>(aTuple)->getAttributes();
- std::size_t nPos = rAttributes.find(0)->getInt();
- Id nId = rAttributes.find(1)->getInt();
- OUString aCustomMark = rAttributes.find(2)->getString();
- resolveSubstream(nPos, nId, aCustomMark);
- }
- else if (std::get<0>(aTuple) == BUFFER_PICTURE)
- m_aStates.top().getPicture() = std::get<1>(aTuple)->getPicture();
- else if (std::get<0>(aTuple) == BUFFER_SETSTYLE)
- {
- if (!m_aStates.empty())
- m_aStates.top().setCurrentStyleIndex(std::get<1>(aTuple)->getInt());
- }
- else
- assert(false);
- }
-}
-
-bool findPropertyName(const std::vector<beans::PropertyValue>& rProperties, const OUString& rName)
-{
- return std::any_of(
- rProperties.begin(), rProperties.end(),
- [&rName](const beans::PropertyValue& rProperty) { return rProperty.Name == rName; });
-}
-
-void RTFDocumentImpl::backupTableRowProperties()
-{
- if (m_nTopLevelCurrentCellX)
- {
- m_aBackupTableRowSprms = m_aStates.top().getTableRowSprms();
- m_aBackupTableRowAttributes = m_aStates.top().getTableRowAttributes();
- m_nBackupTopLevelCurrentCellX = m_nTopLevelCurrentCellX;
- }
-}
-
-void RTFDocumentImpl::restoreTableRowProperties()
-{
- m_aStates.top().getTableRowSprms() = m_aBackupTableRowSprms;
- m_aStates.top().getTableRowAttributes() = m_aBackupTableRowAttributes;
- m_nTopLevelCurrentCellX = m_nBackupTopLevelCurrentCellX;
-}
-
-void RTFDocumentImpl::resetTableRowProperties()
-{
- m_aStates.top().getTableRowSprms() = m_aDefaultState.getTableRowSprms();
- m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, new RTFValue(-1),
- RTFOverwrite::NO_APPEND);
- m_aStates.top().getTableRowAttributes() = m_aDefaultState.getTableRowAttributes();
- if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
- {
- m_nNestedTRLeft = 0;
- m_nNestedCurrentCellX = 0;
- }
- else
- {
- m_nTopLevelTRLeft = 0;
- m_nTopLevelCurrentCellX = 0;
- }
-}
-
-RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam)
-{
- setNeedSect(true);
- checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
- RTFSkipDestination aSkip(*this);
- int nSprm = -1;
- tools::SvRef<RTFValue> pBoolValue(new RTFValue(int(!bParam || nParam != 0)));
-
- // Underline toggles.
- switch (nKeyword)
- {
- case RTFKeyword::UL:
- nSprm = NS_ooxml::LN_Value_ST_Underline_single;
- break;
- case RTFKeyword::ULDASH:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dash;
- break;
- case RTFKeyword::ULDASHD:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash;
- break;
- case RTFKeyword::ULDASHDD:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash;
- break;
- case RTFKeyword::ULDB:
- nSprm = NS_ooxml::LN_Value_ST_Underline_double;
- break;
- case RTFKeyword::ULHWAVE:
- nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy;
- break;
- case RTFKeyword::ULLDASH:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong;
- break;
- case RTFKeyword::ULTH:
- nSprm = NS_ooxml::LN_Value_ST_Underline_thick;
- break;
- case RTFKeyword::ULTHD:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy;
- break;
- case RTFKeyword::ULTHDASH:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy;
- break;
- case RTFKeyword::ULTHDASHD:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy;
- break;
- case RTFKeyword::ULTHDASHDD:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy;
- break;
- case RTFKeyword::ULTHLDASH:
- nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy;
- break;
- case RTFKeyword::ULULDBWAVE:
- nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble;
- break;
- case RTFKeyword::ULWAVE:
- nSprm = NS_ooxml::LN_Value_ST_Underline_wave;
- break;
- default:
- break;
- }
- if (nSprm >= 0)
- {
- auto pValue
- = new RTFValue((!bParam || nParam != 0) ? nSprm : NS_ooxml::LN_Value_ST_Underline_none);
- m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
- return RTFError::OK;
- }
-
- // Accent characters (over dot / over comma).
- switch (nKeyword)
- {
- case RTFKeyword::ACCNONE:
- nSprm = NS_ooxml::LN_Value_ST_Em_none;
- break;
- case RTFKeyword::ACCDOT:
- nSprm = NS_ooxml::LN_Value_ST_Em_dot;
- break;
- case RTFKeyword::ACCCOMMA:
- nSprm = NS_ooxml::LN_Value_ST_Em_comma;
- break;
- case RTFKeyword::ACCCIRCLE:
- nSprm = NS_ooxml::LN_Value_ST_Em_circle;
- break;
- case RTFKeyword::ACCUNDERDOT:
- nSprm = NS_ooxml::LN_Value_ST_Em_underDot;
- break;
- default:
- break;
- }
- if (nSprm >= 0)
- {
- auto pValue = new RTFValue((!bParam || nParam != 0) ? nSprm : 0);
- m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_em, pValue);
- return RTFError::OK;
- }
-
- // Trivial character sprms.
- switch (nKeyword)
- {
- case RTFKeyword::B:
- case RTFKeyword::AB:
- switch (m_aStates.top().getRunType())
- {
- case RTFParserState::RunType::HICH:
- case RTFParserState::RunType::RTLCH_LTRCH_1:
- case RTFParserState::RunType::LTRCH_RTLCH_2:
- nSprm = NS_ooxml::LN_EG_RPrBase_bCs;
- break;
- case RTFParserState::RunType::NONE:
- case RTFParserState::RunType::LOCH:
- case RTFParserState::RunType::LTRCH_RTLCH_1:
- case RTFParserState::RunType::RTLCH_LTRCH_2:
- case RTFParserState::RunType::DBCH:
- default:
- nSprm = NS_ooxml::LN_EG_RPrBase_b;
- break;
- }
- break;
- case RTFKeyword::I:
- case RTFKeyword::AI:
- switch (m_aStates.top().getRunType())
- {
- case RTFParserState::RunType::HICH:
- case RTFParserState::RunType::RTLCH_LTRCH_1:
- case RTFParserState::RunType::LTRCH_RTLCH_2:
- nSprm = NS_ooxml::LN_EG_RPrBase_iCs;
- break;
- case RTFParserState::RunType::NONE:
- case RTFParserState::RunType::LOCH:
- case RTFParserState::RunType::LTRCH_RTLCH_1:
- case RTFParserState::RunType::RTLCH_LTRCH_2:
- case RTFParserState::RunType::DBCH:
- default:
- nSprm = NS_ooxml::LN_EG_RPrBase_i;
- break;
- }
- break;
- case RTFKeyword::OUTL:
- nSprm = NS_ooxml::LN_EG_RPrBase_outline;
- break;
- case RTFKeyword::SHAD:
- nSprm = NS_ooxml::LN_EG_RPrBase_shadow;
- break;
- case RTFKeyword::V:
- nSprm = NS_ooxml::LN_EG_RPrBase_vanish;
- break;
- case RTFKeyword::STRIKE:
- nSprm = NS_ooxml::LN_EG_RPrBase_strike;
- break;
- case RTFKeyword::STRIKED:
- nSprm = NS_ooxml::LN_EG_RPrBase_dstrike;
- break;
- case RTFKeyword::SCAPS:
- nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps;
- break;
- case RTFKeyword::IMPR:
- nSprm = NS_ooxml::LN_EG_RPrBase_imprint;
- break;
- case RTFKeyword::CAPS:
- nSprm = NS_ooxml::LN_EG_RPrBase_caps;
- break;
- default:
- break;
- }
- if (nSprm >= 0)
- {
- if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
- {
- m_aStates.top().getTableSprms().set(nSprm, pBoolValue);
- }
- else
- {
- m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
- }
- return RTFError::OK;
- }
-
- switch (nKeyword)
- {
- case RTFKeyword::ASPALPHA:
- m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE,
- pBoolValue);
- break;
- case RTFKeyword::DELETED:
- case RTFKeyword::REVISED:
- {
- auto pValue
- = new RTFValue(nKeyword == RTFKeyword::DELETED ? oox::XML_del : oox::XML_ins);
- putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
- NS_ooxml::LN_token, pValue);
- }
- break;
- case RTFKeyword::SBAUTO:
- putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
- NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue);
- break;
- case RTFKeyword::SAAUTO:
- putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
- NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue);
- break;
- case RTFKeyword::FACINGP:
- m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue);
- break;
- case RTFKeyword::HYPHAUTO:
- m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue);
- break;
- case RTFKeyword::HYPHPAR:
- m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens,
- new RTFValue(int(bParam && nParam == 0)));
- break;
- default:
- {
- SAL_INFO("writerfilter.rtf",
- "TODO handle toggle '" << keywordToString(nKeyword) << "'");
- aSkip.setParsed(false);
- }
- break;
- }
- return RTFError::OK;
-}
-
-RTFError RTFDocumentImpl::pushState()
-{
- //SAL_INFO("writerfilter.rtf", __func__ << " before push: " << m_pTokenizer->getGroup());
-
- checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
- m_nGroupStartPos = Strm().Tell();
-
- if (m_aStates.empty())
- m_aStates.push(m_aDefaultState);
- else
- {
- // fdo#85812 group resets run type of _current_ and new state (but not RTL)
- if (m_aStates.top().getRunType() != RTFParserState::RunType::LTRCH_RTLCH_2
- && m_aStates.top().getRunType() != RTFParserState::RunType::RTLCH_LTRCH_2)
- {
- m_aStates.top().setRunType(RTFParserState::RunType::NONE);
- }
-
- if (m_aStates.top().getDestination() == Destination::MR)
- lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
- m_bMathNor);
- m_aStates.push(m_aStates.top());
- }
- m_aStates.top().getDestinationText().setLength(0); // was copied: always reset!
-
- m_pTokenizer->pushGroup();
-
- switch (m_aStates.top().getDestination())
- {
- case Destination::FONTTABLE:
- // this is a "faked" destination for the font entry
- m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
- m_aStates.top().setDestination(Destination::FONTENTRY);
- break;
- case Destination::STYLESHEET:
- // this is a "faked" destination for the style sheet entry
- m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
- m_aStates.top().setDestination(Destination::STYLEENTRY);
- {
- // the *default* is \s0 i.e. paragraph style default
- // this will be overwritten by \sN \csN \dsN \tsN
- m_nCurrentStyleIndex = 0;
- auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
- m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, pValue);
- }
- break;
- case Destination::FIELDRESULT:
- case Destination::SHAPETEXT:
- case Destination::FORMFIELD:
- //TODO: if this is pushed then the font encoding is used which results in a broken command string
- // if it is not pushed to NORMAL then it is not restored in time.
- case Destination::FIELDINSTRUCTION:
- case Destination::PICT:
- m_aStates.top().setDestination(Destination::NORMAL);
- break;
- case Destination::MNUM:
- case Destination::MDEN:
- case Destination::ME:
- case Destination::MFNAME:
- case Destination::MLIM:
- case Destination::MSUB:
- case Destination::MSUP:
- case Destination::MDEG:
- case Destination::MOMATH:
- m_aStates.top().setDestination(Destination::MR);
- break;
- case Destination::REVISIONTABLE:
- // this is a "faked" destination for the revision table entry
- m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
- m_aStates.top().setDestination(Destination::REVISIONENTRY);
- break;
- default:
- break;
- }
-
- // If this is true, then ooxml:endtrackchange will be generated. Make sure
- // we don't generate more ooxml:endtrackchange than ooxml:trackchange: new
- // state does not inherit this flag.
- m_aStates.top().setStartedTrackchange(false);
-
- return RTFError::OK;
-}
-
-writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStyleProperties()
-{
- int nBasedOn = 0;
- RTFValue::Pointer_t pBasedOn
- = m_aStates.top().getTableSprms().find(NS_ooxml::LN_CT_Style_basedOn);
- if (pBasedOn)
- nBasedOn = pBasedOn->getInt();
- if (nBasedOn == 0)
- {
- // No parent style, then mimic what Word does: ignore attributes which
- // would set a margin as formatting, but with a default value.
- for (const auto& nId :
- { NS_ooxml::LN_CT_Ind_firstLine, NS_ooxml::LN_CT_Ind_left, NS_ooxml::LN_CT_Ind_right,
- NS_ooxml::LN_CT_Ind_start, NS_ooxml::LN_CT_Ind_end })
- {
- RTFValue::Pointer_t pValue = getNestedAttribute(m_aStates.top().getParagraphSprms(),
- NS_ooxml::LN_CT_PPrBase_ind, nId);
- if (pValue && pValue->getInt() == 0)
- eraseNestedAttribute(m_aStates.top().getParagraphSprms(),
- NS_ooxml::LN_CT_PPrBase_ind, nId);
- }
- }
-
- RTFValue::Pointer_t pParaProps = new RTFValue(m_aStates.top().getParagraphAttributes(),
- m_aStates.top().getParagraphSprms());
- RTFValue::Pointer_t pCharProps = new RTFValue(m_aStates.top().getCharacterAttributes(),
- m_aStates.top().getCharacterSprms());
-
- // resetSprms will clean up this modification
- m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_pPr, pParaProps);
- m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_rPr, pCharProps);
-
- writerfilter::Reference<Properties>::Pointer_t pProps(new RTFReferenceProperties(
- m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
- return pProps;
-}
-
-/** 2 different representations of the styles are needed:
-
- 1) flat content, as read from the input file:
- stored in m_pStyleTableEntries, used as reference input for
- deduplication both here and for hard formatting in getProperties()
-
- 2) real content, with proper override of sprms/attributes where it differs
- from parent style; this is produced here and sent to domain mapper
- */
-RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
-{
- RTFReferenceTable::Entries_t ret;
- for (auto const& it : *m_pStyleTableEntries)
- {
- auto pStyle = it.second;
- ret[it.first] = pStyle;
- // ugly downcasts here, but can't easily replace the members with
- // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway
- RTFValue::Pointer_t const pBasedOn(
- static_cast<RTFReferenceProperties&>(*pStyle).getSprms().find(
- NS_ooxml::LN_CT_Style_basedOn));
- if (pBasedOn)
- {
- int const nBasedOn(pBasedOn->getInt());
- // don't deduplicate yourself - especially a potential problem for the default style.
- if (it.first == nBasedOn)
- continue;
-
- auto const itParent(m_pStyleTableEntries->find(nBasedOn)); // definition as read!
- if (itParent != m_pStyleTableEntries->end())
- {
- auto const pStyleType(
- static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find(
- NS_ooxml::LN_CT_Style_type));
- assert(pStyleType);
- int const nStyleType(pStyleType->getInt());
- RTFSprms sprms(
- static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate(
- static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(),
- nStyleType));
- RTFSprms attributes(
- static_cast<RTFReferenceProperties&>(*pStyle)
- .getAttributes()
- .cloneAndDeduplicate(
- static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(),
- nStyleType));
-
- ret[it.first] = new RTFReferenceProperties(std::move(attributes), std::move(sprms));
- }
- else
- {
- SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn);
- }
- }
- }
- assert(ret.size() == m_pStyleTableEntries->size());
- return ret;
-}
-
-void RTFDocumentImpl::resetSprms()
-{
- m_aStates.top().getTableSprms().clear();
- m_aStates.top().getCharacterSprms().clear();
- m_aStates.top().getParagraphSprms().clear();
-}
-
-void RTFDocumentImpl::resetAttributes()
-{
- m_aStates.top().getTableAttributes().clear();
- m_aStates.top().getCharacterAttributes().clear();
- m_aStates.top().getParagraphAttributes().clear();
-}
-
-static bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties,
- std::u16string_view rName)
-{
- return std::any_of(rProperties.begin(), rProperties.end(),
- [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
-}
-
-RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState)
-{
- switch (rState.getDestination())
- {
- //Note: in fonttbl there may or may not be groups, so process it as no groups
- case Destination::FONTTABLE:
- case Destination::FONTENTRY:
- {
- // Some text unhandled? Seems it is last font name
- if (m_aStates.top().getCurrentDestinationText()->getLength())
- handleFontTableEntry();
-
- if (rState.getDestination() == Destination::FONTTABLE)
- {
- writerfilter::Reference<Table>::Pointer_t const pTable(
- new RTFReferenceTable(m_aFontTableEntries));
- Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
- if (m_nDefaultFontIndex >= 0)
- {
- auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
- putNestedAttribute(m_aDefaultState.getCharacterSprms(),
- NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
- pValue);
- }
- }
- }
- break;
- case Destination::STYLESHEET:
- {
- RTFReferenceTable::Entries_t pStyleTableDeduplicated(deduplicateStyleTable());
- writerfilter::Reference<Table>::Pointer_t const pTable(
- new RTFReferenceTable(std::move(pStyleTableDeduplicated)));
- Mapper().table(NS_ooxml::LN_STYLESHEET, pTable);
- }
- break;
- case Destination::LISTOVERRIDETABLE:
- {
- RTFSprms aListTableAttributes;
- writerfilter::Reference<Properties>::Pointer_t pProp
- = new RTFReferenceProperties(std::move(aListTableAttributes), m_aListTableSprms);
- RTFReferenceTable::Entries_t aListTableEntries;
- aListTableEntries.insert(std::make_pair(0, pProp));
- writerfilter::Reference<Table>::Pointer_t const pTable(
- new RTFReferenceTable(std::move(aListTableEntries)));
- Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
- }
- break;
- case Destination::LISTENTRY:
- for (const auto& rListLevelEntry : rState.getListLevelEntries())
- rState.getTableSprms().set(rListLevelEntry.first, rListLevelEntry.second,
- RTFOverwrite::NO_APPEND);
- break;
- case Destination::FIELDINSTRUCTION:
- {
- auto pValue = new RTFValue(m_aFormfieldAttributes, m_aFormfieldSprms);
- RTFSprms aFFAttributes;
- RTFSprms aFFSprms;
- aFFSprms.set(NS_ooxml::LN_ffdata, pValue);
- if (!m_aStates.top().getCurrentBuffer())
- {
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aFFAttributes), std::move(aFFSprms));
- Mapper().props(pProperties);
- }
- else
- {
- auto pFFValue = new RTFValue(aFFAttributes, aFFSprms);
- bufferProperties(*m_aStates.top().getCurrentBuffer(), pFFValue, nullptr);
- }
- m_aFormfieldAttributes.clear();
- m_aFormfieldSprms.clear();
-
- if (m_aStates.top().isFieldLocked())
- singleChar(cFieldLock);
- singleChar(cFieldSep, true);
- }
- break;
- case Destination::FIELDRESULT:
- singleChar(cFieldEnd);
-
- if (!m_aPicturePath.isEmpty())
- {
- // Read the picture into m_aStates.top().aDestinationText.
- pushState();
- dispatchDestination(RTFKeyword::PICT);
- if (m_aPicturePath.endsWith(".png"))
- dispatchFlag(RTFKeyword::PNGBLIP);
- OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault(
- utl::MediaDescriptor::PROP_URL, OUString());
- OUString aPictureURL;
- try
- {
- aPictureURL = rtl::Uri::convertRelToAbs(aFileURL, m_aPicturePath);
- }
- catch (const rtl::MalformedUriException& rException)
- {
- SAL_WARN("writerfilter.rtf",
- "rtl::Uri::convertRelToAbs() failed: " << rException.getMessage());
- }
-
- if (!aPictureURL.isEmpty())
- {
- SvFileStream aStream(aPictureURL, StreamMode::READ);
- if (aStream.IsOpen())
- {
- OUStringBuffer aBuf;
- while (aStream.good())
- {
- unsigned char ch = 0;
- aStream.ReadUChar(ch);
- if (ch < 16)
- aBuf.append("0");
- aBuf.append(static_cast<sal_Int32>(ch), 16);
- }
- m_aStates.top().getDestinationText() = aBuf;
- }
- }
- popState();
- m_aPicturePath.clear();
- }
-
- break;
- case Destination::LEVELTEXT:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
-
- // The first character is the length of the string (the rest should be ignored).
- sal_Int32 nLength(aStr.toChar());
- OUString aValue;
- if (nLength < aStr.getLength())
- aValue = aStr.copy(1, nLength);
- else
- aValue = aStr;
- auto pValue = new RTFValue(aValue, true);
- rState.getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
- }
- break;
- case Destination::LEVELNUMBERS:
- {
- bool bNestedLevelNumbers = false;
- if (m_aStates.size() > 1)
- // Current destination is levelnumbers and parent destination is levelnumbers as well.
- bNestedLevelNumbers
- = m_aStates[m_aStates.size() - 2].getDestination() == Destination::LEVELNUMBERS;
- if (!bNestedLevelNumbers && rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText))
- {
- RTFSprms& rAttributes
- = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText)->getAttributes();
- RTFValue::Pointer_t pValue = rAttributes.find(NS_ooxml::LN_CT_LevelText_val);
- if (pValue && rState.getLevelNumbersValid())
- {
- OUString aOrig = pValue->getString();
-
- OUStringBuffer aBuf(aOrig.getLength() * 2);
- sal_Int32 nReplaces = 1;
- for (int i = 0; i < aOrig.getLength(); i++)
- {
- if (std::find(rState.getLevelNumbers().begin(),
- rState.getLevelNumbers().end(), i + 1)
- != rState.getLevelNumbers().end())
- {
- aBuf.append('%');
- // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2.
- aBuf.append(sal_Int32(nReplaces++ + rState.getListLevelNum() + 1
- - rState.getLevelNumbers().size()));
- }
- else
- aBuf.append(aOrig[i]);
- }
-
- pValue->setString(aBuf.makeStringAndClear());
- }
- else if (pValue)
- // Have a value, but levelnumbers is not valid -> ignore it.
- pValue->setString(OUString());
- }
- break;
- }
- case Destination::SHAPEPROPERTYNAME:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- rState.getShape().getProperties().emplace_back(
- m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), OUString());
- break;
- case Destination::SHAPEPROPERTYVALUE:
- if (!rState.getShape().getProperties().empty())
- {
- rState.getShape().getProperties().back().second
- = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- if (m_aStates.top().getHadShapeText())
- m_pSdrImport->append(rState.getShape().getProperties().back().first,
- rState.getShape().getProperties().back().second);
- else if (rState.getInShapeGroup() && !rState.getInShape()
- && rState.getShape().getProperties().back().first == "rotation")
- {
- // Rotation should be applied on the groupshape itself, not on each shape.
- rState.getShape().getGroupProperties().push_back(
- rState.getShape().getProperties().back());
- rState.getShape().getProperties().pop_back();
- }
- }
- break;
- case Destination::PICPROP:
- case Destination::SHAPEINSTRUCTION:
- if (m_aStates.size() > 1
- && m_aStates[m_aStates.size() - 2].getDestination()
- == Destination::SHAPEINSTRUCTION)
- {
- // Do not resolve shape if shape instruction destination is inside other shape instruction
- }
- else if (!m_bObject && !rState.getInListpicture() && !rState.getHadShapeText()
- && (!rState.getInShapeGroup() || rState.getInShape()))
- {
- // Don't trigger a shape import in case we're only leaving the \shpinst of the groupshape itself.
- RTFSdrImport::ShapeOrPict eType
- = (rState.getDestination() == Destination::SHAPEINSTRUCTION)
- ? RTFSdrImport::SHAPE
- : RTFSdrImport::PICT;
- if (!m_aStates.top().getCurrentBuffer() || eType != RTFSdrImport::SHAPE)
- m_pSdrImport->resolve(m_aStates.top().getShape(), true, eType);
- else
- {
- // Shape inside table: buffer the import to have correct anchor position.
- // Also buffer the RTFPicture of the state stack as it contains
- // the shape size.
- auto pPictureValue = new RTFValue(m_aStates.top().getPicture());
- m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_PICTURE, pPictureValue,
- nullptr);
- auto pValue = new RTFValue(m_aStates.top().getShape());
-
- // Buffer wrap type.
- for (const auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
- {
- if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
- || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
- {
- m_aStates.top().getShape().getWrapSprm() = rCharacterSprm;
- break;
- }
- }
-
- m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_RESOLVESHAPE, pValue,
- nullptr);
- }
- }
- else if (rState.getInShapeGroup() && !rState.getInShape())
- {
- // End of a groupshape, as we're in shapegroup, but not in a real shape.
- for (const auto& rGroupProperty : rState.getShape().getGroupProperties())
- m_pSdrImport->appendGroupProperty(rGroupProperty.first, rGroupProperty.second);
- rState.getShape().getGroupProperties().clear();
- }
- break;
- case Destination::BOOKMARKSTART:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- int nPos = m_aBookmarks.size();
- m_aBookmarks[aStr] = nPos;
- if (!m_aStates.top().getCurrentBuffer())
- Mapper().props(new RTFReferenceProperties(lcl_getBookmarkProperties(nPos, aStr)));
- else
- bufferProperties(*m_aStates.top().getCurrentBuffer(),
- new RTFValue(lcl_getBookmarkProperties(nPos, aStr)), nullptr);
- }
- break;
- case Destination::BOOKMARKEND:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- if (!m_aStates.top().getCurrentBuffer())
- Mapper().props(new RTFReferenceProperties(
- lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)));
- else
- bufferProperties(*m_aStates.top().getCurrentBuffer(),
- new RTFValue(lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)),
- nullptr);
- }
- break;
- case Destination::INDEXENTRY:
- case Destination::TOCENTRY:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString str(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- // dmapper expects this as a field, so let's fake something...
- auto const field((Destination::INDEXENTRY == rState.getDestination())
- ? std::u16string_view(u"XE")
- : std::u16string_view(u"TC"));
- str = OUString::Concat(field) + " \"" + str.replaceAll("\"", "\\\"") + "\"";
- singleChar(cFieldStart);
- Mapper().utext(str.getStr(), str.getLength());
- singleChar(cFieldSep, true);
- // no result
- singleChar(cFieldEnd);
- }
- break;
- case Destination::FORMFIELDNAME:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- auto pValue
- = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pValue);
- }
- break;
- case Destination::FORMFIELDLIST:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- auto pValue
- = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- // OOXML puts these into a LN_CT_FFData_ddList but FFDataHandler should handle this too
- m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue,
- RTFOverwrite::NO_APPEND);
- }
- break;
- case Destination::DATAFIELD:
- {
- if (m_bFormField)
- {
- OUStringBuffer* pCurrentDestinationText
- = m_aStates.top().getCurrentDestinationText();
- if (&m_aStates.top().getDestinationText() != pCurrentDestinationText)
- break; // not for nested group
- OString aStr
- = OUStringToOString(*pCurrentDestinationText, rState.getCurrentEncoding());
- pCurrentDestinationText->setLength(0);
- // decode hex dump
- OStringBuffer aBuf;
- int b = 0;
- int count = 2;
- for (int i = 0; i < aStr.getLength(); ++i)
- {
- char ch = aStr[i];
- if (ch != 0x0d && ch != 0x0a)
- {
- b = b << 4;
- sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
- if (parsed == -1)
- return RTFError::HEX_INVALID;
- b += parsed;
- count--;
- if (!count)
- {
- aBuf.append(static_cast<char>(b));
- count = 2;
- b = 0;
- }
- }
- }
- aStr = aBuf.makeStringAndClear();
-
- // ignore the first bytes
- if (aStr.getLength() > 8)
- aStr = aStr.copy(8);
- // extract name
- sal_Int32 nLength = aStr.toChar();
- if (!aStr.isEmpty())
- aStr = aStr.copy(1);
- nLength = std::min(nLength, aStr.getLength());
- OString aName = aStr.copy(0, nLength);
- if (aStr.getLength() > nLength)
- aStr = aStr.copy(nLength + 1); // zero-terminated string
- else
- aStr.clear();
- // extract default text
- nLength = aStr.toChar();
- if (!aStr.isEmpty())
- aStr = aStr.copy(1);
- auto pNValue = new RTFValue(OStringToOUString(aName, rState.getCurrentEncoding()));
- m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pNValue);
- if (nLength > 0)
- {
- OString aDefaultText = aStr.copy(0, std::min(nLength, aStr.getLength()));
- auto pDValue = new RTFValue(
- OStringToOUString(aDefaultText, rState.getCurrentEncoding()));
- m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFTextInput_default, pDValue);
- }
-
- m_bFormField = false;
- }
- }
- break;
- case Destination::CREATIONTIME:
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setCreationDate(lcl_getDateTime(rState));
- break;
- case Destination::REVISIONTIME:
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setModificationDate(lcl_getDateTime(rState));
- break;
- case Destination::PRINTTIME:
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setPrintDate(lcl_getDateTime(rState));
- break;
- case Destination::AUTHOR:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setAuthor(
- m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- break;
- case Destination::KEYWORDS:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- {
- OUStringBuffer* pCurrentDestinationText
- = m_aStates.top().getCurrentDestinationText();
- m_xDocumentProperties->setKeywords(
- comphelper::string::convertCommaSeparated(*pCurrentDestinationText));
- pCurrentDestinationText->setLength(0);
- }
- break;
- case Destination::COMMENT:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setGenerator(
- m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- break;
- case Destination::SUBJECT:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setSubject(
- m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- break;
- case Destination::TITLE:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setTitle(
- rState.getCurrentDestinationText()->makeStringAndClear());
- }
- break;
-
- case Destination::DOCCOMM:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- m_xDocumentProperties->setDescription(
- m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- break;
- case Destination::OPERATOR:
- case Destination::COMPANY:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aName = rState.getDestination() == Destination::OPERATOR ? OUString("Operator")
- : OUString("Company");
- uno::Any aValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- if (m_xDocumentProperties.is())
- {
- uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
- = m_xDocumentProperties->getUserDefinedProperties();
- uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
- uno::UNO_QUERY);
- uno::Reference<beans::XPropertySetInfo> xPropertySetInfo
- = xPropertySet->getPropertySetInfo();
- if (xPropertySetInfo->hasPropertyByName(aName))
- xPropertySet->setPropertyValue(aName, aValue);
- else
- xUserDefinedProperties->addProperty(aName, beans::PropertyAttribute::REMOVABLE,
- aValue);
- }
- }
- break;
- case Destination::OBJDATA:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
-
- RTFError eError = handleEmbeddedObject();
- if (eError != RTFError::OK)
- return eError;
- }
- break;
- case Destination::OBJCLASS:
- {
- auto pValue
- = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- m_aOLEAttributes.set(NS_ooxml::LN_CT_OLEObject_ProgID, pValue);
- break;
- }
- case Destination::OBJECT:
- {
- if (!m_bObject)
- {
- // if the object is in a special container we will use the \result
- // element instead of the \objdata
- // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
- break;
- }
-
- RTFSprms aObjectSprms;
- auto pOLEValue = new RTFValue(m_aOLEAttributes);
- aObjectSprms.set(NS_ooxml::LN_OLEObject_OLEObject, pOLEValue);
-
- RTFSprms aObjAttributes;
- RTFSprms aObjSprms;
- auto pValue = new RTFValue(m_aObjectAttributes, aObjectSprms);
- aObjSprms.set(NS_ooxml::LN_object, pValue);
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aObjAttributes), std::move(aObjSprms));
- uno::Reference<drawing::XShape> xShape;
- RTFValue::Pointer_t pShape = m_aObjectAttributes.find(NS_ooxml::LN_shape);
- OSL_ASSERT(pShape);
- if (pShape)
- pShape->getAny() >>= xShape;
- if (xShape.is())
- {
- Mapper().startShape(xShape);
- Mapper().props(pProperties);
- Mapper().endShape();
- }
- m_aObjectAttributes.clear();
- m_aOLEAttributes.clear();
- m_bObject = false;
- }
- break;
- case Destination::ANNOTATIONDATE:
- {
- OUStringBuffer* pCurrentDestinationText = m_aStates.top().getCurrentDestinationText();
- if (&m_aStates.top().getDestinationText() != pCurrentDestinationText)
- break; // not for nested group
- OUString aStr(OStringToOUString(DTTM22OString(o3tl::toInt32(*pCurrentDestinationText)),
- rState.getCurrentEncoding()));
- pCurrentDestinationText->setLength(0);
- auto pValue = new RTFValue(aStr);
- RTFSprms aAnnAttributes;
- aAnnAttributes.set(NS_ooxml::LN_CT_TrackChange_date, pValue);
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aAnnAttributes));
- Mapper().props(pProperties);
- }
- break;
- case Destination::ANNOTATIONAUTHOR:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- m_aAuthor = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- break;
- case Destination::ATNID:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- m_aAuthorInitials = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- break;
- case Destination::ANNOTATIONREFERENCESTART:
- case Destination::ANNOTATIONREFERENCEEND:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- auto pValue = new RTFValue(aStr.toInt32());
- RTFSprms aAttributes;
- if (rState.getDestination() == Destination::ANNOTATIONREFERENCESTART)
- aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart, pValue);
- else
- aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd, pValue);
- if (!m_aStates.top().getCurrentBuffer())
- {
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aAttributes));
- Mapper().props(pProperties);
- }
- else
- {
- auto const pValue2 = new RTFValue(aAttributes, RTFSprms());
- bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue2, nullptr);
- }
- }
- break;
- case Destination::ANNOTATIONREFERENCE:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- RTFSprms aAnnAttributes;
- aAnnAttributes.set(NS_ooxml::LN_CT_Markup_id, new RTFValue(aStr.toInt32()));
- Mapper().props(new RTFReferenceProperties(std::move(aAnnAttributes)));
- }
- break;
- case Destination::FALT:
- {
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- OUString aStr(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- auto pValue = new RTFValue(aStr);
- rState.getTableSprms().set(NS_ooxml::LN_CT_Font_altName, pValue);
- }
- break;
- case Destination::DRAWINGOBJECT:
- if (m_aStates.top().getDrawingObject().getShape().is())
- {
- RTFDrawingObject& rDrawing = m_aStates.top().getDrawingObject();
- const uno::Reference<drawing::XShape>& xShape(rDrawing.getShape());
- const uno::Reference<beans::XPropertySet>& xPropertySet(rDrawing.getPropertySet());
-
- uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
- bool bTextFrame = xServiceInfo->supportsService("com.sun.star.text.TextFrame");
-
- // The default is certainly not inline, but then what Word supports is just at-character.
- xPropertySet->setPropertyValue("AnchorType",
- uno::Any(text::TextContentAnchorType_AT_CHARACTER));
-
- if (bTextFrame)
- {
- xPropertySet->setPropertyValue("HoriOrientPosition",
- uno::Any(rDrawing.getLeft()));
- xPropertySet->setPropertyValue("VertOrientPosition",
- uno::Any(rDrawing.getTop()));
- }
- else
- {
- xShape->setPosition(awt::Point(rDrawing.getLeft(), rDrawing.getTop()));
- }
- xShape->setSize(awt::Size(rDrawing.getRight(), rDrawing.getBottom()));
-
- if (rDrawing.getHasLineColor())
- {
- uno::Any aLineColor(sal_uInt32((rDrawing.getLineColorR() << 16)
- + (rDrawing.getLineColorG() << 8)
- + rDrawing.getLineColorB()));
- uno::Any aLineWidth;
- RTFSdrImport::resolveLineColorAndWidth(bTextFrame, xPropertySet, aLineColor,
- aLineWidth);
- }
- if (rDrawing.getHasFillColor())
- xPropertySet->setPropertyValue(
- "FillColor", uno::Any(sal_uInt32((rDrawing.getFillColorR() << 16)
- + (rDrawing.getFillColorG() << 8)
- + rDrawing.getFillColorB())));
- else if (!bTextFrame)
- // If there is no fill, the Word default is 100% transparency.
- xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_Int32(100)));
-
- RTFSdrImport::resolveFLine(xPropertySet, rDrawing.getFLine());
-
- if (!m_aStates.top().getDrawingObject().getHadShapeText())
- {
- Mapper().startShape(xShape);
- }
- Mapper().endShape();
- }
- break;
- case Destination::PICT:
- // fdo#79319 ignore picture data if it's really a shape
- if (!m_pSdrImport->isFakePict())
- {
- resolvePict(true, m_pSdrImport->getCurrentShape());
- }
- m_bNeedFinalPar = true;
- break;
- case Destination::SHAPE:
- m_bNeedFinalPar = true;
- m_bNeedCr = m_bNeedCrOrig;
- // tdf#47036 insert paragraph break for graphic object inside text
- // frame at start of document - TODO: the object may actually be
- // anchored inside the text frame and this ends up putting the
- // anchor in the body, but better than losing the shape...
- if (rState.getFrame().hasProperties() && m_pSdrImport->isTextGraphicObject())
- {
- // parBreak() modifies m_aStates.top() so we can't apply resetFrame() directly on aState
- resetFrame();
- parBreak();
- // Save this state for later use, so we only reset frame status only for the first shape inside a frame.
- rState = m_aStates.top();
- m_bNeedPap = true;
- }
- break;
- case Destination::MOMATH:
- {
- m_aMathBuffer.appendClosingTag(M_TOKEN(oMath));
-
- SvGlobalName aGlobalName(SO3_SM_CLASSID);
- comphelper::EmbeddedObjectContainer aContainer;
- OUString aName;
- uno::Reference<embed::XEmbeddedObject> xObject
- = aContainer.CreateEmbeddedObject(aGlobalName.GetByteSequence(), aName);
- if (xObject) // rhbz#1766990 starmath might not be available
- {
- uno::Reference<util::XCloseable> xComponent(xObject->getComponent(),
- uno::UNO_SET_THROW);
- if (oox::FormulaImExportBase* pImport
- = dynamic_cast<oox::FormulaImExportBase*>(xComponent.get()))
- pImport->readFormulaOoxml(m_aMathBuffer);
-
- auto pValue = new RTFValue(xObject);
- RTFSprms aMathAttributes;
- aMathAttributes.set(NS_ooxml::LN_starmath, pValue);
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aMathAttributes));
- Mapper().props(pProperties);
- }
-
- m_aMathBuffer = oox::formulaimport::XmlStreamBuilder();
- }
- break;
- case Destination::MR:
- lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
- m_bMathNor);
- break;
- case Destination::MF:
- m_aMathBuffer.appendClosingTag(M_TOKEN(f));
- break;
- case Destination::MFPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(fPr));
- break;
- case Destination::MCTRLPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(ctrlPr));
- break;
- case Destination::MNUM:
- m_aMathBuffer.appendClosingTag(M_TOKEN(num));
- break;
- case Destination::MDEN:
- m_aMathBuffer.appendClosingTag(M_TOKEN(den));
- break;
- case Destination::MACC:
- m_aMathBuffer.appendClosingTag(M_TOKEN(acc));
- break;
- case Destination::MACCPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(accPr));
- break;
- case Destination::MCHR:
- case Destination::MPOS:
- case Destination::MVERTJC:
- case Destination::MSTRIKEH:
- case Destination::MDEGHIDE:
- case Destination::MBEGCHR:
- case Destination::MSEPCHR:
- case Destination::MENDCHR:
- case Destination::MSUBHIDE:
- case Destination::MSUPHIDE:
- case Destination::MTYPE:
- case Destination::MGROW:
- {
- sal_Int32 nMathToken = 0;
- switch (rState.getDestination())
- {
- case Destination::MCHR:
- nMathToken = M_TOKEN(chr);
- break;
- case Destination::MPOS:
- nMathToken = M_TOKEN(pos);
- break;
- case Destination::MVERTJC:
- nMathToken = M_TOKEN(vertJc);
- break;
- case Destination::MSTRIKEH:
- nMathToken = M_TOKEN(strikeH);
- break;
- case Destination::MDEGHIDE:
- nMathToken = M_TOKEN(degHide);
- break;
- case Destination::MBEGCHR:
- nMathToken = M_TOKEN(begChr);
- break;
- case Destination::MSEPCHR:
- nMathToken = M_TOKEN(sepChr);
- break;
- case Destination::MENDCHR:
- nMathToken = M_TOKEN(endChr);
- break;
- case Destination::MSUBHIDE:
- nMathToken = M_TOKEN(subHide);
- break;
- case Destination::MSUPHIDE:
- nMathToken = M_TOKEN(supHide);
- break;
- case Destination::MTYPE:
- nMathToken = M_TOKEN(type);
- break;
- case Destination::MGROW:
- nMathToken = M_TOKEN(grow);
- break;
- default:
- break;
- }
-
- oox::formulaimport::XmlStream::AttributeList aAttribs;
- aAttribs[M_TOKEN(val)]
- = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- m_aMathBuffer.appendOpeningTag(nMathToken, aAttribs);
- m_aMathBuffer.appendClosingTag(nMathToken);
- }
- break;
- case Destination::ME:
- m_aMathBuffer.appendClosingTag(M_TOKEN(e));
- break;
- case Destination::MBAR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(bar));
- break;
- case Destination::MBARPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(barPr));
- break;
- case Destination::MD:
- m_aMathBuffer.appendClosingTag(M_TOKEN(d));
- break;
- case Destination::MDPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(dPr));
- break;
- case Destination::MFUNC:
- m_aMathBuffer.appendClosingTag(M_TOKEN(func));
- break;
- case Destination::MFUNCPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(funcPr));
- break;
- case Destination::MFNAME:
- m_aMathBuffer.appendClosingTag(M_TOKEN(fName));
- break;
- case Destination::MLIMLOW:
- m_aMathBuffer.appendClosingTag(M_TOKEN(limLow));
- break;
- case Destination::MLIMLOWPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(limLowPr));
- break;
- case Destination::MLIM:
- m_aMathBuffer.appendClosingTag(M_TOKEN(lim));
- break;
- case Destination::MM:
- m_aMathBuffer.appendClosingTag(M_TOKEN(m));
- break;
- case Destination::MMPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(mPr));
- break;
- case Destination::MMR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(mr));
- break;
- case Destination::MNARY:
- m_aMathBuffer.appendClosingTag(M_TOKEN(nary));
- break;
- case Destination::MNARYPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(naryPr));
- break;
- case Destination::MSUB:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sub));
- break;
- case Destination::MSUP:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sup));
- break;
- case Destination::MLIMUPP:
- m_aMathBuffer.appendClosingTag(M_TOKEN(limUpp));
- break;
- case Destination::MLIMUPPPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(limUppPr));
- break;
- case Destination::MGROUPCHR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(groupChr));
- break;
- case Destination::MGROUPCHRPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(groupChrPr));
- break;
- case Destination::MBORDERBOX:
- m_aMathBuffer.appendClosingTag(M_TOKEN(borderBox));
- break;
- case Destination::MBORDERBOXPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(borderBoxPr));
- break;
- case Destination::MRAD:
- m_aMathBuffer.appendClosingTag(M_TOKEN(rad));
- break;
- case Destination::MRADPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(radPr));
- break;
- case Destination::MDEG:
- m_aMathBuffer.appendClosingTag(M_TOKEN(deg));
- break;
- case Destination::MSSUB:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sSub));
- break;
- case Destination::MSSUBPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sSubPr));
- break;
- case Destination::MSSUP:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sSup));
- break;
- case Destination::MSSUPPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sSupPr));
- break;
- case Destination::MSSUBSUP:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSup));
- break;
- case Destination::MSSUBSUPPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSupPr));
- break;
- case Destination::MSPRE:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sPre));
- break;
- case Destination::MSPREPR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(sPrePr));
- break;
- case Destination::MBOX:
- m_aMathBuffer.appendClosingTag(M_TOKEN(box));
- break;
- case Destination::MEQARR:
- m_aMathBuffer.appendClosingTag(M_TOKEN(eqArr));
- break;
- case Destination::SHAPEGROUP:
- if (rState.getCreatedShapeGroup())
- m_pSdrImport->popParent();
- break;
- case Destination::PROPNAME:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- rState.setPropName(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
- break;
- case Destination::STATICVAL:
- if (&m_aStates.top().getDestinationText()
- != m_aStates.top().getCurrentDestinationText())
- break; // not for nested group
- if (m_xDocumentProperties.is())
- {
- // Find out what is the key, value type and value we want to set.
- uno::Reference<beans::XPropertyContainer> xPropertyContainer
- = m_xDocumentProperties->getUserDefinedProperties();
- const OUString& rKey = m_aStates.top().getPropName();
- OUString aStaticVal
- = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
- uno::Any aAny;
- if (m_aStates.top().getPropType() == cppu::UnoType<OUString>::get())
- aAny <<= aStaticVal;
- else if (m_aStates.top().getPropType() == cppu::UnoType<sal_Int32>::get())
- aAny <<= aStaticVal.toInt32();
- else if (m_aStates.top().getPropType() == cppu::UnoType<bool>::get())
- aAny <<= aStaticVal.toBoolean();
- else if (m_aStates.top().getPropType() == cppu::UnoType<util::DateTime>::get())
- aAny <<= getDateTimeFromUserProp(aStaticVal);
- else if (m_aStates.top().getPropType() == cppu::UnoType<double>::get())
- aAny <<= aStaticVal.toDouble();
-
- xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
- }
- break;
- case Destination::USERPROPS:
- {
- // These are the imported properties.
- uno::Reference<document::XDocumentProperties> xDocumentProperties
- = m_xDocumentProperties;
-
- // These are the real document properties.
- uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
- m_xDstDoc, uno::UNO_QUERY);
- if (xDocumentPropertiesSupplier.is())
- m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
-
- if (m_xDocumentProperties.is())
- {
- if (!m_bIsNewDoc)
- {
- // Check classification.
- if (!SfxClassificationHelper::ShowPasteInfo(SfxClassificationHelper::CheckPaste(
- xDocumentProperties, m_xDocumentProperties)))
- return RTFError::CLASSIFICATION;
- }
-
- uno::Reference<beans::XPropertyContainer> xClipboardPropertyContainer
- = xDocumentProperties->getUserDefinedProperties();
- uno::Reference<beans::XPropertyContainer> xDocumentPropertyContainer
- = m_xDocumentProperties->getUserDefinedProperties();
- uno::Reference<beans::XPropertySet> xClipboardPropertySet(
- xClipboardPropertyContainer, uno::UNO_QUERY);
- uno::Reference<beans::XPropertySet> xDocumentPropertySet(xDocumentPropertyContainer,
- uno::UNO_QUERY);
- const uno::Sequence<beans::Property> aClipboardProperties
- = xClipboardPropertySet->getPropertySetInfo()->getProperties();
- uno::Sequence<beans::Property> aDocumentProperties
- = xDocumentPropertySet->getPropertySetInfo()->getProperties();
-
- for (const beans::Property& rProperty : aClipboardProperties)
- {
- const OUString& rKey = rProperty.Name;
- uno::Any aValue = xClipboardPropertySet->getPropertyValue(rKey);
-
- try
- {
- if (lcl_containsProperty(aDocumentProperties, rKey))
- {
- // When pasting, don't update existing properties.
- if (!m_bIsNewDoc)
- xDocumentPropertySet->setPropertyValue(rKey, aValue);
- }
- else
- xDocumentPropertyContainer->addProperty(
- rKey, beans::PropertyAttribute::REMOVABLE, aValue);
- }
- catch (const uno::Exception&)
- {
- TOOLS_WARN_EXCEPTION("writerfilter.rtf", "failed to set property " << rKey);
- }
- }
- }
- }
- break;
- default:
- break;
- }
-
- return RTFError::OK;
-}
-
-void RTFDocumentImpl::afterPopState(RTFParserState& rState)
-{
- // list table
- switch (rState.getDestination())
- {
- case Destination::LISTENTRY:
- {
- auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
- m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pValue,
- RTFOverwrite::NO_APPEND);
- m_aListTable[rState.getCurrentListIndex()] = pValue;
- m_nListLevel = -1;
- m_aInvalidListTableFirstIndents[rState.getCurrentListIndex()]
- = m_aInvalidListLevelFirstIndents;
- m_aInvalidListLevelFirstIndents.clear();
- }
- break;
- case Destination::PARAGRAPHNUMBERING:
- {
- RTFValue::Pointer_t pIdValue
- = rState.getTableAttributes().find(NS_ooxml::LN_CT_AbstractNum_nsid);
- if (pIdValue && !m_aStates.empty())
- {
- // Abstract numbering
- RTFSprms aLeveltextAttributes;
- OUString aTextValue;
- RTFValue::Pointer_t pTextBefore
- = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelText_val);
- if (pTextBefore)
- aTextValue += pTextBefore->getString();
- aTextValue += "%1";
- RTFValue::Pointer_t pTextAfter
- = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelSuffix_val);
- if (pTextAfter)
- aTextValue += pTextAfter->getString();
- auto pTextValue = new RTFValue(aTextValue);
- aLeveltextAttributes.set(NS_ooxml::LN_CT_LevelText_val, pTextValue);
-
- RTFSprms aLevelAttributes;
- RTFSprms aLevelSprms;
- auto pIlvlValue = new RTFValue(0);
- aLevelAttributes.set(NS_ooxml::LN_CT_Lvl_ilvl, pIlvlValue);
-
- RTFValue::Pointer_t pFmtValue
- = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_numFmt);
- if (pFmtValue)
- aLevelSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, pFmtValue);
-
- RTFValue::Pointer_t pStartatValue
- = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_start);
- if (pStartatValue)
- aLevelSprms.set(NS_ooxml::LN_CT_Lvl_start, pStartatValue);
-
- auto pLeveltextValue = new RTFValue(aLeveltextAttributes);
- aLevelSprms.set(NS_ooxml::LN_CT_Lvl_lvlText, pLeveltextValue);
- RTFValue::Pointer_t pRunProps
- = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_rPr);
- if (pRunProps)
- aLevelSprms.set(NS_ooxml::LN_CT_Lvl_rPr, pRunProps);
-
- RTFSprms aAbstractAttributes;
- RTFSprms aAbstractSprms;
- aAbstractAttributes.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, pIdValue);
- auto pLevelValue = new RTFValue(aLevelAttributes, aLevelSprms);
- aAbstractSprms.set(NS_ooxml::LN_CT_AbstractNum_lvl, pLevelValue,
- RTFOverwrite::NO_APPEND);
-
- RTFSprms aListTableSprms;
- auto pAbstractValue = new RTFValue(aAbstractAttributes, aAbstractSprms);
- // It's important that Numbering_abstractNum and Numbering_num never overwrites previous values.
- aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pAbstractValue,
- RTFOverwrite::NO_APPEND);
-
- // Numbering
- RTFSprms aNumberingAttributes;
- RTFSprms aNumberingSprms;
- aNumberingAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pIdValue);
- aNumberingSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIdValue);
- auto pNumberingValue = new RTFValue(aNumberingAttributes, aNumberingSprms);
- aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pNumberingValue,
- RTFOverwrite::NO_APPEND);
-
- // Table
- RTFSprms aListTableAttributes;
- writerfilter::Reference<Properties>::Pointer_t pProp = new RTFReferenceProperties(
- std::move(aListTableAttributes), std::move(aListTableSprms));
-
- RTFReferenceTable::Entries_t aListTableEntries;
- aListTableEntries.insert(std::make_pair(0, pProp));
- writerfilter::Reference<Table>::Pointer_t const pTable(
- new RTFReferenceTable(std::move(aListTableEntries)));
- Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
-
- // Use it
- putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
- NS_ooxml::LN_CT_NumPr_ilvl, pIlvlValue, RTFOverwrite::YES_PREPEND);
- putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
- NS_ooxml::LN_CT_NumPr_numId, pIdValue, RTFOverwrite::YES_PREPEND);
- }
- }
- break;
- case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
- if (!m_aStates.empty())
- {
- // FIXME: don't use pDestinationText, points to popped state
- auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
- m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelSuffix_val, pValue);
- }
- break;
- case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
- if (!m_aStates.empty())
- {
- // FIXME: don't use pDestinationText, points to popped state
- auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
- m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
- }
- break;
- case Destination::LISTNAME:
- break;
- case Destination::LISTLEVEL:
- if (!m_aStates.empty())
- {
- auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
- rState.getTableAttributes().set(NS_ooxml::LN_CT_Lvl_ilvl, pInnerValue);
-
- auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
- if (m_aStates.top().getDestination() != Destination::LFOLEVEL)
- m_aStates.top().getListLevelEntries().set(NS_ooxml::LN_CT_AbstractNum_lvl,
- pValue, RTFOverwrite::NO_APPEND);
- else
- m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_NumLvl_lvl, pValue);
- }
- break;
- case Destination::LFOLEVEL:
- if (!m_aStates.empty())
- {
- auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
- rState.getTableAttributes().set(NS_ooxml::LN_CT_NumLvl_ilvl, pInnerValue);
-
- auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
- m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_lvlOverride, pValue,
- RTFOverwrite::NO_APPEND);
- }
- break;
- // list override table
- case Destination::LISTOVERRIDEENTRY:
- if (!m_aStates.empty())
- {
- if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
- {
- // copy properties upwards so upper popState() inserts it
- m_aStates.top().getTableAttributes() = rState.getTableAttributes();
- m_aStates.top().getTableSprms() = rState.getTableSprms();
- }
- else
- {
- auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
- m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pValue,
- RTFOverwrite::NO_APPEND);
- m_aListOverrideTable[rState.getCurrentListOverrideIndex()]
- = rState.getCurrentListIndex();
- }
- }
- break;
- case Destination::LEVELTEXT:
- if (!m_aStates.empty())
- {
- auto pValue = new RTFValue(rState.getTableAttributes());
- m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_lvlText, pValue);
- }
- break;
- case Destination::LEVELNUMBERS:
- if (!m_aStates.empty())
- {
- m_aStates.top().getTableSprms() = rState.getTableSprms();
- if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS
- || m_aStates.top().getDestination() == Destination::LISTLEVEL)
- // Parent state is level number or list level, current state is
- // level numbers: mark parent as invalid as well if necessary.
- m_aStates.top().setLevelNumbersValid(rState.getLevelNumbersValid());
- }
- break;
- case Destination::FIELDINSTRUCTION:
- if (!m_aStates.empty())
- m_aStates.top().setFieldStatus(RTFFieldStatus::INSTRUCTION);
- break;
- case Destination::FIELDRESULT:
- if (!m_aStates.empty())
- m_aStates.top().setFieldStatus(RTFFieldStatus::RESULT);
- break;
- case Destination::FIELD:
- if (rState.getFieldStatus() == RTFFieldStatus::INSTRUCTION)
- singleChar(cFieldEnd);
- break;
- case Destination::DOCVAR:
- if (!m_aStates.empty())
- {
- OUString docvar(rState.getDocVar());
- if (m_aStates.top().getDocVarName().isEmpty())
- {
- m_aStates.top().setDocVarName(docvar);
- }
- else
- {
- uno::Reference<beans::XPropertySet> xMaster(
- m_xModelFactory->createInstance("com.sun.star.text.FieldMaster.User"),
- uno::UNO_QUERY_THROW);
- xMaster->setPropertyValue("Name", uno::Any(m_aStates.top().getDocVarName()));
- uno::Reference<text::XDependentTextField> xField(
- m_xModelFactory->createInstance("com.sun.star.text.TextField.User"),
- uno::UNO_QUERY);
- xField->attachTextFieldMaster(xMaster);
- xField->getTextFieldMaster()->setPropertyValue("Content", uno::Any(docvar));
-
- m_aStates.top().clearDocVarName();
- }
- }
- break;
- case Destination::SHAPEPROPERTYVALUEPICT:
- if (!m_aStates.empty())
- {
- m_aStates.top().getPicture() = rState.getPicture();
- // both \sp and \sv are destinations, copy the text up-ward for later
- m_aStates.top().getDestinationText() = rState.getDestinationText();
- }
- break;
- case Destination::FALT:
- if (!m_aStates.empty())
- m_aStates.top().getTableSprms() = rState.getTableSprms();
- break;
- case Destination::SHAPEPROPERTYNAME:
- case Destination::SHAPEPROPERTYVALUE:
- case Destination::SHAPEPROPERTY:
- if (!m_aStates.empty())
- {
- m_aStates.top().getShape() = rState.getShape();
- m_aStates.top().getPicture() = rState.getPicture();
- m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
- }
- break;
- case Destination::SHAPEINSTRUCTION:
- if (!m_aStates.empty()
- && m_aStates.top().getDestination() == Destination::SHAPEINSTRUCTION)
- {
- // Shape instruction inside other shape instruction: just copy new shape settings:
- // it will be resolved on end of topmost shape instruction destination
- m_aStates.top().getShape() = rState.getShape();
- m_aStates.top().getPicture() = rState.getPicture();
- m_aStates.top().getCharacterSprms() = rState.getCharacterSprms();
- m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
- }
- break;
- case Destination::FLYMAINCONTENT:
- case Destination::SHPPICT:
- case Destination::SHAPE:
- if (!m_aStates.empty())
- {
- m_aStates.top().getFrame() = rState.getFrame();
- if (rState.getDestination() == Destination::SHPPICT
- && m_aStates.top().getDestination() == Destination::LISTPICTURE)
- {
- RTFSprms aAttributes;
- aAttributes.set(NS_ooxml::LN_CT_NumPicBullet_numPicBulletId,
- new RTFValue(m_nListPictureId++));
- RTFSprms aSprms;
- // Dummy value, real picture is already sent to dmapper.
- aSprms.set(NS_ooxml::LN_CT_NumPicBullet_pict, new RTFValue(0));
- auto pValue = new RTFValue(aAttributes, aSprms);
- m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_numPicBullet, pValue,
- RTFOverwrite::NO_APPEND);
- }
- }
- break;
- case Destination::SHAPETEXT:
- if (!m_aStates.empty())
- {
- // If we're leaving the shapetext group (it may have nested ones) and this is a shape, not an old drawingobject.
- if (m_aStates.top().getDestination() != Destination::SHAPETEXT
- && !m_aStates.top().getDrawingObject().getHadShapeText())
- {
- m_aStates.top().setHadShapeText(true);
- if (!m_aStates.top().getCurrentBuffer())
- m_pSdrImport->close();
- else
- m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_ENDSHAPE, nullptr,
- nullptr);
- }
-
- // It's allowed to declare these inside the shape text, and they
- // are expected to have an effect for the whole shape.
- if (rState.getDrawingObject().getLeft())
- m_aStates.top().getDrawingObject().setLeft(rState.getDrawingObject().getLeft());
- if (rState.getDrawingObject().getTop())
- m_aStates.top().getDrawingObject().setTop(rState.getDrawingObject().getTop());
- if (rState.getDrawingObject().getRight())
- m_aStates.top().getDrawingObject().setRight(
- rState.getDrawingObject().getRight());
- if (rState.getDrawingObject().getBottom())
- m_aStates.top().getDrawingObject().setBottom(
- rState.getDrawingObject().getBottom());
- }
- break;
- case Destination::PROPNAME:
- if (m_aStates.top().getDestination() == Destination::USERPROPS)
- m_aStates.top().setPropName(rState.getPropName());
- break;
- default:
- {
- if (!m_aStates.empty() && m_aStates.top().getDestination() == Destination::PICT)
- m_aStates.top().getPicture() = rState.getPicture();
- }
- break;
- }
-}
-
-RTFError RTFDocumentImpl::popState()
-{
- //SAL_INFO("writerfilter", __func__ << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
- // ", dest state: " << m_aStates.top().eDestination);
-
- checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
- RTFParserState aState(m_aStates.top());
- m_bWasInFrame = aState.getFrame().hasProperties();
-
- // dmapper expects some content in header/footer, so if there would be nothing, add an empty paragraph.
- if (m_pTokenizer->getGroup() == 1 && m_bFirstRun)
- {
- switch (m_nStreamType)
- {
- case NS_ooxml::LN_headerl:
- case NS_ooxml::LN_headerr:
- case NS_ooxml::LN_headerf:
- case NS_ooxml::LN_footerl:
- case NS_ooxml::LN_footerr:
- case NS_ooxml::LN_footerf:
- dispatchSymbol(RTFKeyword::PAR);
- break;
- }
- }
-
- RTFError eError = beforePopState(aState);
- if (eError != RTFError::OK)
- return eError;
-
- // See if we need to end a track change
- if (aState.getStartedTrackchange())
- {
- RTFSprms aTCSprms;
- auto pValue = new RTFValue(0);
- aTCSprms.set(NS_ooxml::LN_endtrackchange, pValue);
- if (!m_aStates.top().getCurrentBuffer())
- Mapper().props(new RTFReferenceProperties(RTFSprms(), std::move(aTCSprms)));
- else
- bufferProperties(*m_aStates.top().getCurrentBuffer(),
- new RTFValue(RTFSprms(), aTCSprms), nullptr);
- }
-
- // This is the end of the doc, see if we need to close the last section.
- if (m_pTokenizer->getGroup() == 1 && !m_bFirstRun)
- {
- // \par means an empty paragraph at the end of footnotes/endnotes, but
- // not in case of other substreams, like headers.
- if (m_bNeedCr && m_nStreamType != NS_ooxml::LN_footnote
- && m_nStreamType != NS_ooxml::LN_endnote)
- {
- if (!m_bIsNewDoc)
- {
- // Make sure all the paragraph settings are set, but do not add next paragraph
- Mapper().markLastParagraph();
- }
- dispatchSymbol(RTFKeyword::PAR);
- }
- if (m_bNeedSect) // may be set by dispatchSymbol above!
- sectBreak(true);
- else if (!m_pSuperstream)
- {
- Mapper().markLastSectionGroup(); // ensure it's set for \par below
- }
- if (m_bNeedPar && !m_pSuperstream)
- {
- assert(!m_bNeedSect);
- dispatchSymbol(RTFKeyword::PAR);
- m_bNeedSect = false; // reset - m_bNeedPar was set for \sect at
- // end of doc so don't need another one
- }
- }
-
- m_aStates.pop();
-
- m_pTokenizer->popGroup();
-
- afterPopState(aState);
-
- if (aState.getCurrentBuffer() == &m_aSuperBuffer)
- {
- OSL_ASSERT(!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr);
-
- if (!m_aSuperBuffer.empty())
- replayBuffer(m_aSuperBuffer, nullptr, nullptr);
- }
-
- if (!m_aStates.empty() && m_aStates.top().getTableRowWidthAfter() > 0
- && aState.getTableRowWidthAfter() == 0)
- // An RTFKeyword::ROW in the inner group already parsed nTableRowWidthAfter,
- // don't do it again in the outer state later.
- m_aStates.top().setTableRowWidthAfter(0);
-
- if (m_nResetBreakOnSectBreak != RTFKeyword::invalid && !m_aStates.empty())
- {
- // Section break type created for \page still has an effect in the
- // outer state as well.
- RTFValue::Pointer_t pType
- = aState.getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
- if (pType)
- m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pType);
- }
-
- return RTFError::OK;
-}
-
-RTFError RTFDocumentImpl::handleEmbeddedObject()
-{
- OUStringBuffer* pCurrentDestinationText = m_aStates.top().getCurrentDestinationText();
- OString aStr = OUStringToOString(*pCurrentDestinationText, RTL_TEXTENCODING_ASCII_US);
- pCurrentDestinationText->setLength(0);
- std::unique_ptr<SvStream> pStream(new SvMemoryStream());
- if (!msfilter::rtfutil::ExtractOLE2FromObjdata(aStr, *pStream))
- return RTFError::HEX_INVALID;
-
- uno::Reference<io::XInputStream> xInputStream(
- new utl::OSeekableInputStreamWrapper(pStream.release(), /*_bOwner=*/true));
- m_aOLEAttributes.set(NS_ooxml::LN_inputstream, new RTFValue(xInputStream));
-
- return RTFError::OK;
-}
-
-bool RTFDocumentImpl::isInBackground() { return m_aStates.top().getInBackground(); }
-
-RTFInternalState RTFDocumentImpl::getInternalState() { return m_aStates.top().getInternalState(); }
-
-void RTFDocumentImpl::setInternalState(RTFInternalState nInternalState)
-{
- m_aStates.top().setInternalState(nInternalState);
-}
-
-Destination RTFDocumentImpl::getDestination() { return m_aStates.top().getDestination(); }
-
-void RTFDocumentImpl::setDestination(Destination eDestination)
-{
- m_aStates.top().setDestination(eDestination);
-}
-
-// this is a questionably named method that is used only in a very special
-// situation where it looks like the "current" buffer is needed?
-void RTFDocumentImpl::setDestinationText(std::u16string_view rString)
-{
- m_aStates.top().getDestinationText().setLength(0);
- m_aStates.top().getDestinationText().append(rString);
-}
-
-bool RTFDocumentImpl::getSkipUnknown() { return m_bSkipUnknown; }
-
-void RTFDocumentImpl::setSkipUnknown(bool bSkipUnknown) { m_bSkipUnknown = bSkipUnknown; }
-
-static auto FilterControlChars(Destination const destination, OUString const& rString) -> OUString
-{
- if (destination == Destination::LEVELNUMBERS || destination == Destination::LEVELTEXT)
- { // control characters are magic here!
- return rString;
- }
- OUStringBuffer buf(rString.getLength());
- for (sal_Int32 i = 0; i < rString.getLength(); ++i)
- {
- sal_Unicode const ch(rString[i]);
- if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
- {
- buf.append(ch);
- }
- else
- {
- SAL_INFO("writerfilter.rtf", "filtering control character");
- }
- }
- return buf.makeStringAndClear();
-}
-
-void RTFDocumentImpl::checkUnicode(bool bUnicode, bool bHex)
-{
- if (bUnicode && !m_aUnicodeBuffer.isEmpty())
- {
- OUString aString = m_aUnicodeBuffer.toString();
- m_aUnicodeBuffer.setLength(0);
- aString = FilterControlChars(m_aStates.top().getDestination(), aString);
- text(aString);
- }
- if (bHex && !m_aHexBuffer.isEmpty())
- {
- rtl_TextEncoding nEncoding = m_aStates.top().getCurrentEncoding();
- if (nEncoding == RTL_TEXTENCODING_SYMBOL
- && (m_aStates.top().getDestination() == Destination::FONTENTRY
- || (m_aStates.size() > 1
- && m_aStates[m_aStates.size() - 2].getDestination()
- == Destination::FIELDINSTRUCTION)))
- nEncoding = RTL_TEXTENCODING_MS_1252;
- OUString aString = OStringToOUString(m_aHexBuffer, nEncoding);
- m_aHexBuffer.setLength(0);
- aString = FilterControlChars(m_aStates.top().getDestination(), aString);
- text(aString);
- }
-}
-
-RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl)
- : m_pDocumentImpl(pDocumentImpl)
- , m_nInternalState(RTFInternalState::NORMAL)
- , m_eDestination(Destination::NORMAL)
- , m_eFieldStatus(RTFFieldStatus::NONE)
- , m_bFieldLocked(false)
- , m_nBorderState(RTFBorderState::NONE)
- , m_nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0))
- , m_nUc(1)
- , m_nCharsToSkip(0)
- , m_nBinaryToRead(0)
- , m_nListLevelNum(0)
- , m_bLevelNumbersValid(true)
- , m_aFrame(this)
- , m_eRunType(RunType::NONE)
- , m_nYear(0)
- , m_nMonth(0)
- , m_nDay(0)
- , m_nHour(0)
- , m_nMinute(0)
- , m_pCurrentDestinationText(nullptr)
- , m_nCurrentStyleIndex(0)
- , m_nCurrentCharacterStyleIndex(-1)
- , m_pCurrentBuffer(nullptr)
- , m_bInListpicture(false)
- , m_bInBackground(false)
- , m_bHadShapeText(false)
- , m_bInShapeGroup(false)
- , m_bInShape(false)
- , m_bCreatedShapeGroup(false)
- , m_bStartedTrackchange(false)
- , m_nTableRowWidthAfter(0)
-{
-}
-
-void RTFDocumentImpl::resetFrame() { m_aStates.top().getFrame() = RTFFrame(&m_aStates.top()); }
-
-void RTFDocumentImpl::bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
- const tools::SvRef<TableRowBuffer>& pTableProperties,
- Id const nStyleType)
-{
- rBuffer.emplace_back(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()),
- nullptr);
- assert(nStyleType == 0 || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character);
- rBuffer.emplace_back(nStyleType == NS_ooxml::LN_Value_ST_StyleType_character ? BUFFER_PROPS_CHAR
- : BUFFER_PROPS,
- pValue, pTableProperties);
-}
-
-RTFShape::RTFShape() = default;
-
-RTFDrawingObject::RTFDrawingObject() = default;
-
-RTFFrame::RTFFrame(RTFParserState* pParserState)
- : m_pDocumentImpl(pParserState->getDocumentImpl())
- , m_nX(0)
- , m_nY(0)
- , m_nW(0)
- , m_nH(0)
- , m_nHoriPadding(0)
- , m_nVertPadding(0)
- , m_nHoriAlign(0)
- , m_nHoriAnchor(0)
- , m_nVertAlign(0)
- , m_nVertAnchor(0)
- , m_nHRule(NS_ooxml::LN_Value_doc_ST_HeightRule_auto)
-{
-}
-
-void RTFFrame::setSprm(Id nId, Id nValue)
-{
- switch (nId)
- {
- case NS_ooxml::LN_CT_FramePr_w:
- m_nW = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_h:
- m_nH = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_x:
- m_nX = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_y:
- m_nY = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_hSpace:
- m_nHoriPadding = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_vSpace:
- m_nVertPadding = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_xAlign:
- m_nHoriAlign = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_hAnchor:
- m_nHoriAnchor = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_yAlign:
- m_nVertAlign = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_vAnchor:
- m_nVertAnchor = nValue;
- break;
- case NS_ooxml::LN_CT_FramePr_wrap:
- m_oWrap = nValue;
- break;
- default:
- break;
- }
-
- if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport() && hasProperties())
- {
- m_pDocumentImpl->checkFirstRun();
- m_pDocumentImpl->setNeedPar(false);
- }
-}
-
-RTFSprms RTFFrame::getSprms()
-{
- RTFSprms sprms;
-
- static const Id pNames[]
- = { NS_ooxml::LN_CT_FramePr_x, NS_ooxml::LN_CT_FramePr_y,
- NS_ooxml::LN_CT_FramePr_hRule, // Make sure nHRule is processed before nH
- NS_ooxml::LN_CT_FramePr_h, NS_ooxml::LN_CT_FramePr_w,
- NS_ooxml::LN_CT_FramePr_hSpace, NS_ooxml::LN_CT_FramePr_vSpace,
- NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_CT_FramePr_vAnchor,
- NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_CT_FramePr_yAlign,
- NS_ooxml::LN_CT_FramePr_wrap, NS_ooxml::LN_CT_FramePr_dropCap,
- NS_ooxml::LN_CT_FramePr_lines };
-
- for (Id nId : pNames)
- {
- RTFValue::Pointer_t pValue;
-
- switch (nId)
- {
- case NS_ooxml::LN_CT_FramePr_x:
- if (m_nX != 0)
- pValue = new RTFValue(m_nX);
- break;
- case NS_ooxml::LN_CT_FramePr_y:
- if (m_nY != 0)
- pValue = new RTFValue(m_nY);
- break;
- case NS_ooxml::LN_CT_FramePr_h:
- if (m_nH != 0)
- {
- if (m_nHRule == NS_ooxml::LN_Value_doc_ST_HeightRule_exact)
- pValue = new RTFValue(-m_nH); // The negative value just sets nHRule
- else
- pValue = new RTFValue(m_nH);
- }
- break;
- case NS_ooxml::LN_CT_FramePr_w:
- if (m_nW != 0)
- pValue = new RTFValue(m_nW);
- break;
- case NS_ooxml::LN_CT_FramePr_hSpace:
- if (m_nHoriPadding != 0)
- pValue = new RTFValue(m_nHoriPadding);
- break;
- case NS_ooxml::LN_CT_FramePr_vSpace:
- if (m_nVertPadding != 0)
- pValue = new RTFValue(m_nVertPadding);
- break;
- case NS_ooxml::LN_CT_FramePr_hAnchor:
- {
- if (m_nHoriAnchor == 0)
- m_nHoriAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_text;
- pValue = new RTFValue(m_nHoriAnchor);
- }
- break;
- case NS_ooxml::LN_CT_FramePr_vAnchor:
- {
- if (m_nVertAnchor == 0)
- m_nVertAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
- pValue = new RTFValue(m_nVertAnchor);
- }
- break;
- case NS_ooxml::LN_CT_FramePr_xAlign:
- pValue = new RTFValue(m_nHoriAlign);
- break;
- case NS_ooxml::LN_CT_FramePr_yAlign:
- pValue = new RTFValue(m_nVertAlign);
- break;
- case NS_ooxml::LN_CT_FramePr_hRule:
- {
- if (m_nH < 0)
- m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_exact;
- else if (m_nH > 0)
- m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_atLeast;
- pValue = new RTFValue(m_nHRule);
- }
- break;
- case NS_ooxml::LN_CT_FramePr_wrap:
- if (m_oWrap)
- pValue = new RTFValue(*m_oWrap);
- break;
- default:
- break;
- }
-
- if (pValue)
- sprms.set(nId, pValue);
- }
-
- RTFSprms frameprSprms;
- frameprSprms.set(NS_ooxml::LN_CT_PPrBase_framePr, new RTFValue(sprms));
- return frameprSprms;
-}
-
-bool RTFFrame::hasProperties() const
-{
- // tdf#153178 \dxfrtext \dfrmtxtx \dfrmtxty \wrapdefault do *not* create frame
- return m_nX != 0 || m_nY != 0 || m_nW != 0 || m_nH != 0
- || (m_nHoriAlign && m_nHoriAlign != NS_ooxml::LN_Value_doc_ST_XAlign_left)
- || (m_nHoriAnchor && m_nHoriAnchor != NS_ooxml::LN_Value_doc_ST_HAnchor_text)
- || (m_nVertAlign && m_nVertAlign != NS_ooxml::LN_Value_doc_ST_YAlign_inline)
- || (m_nVertAnchor && m_nVertAnchor != NS_ooxml::LN_Value_doc_ST_VAnchor_margin)
- || (m_oWrap && *m_oWrap != NS_ooxml::LN_Value_doc_ST_Wrap_auto);
-}
-
-} // namespace writerfilter
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */