diff options
Diffstat (limited to 'writerfilter/source/rtftok/rtfdocumentimpl.cxx')
-rw-r--r-- | writerfilter/source/rtftok/rtfdocumentimpl.cxx | 784 |
1 files changed, 497 insertions, 287 deletions
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index dc014457c8d5..ab700ff0dc14 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -8,14 +8,20 @@ */ #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> @@ -23,15 +29,14 @@ #include <filter/msfilter/util.hxx> #include <filter/msfilter/rtfutil.hxx> #include <comphelper/string.hxx> -#include <tools/diagnose_ex.h> +#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/sfxbasemodel.hxx> #include <sfx2/classificationhelper.hxx> -#include <oox/mathml/import.hxx> +#include <oox/mathml/imexport.hxx> #include <ooxml/resourceids.hxx> #include <oox/token/namespaces.hxx> #include <oox/drawingml/drawingmltypes.hxx> @@ -49,26 +54,27 @@ #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(const OUString& rString) +util::DateTime getDateTimeFromUserProp(std::u16string_view rString) { util::DateTime aRet; - sal_Int32 nLen = rString.getLength(); + size_t nLen = rString.size(); if (nLen >= 4) { - aRet.Year = rString.copy(0, 4).toInt32(); + aRet.Year = o3tl::toInt32(rString.substr(0, 4)); - if (nLen >= 8 && rString.match(". ", 4)) + if (nLen >= 8 && o3tl::starts_with(rString.substr(4), u". ")) { - aRet.Month = rString.copy(6, 2).toInt32(); + aRet.Month = o3tl::toInt32(rString.substr(6, 2)); - if (nLen >= 12 && rString.match(". ", 8)) - aRet.Day = rString.copy(10, 2).toInt32(); + if (nLen >= 12 && o3tl::starts_with(rString.substr(8), u". ")) + aRet.Day = o3tl::toInt32(rString.substr(10, 2)); } } return aRet; @@ -79,8 +85,9 @@ 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 }; + 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]; } @@ -183,6 +190,21 @@ void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pVa 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); } @@ -290,11 +312,12 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x , 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(RTF_invalid) + , m_nResetBreakOnSectBreak(RTFKeyword::invalid) , m_bNeedSect(false) // done by checkFirstRun , m_bWasInFrame(false) , m_bHadPicture(false) @@ -307,7 +330,6 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x , m_hasFHeader(false) , m_hasRFooter(false) , m_hasFFooter(false) - , m_bAfterCellBeforeRow(false) { OSL_ASSERT(xInputStream.is()); m_pInStream = utl::UcbStreamHelper::CreateStream(xInputStream, true); @@ -323,6 +345,9 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x 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; @@ -362,6 +387,7 @@ void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& 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); @@ -371,11 +397,15 @@ void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& 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(aSettingsTableEntries); + writerfilter::Reference<Table>::Pointer_t pTable + = new RTFReferenceTable(std::move(aSettingsTableEntries)); Mapper().table(NS_ooxml::LN_settings_settings, pTable); } @@ -390,16 +420,22 @@ void RTFDocumentImpl::checkFirstRun() assert(!m_bNeedSect || m_bFirstRunException); setNeedSect(true); // first call that succeeds - // set the requested default font, if there are none + // 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); - RTFValue::Pointer_t pCurrentFont - = getNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts, - NS_ooxml::LN_CT_Fonts_ascii); - if (pFont && !pCurrentFont) - putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts, - NS_ooxml::LN_CT_Fonts_ascii, pFont); + 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; } @@ -493,16 +529,16 @@ RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSpr int nStyle = 0; if (!m_aStates.empty()) nStyle = m_aStates.top().getCurrentStyleIndex(); - auto it = m_aStyleTableEntries.find(nStyle); - if (it != m_aStyleTableEntries.end()) + 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_aStyleTableEntries.end(); + auto itChar = m_pStyleTableEntries->end(); if (!m_aStates.empty()) { int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex(); - itChar = m_aStyleTableEntries.find(nCharStyle); + itChar = m_pStyleTableEntries->find(nCharStyle); } RTFSprms aStyleSprms; @@ -513,7 +549,7 @@ RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSpr RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get()); lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms); - if (itChar != m_aStyleTableEntries.end()) + if (itChar != m_pStyleTableEntries->end()) { // Found active character style, then update aStyleSprms/Attributes. if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character) @@ -524,17 +560,15 @@ RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSpr } } - // Get rid of direct formatting what is already in the style. - RTFSprms const sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true, &aSprms)); - RTFSprms const attributes( - rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true)); - return new RTFReferenceProperties(attributes, sprms); + 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, aSprms); + = new RTFReferenceProperties(rAttributes, std::move(aSprms)); return pRet; } @@ -555,19 +589,20 @@ void RTFDocumentImpl::checkNeedPap() 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 - = m_aStates.top().getFrame().hasProperties() + = bIsInFrame && m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore); if (hasBreakBeforeFrame) { - dispatchSymbol(RTF_PAR); + dispatchSymbol(RTFKeyword::PAR); m_bNeedPap = false; } Mapper().props(pParagraphProperties); if (hasBreakBeforeFrame) - dispatchSymbol(RTF_PAR); + dispatchSymbol(RTFKeyword::PAR); - if (m_aStates.top().getFrame().hasProperties()) + if (bIsInFrame) { writerfilter::Reference<Properties>::Pointer_t const pFrameProperties( new RTFReferenceProperties(RTFSprms(), m_aStates.top().getFrame().getSprms())); @@ -595,7 +630,8 @@ void RTFDocumentImpl::runProps() { auto pValue = new RTFValue(m_aStates.top().getCharacterAttributes(), m_aStates.top().getCharacterSprms()); - bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr); + 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. @@ -611,13 +647,14 @@ void RTFDocumentImpl::runProps() void RTFDocumentImpl::runBreak() { - sal_uInt8 const sBreak[] = { 0xd }; - Mapper().text(sBreak, 1); + 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(); @@ -636,7 +673,10 @@ void RTFDocumentImpl::parBreak() m_bHadPicture = false; // start new one - Mapper().startParagraphGroup(); + if (!m_bParAtEndOfSection) + { + Mapper().startParagraphGroup(); + } } void RTFDocumentImpl::sectBreak(bool bFinal) @@ -645,22 +685,31 @@ void RTFDocumentImpl::sectBreak(bool bFinal) bool bNeedSect = m_bNeedSect; RTFValue::Pointer_t pBreak = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type); - bool bContinuous - = pBreak - && pBreak->getInt() - == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous); + 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) - dispatchSymbol(RTF_PAR); + { + 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(RTF_PARD); - dispatchSymbol(RTF_PAR); + 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(); @@ -684,7 +733,7 @@ void RTFDocumentImpl::sectBreak(bool bFinal) RTFSprms aSprms; aSprms.set(NS_ooxml::LN_CT_PPr_sectPr, pValue); writerfilter::Reference<Properties>::Pointer_t pProperties - = new RTFReferenceProperties(aAttributes, aSprms); + = 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. @@ -693,7 +742,6 @@ void RTFDocumentImpl::sectBreak(bool bFinal) // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects. Mapper().props(pProperties); - Mapper().endParagraphGroup(); // End Section if (!m_pSuperstream) @@ -761,8 +809,9 @@ OUString RTFDocumentImpl::getStyleName(int nIndex) if (!m_pSuperstream) { OUString aRet; - if (m_aStyleNames.find(nIndex) != m_aStyleNames.end()) - aRet = m_aStyleNames[nIndex]; + auto it = m_aStyleNames.find(nIndex); + if (it != m_aStyleNames.end()) + aRet = it->second; return aRet; } @@ -774,8 +823,9 @@ Id RTFDocumentImpl::getStyleType(int nIndex) if (!m_pSuperstream) { Id nRet = 0; - if (m_aStyleTypes.find(nIndex) != m_aStyleTypes.end()) - nRet = m_aStyleTypes[nIndex]; + auto it = m_aStyleTypes.find(nIndex); + if (it != m_aStyleTypes.end()) + nRet = it->second; return nRet; } @@ -844,8 +894,9 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS int count = 2; // Feed the destination text to a stream. - OString aStr = OUStringToOString(m_aStates.top().getDestinationText().makeStringAndClear(), - RTL_TEXTENCODING_ASCII_US); + 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]; @@ -896,12 +947,18 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream)); WmfExternal aExtHeader; aExtHeader.mapMode = m_aStates.top().getPicture().eWMetafile; - 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? + 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); @@ -927,8 +984,23 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS m_aStates.top().getPicture().nHeight = aSize.Height(); } - // Wrap it in an XShape. 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); @@ -963,7 +1035,7 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS xPropertySet->setPropertyValue("Graphic", uno::Any(xGraphic)); // check if the picture is in an OLE object and if the \objdata element is used - // (see RTF_OBJECT in RTFDocumentImpl::dispatchDestination) + // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination) if (m_bObject) { // Set the object size @@ -978,7 +1050,7 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert(). xPropertySet->setPropertyValue("AnchorType", - uno::makeAny(text::TextContentAnchorType_AS_CHARACTER)); + uno::Any(text::TextContentAnchorType_AS_CHARACTER)); auto pShapeValue = new RTFValue(xShape); m_aObjectAttributes.set(NS_ooxml::LN_shape, pShapeValue); @@ -998,6 +1070,16 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS 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 @@ -1028,12 +1110,6 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS * (nYExt - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB))) / 100L; - if (m_aStates.top().getInShape()) - { - // Picture in shape: it looks like pib picture, so we will stretch the picture to shape size (tdf#49893) - nXExt = m_aStates.top().getShape().getRight() - m_aStates.top().getShape().getLeft(); - nYExt = m_aStates.top().getShape().getBottom() - m_aStates.top().getShape().getTop(); - } 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); @@ -1143,12 +1219,12 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS auto pValue = new RTFValue(m_aStates.top().getShape().getAnchorAttributes(), aAnchorSprms); aSprms.set(NS_ooxml::LN_anchor_anchor, pValue); } - writerfilter::Reference<Properties>::Pointer_t pProperties - = new RTFReferenceProperties(aAttributes, aSprms); 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; @@ -1249,7 +1325,7 @@ RTFError RTFDocumentImpl::resolveChars(char ch) && m_aStates.top().getDestination() != Destination::LEVELTEXT) { checkUnicode(/*bUnicode =*/false, /*bHex =*/true); - dispatchSymbol(RTF_PAR); + dispatchSymbol(RTFKeyword::PAR); } else { @@ -1287,8 +1363,6 @@ RTFError RTFDocumentImpl::resolveChars(char ch) return RTFError::OK; } -bool RTFFrame::inFrame() const { return m_nW > 0 || m_nH > 0 || m_nX > 0 || m_nY > 0; } - void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps) { sal_uInt8 sValue[] = { nValue }; @@ -1297,19 +1371,95 @@ void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps) if (!pCurrentBuffer) { Mapper().startCharacterGroup(); - // Should we send run properties? - if (bRunProps) - runProps(); + } + 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 { - pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, nullptr, nullptr)); auto pValue = new RTFValue(*sValue); - pCurrentBuffer->push_back(Buf_t(BUFFER_TEXT, pValue, nullptr)); - pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, nullptr, nullptr)); + 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) @@ -1325,10 +1475,7 @@ void RTFDocumentImpl::text(OUString& rString) bool bRet = true; switch (m_aStates.top().getDestination()) { - // Note: in fonttbl there may or may not be groups; in stylesheet - // and revtbl groups are mandatory - case Destination::FONTTABLE: - case Destination::FONTENTRY: + // Note: in stylesheet and revtbl groups are mandatory case Destination::STYLEENTRY: case Destination::LISTNAME: case Destination::REVISIONENTRY: @@ -1348,34 +1495,6 @@ void RTFDocumentImpl::text(OUString& rString) = m_aStates.top().getCurrentDestinationText()->makeStringAndClear(); switch (m_aStates.top().getDestination()) { - case Destination::FONTTABLE: - case Destination::FONTENTRY: - { - m_aFontNames[m_nCurrentFontIndex] = aName; - 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(aName)); - - 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)); - } - break; case Destination::STYLEENTRY: { RTFValue::Pointer_t pType @@ -1392,7 +1511,7 @@ void RTFDocumentImpl::text(OUString& rString) writerfilter::Reference<Properties>::Pointer_t const pProp( createStyleProperties()); - m_aStyleTableEntries.insert( + m_pStyleTableEntries->insert( std::make_pair(m_nCurrentStyleIndex, pProp)); } else @@ -1413,6 +1532,13 @@ void RTFDocumentImpl::text(OUString& rString) } } 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: @@ -1483,8 +1609,7 @@ void RTFDocumentImpl::text(OUString& rString) if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign) && m_nTopLevelCells == 0) { - m_aTableBufferStack.back().emplace_back( - Buf_t(BUFFER_UTEXT, new RTFValue(rString), nullptr)); + m_aTableBufferStack.back().emplace_back(BUFFER_UTEXT, new RTFValue(rString), nullptr); return; } @@ -1505,7 +1630,7 @@ void RTFDocumentImpl::text(OUString& rString) else if (pCurrentBuffer) { RTFValue::Pointer_t pValue; - pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, pValue, nullptr)); + pCurrentBuffer->emplace_back(BUFFER_STARTRUN, pValue, nullptr); } if (m_aStates.top().getDestination() == Destination::NORMAL @@ -1514,11 +1639,11 @@ void RTFDocumentImpl::text(OUString& rString) runProps(); if (!pCurrentBuffer) - Mapper().utext(reinterpret_cast<sal_uInt8 const*>(rString.getStr()), rString.getLength()); + Mapper().utext(rString.getStr(), rString.getLength()); else { auto pValue = new RTFValue(rString); - pCurrentBuffer->push_back(Buf_t(BUFFER_UTEXT, pValue, nullptr)); + pCurrentBuffer->emplace_back(BUFFER_UTEXT, pValue, nullptr); } m_bNeedCr = true; @@ -1528,7 +1653,7 @@ void RTFDocumentImpl::text(OUString& rString) else if (pCurrentBuffer) { RTFValue::Pointer_t pValue; - pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, pValue, nullptr)); + pCurrentBuffer->emplace_back(BUFFER_ENDRUN, pValue, nullptr); } } @@ -1599,20 +1724,20 @@ void RTFDocumentImpl::sendProperties( tableBreak(); } -void RTFDocumentImpl::replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSrpms, +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, &rCellsSrpms.front(), &rCellsAttributes.front()); - rCellsSrpms.pop_front(); + 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(rCellsSrpms.empty()); + assert(rCellsSprms.empty()); assert(rCellsAttributes.empty()); } @@ -1623,11 +1748,13 @@ void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms, { Buf_t aTuple(rBuffer.front()); rBuffer.pop_front(); - if (std::get<0>(aTuple) == BUFFER_PROPS) + 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(), 0)); + 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) @@ -1661,8 +1788,7 @@ void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms, else if (std::get<0>(aTuple) == BUFFER_UTEXT) { OUString const aString(std::get<1>(aTuple)->getString()); - Mapper().utext(reinterpret_cast<sal_uInt8 const*>(aString.getStr()), - aString.getLength()); + Mapper().utext(aString.getStr(), aString.getLength()); } else if (std::get<0>(aTuple) == BUFFER_ENDRUN) Mapper().endCharacterGroup(); @@ -1679,9 +1805,11 @@ void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms, // 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) @@ -1759,49 +1887,49 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n // Underline toggles. switch (nKeyword) { - case RTF_UL: + case RTFKeyword::UL: nSprm = NS_ooxml::LN_Value_ST_Underline_single; break; - case RTF_ULDASH: + case RTFKeyword::ULDASH: nSprm = NS_ooxml::LN_Value_ST_Underline_dash; break; - case RTF_ULDASHD: + case RTFKeyword::ULDASHD: nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash; break; - case RTF_ULDASHDD: + case RTFKeyword::ULDASHDD: nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash; break; - case RTF_ULDB: + case RTFKeyword::ULDB: nSprm = NS_ooxml::LN_Value_ST_Underline_double; break; - case RTF_ULHWAVE: + case RTFKeyword::ULHWAVE: nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy; break; - case RTF_ULLDASH: + case RTFKeyword::ULLDASH: nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong; break; - case RTF_ULTH: + case RTFKeyword::ULTH: nSprm = NS_ooxml::LN_Value_ST_Underline_thick; break; - case RTF_ULTHD: + case RTFKeyword::ULTHD: nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy; break; - case RTF_ULTHDASH: + case RTFKeyword::ULTHDASH: nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy; break; - case RTF_ULTHDASHD: + case RTFKeyword::ULTHDASHD: nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy; break; - case RTF_ULTHDASHDD: + case RTFKeyword::ULTHDASHDD: nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy; break; - case RTF_ULTHLDASH: + case RTFKeyword::ULTHLDASH: nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy; break; - case RTF_ULULDBWAVE: + case RTFKeyword::ULULDBWAVE: nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble; break; - case RTF_ULWAVE: + case RTFKeyword::ULWAVE: nSprm = NS_ooxml::LN_Value_ST_Underline_wave; break; default: @@ -1818,19 +1946,19 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n // Accent characters (over dot / over comma). switch (nKeyword) { - case RTF_ACCNONE: + case RTFKeyword::ACCNONE: nSprm = NS_ooxml::LN_Value_ST_Em_none; break; - case RTF_ACCDOT: + case RTFKeyword::ACCDOT: nSprm = NS_ooxml::LN_Value_ST_Em_dot; break; - case RTF_ACCCOMMA: + case RTFKeyword::ACCCOMMA: nSprm = NS_ooxml::LN_Value_ST_Em_comma; break; - case RTF_ACCCIRCLE: + case RTFKeyword::ACCCIRCLE: nSprm = NS_ooxml::LN_Value_ST_Em_circle; break; - case RTF_ACCUNDERDOT: + case RTFKeyword::ACCUNDERDOT: nSprm = NS_ooxml::LN_Value_ST_Em_underDot; break; default: @@ -1846,66 +1974,66 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n // Trivial character sprms. switch (nKeyword) { - case RTF_B: - case RTF_AB: + 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: - case RTFParserState::RunType::DBCH: 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 RTF_I: - case RTF_AI: + 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: - case RTFParserState::RunType::DBCH: 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 RTF_OUTL: + case RTFKeyword::OUTL: nSprm = NS_ooxml::LN_EG_RPrBase_outline; break; - case RTF_SHAD: + case RTFKeyword::SHAD: nSprm = NS_ooxml::LN_EG_RPrBase_shadow; break; - case RTF_V: + case RTFKeyword::V: nSprm = NS_ooxml::LN_EG_RPrBase_vanish; break; - case RTF_STRIKE: + case RTFKeyword::STRIKE: nSprm = NS_ooxml::LN_EG_RPrBase_strike; break; - case RTF_STRIKED: + case RTFKeyword::STRIKED: nSprm = NS_ooxml::LN_EG_RPrBase_dstrike; break; - case RTF_SCAPS: + case RTFKeyword::SCAPS: nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps; break; - case RTF_IMPR: + case RTFKeyword::IMPR: nSprm = NS_ooxml::LN_EG_RPrBase_imprint; break; - case RTF_CAPS: + case RTFKeyword::CAPS: nSprm = NS_ooxml::LN_EG_RPrBase_caps; break; default: @@ -1913,39 +2041,47 @@ RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int n } if (nSprm >= 0) { - m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue); + 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 RTF_ASPALPHA: + case RTFKeyword::ASPALPHA: m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE, pBoolValue); break; - case RTF_DELETED: - case RTF_REVISED: + case RTFKeyword::DELETED: + case RTFKeyword::REVISED: { - auto pValue = new RTFValue(nKeyword == RTF_DELETED ? oox::XML_del : oox::XML_ins); + 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 RTF_SBAUTO: + case RTFKeyword::SBAUTO: putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue); break; - case RTF_SAAUTO: + case RTFKeyword::SAAUTO: putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue); break; - case RTF_FACINGP: + case RTFKeyword::FACINGP: m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue); break; - case RTF_HYPHAUTO: + case RTFKeyword::HYPHAUTO: m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue); break; - case RTF_HYPHPAR: + case RTFKeyword::HYPHPAR: m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens, new RTFValue(int(bParam && nParam == 0))); break; @@ -2009,6 +2145,8 @@ RTFError RTFDocumentImpl::pushState() 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); @@ -2081,7 +2219,7 @@ writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStylePrope /** 2 different representations of the styles are needed: 1) flat content, as read from the input file: - stored in m_aStyleTableEntries, used as reference input for + 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 @@ -2090,7 +2228,7 @@ writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStylePrope RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable() { RTFReferenceTable::Entries_t ret; - for (auto const& it : m_aStyleTableEntries) + for (auto const& it : *m_pStyleTableEntries) { auto pStyle = it.second; ret[it.first] = pStyle; @@ -2106,26 +2244,26 @@ RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable() if (it.first == nBasedOn) continue; - auto const itParent(m_aStyleTableEntries.find(nBasedOn)); // definition as read! - if (itParent != m_aStyleTableEntries.end()) + 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 const sprms( + RTFSprms sprms( static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate( static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(), nStyleType)); - RTFSprms const attributes( + RTFSprms attributes( static_cast<RTFReferenceProperties&>(*pStyle) .getAttributes() .cloneAndDeduplicate( static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(), nStyleType)); - ret[it.first] = new RTFReferenceProperties(attributes, sprms); + ret[it.first] = new RTFReferenceProperties(std::move(attributes), std::move(sprms)); } else { @@ -2133,7 +2271,7 @@ RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable() } } } - assert(ret.size() == m_aStyleTableEntries.size()); + assert(ret.size() == m_pStyleTableEntries->size()); return ret; } @@ -2162,25 +2300,34 @@ 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: { - writerfilter::Reference<Table>::Pointer_t const pTable( - new RTFReferenceTable(m_aFontTableEntries)); - Mapper().table(NS_ooxml::LN_FONTTABLE, pTable); - if (m_nDefaultFontIndex >= 0) + // Some text unhandled? Seems it is last font name + if (m_aStates.top().getCurrentDestinationText()->getLength()) + handleFontTableEntry(); + + if (rState.getDestination() == Destination::FONTTABLE) { - 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); + 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 const pStyleTableDeduplicated(deduplicateStyleTable()); + RTFReferenceTable::Entries_t pStyleTableDeduplicated(deduplicateStyleTable()); writerfilter::Reference<Table>::Pointer_t const pTable( - new RTFReferenceTable(pStyleTableDeduplicated)); + new RTFReferenceTable(std::move(pStyleTableDeduplicated))); Mapper().table(NS_ooxml::LN_STYLESHEET, pTable); } break; @@ -2188,11 +2335,11 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) { RTFSprms aListTableAttributes; writerfilter::Reference<Properties>::Pointer_t pProp - = new RTFReferenceProperties(aListTableAttributes, m_aListTableSprms); + = 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(aListTableEntries)); + new RTFReferenceTable(std::move(aListTableEntries))); Mapper().table(NS_ooxml::LN_NUMBERING, pTable); } break; @@ -2210,7 +2357,7 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) if (!m_aStates.top().getCurrentBuffer()) { writerfilter::Reference<Properties>::Pointer_t pProperties - = new RTFReferenceProperties(aFFAttributes, aFFSprms); + = new RTFReferenceProperties(std::move(aFFAttributes), std::move(aFFSprms)); Mapper().props(pProperties); } else @@ -2220,7 +2367,10 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) } m_aFormfieldAttributes.clear(); m_aFormfieldSprms.clear(); - singleChar(cFieldSep); + + if (m_aStates.top().isFieldLocked()) + singleChar(cFieldLock); + singleChar(cFieldSep, true); } break; case Destination::FIELDRESULT: @@ -2230,11 +2380,11 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) { // Read the picture into m_aStates.top().aDestinationText. pushState(); - dispatchDestination(RTF_PICT); + dispatchDestination(RTFKeyword::PICT); if (m_aPicturePath.endsWith(".png")) - dispatchFlag(RTF_PNGBLIP); + dispatchFlag(RTFKeyword::PNGBLIP); OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault( - utl::MediaDescriptor::PROP_URL(), OUString()); + utl::MediaDescriptor::PROP_URL, OUString()); OUString aPictureURL; try { @@ -2258,7 +2408,7 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) aStream.ReadUChar(ch); if (ch < 16) aBuf.append("0"); - aBuf.append(OUString::number(ch, 16)); + aBuf.append(static_cast<sal_Int32>(ch), 16); } m_aStates.top().getDestinationText() = aBuf; } @@ -2376,8 +2526,8 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) // 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()->push_back( - Buf_t(BUFFER_PICTURE, pPictureValue, nullptr)); + m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_PICTURE, pPictureValue, + nullptr); auto pValue = new RTFValue(m_aStates.top().getShape()); // Buffer wrap type. @@ -2391,8 +2541,8 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) } } - m_aStates.top().getCurrentBuffer()->push_back( - Buf_t(BUFFER_RESOLVESHAPE, pValue, nullptr)); + m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_RESOLVESHAPE, pValue, + nullptr); } } else if (rState.getInShapeGroup() && !rState.getInShape()) @@ -2442,12 +2592,12 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) 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()) - ? OUStringLiteral(u"XE") - : OUStringLiteral(u"TC")); - str = field + " \"" + str.replaceAll("\"", "\\\"") + "\""; + ? std::u16string_view(u"XE") + : std::u16string_view(u"TC")); + str = OUString::Concat(field) + " \"" + str.replaceAll("\"", "\\\"") + "\""; singleChar(cFieldStart); - Mapper().utext(reinterpret_cast<sal_uInt8 const*>(str.getStr()), str.getLength()); - singleChar(cFieldSep); + Mapper().utext(str.getStr(), str.getLength()); + singleChar(cFieldSep, true); // no result singleChar(cFieldEnd); } @@ -2469,19 +2619,22 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) break; // not for nested group auto pValue = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear()); - m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue); + // 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) { - if (&m_aStates.top().getDestinationText() - != m_aStates.top().getCurrentDestinationText()) + OUStringBuffer* pCurrentDestinationText + = m_aStates.top().getCurrentDestinationText(); + if (&m_aStates.top().getDestinationText() != pCurrentDestinationText) break; // not for nested group - OString aStr = OUStringToOString( - m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), - rState.getCurrentEncoding()); + OString aStr + = OUStringToOString(*pCurrentDestinationText, rState.getCurrentEncoding()); + pCurrentDestinationText->setLength(0); // decode hex dump OStringBuffer aBuf; int b = 0; @@ -2563,8 +2716,13 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) != m_aStates.top().getCurrentDestinationText()) break; // not for nested group if (m_xDocumentProperties.is()) - m_xDocumentProperties->setKeywords(comphelper::string::convertCommaSeparated( - m_aStates.top().getCurrentDestinationText()->makeStringAndClear())); + { + 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() @@ -2609,8 +2767,7 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) break; // not for nested group OUString aName = rState.getDestination() == Destination::OPERATOR ? OUString("Operator") : OUString("Company"); - uno::Any aValue - = uno::makeAny(m_aStates.top().getCurrentDestinationText()->makeStringAndClear()); + uno::Any aValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear()); if (m_xDocumentProperties.is()) { uno::Reference<beans::XPropertyContainer> xUserDefinedProperties @@ -2651,7 +2808,7 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) { // if the object is in a special container we will use the \result // element instead of the \objdata - // (see RTF_OBJECT in RTFDocumentImpl::dispatchDestination) + // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination) break; } @@ -2664,7 +2821,7 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) auto pValue = new RTFValue(m_aObjectAttributes, aObjectSprms); aObjSprms.set(NS_ooxml::LN_object, pValue); writerfilter::Reference<Properties>::Pointer_t pProperties - = new RTFReferenceProperties(aObjAttributes, aObjSprms); + = 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); @@ -2683,18 +2840,17 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) break; case Destination::ANNOTATIONDATE: { - if (&m_aStates.top().getDestinationText() - != m_aStates.top().getCurrentDestinationText()) + OUStringBuffer* pCurrentDestinationText = m_aStates.top().getCurrentDestinationText(); + if (&m_aStates.top().getDestinationText() != pCurrentDestinationText) break; // not for nested group - OUString aStr(OStringToOUString( - DTTM22OString( - m_aStates.top().getCurrentDestinationText()->makeStringAndClear().toInt32()), - rState.getCurrentEncoding())); + 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(aAnnAttributes); + = new RTFReferenceProperties(std::move(aAnnAttributes)); Mapper().props(pProperties); } break; @@ -2723,10 +2879,10 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart, pValue); else aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd, pValue); - writerfilter::Reference<Properties>::Pointer_t pProperties - = new RTFReferenceProperties(aAttributes); if (!m_aStates.top().getCurrentBuffer()) { + writerfilter::Reference<Properties>::Pointer_t pProperties + = new RTFReferenceProperties(std::move(aAttributes)); Mapper().props(pProperties); } else @@ -2744,7 +2900,7 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) 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(aAnnAttributes)); + Mapper().props(new RTFReferenceProperties(std::move(aAnnAttributes))); } break; case Destination::FALT: @@ -2768,15 +2924,15 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) 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::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + xPropertySet->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AT_CHARACTER)); if (bTextFrame) { xPropertySet->setPropertyValue("HoriOrientPosition", - uno::makeAny(rDrawing.getLeft())); + uno::Any(rDrawing.getLeft())); xPropertySet->setPropertyValue("VertOrientPosition", - uno::makeAny(rDrawing.getTop())); + uno::Any(rDrawing.getTop())); } else { @@ -2786,22 +2942,21 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) if (rDrawing.getHasLineColor()) { - uno::Any aLineColor = uno::makeAny(sal_uInt32((rDrawing.getLineColorR() << 16) - + (rDrawing.getLineColorG() << 8) - + rDrawing.getLineColorB())); + 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::makeAny(sal_uInt32((rDrawing.getFillColorR() << 16) - + (rDrawing.getFillColorG() << 8) - + rDrawing.getFillColorB()))); + "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::makeAny(sal_Int32(100))); + xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_Int32(100))); RTFSdrImport::resolveFLine(xPropertySet, rDrawing.getFLine()); @@ -2823,7 +2978,11 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) case Destination::SHAPE: m_bNeedFinalPar = true; m_bNeedCr = m_bNeedCrOrig; - if (rState.getFrame().inFrame()) + // 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(); @@ -2846,18 +3005,15 @@ RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState) { uno::Reference<util::XCloseable> xComponent(xObject->getComponent(), uno::UNO_SET_THROW); - // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class, - // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated - // to RTLD_GLOBAL, so most probably a gcc bug. - auto& rImport = dynamic_cast<oox::FormulaImportBase&>( - dynamic_cast<SfxBaseModel&>(*xComponent)); - rImport.readFormulaOoxml(m_aMathBuffer); + 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(aMathAttributes); + = new RTFReferenceProperties(std::move(aMathAttributes)); Mapper().props(pProperties); } @@ -3251,20 +3407,20 @@ void RTFDocumentImpl::afterPopState(RTFParserState& rState) // Table RTFSprms aListTableAttributes; - writerfilter::Reference<Properties>::Pointer_t pProp - = new RTFReferenceProperties(aListTableAttributes, aListTableSprms); + 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(aListTableEntries)); + 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); + 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); + NS_ooxml::LN_CT_NumPr_numId, pIdValue, RTFOverwrite::YES_PREPEND); } } break; @@ -3361,6 +3517,30 @@ void RTFDocumentImpl::afterPopState(RTFParserState& rState) 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()) { @@ -3427,8 +3607,8 @@ void RTFDocumentImpl::afterPopState(RTFParserState& rState) if (!m_aStates.top().getCurrentBuffer()) m_pSdrImport->close(); else - m_aStates.top().getCurrentBuffer()->push_back( - Buf_t(BUFFER_ENDSHAPE, nullptr, nullptr)); + m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_ENDSHAPE, nullptr, + nullptr); } // It's allowed to declare these inside the shape text, and they @@ -3465,7 +3645,7 @@ RTFError RTFDocumentImpl::popState() checkUnicode(/*bUnicode =*/true, /*bHex =*/true); RTFParserState aState(m_aStates.top()); - m_bWasInFrame = aState.getFrame().inFrame(); + 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) @@ -3478,7 +3658,7 @@ RTFError RTFDocumentImpl::popState() case NS_ooxml::LN_footerl: case NS_ooxml::LN_footerr: case NS_ooxml::LN_footerf: - dispatchSymbol(RTF_PAR); + dispatchSymbol(RTFKeyword::PAR); break; } } @@ -3494,7 +3674,7 @@ RTFError RTFDocumentImpl::popState() auto pValue = new RTFValue(0); aTCSprms.set(NS_ooxml::LN_endtrackchange, pValue); if (!m_aStates.top().getCurrentBuffer()) - Mapper().props(new RTFReferenceProperties(RTFSprms(), aTCSprms)); + Mapper().props(new RTFReferenceProperties(RTFSprms(), std::move(aTCSprms))); else bufferProperties(*m_aStates.top().getCurrentBuffer(), new RTFValue(RTFSprms(), aTCSprms), nullptr); @@ -3506,10 +3686,28 @@ RTFError RTFDocumentImpl::popState() // \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 && m_bIsNewDoc) - dispatchSymbol(RTF_PAR); + && 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(); @@ -3528,11 +3726,11 @@ RTFError RTFDocumentImpl::popState() if (!m_aStates.empty() && m_aStates.top().getTableRowWidthAfter() > 0 && aState.getTableRowWidthAfter() == 0) - // An RTF_ROW in the inner group already parsed nTableRowWidthAfter, + // 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 != RTF_invalid && !m_aStates.empty()) + if (m_nResetBreakOnSectBreak != RTFKeyword::invalid && !m_aStates.empty()) { // Section break type created for \page still has an effect in the // outer state as well. @@ -3547,17 +3745,16 @@ RTFError RTFDocumentImpl::popState() RTFError RTFDocumentImpl::handleEmbeddedObject() { - OString aStr - = OUStringToOString(m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), - RTL_TEXTENCODING_ASCII_US); + 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)); - auto pStreamValue = new RTFValue(xInputStream); - m_aOLEAttributes.set(NS_ooxml::LN_inputstream, pStreamValue); + m_aOLEAttributes.set(NS_ooxml::LN_inputstream, new RTFValue(xInputStream)); return RTFError::OK; } @@ -3580,7 +3777,7 @@ void RTFDocumentImpl::setDestination(Destination 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(OUString const& rString) +void RTFDocumentImpl::setDestinationText(std::u16string_view rString) { m_aStates.top().getDestinationText().setLength(0); m_aStates.top().getDestinationText().append(rString); @@ -3624,10 +3821,13 @@ void RTFDocumentImpl::checkUnicode(bool bUnicode, bool bHex) if (bHex && !m_aHexBuffer.isEmpty()) { rtl_TextEncoding nEncoding = m_aStates.top().getCurrentEncoding(); - if (m_aStates.top().getDestination() == Destination::FONTENTRY - && m_aStates.top().getCurrentEncoding() == RTL_TEXTENCODING_SYMBOL) + 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.toString(), nEncoding); + OUString aString = OStringToOUString(m_aHexBuffer, nEncoding); m_aHexBuffer.setLength(0); aString = FilterControlChars(m_aStates.top().getDestination(), aString); text(aString); @@ -3639,6 +3839,7 @@ RTFParserState::RTFParserState(RTFDocumentImpl* 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) @@ -3654,7 +3855,7 @@ RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl) , m_nHour(0) , m_nMinute(0) , m_pCurrentDestinationText(nullptr) - , m_nCurrentStyleIndex(-1) + , m_nCurrentStyleIndex(0) , m_nCurrentCharacterStyleIndex(-1) , m_pCurrentBuffer(nullptr) , m_bInListpicture(false) @@ -3671,11 +3872,15 @@ RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl) 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) + const tools::SvRef<TableRowBuffer>& pTableProperties, + Id const nStyleType) { - rBuffer.emplace_back( - Buf_t(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()), nullptr)); - rBuffer.emplace_back(Buf_t(BUFFER_PROPS, pValue, pTableProperties)); + 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; @@ -3700,11 +3905,6 @@ RTFFrame::RTFFrame(RTFParserState* pParserState) void RTFFrame::setSprm(Id nId, Id nValue) { - if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport()) - { - m_pDocumentImpl->checkFirstRun(); - m_pDocumentImpl->setNeedPar(false); - } switch (nId) { case NS_ooxml::LN_CT_FramePr_w: @@ -3743,6 +3943,12 @@ void RTFFrame::setSprm(Id nId, Id nValue) default: break; } + + if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport() && hasProperties()) + { + m_pDocumentImpl->checkFirstRun(); + m_pDocumentImpl->setNeedPar(false); + } } RTFSprms RTFFrame::getSprms() @@ -3797,7 +4003,7 @@ RTFSprms RTFFrame::getSprms() case NS_ooxml::LN_CT_FramePr_hAnchor: { if (m_nHoriAnchor == 0) - m_nHoriAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin; + m_nHoriAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_text; pValue = new RTFValue(m_nHoriAnchor); } break; @@ -3842,9 +4048,13 @@ RTFSprms RTFFrame::getSprms() bool RTFFrame::hasProperties() const { - return 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; + // 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 |