writerfilter/Library_writerfilter.mk | 4 writerfilter/source/rtftok/rtfcontrolwords.hxx | 1 writerfilter/source/rtftok/rtfdispatchdestination.cxx | 623 +++ writerfilter/source/rtftok/rtfdispatchflag.cxx | 1083 +++++ writerfilter/source/rtftok/rtfdispatchsymbol.cxx | 409 ++ writerfilter/source/rtftok/rtfdispatchvalue.cxx | 1347 +++++++ writerfilter/source/rtftok/rtfdocumentimpl.cxx | 3411 ------------------ writerfilter/source/rtftok/rtfdocumentimpl.hxx | 12 writerfilter/source/rtftok/rtffly.hxx | 4 9 files changed, 3522 insertions(+), 3372 deletions(-)
New commits: commit a3615d5517ee84ddf9a9b2c28ff6a3a37fcb70db Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Mon May 9 09:13:25 2016 +0200 writerfilter: extract dispatch{destination,flag,symbol,value} from rtfdocimpl These were half of the lines of rtfdocumentimpl. Change-Id: I3f24cd5d23c91bf0d53b898266c187699ae6ee56 Reviewed-on: https://gerrit.libreoffice.org/24790 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@libreoffice.org> diff --git a/writerfilter/Library_writerfilter.mk b/writerfilter/Library_writerfilter.mk index 27eb752..b23256e 100644 --- a/writerfilter/Library_writerfilter.mk +++ b/writerfilter/Library_writerfilter.mk @@ -64,6 +64,10 @@ $(eval $(call gb_Library_use_externals,writerfilter,\ $(eval $(call gb_Library_add_exception_objects,writerfilter,\ writerfilter/source/rtftok/rtfcharsets \ writerfilter/source/rtftok/rtfcontrolwords \ + writerfilter/source/rtftok/rtfdispatchdestination \ + writerfilter/source/rtftok/rtfdispatchflag \ + writerfilter/source/rtftok/rtfdispatchsymbol \ + writerfilter/source/rtftok/rtfdispatchvalue \ writerfilter/source/rtftok/rtfdocumentfactory \ writerfilter/source/rtftok/rtfdocumentimpl \ writerfilter/source/rtftok/rtflookahead \ diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx index 80a2d1e..2a7d596 100644 --- a/writerfilter/source/rtftok/rtfcontrolwords.hxx +++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx @@ -1980,6 +1980,7 @@ enum RTFKeyword RTF_FLYHORZ, RTF_FLYANCHOR }; +const char* keywordToString(RTFKeyword nKeyword); /// Types of an RTF Control Word enum RTFControlTypes diff --git a/writerfilter/source/rtftok/rtfdispatchdestination.cxx b/writerfilter/source/rtftok/rtfdispatchdestination.cxx new file mode 100644 index 0000000..af8a3f1 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchdestination.cxx @@ -0,0 +1,623 @@ +/* -*- 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 <com/sun/star/document/DocumentProperties.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> + +#include <filter/msfilter/escherex.hxx> +#include <tools/stream.hxx> + +#include <dmapper/DomainMapperFactory.hxx> +#include <ooxml/resourceids.hxx> + +#include <rtflookahead.hxx> +#include <rtfreferenceproperties.hxx> +#include <rtfsdrimport.hxx> +#include <rtfskipdestination.hxx> + +using namespace com::sun::star; + +namespace writerfilter +{ +namespace rtftok +{ + +RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword) +{ + setNeedSect(true); + checkUnicode(/*bUnicode =*/ true, /*bHex =*/ true); + RTFSkipDestination aSkip(*this); + // special case \upr: ignore everything except nested \ud + if (Destination::UPR == m_aStates.top().eDestination && RTF_UD != nKeyword) + { + m_aStates.top().eDestination = Destination::SKIP; + aSkip.setParsed(false); + } + else + switch (nKeyword) + { + case RTF_RTF: + break; + case RTF_FONTTBL: + m_aStates.top().eDestination = Destination::FONTTABLE; + break; + case RTF_COLORTBL: + m_aStates.top().eDestination = Destination::COLORTABLE; + break; + case RTF_STYLESHEET: + m_aStates.top().eDestination = Destination::STYLESHEET; + break; + case RTF_FIELD: + m_aStates.top().eDestination = Destination::FIELD; + break; + case RTF_FLDINST: + { + // Look for the field type + sal_Size nPos = Strm().Tell(); + OStringBuffer aBuf; + char ch = 0; + bool bFoundCode = false; + bool bInKeyword = false; + while (!bFoundCode && ch != '}') + { + Strm().ReadChar(ch); + if ('\\' == ch) + bInKeyword = true; + if (!bInKeyword && isalnum(ch)) + aBuf.append(ch); + else if (bInKeyword && isspace(ch)) + bInKeyword = false; + if (!aBuf.isEmpty() && !isalnum(ch)) + bFoundCode = true; + } + + if (aBuf.toString() == "INCLUDEPICTURE") + { + // Extract the field argument of INCLUDEPICTURE: we handle that + // at a tokenizer level, as DOCX has no such field. + aBuf.append(ch); + while (true) + { + Strm().ReadChar(ch); + if (ch == '}') + break; + aBuf.append(ch); + } + OUString aFieldCommand = OStringToOUString(aBuf.toString(), RTL_TEXTENCODING_UTF8); + std::tuple<OUString, std::vector<OUString>, std::vector<OUString> > aResult = writerfilter::dmapper::splitFieldCommand(aFieldCommand); + m_aPicturePath = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front(); + } + + Strm().Seek(nPos); + + // Form data should be handled only for form fields if any + if (aBuf.toString().indexOf(OString("FORM")) != -1) + m_bFormField = true; + + singleChar(cFieldStart); + m_aStates.top().eDestination = Destination::FIELDINSTRUCTION; + } + break; + case RTF_FLDRSLT: + m_aStates.top().eDestination = Destination::FIELDRESULT; + break; + case RTF_LISTTABLE: + m_aStates.top().eDestination = Destination::LISTTABLE; + break; + case RTF_LISTPICTURE: + m_aStates.top().eDestination = Destination::LISTPICTURE; + m_aStates.top().bInListpicture = true; + break; + case RTF_LIST: + m_aStates.top().eDestination = Destination::LISTENTRY; + break; + case RTF_LISTNAME: + m_aStates.top().eDestination = Destination::LISTNAME; + break; + case RTF_LFOLEVEL: + m_aStates.top().eDestination = Destination::LFOLEVEL; + m_aStates.top().aTableSprms.clear(); + break; + case RTF_LISTOVERRIDETABLE: + m_aStates.top().eDestination = Destination::LISTOVERRIDETABLE; + break; + case RTF_LISTOVERRIDE: + m_aStates.top().eDestination = Destination::LISTOVERRIDEENTRY; + break; + case RTF_LISTLEVEL: + m_aStates.top().eDestination = Destination::LISTLEVEL; + break; + case RTF_LEVELTEXT: + m_aStates.top().eDestination = Destination::LEVELTEXT; + break; + case RTF_LEVELNUMBERS: + m_aStates.top().eDestination = Destination::LEVELNUMBERS; + break; + case RTF_SHPPICT: + resetFrame(); + m_aStates.top().eDestination = Destination::SHPPICT; + break; + case RTF_PICT: + if (m_aStates.top().eDestination != Destination::SHAPEPROPERTYVALUE) + m_aStates.top().eDestination = Destination::PICT; // as character + else + m_aStates.top().eDestination = Destination::SHAPEPROPERTYVALUEPICT; // anchored inside a shape + break; + case RTF_PICPROP: + m_aStates.top().eDestination = Destination::PICPROP; + break; + case RTF_SP: + m_aStates.top().eDestination = Destination::SHAPEPROPERTY; + break; + case RTF_SN: + m_aStates.top().eDestination = Destination::SHAPEPROPERTYNAME; + break; + case RTF_SV: + m_aStates.top().eDestination = Destination::SHAPEPROPERTYVALUE; + break; + case RTF_SHP: + m_bNeedCrOrig = m_bNeedCr; + m_aStates.top().eDestination = Destination::SHAPE; + m_aStates.top().bInShape = true; + break; + case RTF_SHPINST: + m_aStates.top().eDestination = Destination::SHAPEINSTRUCTION; + break; + case RTF_NESTTABLEPROPS: + // do not set any properties of outer table at nested table! + m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms; + m_aStates.top().aTableCellAttributes = + m_aDefaultState.aTableCellAttributes; + m_aNestedTableCellsSprms.clear(); + m_aNestedTableCellsAttributes.clear(); + m_nNestedCells = 0; + m_aStates.top().eDestination = Destination::NESTEDTABLEPROPERTIES; + break; + case RTF_HEADER: + case RTF_FOOTER: + case RTF_HEADERL: + case RTF_HEADERR: + case RTF_HEADERF: + case RTF_FOOTERL: + case RTF_FOOTERR: + case RTF_FOOTERF: + if (!m_pSuperstream) + { + Id nId = 0; + sal_Size nPos = m_nGroupStartPos - 1; + switch (nKeyword) + { + case RTF_HEADER: + nId = NS_ooxml::LN_headerr; + break; + case RTF_FOOTER: + nId = NS_ooxml::LN_footerr; + break; + case RTF_HEADERL: + nId = NS_ooxml::LN_headerl; + break; + case RTF_HEADERR: + nId = NS_ooxml::LN_headerr; + break; + case RTF_HEADERF: + nId = NS_ooxml::LN_headerf; + break; + case RTF_FOOTERL: + nId = NS_ooxml::LN_footerl; + break; + case RTF_FOOTERR: + nId = NS_ooxml::LN_footerr; + break; + case RTF_FOOTERF: + nId = NS_ooxml::LN_footerf; + break; + default: + break; + } + m_nHeaderFooterPositions.push(std::make_pair(nId, nPos)); + m_aStates.top().eDestination = Destination::SKIP; + } + break; + case RTF_FOOTNOTE: + checkFirstRun(); + if (!m_pSuperstream) + { + Id nId = NS_ooxml::LN_footnote; + + // Check if this is an endnote. + OStringBuffer aBuf; + char ch; + sal_Size nCurrent = Strm().Tell(); + for (int i = 0; i < 7; ++i) + { + Strm().ReadChar(ch); + aBuf.append(ch); + } + Strm().Seek(nCurrent); + OString aKeyword = aBuf.makeStringAndClear(); + if (aKeyword.equals("\\ftnalt")) + nId = NS_ooxml::LN_endnote; + + if (m_aStates.top().pCurrentBuffer == &m_aSuperBuffer) + m_aStates.top().pCurrentBuffer = nullptr; + bool bCustomMark = false; + OUString aCustomMark; + while (m_aSuperBuffer.size()) + { + Buf_t aTuple = m_aSuperBuffer.front(); + m_aSuperBuffer.pop_front(); + if (std::get<0>(aTuple) == BUFFER_UTEXT) + { + aCustomMark = std::get<1>(aTuple)->getString(); + bCustomMark = true; + } + } + m_aStates.top().eDestination = Destination::FOOTNOTE; + if (bCustomMark) + Mapper().startCharacterGroup(); + if (!m_aStates.top().pCurrentBuffer) + resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark); + else + { + RTFSprms aAttributes; + aAttributes.set(Id(0), std::make_shared<RTFValue>(m_nGroupStartPos - 1)); + aAttributes.set(Id(1), std::make_shared<RTFValue>(nId)); + aAttributes.set(Id(2), std::make_shared<RTFValue>(aCustomMark)); + m_aStates.top().pCurrentBuffer->push_back(Buf_t(BUFFER_RESOLVESUBSTREAM, std::make_shared<RTFValue>(aAttributes), nullptr)); + } + if (bCustomMark) + { + m_aStates.top().aCharacterAttributes.clear(); + m_aStates.top().aCharacterSprms.clear(); + auto pValue = std::make_shared<RTFValue>(1); + m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue); + text(aCustomMark); + Mapper().endCharacterGroup(); + } + m_aStates.top().eDestination = Destination::SKIP; + } + break; + case RTF_BKMKSTART: + m_aStates.top().eDestination = Destination::BOOKMARKSTART; + break; + case RTF_BKMKEND: + m_aStates.top().eDestination = Destination::BOOKMARKEND; + break; + case RTF_XE: + m_aStates.top().eDestination = Destination::INDEXENTRY; + break; + case RTF_TC: + case RTF_TCN: + m_aStates.top().eDestination = Destination::TOCENTRY; + break; + case RTF_REVTBL: + m_aStates.top().eDestination = Destination::REVISIONTABLE; + break; + case RTF_ANNOTATION: + if (!m_pSuperstream) + { + resolveSubstream(m_nGroupStartPos - 1, NS_ooxml::LN_annotation); + m_aStates.top().eDestination = Destination::SKIP; + } + else + { + // If there is an author set, emit it now. + if (!m_aAuthor.isEmpty() || !m_aAuthorInitials.isEmpty()) + { + RTFSprms aAttributes; + if (!m_aAuthor.isEmpty()) + { + auto pValue = std::make_shared<RTFValue>(m_aAuthor); + aAttributes.set(NS_ooxml::LN_CT_TrackChange_author, pValue); + } + if (!m_aAuthorInitials.isEmpty()) + { + auto pValue = std::make_shared<RTFValue>(m_aAuthorInitials); + aAttributes.set(NS_ooxml::LN_CT_Comment_initials, pValue); + } + writerfilter::Reference<Properties>::Pointer_t pProperties = std::make_shared<RTFReferenceProperties>(aAttributes); + Mapper().props(pProperties); + } + } + break; + case RTF_SHPTXT: + case RTF_DPTXBXTEXT: + { + bool bPictureFrame = false; + for (std::size_t i = 0; i < m_aStates.top().aShape.aProperties.size(); ++i) + { + std::pair<OUString, OUString>& rProperty = m_aStates.top().aShape.aProperties[i]; + if (rProperty.first == "shapeType" && rProperty.second == OUString::number(ESCHER_ShpInst_PictureFrame)) + { + bPictureFrame = true; + break; + } + } + if (bPictureFrame) + // Skip text on picture frames. + m_aStates.top().eDestination = Destination::SKIP; + else + { + m_aStates.top().eDestination = Destination::SHAPETEXT; + checkFirstRun(); + dispatchFlag(RTF_PARD); + m_bNeedPap = true; + if (nKeyword == RTF_SHPTXT) + { + if (!m_aStates.top().pCurrentBuffer) + m_pSdrImport->resolve(m_aStates.top().aShape, false, RTFSdrImport::SHAPE); + else + { + auto pValue = std::make_shared<RTFValue>(m_aStates.top().aShape); + m_aStates.top().pCurrentBuffer->push_back(Buf_t(BUFFER_STARTSHAPE, pValue, nullptr)); + } + } + } + } + break; + case RTF_FORMFIELD: + if (m_aStates.top().eDestination == Destination::FIELDINSTRUCTION) + m_aStates.top().eDestination = Destination::FORMFIELD; + break; + case RTF_FFNAME: + m_aStates.top().eDestination = Destination::FORMFIELDNAME; + break; + case RTF_FFL: + m_aStates.top().eDestination = Destination::FORMFIELDLIST; + break; + case RTF_DATAFIELD: + m_aStates.top().eDestination = Destination::DATAFIELD; + break; + case RTF_INFO: + m_aStates.top().eDestination = Destination::INFO; + break; + case RTF_CREATIM: + m_aStates.top().eDestination = Destination::CREATIONTIME; + break; + case RTF_REVTIM: + m_aStates.top().eDestination = Destination::REVISIONTIME; + break; + case RTF_PRINTIM: + m_aStates.top().eDestination = Destination::PRINTTIME; + break; + case RTF_AUTHOR: + m_aStates.top().eDestination = Destination::AUTHOR; + break; + case RTF_KEYWORDS: + m_aStates.top().eDestination = Destination::KEYWORDS; + break; + case RTF_OPERATOR: + m_aStates.top().eDestination = Destination::OPERATOR; + break; + case RTF_COMPANY: + m_aStates.top().eDestination = Destination::COMPANY; + break; + case RTF_COMMENT: + m_aStates.top().eDestination = Destination::COMMENT; + break; + case RTF_OBJECT: + { + // beginning of an OLE Object + m_aStates.top().eDestination = Destination::OBJECT; + + // check if the object is in a special container (e.g. a table) + if (!m_aStates.top().pCurrentBuffer) + { + // the object is in a table or another container. + // Don't try to treat it as an OLE object (fdo#53594). + // Use the \result (RTF_RESULT) element of the object instead, + // the result element contain picture representing the OLE Object. + m_bObject = true; + } + } + break; + case RTF_OBJDATA: + // check if the object is in a special container (e.g. a table) + if (m_aStates.top().pCurrentBuffer) + { + // the object is in a table or another container. + // Use the \result (RTF_RESULT) element of the object instead, + // of the \objdata. + m_aStates.top().eDestination = Destination::SKIP; + } + else + { + m_aStates.top().eDestination = Destination::OBJDATA; + } + break; + case RTF_OBJCLASS: + m_aStates.top().eDestination = Destination::OBJCLASS; + break; + case RTF_RESULT: + m_aStates.top().eDestination = Destination::RESULT; + break; + case RTF_ATNDATE: + m_aStates.top().eDestination = Destination::ANNOTATIONDATE; + break; + case RTF_ATNAUTHOR: + m_aStates.top().eDestination = Destination::ANNOTATIONAUTHOR; + break; + case RTF_ATNREF: + m_aStates.top().eDestination = Destination::ANNOTATIONREFERENCE; + break; + case RTF_FALT: + m_aStates.top().eDestination = Destination::FALT; + break; + case RTF_FLYMAINCNT: + m_aStates.top().eDestination = Destination::FLYMAINCONTENT; + break; + case RTF_LISTTEXT: + // Should be ignored by any reader that understands Word 97 through Word 2007 numbering. + case RTF_NONESTTABLES: + // This destination should be ignored by readers that support nested tables. + m_aStates.top().eDestination = Destination::SKIP; + break; + case RTF_DO: + m_aStates.top().eDestination = Destination::DRAWINGOBJECT; + break; + case RTF_PN: + m_aStates.top().eDestination = Destination::PARAGRAPHNUMBERING; + break; + case RTF_PNTEXT: + // This destination should be ignored by readers that support paragraph numbering. + m_aStates.top().eDestination = Destination::SKIP; + break; + case RTF_PNTXTA: + m_aStates.top().eDestination = Destination::PARAGRAPHNUMBERING_TEXTAFTER; + break; + case RTF_PNTXTB: + m_aStates.top().eDestination = Destination::PARAGRAPHNUMBERING_TEXTBEFORE; + break; + case RTF_TITLE: + m_aStates.top().eDestination = Destination::TITLE; + break; + case RTF_SUBJECT: + m_aStates.top().eDestination = Destination::SUBJECT; + break; + case RTF_DOCCOMM: + m_aStates.top().eDestination = Destination::DOCCOMM; + break; + case RTF_ATRFSTART: + m_aStates.top().eDestination = Destination::ANNOTATIONREFERENCESTART; + break; + case RTF_ATRFEND: + m_aStates.top().eDestination = Destination::ANNOTATIONREFERENCEEND; + break; + case RTF_ATNID: + m_aStates.top().eDestination = Destination::ATNID; + break; + case RTF_MMATH: + case RTF_MOMATHPARA: + // Nothing to do here (just enter the destination) till RTF_MMATHPR is implemented. + break; + case RTF_MR: + m_aStates.top().eDestination = Destination::MR; + break; + case RTF_MCHR: + m_aStates.top().eDestination = Destination::MCHR; + break; + case RTF_MPOS: + m_aStates.top().eDestination = Destination::MPOS; + break; + case RTF_MVERTJC: + m_aStates.top().eDestination = Destination::MVERTJC; + break; + case RTF_MSTRIKEH: + m_aStates.top().eDestination = Destination::MSTRIKEH; + break; + case RTF_MDEGHIDE: + m_aStates.top().eDestination = Destination::MDEGHIDE; + break; + case RTF_MTYPE: + m_aStates.top().eDestination = Destination::MTYPE; + break; + case RTF_MGROW: + m_aStates.top().eDestination = Destination::MGROW; + break; + case RTF_MHIDETOP: + case RTF_MHIDEBOT: + case RTF_MHIDELEFT: + case RTF_MHIDERIGHT: + // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now. + m_aStates.top().eDestination = Destination::SKIP; + break; + case RTF_MSUBHIDE: + m_aStates.top().eDestination = Destination::MSUBHIDE; + break; + case RTF_MSUPHIDE: + m_aStates.top().eDestination = Destination::MSUPHIDE; + break; + case RTF_MBEGCHR: + m_aStates.top().eDestination = Destination::MBEGCHR; + break; + case RTF_MSEPCHR: + m_aStates.top().eDestination = Destination::MSEPCHR; + break; + case RTF_MENDCHR: + m_aStates.top().eDestination = Destination::MENDCHR; + break; + case RTF_UPR: + m_aStates.top().eDestination = Destination::UPR; + break; + case RTF_UD: + // Anything inside \ud is just normal Unicode content. + m_aStates.top().eDestination = Destination::NORMAL; + break; + case RTF_BACKGROUND: + m_aStates.top().eDestination = Destination::BACKGROUND; + m_aStates.top().bInBackground = true; + break; + case RTF_SHPGRP: + { + RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart()); + if (!aLookahead.hasTable()) + { + uno::Reference<drawing::XShapes> xGroupShape(m_xModelFactory->createInstance("com.sun.star.drawing.GroupShape"), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc, uno::UNO_QUERY); + if (xDrawSupplier.is()) + { + uno::Reference<drawing::XShape> xShape(xGroupShape, uno::UNO_QUERY); + xDrawSupplier->getDrawPage()->add(xShape); + } + m_pSdrImport->pushParent(xGroupShape); + m_aStates.top().bCreatedShapeGroup = true; + } + m_aStates.top().eDestination = Destination::SHAPEGROUP; + m_aStates.top().bInShapeGroup = true; + } + break; + case RTF_FTNSEP: + m_aStates.top().eDestination = Destination::FOOTNOTESEPARATOR; + m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_FtnEdn_type, std::make_shared<RTFValue>(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator)); + break; + case RTF_USERPROPS: + // Container of all user-defined properties. + m_aStates.top().eDestination = Destination::USERPROPS; + if (m_xDocumentProperties.is()) + // Create a custom document properties to be able to process them later all at once. + m_xDocumentProperties = document::DocumentProperties::create(m_xContext); + break; + case RTF_PROPNAME: + m_aStates.top().eDestination = Destination::PROPNAME; + break; + case RTF_STATICVAL: + m_aStates.top().eDestination = Destination::STATICVAL; + break; + default: + { + // Check if it's a math token. + RTFMathSymbol aSymbol; + aSymbol.eKeyword = nKeyword; + if (RTFTokenizer::lookupMathKeyword(aSymbol)) + { + m_aMathBuffer.appendOpeningTag(aSymbol.nToken); + m_aStates.top().eDestination = aSymbol.eDestination; + return RTFError::OK; + } + + SAL_INFO("writerfilter", "TODO handle destination '" << keywordToString(nKeyword) << "'"); + // Make sure we skip destinations (even without \*) till we don't handle them + m_aStates.top().eDestination = Destination::SKIP; + aSkip.setParsed(false); + } + break; + } + + // new destination => use new destination text + m_aStates.top().pDestinationText = &m_aStates.top().aDestinationText; + + return RTFError::OK; +} + +} // namespace rtftok +} // namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/rtftok/rtfdispatchflag.cxx b/writerfilter/source/rtftok/rtfdispatchflag.cxx new file mode 100644 index 0000000..d3bc517 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx @@ -0,0 +1,1083 @@ +/* -*- 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 <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> +#include <com/sun/star/text/RelOrientation.hpp> + +#include <filter/msfilter/escherex.hxx> + +#include <ooxml/resourceids.hxx> + +#include <rtfsdrimport.hxx> +#include <rtfskipdestination.hxx> + +using namespace com::sun::star; + +namespace writerfilter +{ +namespace rtftok +{ + +RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword) +{ + setNeedSect(true); + checkUnicode(/*bUnicode =*/ true, /*bHex =*/ true); + RTFSkipDestination aSkip(*this); + int nParam = -1; + int nSprm = -1; + + // Underline flags. + switch (nKeyword) + { + case RTF_ULD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dotted; + break; + case RTF_ULW: + nSprm = NS_ooxml::LN_Value_ST_Underline_words; + break; + default: + break; + } + if (nSprm >= 0) + { + auto pValue = std::make_shared<RTFValue>(nSprm); + m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_Underline_val, pValue); + return RTFError::OK; + } + + // Indentation + switch (nKeyword) + { + case RTF_QC: + nParam = NS_ooxml::LN_Value_ST_Jc_center; + break; + case RTF_QJ: + nParam = NS_ooxml::LN_Value_ST_Jc_both; + break; + case RTF_QL: + nParam = NS_ooxml::LN_Value_ST_Jc_left; + break; + case RTF_QR: + nParam = NS_ooxml::LN_Value_ST_Jc_right; + break; + case RTF_QD: + nParam = NS_ooxml::LN_Value_ST_Jc_both; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_jc, pValue); + m_bNeedPap = true; + return RTFError::OK; + } + + // Font Alignment + switch (nKeyword) + { + case RTF_FAFIXED: + case RTF_FAAUTO: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_auto; + break; + case RTF_FAHANG: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_top; + break; + case RTF_FACENTER: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_center; + break; + case RTF_FAROMAN: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline; + break; + case RTF_FAVAR: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_bottom; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_textAlignment, pValue); + return RTFError::OK; + } + + // Tab kind. + switch (nKeyword) + { + case RTF_TQR: + nParam = NS_ooxml::LN_Value_ST_TabJc_right; + break; + case RTF_TQC: + nParam = NS_ooxml::LN_Value_ST_TabJc_center; + break; + case RTF_TQDEC: + nParam = NS_ooxml::LN_Value_ST_TabJc_decimal; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aTabAttributes.set(NS_ooxml::LN_CT_TabStop_val, pValue); + return RTFError::OK; + } + + // Tab lead. + switch (nKeyword) + { + case RTF_TLDOT: + nParam = NS_ooxml::LN_Value_ST_TabTlc_dot; + break; + case RTF_TLMDOT: + nParam = NS_ooxml::LN_Value_ST_TabTlc_middleDot; + break; + case RTF_TLHYPH: + nParam = NS_ooxml::LN_Value_ST_TabTlc_hyphen; + break; + case RTF_TLUL: + nParam = NS_ooxml::LN_Value_ST_TabTlc_underscore; + break; + case RTF_TLTH: + nParam = NS_ooxml::LN_Value_ST_TabTlc_hyphen; + break; // thick line is not supported by dmapper, this is just a hack + case RTF_TLEQ: + nParam = NS_ooxml::LN_Value_ST_TabTlc_none; + break; // equal sign isn't, either + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aTabAttributes.set(NS_ooxml::LN_CT_TabStop_leader, pValue); + return RTFError::OK; + } + + // Border types + { + switch (nKeyword) + { + // brdrhair and brdrs are the same, brdrw will make a difference + // map to values in ooxml/model.xml resource ST_Border + case RTF_BRDRHAIR: + case RTF_BRDRS: + nParam = NS_ooxml::LN_Value_ST_Border_single; + break; + case RTF_BRDRDOT: + nParam = NS_ooxml::LN_Value_ST_Border_dotted; + break; + case RTF_BRDRDASH: + nParam = NS_ooxml::LN_Value_ST_Border_dashed; + break; + case RTF_BRDRDB: + nParam = NS_ooxml::LN_Value_ST_Border_double; + break; + case RTF_BRDRTNTHSG: + nParam = NS_ooxml::LN_Value_ST_Border_thinThickSmallGap; + break; + case RTF_BRDRTNTHMG: + nParam = NS_ooxml::LN_Value_ST_Border_thinThickMediumGap; + break; + case RTF_BRDRTNTHLG: + nParam = NS_ooxml::LN_Value_ST_Border_thinThickLargeGap; + break; + case RTF_BRDRTHTNSG: + nParam = NS_ooxml::LN_Value_ST_Border_thickThinSmallGap; + break; + case RTF_BRDRTHTNMG: + nParam = NS_ooxml::LN_Value_ST_Border_thickThinMediumGap; + break; + case RTF_BRDRTHTNLG: + nParam = NS_ooxml::LN_Value_ST_Border_thickThinLargeGap; + break; + case RTF_BRDREMBOSS: + nParam = NS_ooxml::LN_Value_ST_Border_threeDEmboss; + break; + case RTF_BRDRENGRAVE: + nParam = NS_ooxml::LN_Value_ST_Border_threeDEngrave; + break; + case RTF_BRDROUTSET: + nParam = NS_ooxml::LN_Value_ST_Border_outset; + break; + case RTF_BRDRINSET: + nParam = NS_ooxml::LN_Value_ST_Border_inset; + break; + case RTF_BRDRNONE: + nParam = NS_ooxml::LN_Value_ST_Border_none; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_val, pValue); + return RTFError::OK; + } + } + + // Section breaks + switch (nKeyword) + { + case RTF_SBKNONE: + nParam = NS_ooxml::LN_Value_ST_SectionMark_continuous; + break; + case RTF_SBKCOL: + nParam = NS_ooxml::LN_Value_ST_SectionMark_nextColumn; + break; + case RTF_SBKPAGE: + nParam = NS_ooxml::LN_Value_ST_SectionMark_nextPage; + break; + case RTF_SBKEVEN: + nParam = NS_ooxml::LN_Value_ST_SectionMark_evenPage; + break; + case RTF_SBKODD: + nParam = NS_ooxml::LN_Value_ST_SectionMark_oddPage; + break; + default: + break; + } + if (nParam >= 0) + { + if (m_nResetBreakOnSectBreak != RTF_invalid) + { + m_nResetBreakOnSectBreak = nKeyword; + } + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aSectionSprms.set(NS_ooxml::LN_EG_SectPrContents_type, pValue); + return RTFError::OK; + } + + // Footnote numbering + switch (nKeyword) + { + case RTF_FTNNAR: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal; + break; + case RTF_FTNNALC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter; + break; + case RTF_FTNNAUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter; + break; + case RTF_FTNNRLC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman; + break; + case RTF_FTNNRUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman; + break; + case RTF_FTNNCHI: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + putNestedSprm(m_aDefaultState.aParagraphSprms, NS_ooxml::LN_EG_SectPrContents_footnotePr, NS_ooxml::LN_CT_FtnProps_numFmt, pValue); + return RTFError::OK; + } + + // Footnote restart type + switch (nKeyword) + { + case RTF_FTNRSTPG: + nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachPage; + break; + case RTF_FTNRESTART: + nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachSect; + break; + case RTF_FTNRSTCONT: + nParam = NS_ooxml::LN_Value_ST_RestartNumber_continuous; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + putNestedSprm(m_aDefaultState.aParagraphSprms, NS_ooxml::LN_EG_SectPrContents_footnotePr, NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue); + return RTFError::OK; + } + + // Endnote numbering + switch (nKeyword) + { + case RTF_AFTNNAR: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal; + break; + case RTF_AFTNNALC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter; + break; + case RTF_AFTNNAUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter; + break; + case RTF_AFTNNRLC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman; + break; + case RTF_AFTNNRUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman; + break; + case RTF_AFTNNCHI: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + putNestedSprm(m_aDefaultState.aParagraphSprms, NS_ooxml::LN_EG_SectPrContents_endnotePr, NS_ooxml::LN_CT_EdnProps_numFmt, pValue); + return RTFError::OK; + } + + switch (nKeyword) + { + case RTF_TRQL: + nParam = NS_ooxml::LN_Value_ST_Jc_left; + break; + case RTF_TRQC: + nParam = NS_ooxml::LN_Value_ST_Jc_center; + break; + case RTF_TRQR: + nParam = NS_ooxml::LN_Value_ST_Jc_right; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TrPrBase_jc, pValue); + return RTFError::OK; + } + + // Cell Text Flow + switch (nKeyword) + { + case RTF_CLTXLRTB: + nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTb; + break; + case RTF_CLTXTBRL: + nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRl; + break; + case RTF_CLTXBTLR: + nParam = NS_ooxml::LN_Value_ST_TextDirection_btLr; + break; + case RTF_CLTXLRTBV: + nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTbV; + break; + case RTF_CLTXTBRLV: + nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRlV; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aTableCellSprms.set(NS_ooxml::LN_CT_TcPrBase_textDirection, pValue); + } + + // Trivial paragraph flags + switch (nKeyword) + { + case RTF_KEEP: + if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back()) + nParam = NS_ooxml::LN_CT_PPrBase_keepLines; + break; + case RTF_KEEPN: + if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back()) + nParam = NS_ooxml::LN_CT_PPrBase_keepNext; + break; + case RTF_INTBL: + { + m_aStates.top().pCurrentBuffer = &m_aTableBufferStack.back(); + nParam = NS_ooxml::LN_inTbl; + } + break; + case RTF_PAGEBB: + nParam = NS_ooxml::LN_CT_PPrBase_pageBreakBefore; + break; + default: + break; + } + if (nParam >= 0) + { + auto pValue = std::make_shared<RTFValue>(1); + m_aStates.top().aParagraphSprms.erase(NS_ooxml::LN_inTbl); + m_aStates.top().aParagraphSprms.set(nParam, pValue); + return RTFError::OK; + } + + switch (nKeyword) + { + case RTF_FNIL: + case RTF_FROMAN: + case RTF_FSWISS: + case RTF_FMODERN: + case RTF_FSCRIPT: + case RTF_FDECOR: + case RTF_FTECH: + case RTF_FBIDI: + // TODO ooxml:CT_Font_family seems to be ignored by the domain mapper + break; + case RTF_ANSI: + m_aStates.top().nCurrentEncoding = RTL_TEXTENCODING_MS_1252; + break; + case RTF_MAC: + m_aDefaultState.nCurrentEncoding = RTL_TEXTENCODING_APPLE_ROMAN; + m_aStates.top().nCurrentEncoding = m_aDefaultState.nCurrentEncoding; + break; + case RTF_PC: + m_aDefaultState.nCurrentEncoding = RTL_TEXTENCODING_IBM_437; + m_aStates.top().nCurrentEncoding = m_aDefaultState.nCurrentEncoding; + break; + case RTF_PCA: + m_aDefaultState.nCurrentEncoding = RTL_TEXTENCODING_IBM_850; + m_aStates.top().nCurrentEncoding = m_aDefaultState.nCurrentEncoding; + break; + case RTF_PLAIN: + { + m_aStates.top().aCharacterSprms = getDefaultState().aCharacterSprms; + m_aStates.top().nCurrentEncoding = getEncoding(getFontIndex(m_nDefaultFontIndex)); + m_aStates.top().aCharacterAttributes = getDefaultState().aCharacterAttributes; + m_aStates.top().nCurrentCharacterStyleIndex = -1; + m_aStates.top().isRightToLeft = false; + m_aStates.top().eRunType = RTFParserState::LOCH; + } + break; + case RTF_PARD: + if (m_bHadPicture) + dispatchSymbol(RTF_PAR); + // \pard is allowed between \cell and \row, but in that case it should not reset the fact that we're inside a table. + m_aStates.top().aParagraphSprms = m_aDefaultState.aParagraphSprms; + m_aStates.top().aParagraphAttributes = m_aDefaultState.aParagraphAttributes; + + if (m_nTopLevelCells == 0 && m_nNestedCells == 0) + { + // Reset that we're in a table. + m_aStates.top().pCurrentBuffer = nullptr; + } + else + { + // We are still in a table. + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_inTbl, std::make_shared<RTFValue>(1)); + // Ideally getDefaultSPRM() would take care of this, but it would not when we're buffering. + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_tabs, std::make_shared<RTFValue>()); + } + resetFrame(); + + // Reset currently selected paragraph style as well. + // By default the style with index 0 is applied. + { + OUString const aName = getStyleName(0); + if (!aName.isEmpty()) + { + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_pStyle, std::make_shared<RTFValue>(aName)); + m_aStates.top().nCurrentStyleIndex = 0; + } + else + { + m_aStates.top().nCurrentStyleIndex = -1; + } + } + // Need to send paragraph properties again, if there will be any. + m_bNeedPap = true; + break; + case RTF_SECTD: + { + m_aStates.top().aSectionSprms = m_aDefaultState.aSectionSprms; + m_aStates.top().aSectionAttributes = m_aDefaultState.aSectionAttributes; + } + break; + case RTF_TROWD: + { + // Back these up, in case later we still need this info. + backupTableRowProperties(); + resetTableRowProperties(); + // In case the table definition is in the middle of the row + // (invalid), make sure table definition is emitted. + m_bNeedPap = true; + } + break; + case RTF_WIDCTLPAR: + case RTF_NOWIDCTLPAR: + { + auto pValue = std::make_shared<RTFValue>(int(nKeyword == RTF_WIDCTLPAR)); + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_widowControl, pValue); + } + break; + case RTF_BOX: + { + RTFSprms aAttributes; + auto pValue = std::make_shared<RTFValue>(aAttributes); + for (int i = 0; i < 4; i++) + m_aStates.top().aParagraphSprms.set(getParagraphBorder(i), pValue); + m_aStates.top().nBorderState = RTFBorderState::PARAGRAPH_BOX; + } + break; + case RTF_LTRSECT: + case RTF_RTLSECT: + { + auto pValue = std::make_shared<RTFValue>(nKeyword == RTF_LTRSECT ? 0 : 1); + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_EG_SectPrContents_textDirection, pValue); + } + break; + case RTF_LTRPAR: + case RTF_RTLPAR: + { + auto pValue = std::make_shared<RTFValue>(nKeyword == RTF_LTRPAR ? 0 : 1); + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_bidi, pValue); + } + break; + case RTF_LTRROW: + case RTF_RTLROW: + m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblPrBase_bidiVisual, std::make_shared<RTFValue>(int(nKeyword == RTF_RTLROW))); + break; + case RTF_LTRCH: + // dmapper does not support this. + m_aStates.top().isRightToLeft = false; + break; + case RTF_RTLCH: + m_aStates.top().isRightToLeft = true; + if (m_aDefaultState.nCurrentEncoding == RTL_TEXTENCODING_MS_1255) + m_aStates.top().nCurrentEncoding = m_aDefaultState.nCurrentEncoding; + break; + case RTF_ULNONE: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_Underline_none); + m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_Underline_val, pValue); + } + break; + case RTF_NONSHPPICT: + case RTF_MMATHPICT: // Picture group used by readers not understanding \moMath group + m_aStates.top().eDestination = Destination::SKIP; + break; + case RTF_CLBRDRT: + case RTF_CLBRDRL: + case RTF_CLBRDRB: + case RTF_CLBRDRR: + { + RTFSprms aAttributes; + RTFSprms aSprms; + auto pValue = std::make_shared<RTFValue>(aAttributes, aSprms); + switch (nKeyword) + { + case RTF_CLBRDRT: + nParam = NS_ooxml::LN_CT_TcBorders_top; + break; + case RTF_CLBRDRL: + nParam = NS_ooxml::LN_CT_TcBorders_left; + break; + case RTF_CLBRDRB: + nParam = NS_ooxml::LN_CT_TcBorders_bottom; + break; + case RTF_CLBRDRR: + nParam = NS_ooxml::LN_CT_TcBorders_right; + break; + default: + break; + } + putNestedSprm(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcBorders, nParam, pValue); + m_aStates.top().nBorderState = RTFBorderState::CELL; + } + break; + case RTF_PGBRDRT: + case RTF_PGBRDRL: + case RTF_PGBRDRB: + case RTF_PGBRDRR: + { + RTFSprms aAttributes; + RTFSprms aSprms; + auto pValue = std::make_shared<RTFValue>(aAttributes, aSprms); + switch (nKeyword) + { + case RTF_PGBRDRT: + nParam = NS_ooxml::LN_CT_PageBorders_top; + break; + case RTF_PGBRDRL: + nParam = NS_ooxml::LN_CT_PageBorders_left; + break; + case RTF_PGBRDRB: + nParam = NS_ooxml::LN_CT_PageBorders_bottom; + break; + case RTF_PGBRDRR: + nParam = NS_ooxml::LN_CT_PageBorders_right; + break; + default: + break; + } + putNestedSprm(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgBorders, nParam, pValue); + m_aStates.top().nBorderState = RTFBorderState::PAGE; + } + break; + case RTF_BRDRT: + case RTF_BRDRL: + case RTF_BRDRB: + case RTF_BRDRR: + { + RTFSprms aAttributes; + RTFSprms aSprms; + auto pValue = std::make_shared<RTFValue>(aAttributes, aSprms); + switch (nKeyword) + { + case RTF_BRDRT: + nParam = getParagraphBorder(0); + break; + case RTF_BRDRL: + nParam = getParagraphBorder(1); + break; + case RTF_BRDRB: + nParam = getParagraphBorder(2); + break; + case RTF_BRDRR: + nParam = getParagraphBorder(3); + break; + default: + break; + } + putNestedSprm(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PrBase_pBdr, nParam, pValue); + m_aStates.top().nBorderState = RTFBorderState::PARAGRAPH; + } + break; + case RTF_CHBRDR: + { + RTFSprms aAttributes; + auto pValue = std::make_shared<RTFValue>(aAttributes); + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_bdr, pValue); + m_aStates.top().nBorderState = RTFBorderState::CHARACTER; + } + break; + case RTF_CLMGF: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_Merge_restart); + m_aStates.top().aTableCellSprms.set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue); + } + break; + case RTF_CLMRG: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_Merge_continue); + m_aStates.top().aTableCellSprms.set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue); + } + break; + case RTF_CLVMGF: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_Merge_restart); + m_aStates.top().aTableCellSprms.set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue); + } + break; + case RTF_CLVMRG: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_Merge_continue); + m_aStates.top().aTableCellSprms.set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue); + } + break; + case RTF_CLVERTALT: + case RTF_CLVERTALC: + case RTF_CLVERTALB: + { + switch (nKeyword) + { + case RTF_CLVERTALT: + nParam = NS_ooxml::LN_Value_ST_VerticalJc_top; + break; + case RTF_CLVERTALC: + nParam = NS_ooxml::LN_Value_ST_VerticalJc_center; + break; + case RTF_CLVERTALB: + nParam = NS_ooxml::LN_Value_ST_VerticalJc_bottom; + break; + default: + break; + } + auto pValue = std::make_shared<RTFValue>(nParam); + m_aStates.top().aTableCellSprms.set(NS_ooxml::LN_CT_TcPrBase_vAlign, pValue); + } + break; + case RTF_TRKEEP: + { + auto pValue = std::make_shared<RTFValue>(1); + m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TrPrBase_cantSplit, pValue); + } + break; + case RTF_SECTUNLOCKED: + { + auto pValue = std::make_shared<RTFValue>(int(!nParam)); + m_aStates.top().aSectionSprms.set(NS_ooxml::LN_EG_SectPrContents_formProt, pValue); + } + break; + case RTF_PGNBIDIA: + case RTF_PGNBIDIB: + // These should be mapped to NS_ooxml::LN_EG_SectPrContents_pgNumType, but dmapper has no API for that at the moment. + break; + case RTF_LOCH: + m_aStates.top().eRunType = RTFParserState::LOCH; + break; + case RTF_HICH: + m_aStates.top().eRunType = RTFParserState::HICH; + break; + case RTF_DBCH: + m_aStates.top().eRunType = RTFParserState::DBCH; + break; + case RTF_TITLEPG: + { + auto pValue = std::make_shared<RTFValue>(1); + m_aStates.top().aSectionSprms.set(NS_ooxml::LN_EG_SectPrContents_titlePg, pValue); + } + break; + case RTF_SUPER: + { + if (!m_aStates.top().pCurrentBuffer) + m_aStates.top().pCurrentBuffer = &m_aSuperBuffer; + + auto pValue = std::make_shared<RTFValue>("superscript"); + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue); + } + break; + case RTF_SUB: + { + auto pValue = std::make_shared<RTFValue>("subscript"); + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue); + } + break; + case RTF_NOSUPERSUB: + { + if (m_aStates.top().pCurrentBuffer == &m_aSuperBuffer) + { + replayBuffer(m_aSuperBuffer, nullptr, nullptr); + m_aStates.top().pCurrentBuffer = nullptr; + } + m_aStates.top().aCharacterSprms.erase(NS_ooxml::LN_EG_RPrBase_vertAlign); + } + break; + case RTF_LINEPPAGE: + case RTF_LINECONT: + { + auto pValue = std::make_shared<RTFValue>(nKeyword == RTF_LINEPPAGE ? NS_ooxml::LN_Value_ST_LineNumberRestart_newPage : NS_ooxml::LN_Value_ST_LineNumberRestart_continuous); + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_lnNumType, NS_ooxml::LN_CT_LineNumber_restart, pValue); + } + break; + case RTF_AENDDOC: + // Noop, this is the default in Writer. + break; + case RTF_AENDNOTES: + // Noop, Writer does not support having endnotes at the end of section. + break; + case RTF_AFTNRSTCONT: + // Noop, this is the default in Writer. + break; + case RTF_AFTNRESTART: + // Noop, Writer does not support restarting endnotes at each section. + break; + case RTF_FTNBJ: + // Noop, this is the default in Writer. + break; + case RTF_ENDDOC: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_RestartNumber_eachSect); + putNestedSprm(m_aDefaultState.aParagraphSprms, NS_ooxml::LN_EG_SectPrContents_footnotePr, NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue); + } + break; + case RTF_NOLINE: + eraseNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_lnNumType, NS_ooxml::LN_CT_LineNumber_distance); + break; + case RTF_FORMSHADE: + // Noop, this is the default in Writer. + break; + case RTF_PNGBLIP: + m_aStates.top().aPicture.eStyle = RTFBmpStyle::PNG; + break; + case RTF_JPEGBLIP: + m_aStates.top().aPicture.eStyle = RTFBmpStyle::JPEG; + break; + case RTF_POSYT: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, NS_ooxml::LN_Value_doc_ST_YAlign_top); + break; + case RTF_POSYB: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, NS_ooxml::LN_Value_doc_ST_YAlign_bottom); + break; + case RTF_POSYC: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, NS_ooxml::LN_Value_doc_ST_YAlign_center); + break; + case RTF_POSYIN: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, NS_ooxml::LN_Value_doc_ST_YAlign_inside); + break; + case RTF_POSYOUT: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, NS_ooxml::LN_Value_doc_ST_YAlign_outside); + break; + case RTF_POSYIL: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, NS_ooxml::LN_Value_doc_ST_YAlign_inline); + break; + + case RTF_PHMRG: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_Value_doc_ST_HAnchor_margin); + break; + case RTF_PVMRG: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, NS_ooxml::LN_Value_doc_ST_VAnchor_margin); + break; + case RTF_PHPG: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_Value_doc_ST_HAnchor_page); + break; + case RTF_PVPG: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, NS_ooxml::LN_Value_doc_ST_VAnchor_page); + break; + case RTF_PHCOL: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_Value_doc_ST_HAnchor_text); + break; + case RTF_PVPARA: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, NS_ooxml::LN_Value_doc_ST_VAnchor_text); + break; + + case RTF_POSXC: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_Value_doc_ST_XAlign_center); + break; + case RTF_POSXI: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_Value_doc_ST_XAlign_inside); + break; + case RTF_POSXO: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_Value_doc_ST_XAlign_outside); + break; + case RTF_POSXL: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_Value_doc_ST_XAlign_left); + break; + case RTF_POSXR: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_Value_doc_ST_XAlign_right); + break; + + case RTF_DPLINE: + case RTF_DPRECT: + case RTF_DPELLIPSE: + case RTF_DPTXBX: + case RTF_DPPOLYLINE: + case RTF_DPPOLYGON: + { + sal_Int32 nType = 0; + switch (nKeyword) + { + case RTF_DPLINE: + m_aStates.top().aDrawingObject.xShape.set(getModelFactory()->createInstance("com.sun.star.drawing.LineShape"), uno::UNO_QUERY); + break; + case RTF_DPPOLYLINE: + // The reason this is not a simple CustomShape is that in the old syntax we have no ViewBox info. + m_aStates.top().aDrawingObject.xShape.set(getModelFactory()->createInstance("com.sun.star.drawing.PolyLineShape"), uno::UNO_QUERY); + break; + case RTF_DPPOLYGON: + m_aStates.top().aDrawingObject.xShape.set(getModelFactory()->createInstance("com.sun.star.drawing.PolyPolygonShape"), uno::UNO_QUERY); + break; + case RTF_DPRECT: + m_aStates.top().aDrawingObject.xShape.set(getModelFactory()->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + break; + case RTF_DPELLIPSE: + nType = ESCHER_ShpInst_Ellipse; + break; + case RTF_DPTXBX: + { + m_aStates.top().aDrawingObject.xShape.set(getModelFactory()->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY); + std::vector<beans::PropertyValue> aDefaults = RTFSdrImport::getTextFrameDefaults(false); + for (std::size_t i = 0; i < aDefaults.size(); ++i) + { + if (!findPropertyName(m_aStates.top().aDrawingObject.aPendingProperties, aDefaults[i].Name)) + m_aStates.top().aDrawingObject.aPendingProperties.push_back(aDefaults[i]); + } + checkFirstRun(); + Mapper().startShape(m_aStates.top().aDrawingObject.xShape); + m_aStates.top().aDrawingObject.bHadShapeText = true; + } + break; + default: + break; + } + if (nType) + m_aStates.top().aDrawingObject.xShape.set(getModelFactory()->createInstance("com.sun.star.drawing.CustomShape"), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc, uno::UNO_QUERY); + if (xDrawSupplier.is()) + { + uno::Reference<drawing::XShapes> xShapes(xDrawSupplier->getDrawPage(), uno::UNO_QUERY); + if (xShapes.is() && nKeyword != RTF_DPTXBX) + xShapes->add(m_aStates.top().aDrawingObject.xShape); + } + if (nType) + { + uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(m_aStates.top().aDrawingObject.xShape, uno::UNO_QUERY); + xDefaulter->createCustomShapeDefaults(OUString::number(nType)); + } + m_aStates.top().aDrawingObject.xPropertySet.set(m_aStates.top().aDrawingObject.xShape, uno::UNO_QUERY); + std::vector<beans::PropertyValue>& rPendingProperties = m_aStates.top().aDrawingObject.aPendingProperties; + for (std::vector<beans::PropertyValue>::iterator i = rPendingProperties.begin(); i != rPendingProperties.end(); ++i) + m_aStates.top().aDrawingObject.xPropertySet->setPropertyValue(i->Name, i->Value); + m_pSdrImport->resolveDhgt(m_aStates.top().aDrawingObject.xPropertySet, m_aStates.top().aDrawingObject.nDhgt, /*bOldStyle=*/true); + } + break; + case RTF_DOBXMARGIN: + case RTF_DOBYMARGIN: + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name = (nKeyword == RTF_DOBXMARGIN ? OUString("HoriOrientRelation") : OUString("VertOrientRelation")); + aPropertyValue.Value <<= text::RelOrientation::PAGE_PRINT_AREA; + m_aStates.top().aDrawingObject.aPendingProperties.push_back(aPropertyValue); + } + break; + case RTF_DOBXPAGE: + case RTF_DOBYPAGE: + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name = (nKeyword == RTF_DOBXPAGE ? OUString("HoriOrientRelation") : OUString("VertOrientRelation")); + aPropertyValue.Value <<= text::RelOrientation::PAGE_FRAME; + m_aStates.top().aDrawingObject.aPendingProperties.push_back(aPropertyValue); + } + break; + case RTF_DOBYPARA: + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name = "VertOrientRelation"; + aPropertyValue.Value <<= text::RelOrientation::FRAME; + m_aStates.top().aDrawingObject.aPendingProperties.push_back(aPropertyValue); + } + break; + case RTF_CONTEXTUALSPACE: + { + auto pValue = std::make_shared<RTFValue>(1); + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_contextualSpacing, pValue); + } + break; + case RTF_LINKSTYLES: + { + auto pValue = std::make_shared<RTFValue>(1); + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_linkStyles, pValue); + } + break; + case RTF_PNLVLBODY: + { + auto pValue = std::make_shared<RTFValue>(2); + m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pValue); + } + break; + case RTF_PNDEC: + { + auto pValue = std::make_shared<RTFValue>(0); // decimal, same as \levelnfc0 + m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, pValue); + } + break; + case RTF_PNLVLBLT: + { + m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, std::make_shared<RTFValue>(1)); + m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, std::make_shared<RTFValue>(23)); // bullets, same as \levelnfc23 + } + break; + case RTF_LANDSCAPE: // fall through: set the default + current value + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_PageOrientation_landscape); + putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient, pValue); + } + case RTF_LNDSCPSXN: + { + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_PageOrientation_landscape); + putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient, pValue); + } + break; + case RTF_SHPBXPAGE: + m_aStates.top().aShape.nHoriOrientRelation = text::RelOrientation::PAGE_FRAME; + m_aStates.top().aShape.nHoriOrientRelationToken = NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page; + break; + case RTF_SHPBYPAGE: + m_aStates.top().aShape.nVertOrientRelation = text::RelOrientation::PAGE_FRAME; + m_aStates.top().aShape.nVertOrientRelationToken = NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page; + break; + case RTF_DPLINEHOLLOW: + m_aStates.top().aDrawingObject.nFLine = 0; + break; + case RTF_DPROUNDR: + if (m_aStates.top().aDrawingObject.xPropertySet.is()) + // Seems this old syntax has no way to specify a custom radius, and this is the default + m_aStates.top().aDrawingObject.xPropertySet->setPropertyValue("CornerRadius", uno::makeAny(sal_Int32(83))); + break; + case RTF_NOWRAP: + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_wrap, NS_ooxml::LN_Value_doc_ST_Wrap_notBeside); + break; + case RTF_MNOR: + m_bMathNor = true; + break; + case RTF_REVISIONS: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_trackRevisions, std::make_shared<RTFValue>(1)); + break; + case RTF_BRDRSH: + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_shadow, std::make_shared<RTFValue>(1)); + break; + case RTF_NOCOLBAL: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_noColumnBalance, std::make_shared<RTFValue>(1)); + break; + case RTF_MARGMIRROR: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_mirrorMargins, std::make_shared<RTFValue>(1)); + break; + case RTF_SAUTOUPD: + m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Style_autoRedefine, std::make_shared<RTFValue>(1)); + break; + case RTF_WIDOWCTRL: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_widowControl, std::make_shared<RTFValue>(1)); + break; + case RTF_LINEBETCOL: + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_sep, std::make_shared<RTFValue>(1)); + break; + case RTF_PGNRESTART: + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgNumType, NS_ooxml::LN_CT_PageNumber_start, std::make_shared<RTFValue>(1)); + break; + case RTF_PGNUCLTR: + { + auto pIntValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_NumberFormat_upperLetter); + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgNumType, NS_ooxml::LN_CT_PageNumber_fmt, pIntValue); + } + break; + case RTF_PGNLCLTR: + { + auto pIntValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter); + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgNumType, NS_ooxml::LN_CT_PageNumber_fmt, pIntValue); + } + break; + case RTF_PGNUCRM: + { + auto pIntValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_NumberFormat_upperRoman); + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgNumType, NS_ooxml::LN_CT_PageNumber_fmt, pIntValue); + } + break; + case RTF_PGNLCRM: + { + auto pIntValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman); + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgNumType, NS_ooxml::LN_CT_PageNumber_fmt, pIntValue); + } + break; + case RTF_PGNDEC: + { + auto pIntValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_NumberFormat_decimal); + putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgNumType, NS_ooxml::LN_CT_PageNumber_fmt, pIntValue); + } + break; + default: + { + SAL_INFO("writerfilter", "TODO handle flag '" << keywordToString(nKeyword) << "'"); + aSkip.setParsed(false); + } + break; + } + return RTFError::OK; +} + +} // namespace rtftok +} // namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/rtftok/rtfdispatchsymbol.cxx b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx new file mode 100644 index 0000000..98aa43d --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx @@ -0,0 +1,409 @@ +/* -*- 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 <svl/lngmisc.hxx> + +#include <ooxml/resourceids.hxx> + +#include <rtfreferenceproperties.hxx> +#include <rtfskipdestination.hxx> + +using namespace com::sun::star; + +namespace writerfilter +{ +namespace rtftok +{ + +RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword) +{ + setNeedSect(true); + if (nKeyword != RTF_HEXCHAR) + checkUnicode(/*bUnicode =*/ true, /*bHex =*/ true); + else + checkUnicode(/*bUnicode =*/ true, /*bHex =*/ false); + RTFSkipDestination aSkip(*this); + + if (RTF_LINE == nKeyword) + { + // very special handling since text() will eat lone '\n' + singleChar('\n'); + return RTFError::OK; + } + // Trivial symbols + sal_uInt8 cCh = 0; + switch (nKeyword) + { + case RTF_TAB: + cCh = '\t'; + break; + case RTF_BACKSLASH: + cCh = '\\'; + break; + case RTF_LBRACE: + cCh = '{'; + break; + case RTF_RBRACE: + cCh = '}'; + break; + case RTF_EMDASH: + cCh = 151; + break; + case RTF_ENDASH: + cCh = 150; + break; + case RTF_BULLET: + cCh = 149; + break; + case RTF_LQUOTE: + cCh = 145; + break; + case RTF_RQUOTE: + cCh = 146; + break; + case RTF_LDBLQUOTE: + cCh = 147; + break; + case RTF_RDBLQUOTE: + cCh = 148; + break; + default: + break; + } + if (cCh > 0) + { + OUString aStr(OStringToOUString(OString(cCh), RTL_TEXTENCODING_MS_1252)); + text(aStr); + return RTFError::OK; + } + + switch (nKeyword) + { + case RTF_IGNORE: + { + m_bSkipUnknown = true; + aSkip.setReset(false); + return RTFError::OK; + } + break; + case RTF_PAR: + { + if (m_aStates.top().eDestination == Destination::FOOTNOTESEPARATOR) + break; // just ignore it - only thing we read in here is CHFTNSEP + checkFirstRun(); + bool bNeedPap = m_bNeedPap; + checkNeedPap(); + if (bNeedPap) + runProps(); + if (!m_aStates.top().pCurrentBuffer) + { + parBreak(); + // Not in table? Reset max width. + if (m_nCellxMax) + { + // Was in table, but not anymore -> tblEnd. + RTFSprms aAttributes; + RTFSprms aSprms; + aSprms.set(NS_ooxml::LN_tblEnd, std::make_shared<RTFValue>(1)); + writerfilter::Reference<Properties>::Pointer_t pProperties = std::make_shared<RTFReferenceProperties>(aAttributes, aSprms); + Mapper().props(pProperties); + } + m_nCellxMax = 0; + } + else if (m_aStates.top().eDestination != Destination::SHAPETEXT) + { + RTFValue::Pointer_t pValue; + m_aStates.top().pCurrentBuffer->push_back( + Buf_t(BUFFER_PAR, pValue, nullptr)); + } + // but don't emit properties yet, since they may change till the first text token arrives + m_bNeedPap = true; + if (!m_aStates.top().aFrame.inFrame()) + m_bNeedPar = false; + m_bNeedFinalPar = false; + } + break; + case RTF_SECT: + { + m_bHadSect = true; + if (m_bIgnoreNextContSectBreak) + m_bIgnoreNextContSectBreak = false; + else + { + sectBreak(); + if (m_nResetBreakOnSectBreak != RTF_invalid) + { + // this should run on _second_ \sect after \page + dispatchSymbol(m_nResetBreakOnSectBreak); // lazy reset + m_nResetBreakOnSectBreak = RTF_invalid; + m_bNeedSect = false; // dispatchSymbol set it + } + } + } + break; + case RTF_NOBREAK: + { + OUString aStr(SVT_HARD_SPACE); + text(aStr); + } + break; + case RTF_NOBRKHYPH: + { + OUString aStr(SVT_HARD_HYPHEN); + text(aStr); + } + break; + case RTF_OPTHYPH: + { + OUString aStr(SVT_SOFT_HYPHEN); + text(aStr); + } + break; + case RTF_HEXCHAR: + m_aStates.top().nInternalState = RTFInternalState::HEX; + break; + case RTF_CELL: + case RTF_NESTCELL: + { + checkFirstRun(); + if (m_bNeedPap) + { + // There were no runs in the cell, so we need to send paragraph and character properties here. + auto pPValue = std::make_shared<RTFValue>(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms); + m_aTableBufferStack.back().push_back(Buf_t(BUFFER_PROPS, pPValue, nullptr)); + auto pCValue = std::make_shared<RTFValue>(m_aStates.top().aCharacterAttributes, m_aStates.top().aCharacterSprms); + m_aTableBufferStack.back().push_back(Buf_t(BUFFER_PROPS, pCValue, nullptr)); + } + + RTFValue::Pointer_t pValue; + m_aTableBufferStack.back().push_back(Buf_t(BUFFER_CELLEND, pValue, nullptr)); + m_bNeedPap = true; + } + break; + case RTF_NESTROW: + { + std::shared_ptr<TableRowBuffer> const pBuffer( + new TableRowBuffer( + m_aTableBufferStack.back(), + m_aNestedTableCellsSprms, + m_aNestedTableCellsAttributes, + m_nNestedCells)); + prepareProperties(m_aStates.top(), + pBuffer->pParaProperties, + pBuffer->pFrameProperties, + pBuffer->pRowProperties, + m_nNestedCells, m_nNestedCurrentCellX); + + assert(m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back()); + if (m_aTableBufferStack.size() == 1) + { + throw io::WrongFormatException( + "mismatch between \\itap and number of \\nestrow", nullptr); + } + // note: there may be several states pointing to table buffer! + for (std::size_t i = 0; i < m_aStates.size(); ++i) + { + if (m_aStates[i].pCurrentBuffer == &m_aTableBufferStack.back()) + { + m_aStates[i].pCurrentBuffer = + &m_aTableBufferStack[m_aTableBufferStack.size()-2]; + } + } + m_aTableBufferStack.pop_back(); + m_aTableBufferStack.back().push_back( + Buf_t(BUFFER_NESTROW, RTFValue::Pointer_t(), pBuffer)); + + m_aNestedTableCellsSprms.clear(); + m_aNestedTableCellsAttributes.clear(); + m_nNestedCells = 0; + m_bNeedPap = true; + } + break; + case RTF_ROW: + { + bool bRestored = false; + // Ending a row, but no cells defined? + // See if there was an invalid table row reset, so we can restore cell infos to help invalid documents. + if (!m_nTopLevelCurrentCellX && m_nBackupTopLevelCurrentCellX) + { + restoreTableRowProperties(); + bRestored = true; + } + + // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell + const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames. + if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY) + { + auto pXValueLast = m_aStates.top().aTableRowSprms.find(NS_ooxml::LN_CT_TblGridBase_gridCol, false); + auto pXValue = std::make_shared<RTFValue>(pXValueLast->getInt() + m_nCellxMax - m_nTopLevelCurrentCellX); + m_aStates.top().aTableRowSprms.eraseLast(NS_ooxml::LN_CT_TblGridBase_gridCol); + m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue, RTFOverwrite::NO_APPEND); + m_nTopLevelCurrentCellX = m_nCellxMax; + } + + if (m_nTopLevelCells) + { + // Make a backup before we start popping elements + m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms; + m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes; + m_nInheritingCells = m_nTopLevelCells; + } + else + { + // No table definition? Then inherit from the previous row + m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms; + m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes; + m_nTopLevelCells = m_nInheritingCells; + } + + while (m_aTableBufferStack.size() > 1) + { + SAL_WARN("writerfilter.rtf", "dropping extra table buffer"); + // note: there may be several states pointing to table buffer! + for (std::size_t i = 0; i < m_aStates.size(); ++i) + { + if (m_aStates[i].pCurrentBuffer == &m_aTableBufferStack.back()) + { + m_aStates[i].pCurrentBuffer = + &m_aTableBufferStack.front(); + } + } + m_aTableBufferStack.pop_back(); + } + + replayRowBuffer(m_aTableBufferStack.back(), + m_aTopLevelTableCellsSprms, m_aTopLevelTableCellsAttributes, + m_nTopLevelCells); + + m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms; + m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes; + + writerfilter::Reference<Properties>::Pointer_t paraProperties; + writerfilter::Reference<Properties>::Pointer_t frameProperties; + writerfilter::Reference<Properties>::Pointer_t rowProperties; + prepareProperties(m_aStates.top(), + paraProperties, frameProperties, rowProperties, + m_nTopLevelCells, m_nTopLevelCurrentCellX); + sendProperties(paraProperties, frameProperties, rowProperties); + + m_bNeedPap = true; + m_bNeedFinalPar = true; + m_aTableBufferStack.back().clear(); + m_nTopLevelCells = 0; + + if (bRestored) + // We restored cell definitions, clear these now. + // This is necessary, as later cell definitions want to overwrite the restored ones. + resetTableRowProperties(); + } + break; + case RTF_COLUMN: + { + bool bColumns = false; // If we have multiple columns + RTFValue::Pointer_t pCols = m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_cols); + if (pCols.get()) + { + RTFValue::Pointer_t pNum = pCols->getAttributes().find(NS_ooxml::LN_CT_Columns_num); + if (pNum.get() && pNum->getInt() > 1) + bColumns = true; + } + checkFirstRun(); + if (bColumns) + { + sal_uInt8 sBreak[] = { 0xe }; + Mapper().startCharacterGroup(); + Mapper().text(sBreak, 1); + Mapper().endCharacterGroup(); + } + else + dispatchSymbol(RTF_PAGE); + } + break; + case RTF_CHFTN: + { + if (m_aStates.top().pCurrentBuffer == &m_aSuperBuffer) + // Stop buffering, there will be no custom mark for this footnote or endnote. + m_aStates.top().pCurrentBuffer = nullptr; + break; + } + case RTF_PAGE: + { + // Ignore page breaks inside tables. + if (m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back()) + break; + + // If we're inside a continuous section, we should send a section break, not a page one. + RTFValue::Pointer_t pBreak = m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_type); + // Unless we're on a title page. + RTFValue::Pointer_t pTitlePg = m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_titlePg); + if (((pBreak.get() && pBreak->getInt() == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous)) + || m_nResetBreakOnSectBreak == RTF_SBKNONE) + && !(pTitlePg.get() && pTitlePg->getInt())) + { + if (m_bWasInFrame) + { + dispatchSymbol(RTF_PAR); + m_bWasInFrame = false; + } + sectBreak(); + // note: this will not affect the following section break + // but the one just pushed + dispatchFlag(RTF_SBKPAGE); + if (m_bNeedPar) + dispatchSymbol(RTF_PAR); + m_bIgnoreNextContSectBreak = true; + // arrange to clean up the synthetic RTF_SBKPAGE + m_nResetBreakOnSectBreak = RTF_SBKNONE; + } + else + { + checkFirstRun(); + checkNeedPap(); + sal_uInt8 sBreak[] = { 0xc }; + Mapper().text(sBreak, 1); + if (!m_bNeedPap) + { + parBreak(); + m_bNeedPap = true; + } + m_bNeedCr = true; + } + } + break; + case RTF_CHPGN: + { + OUString aStr("PAGE"); + singleChar(cFieldStart); + text(aStr); + singleChar(cFieldSep, true); + singleChar(cFieldEnd); + } + break; + case RTF_CHFTNSEP: + { + static const sal_Unicode uFtnEdnSep = 0x3; + Mapper().utext(reinterpret_cast<const sal_uInt8*>(&uFtnEdnSep), 1); + } + break; + default: + { + SAL_INFO("writerfilter", "TODO handle symbol '" << keywordToString(nKeyword) << "'"); + aSkip.setParsed(false); + } + break; + } + return RTFError::OK; +} + +} // namespace rtftok +} // namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx b/writerfilter/source/rtftok/rtfdispatchvalue.cxx new file mode 100644 index 0000000..76e24dd --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx @@ -0,0 +1,1347 @@ +/* -*- 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 <com/sun/star/text/WrapTextMode.hpp> + +#include <comphelper/sequence.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <rtl/tencinfo.h> +#include <tools/colordata.hxx> +#include <tools/mapunit.hxx> + +#include <ooxml/resourceids.hxx> + +#include <rtfcharsets.hxx> +#include <rtffly.hxx> +#include <rtfreferenceproperties.hxx> +#include <rtfskipdestination.hxx> + +using namespace com::sun::star; + +namespace writerfilter +{ + +int getNumberFormat(int nParam) +{ + static const int aMap[] = + { + NS_ooxml::LN_Value_ST_NumberFormat_decimal, + NS_ooxml::LN_Value_ST_NumberFormat_upperRoman, + NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman, + NS_ooxml::LN_Value_ST_NumberFormat_upperLetter, + NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter, + NS_ooxml::LN_Value_ST_NumberFormat_ordinal, + NS_ooxml::LN_Value_ST_NumberFormat_cardinalText, + NS_ooxml::LN_Value_ST_NumberFormat_ordinalText, + NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec. + NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec. + NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital, + NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting, + NS_ooxml::LN_Value_ST_NumberFormat_aiueo, + NS_ooxml::LN_Value_ST_NumberFormat_iroha, + NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth, + NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth, + NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal, + NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand , + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese, + NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2, + NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth, + NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth, + NS_ooxml::LN_Value_ST_NumberFormat_decimalZero, + NS_ooxml::LN_Value_ST_NumberFormat_bullet, + NS_ooxml::LN_Value_ST_NumberFormat_ganada, + NS_ooxml::LN_Value_ST_NumberFormat_chosung, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese, + NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle, + NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional, + NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac, + NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional, + NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting, + NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional, + NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand, + NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital, + NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting, + NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified, + NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand, + NS_ooxml::LN_Value_ST_NumberFormat_decimal, + NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital, + NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting, + NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal, + NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2, + NS_ooxml::LN_Value_ST_NumberFormat_hebrew1, + NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha, + NS_ooxml::LN_Value_ST_NumberFormat_hebrew2, + NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad + }; + const int nLen = SAL_N_ELEMENTS(aMap); + int nValue = 0; + if (nParam >= 0 && nParam < nLen) + nValue = aMap[nParam]; + else // 255 and the other cases. + nValue = NS_ooxml::LN_Value_ST_NumberFormat_none; + return nValue; +} + +namespace rtftok +{ + +RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) +{ + setNeedSect(true); + checkUnicode(/*bUnicode =*/ nKeyword != RTF_U, /*bHex =*/ true); + RTFSkipDestination aSkip(*this); + int nSprm = 0; + auto pIntValue = std::make_shared<RTFValue>(nParam); + // Trivial table sprms. + switch (nKeyword) + { + case RTF_LEVELJC: + { + nSprm = NS_ooxml::LN_CT_Lvl_lvlJc; + int nValue = 0; + switch (nParam) + { + case 0: + nValue = NS_ooxml::LN_Value_ST_Jc_left; + break; + case 1: + nValue = NS_ooxml::LN_Value_ST_Jc_center; + break; + case 2: + nValue = NS_ooxml::LN_Value_ST_Jc_right; + break; + } + pIntValue = std::make_shared<RTFValue>(nValue); + break; + } + case RTF_LEVELNFC: + nSprm = NS_ooxml::LN_CT_Lvl_numFmt; + pIntValue = std::make_shared<RTFValue>(getNumberFormat(nParam)); + break; + case RTF_LEVELSTARTAT: + nSprm = NS_ooxml::LN_CT_Lvl_start; + break; + case RTF_LEVELPICTURE: + nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId; + break; + case RTF_SBASEDON: + nSprm = NS_ooxml::LN_CT_Style_basedOn; + pIntValue = std::make_shared<RTFValue>(getStyleName(nParam)); + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().aTableSprms.set(nSprm, pIntValue); + return RTFError::OK; + } + // Trivial character sprms. + switch (nKeyword) + { + case RTF_FS: + case RTF_AFS: + nSprm = (m_aStates.top().isRightToLeft || m_aStates.top().eRunType == RTFParserState::HICH) ? NS_ooxml::LN_EG_RPrBase_szCs : NS_ooxml::LN_EG_RPrBase_sz; + break; + case RTF_ANIMTEXT: + nSprm = NS_ooxml::LN_EG_RPrBase_effect; + break; + case RTF_EXPNDTW: + nSprm = NS_ooxml::LN_EG_RPrBase_spacing; + break; + case RTF_KERNING: + nSprm = NS_ooxml::LN_EG_RPrBase_kern; + break; + case RTF_CHARSCALEX: + nSprm = NS_ooxml::LN_EG_RPrBase_w; + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().aCharacterSprms.set(nSprm, pIntValue); + return RTFError::OK; + } + // Trivial character attributes. + switch (nKeyword) + { + case RTF_LANG: + case RTF_ALANG: + if (m_aStates.top().isRightToLeft || m_aStates.top().eRunType == RTFParserState::HICH) + { + nSprm = NS_ooxml::LN_CT_Language_bidi; + } + else if (m_aStates.top().eRunType == RTFParserState::DBCH) + { + nSprm = NS_ooxml::LN_CT_Language_eastAsia; + } + else + { + assert(m_aStates.top().eRunType == RTFParserState::LOCH); + nSprm = NS_ooxml::LN_CT_Language_val; + } + break; + case RTF_LANGFE: // this one is always CJK apparently + nSprm = NS_ooxml::LN_CT_Language_eastAsia; + break; + default: + break; + } + if (nSprm > 0) + { + LanguageTag aTag((LanguageType)nParam); + auto pValue = std::make_shared<RTFValue>(aTag.getBcp47()); + putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_EG_RPrBase_lang, nSprm, pValue); + // Language is a character property, but we should store it at a paragraph level as well for fields. + if (nKeyword == RTF_LANG && m_bNeedPap) + putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_EG_RPrBase_lang, nSprm, pValue); + return RTFError::OK; + } + // Trivial paragraph sprms. + switch (nKeyword) + { + case RTF_ITAP: + nSprm = NS_ooxml::LN_tblDepth; + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().aParagraphSprms.set(nSprm, pIntValue); + if (nKeyword == RTF_ITAP && nParam > 0) + { + while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam)) + { + m_aTableBufferStack.push_back(RTFBuffer_t()); + } + // Invalid tables may omit INTBL after ITAP + dispatchFlag(RTF_INTBL); // sets newly pushed buffer as current + assert(m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back()); + } + return RTFError::OK; + } + + // Info group. + switch (nKeyword) + { + case RTF_YR: + { + m_aStates.top().nYear = nParam; + nSprm = 1; + } + break; + case RTF_MO: + { + m_aStates.top().nMonth = nParam; + nSprm = 1; + } + break; + case RTF_DY: + { + m_aStates.top().nDay = nParam; + nSprm = 1; + } + break; + case RTF_HR: + { + m_aStates.top().nHour = nParam; + nSprm = 1; + } + break; + case RTF_MIN: + { + m_aStates.top().nMinute = nParam; + nSprm = 1; + } + break; + default: + break; + } + if (nSprm > 0) + return RTFError::OK; + + // Frame size / position. + Id nId = 0; + switch (nKeyword) + { + case RTF_ABSW: + nId = NS_ooxml::LN_CT_FramePr_w; + break; + case RTF_ABSH: + nId = NS_ooxml::LN_CT_FramePr_h; + break; + case RTF_POSX: + { + nId = NS_ooxml::LN_CT_FramePr_x; + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0); + } + break; + case RTF_POSY: + { + nId = NS_ooxml::LN_CT_FramePr_y; + m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0); + } + break; + default: + break; + } + + if (nId > 0) + { + m_bNeedPap = true; + // Don't try to support text frames inside tables for now. + if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back()) + m_aStates.top().aFrame.setSprm(nId, nParam); + + return RTFError::OK; + } + + // Then check for the more complex ones. + switch (nKeyword) + { + case RTF_F: + case RTF_AF: + if (m_aStates.top().isRightToLeft || m_aStates.top().eRunType == RTFParserState::HICH) + { + nSprm = NS_ooxml::LN_CT_Fonts_cs; + } + else if (m_aStates.top().eRunType == RTFParserState::DBCH) + { + nSprm = NS_ooxml::LN_CT_Fonts_eastAsia; + } + else + { + assert(m_aStates.top().eRunType == RTFParserState::LOCH); + nSprm = NS_ooxml::LN_CT_Fonts_ascii; + } + if (m_aStates.top().eDestination == Destination::FONTTABLE || m_aStates.top().eDestination == Destination::FONTENTRY) + { + m_aFontIndexes.push_back(nParam); + m_nCurrentFontIndex = getFontIndex(nParam); + } + else if (m_aStates.top().eDestination == Destination::LISTLEVEL) + { + RTFSprms aFontAttributes; + aFontAttributes.set(nSprm, std::make_shared<RTFValue>(m_aFontNames[getFontIndex(nParam)])); + RTFSprms aRunPropsSprms; + aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, std::make_shared<RTFValue>(aFontAttributes)); + m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_rPr, std::make_shared<RTFValue>(RTFSprms(), aRunPropsSprms), RTFOverwrite::NO_APPEND); + } + else + { + m_nCurrentFontIndex = getFontIndex(nParam); + auto pValue = std::make_shared<RTFValue>(getFontName(m_nCurrentFontIndex)); + putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue); + if (nKeyword == RTF_F) + m_aStates.top().nCurrentEncoding = getEncoding(m_nCurrentFontIndex); + } + break; + case RTF_RED: + m_aStates.top().aCurrentColor.nRed = nParam; + break; + case RTF_GREEN: + m_aStates.top().aCurrentColor.nGreen = nParam; + break; + case RTF_BLUE: + m_aStates.top().aCurrentColor.nBlue = nParam; + break; + case RTF_FCHARSET: + { + // we always send text to the domain mapper in OUString, so no + // need to send encoding info + int i; + for (i = 0; i < nRTFEncodings; i++) + { + if (aRTFEncodings[i].charset == nParam) + break; + } + if (i == nRTFEncodings) + // not found + return RTFError::OK; + + m_nCurrentEncoding = rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage); + m_aStates.top().nCurrentEncoding = m_nCurrentEncoding; + } + break; + case RTF_ANSICPG: + { + m_aDefaultState.nCurrentEncoding = rtl_getTextEncodingFromWindowsCodePage(nParam); + m_aStates.top().nCurrentEncoding = rtl_getTextEncodingFromWindowsCodePage(nParam); + } + break; + case RTF_CPG: + m_nCurrentEncoding = rtl_getTextEncodingFromWindowsCodePage(nParam); + m_aStates.top().nCurrentEncoding = m_nCurrentEncoding; + break; + case RTF_CF: + { + RTFSprms aAttributes; + auto pValue = std::make_shared<RTFValue>(getColorTable(nParam)); + aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue); + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_color, std::make_shared<RTFValue>(aAttributes)); + } + break; + case RTF_S: + { + m_aStates.top().nCurrentStyleIndex = nParam; + + if (m_aStates.top().eDestination == Destination::STYLESHEET || m_aStates.top().eDestination == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_StyleType_paragraph); + m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type, pValue); // paragraph style + } + else + { + OUString aName = getStyleName(nParam); + if (!aName.isEmpty()) + { + if (m_aStates.top().eDestination == Destination::LISTLEVEL) + m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_pStyle, std::make_shared<RTFValue>(aName)); + else + m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_pStyle, std::make_shared<RTFValue>(aName)); + + } + } + } + break; + case RTF_CS: + m_aStates.top().nCurrentCharacterStyleIndex = nParam; + if (m_aStates.top().eDestination == Destination::STYLESHEET || m_aStates.top().eDestination == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + auto pValue = std::make_shared<RTFValue>(NS_ooxml::LN_Value_ST_StyleType_character); + m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type, pValue); // character style + } + else + { + OUString aName = getStyleName(nParam); + if (!aName.isEmpty()) + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_rStyle, std::make_shared<RTFValue>(aName)); + } + break; + case RTF_DS: + if (m_aStates.top().eDestination == Destination::STYLESHEET || m_aStates.top().eDestination == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + auto pValue = std::make_shared<RTFValue>(0); // TODO no value in enum StyleType? + m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type, pValue); // section style + } + break; + case RTF_TS: + if (m_aStates.top().eDestination == Destination::STYLESHEET || m_aStates.top().eDestination == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + // FIXME the correct value would be NS_ooxml::LN_Value_ST_StyleType_table but maybe table styles mess things up in dmapper, be cautious and disable them for now + auto pValue = std::make_shared<RTFValue>(0); + m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type, pValue); // table style + } + break; + case RTF_DEFF: + m_nDefaultFontIndex = nParam; + break; + case RTF_DEFLANG: + case RTF_ADEFLANG: + { + LanguageTag aTag((LanguageType)nParam); + auto pValue = std::make_shared<RTFValue>(aTag.getBcp47()); + putNestedAttribute(m_aStates.top().aCharacterSprms, (nKeyword == RTF_DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang : NS_ooxml::LN_CT_Language_bidi), nSprm, pValue); + } + break; + case RTF_CHCBPAT: + { + auto pValue = std::make_shared<RTFValue>(nParam ? getColorTable(nParam) : COL_AUTO); + putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_EG_RPrBase_shd, NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTF_CLCBPAT: + { + auto pValue = std::make_shared<RTFValue>(getColorTable(nParam)); + putNestedAttribute(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_shd, NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTF_CBPAT: + if (nParam) + { + auto pValue = std::make_shared<RTFValue>(getColorTable(nParam)); + putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PrBase_shd, NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTF_ULC: + { + auto pValue = std::make_shared<RTFValue>(getColorTable(nParam)); + m_aStates.top().aCharacterSprms.set(0x6877, pValue); + } + break; + case RTF_HIGHLIGHT: + { + auto pValue = std::make_shared<RTFValue>(nParam ? getColorTable(nParam) : COL_AUTO); + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_highlight, pValue); + } + break; + case RTF_UP: + case RTF_DN: + { + auto pValue = std::make_shared<RTFValue>(nParam * (nKeyword == RTF_UP ? 1 : -1)); + m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_position, pValue); + } + break; + case RTF_HORZVERT: + { + auto pValue = std::make_shared<RTFValue>(int(true)); + m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_EastAsianLayout_vert, pValue); + if (nParam) + // rotate fits to a single line ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits