diff options
Diffstat (limited to 'writerfilter/source/rtftok/rtfdocumentimpl.cxx')
-rw-r--r-- | writerfilter/source/rtftok/rtfdocumentimpl.cxx | 2547 |
1 files changed, 2547 insertions, 0 deletions
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx new file mode 100644 index 000000000000..930059d431d0 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -0,0 +1,2547 @@ +/* + * Version: MPL 1.1 / GPLv3+ / LGPLv3+ + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developer of the Original Code is + * Miklos Vajna <vmiklos@frugalware.org> + * Portions created by the Initial Developer are Copyright (C) 2011 the + * Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 3 or later (the "GPLv3+"), or + * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), + * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable + * instead of those above. + */ + +#include <rtfdocumentimpl.hxx> +#include <rtftypes.hxx> +#include <rtfcontrolwords.hxx> +#include <rtfvalue.hxx> +#include <rtfsprm.hxx> +#include <rtfreferenceproperties.hxx> +#include <doctok/sprmids.hxx> // NS_sprm namespace +#include <doctok/resourceids.hxx> // NS_rtf namespace +#include <ooxml/resourceids.hxx> // NS_ooxml namespace +#include <ooxml/OOXMLFastTokens.hxx> // ooxml namespace +#include <unotools/ucbstreamhelper.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/tencinfo.h> +#include <svl/lngmisc.hxx> +#include <editeng/borderline.hxx> +#include <unotools/streamwrap.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +using std::make_pair; +using rtl::OString; +using rtl::OStringBuffer; +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OUStringToOString; + +namespace writerfilter { +namespace rtftok { + +static RTFSprms_t& lcl_getNumPr(std::stack<RTFParserState>& aStates) +{ + // insert the numpr sprm if necessary + RTFValue::Pointer_t p = RTFSprm::find(aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_numPr); + if (!p.get()) + { + RTFSprms_t aAttributes; + RTFSprms_t aSprms; + RTFValue::Pointer_t pValue(new RTFValue(aAttributes, aSprms)); + aStates.top().aParagraphSprms.push_back(make_pair(NS_ooxml::LN_CT_PPrBase_numPr, pValue)); + p = RTFSprm::find(aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_numPr); + } + return p->getSprms(); +} + +static Id lcl_getParagraphBorder(sal_uInt32 nIndex) +{ + static const Id aBorderIds[] = + { + NS_sprm::LN_PBrcTop, NS_sprm::LN_PBrcLeft, NS_sprm::LN_PBrcBottom, NS_sprm::LN_PBrcRight + }; + + return aBorderIds[nIndex]; +} + +static void lcl_putNestedAttribute(RTFSprms_t& rSprms, Id nParent, Id nId, RTFValue::Pointer_t pValue, + bool bOverwrite = false, bool bAttribute = true) +{ + RTFValue::Pointer_t pParent = RTFSprm::find(rSprms, nParent); + if (!pParent.get()) + { + RTFSprms_t aAttributes; + RTFValue::Pointer_t pParentValue(new RTFValue(aAttributes)); + rSprms.push_back(make_pair(nParent, pParentValue)); + pParent = pParentValue; + } + RTFSprms_t& rAttributes = (bAttribute ? pParent->getAttributes() : pParent->getSprms()); + if (bOverwrite) + for (RTFSprms_t::iterator i = rAttributes.begin(); i != rAttributes.end(); ++i) + if (i->first == nId) + { + i->second = pValue; + return; + } + rAttributes.push_back(make_pair(nId, pValue)); +} + +static void lcl_putNestedSprm(RTFSprms_t& rSprms, Id nParent, Id nId, RTFValue::Pointer_t pValue, bool bOverwrite = false) +{ + lcl_putNestedAttribute(rSprms, nParent, nId, pValue, bOverwrite, false); +} + +static RTFSprms_t& lcl_getLastAttributes(RTFSprms_t& rSprms, Id nId) +{ + RTFValue::Pointer_t p = RTFSprm::find(rSprms, nId); + if (p->getSprms().size()) + return p->getSprms().back().second->getAttributes(); + else + { + OSL_FAIL("trying to set property when no type is defined"); + return p->getSprms(); + } +} + +static void lcl_putBorderProperty(std::stack<RTFParserState>& aStates, Id nId, RTFValue::Pointer_t pValue) +{ + if (aStates.top().nBorderState == BORDER_PARAGRAPH) + for (int i = 0; i < 4; i++) + { + RTFValue::Pointer_t p = RTFSprm::find(aStates.top().aParagraphSprms, lcl_getParagraphBorder(i)); + if (p.get()) + { + RTFSprms_t& rAttributes = p->getAttributes(); + rAttributes.push_back(make_pair(nId, pValue)); + } + } + else if (aStates.top().nBorderState == BORDER_CELL) + { + // Attributes of the last border type + RTFSprms_t& rAttributes = lcl_getLastAttributes(aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcBorders); + rAttributes.push_back(make_pair(nId, pValue)); + } + else if (aStates.top().nBorderState == BORDER_PAGE) + { + // Attributes of the last border type + RTFSprms_t& rAttributes = lcl_getLastAttributes(aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgBorders); + rAttributes.push_back(make_pair(nId, pValue)); + } +} + +static void lcl_Break(Stream& rMapper) +{ + sal_uInt8 sBreak[] = { 0xd }; + rMapper.text(sBreak, 1); +} + +static void lcl_TableBreak(Stream& rMapper) +{ + lcl_Break(rMapper); + rMapper.endParagraphGroup(); + rMapper.startParagraphGroup(); +} + +// NEEDSWORK: DocxAttributeOutput's impl_AppendTwoDigits does the same. +static void lcl_AppendTwoDigits(OStringBuffer &rBuffer, sal_Int32 nNum) +{ + if ( nNum < 0 || nNum > 99 ) + { + rBuffer.append( "00" ); + return; + } + + if ( nNum < 10 ) + rBuffer.append( '0' ); + + rBuffer.append( nNum ); +} + +// NEEDSWORK: sw::ms::DTTM2DateTime and DocxAttributeOutput's +// impl_DateTimeToOString could be combined to do the same. +static OString lcl_DTTM22OString(long lDTTM) +{ + sal_uInt16 lMin = (sal_uInt16)(lDTTM & 0x0000003F); + lDTTM >>= 6; + sal_uInt16 lHour= (sal_uInt16)(lDTTM & 0x0000001F); + lDTTM >>= 5; + sal_uInt16 lDay = (sal_uInt16)(lDTTM & 0x0000001F); + lDTTM >>= 5; + sal_uInt16 lMon = (sal_uInt16)(lDTTM & 0x0000000F); + lDTTM >>= 4; + sal_uInt16 lYear= (sal_uInt16)(lDTTM & 0x000001FF) + 1900; + + OStringBuffer aBuf; + aBuf.append(sal_Int32(lYear)); + aBuf.append('-'); + lcl_AppendTwoDigits(aBuf, lMon); + aBuf.append('-'); + lcl_AppendTwoDigits(aBuf, lDay); + aBuf.append('T'); + lcl_AppendTwoDigits(aBuf, lHour); + aBuf.append(':'); + lcl_AppendTwoDigits(aBuf, lMin); + aBuf.append(":00Z"); + return aBuf.makeStringAndClear(); +} + +static writerfilter::Reference<Properties>::Pointer_t lcl_getBookmarkProperties(int nPos, OUString& rString) +{ + RTFSprms_t aAttributes; + RTFValue::Pointer_t pPos(new RTFValue(nPos)); + if (rString.getLength()) + { + // If present, this should be sent first. + RTFValue::Pointer_t pString(new RTFValue(rString)); + aAttributes.push_back(make_pair(NS_rtf::LN_BOOKMARKNAME, pString)); + } + aAttributes.push_back(make_pair(NS_rtf::LN_IBKL, pPos)); + return writerfilter::Reference<Properties>::Pointer_t(new RTFReferenceProperties(aAttributes)); +} + +static writerfilter::Reference<Properties>::Pointer_t lcl_getBookmarkProperties(int nPos) +{ + OUString aStr; + return lcl_getBookmarkProperties(nPos, aStr); +} + +static int lcl_AsHex(char ch) +{ + int ret = 0; + if (isdigit(ch)) + ret = ch - '0'; + else + { + if (islower(ch)) + { + if (ch < 'a' || ch > 'f') + return -1; + ret = ch - 'a'; + } + else + { + if (ch < 'A' || ch > 'F') + return -1; + ret = ch - 'A'; + } + ret += 10; + } + return ret; +} + +static const char* lcl_RtfToString(RTFKeyword nKeyword) +{ + for (int i = 0; i < nRTFControlWords; i++) + { + if (nKeyword == aRTFControlWords[i].nIndex) + return aRTFControlWords[i].sKeyword; + } + return NULL; +} +RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& xContext, + uno::Reference<io::XInputStream> const& xInputStream, + uno::Reference<lang::XComponent> const& xDstDoc, + uno::Reference<frame::XFrame> const& xFrame) + : m_xContext(xContext), + m_xInputStream(xInputStream), + m_xDstDoc(xDstDoc), + m_xFrame(xFrame), + m_nGroup(0), + m_aDefaultState(), + m_bSkipUnknown(false), + m_aFontEncodings(), + m_aColorTable(), + m_bFirstRun(true), + m_bNeedPap(false), + m_aListTableSprms(), + m_aSettingsTableSprms(), + m_xStorage(), + m_aTableBuffer(), + m_bTable(false), + m_aSuperBuffer(), + m_bSuper(false), + m_bHasFootnote(false), + m_bIsSubstream(false), + m_nHeaderFooterPositions(), + m_nGroupStartPos(0), + m_aBookmarks(), + m_aAuthors() +{ + OSL_ENSURE(xInputStream.is(), "no input stream"); + if (!xInputStream.is()) + throw uno::RuntimeException(); + m_pInStream = utl::UcbStreamHelper::CreateStream( xInputStream, sal_True ); + + m_xModelFactory.set(m_xDstDoc, uno::UNO_QUERY); + OSL_ASSERT(m_xModelFactory.is()); + + m_pGraphicHelper = new oox::GraphicHelper(m_xContext, xFrame, m_xStorage); +} + +RTFDocumentImpl::~RTFDocumentImpl() +{ +} + +SvStream& RTFDocumentImpl::Strm() +{ + return *m_pInStream; +} + +Stream& RTFDocumentImpl::Mapper() +{ + return *m_pMapperStream; +} + +void RTFDocumentImpl::setSubstream(bool bIsSubtream) +{ + m_bIsSubstream = bIsSubtream; +} + +void RTFDocumentImpl::setIgnoreFirst(OUString& rIgnoreFirst) +{ + m_aIgnoreFirst = rIgnoreFirst; +} + +void RTFDocumentImpl::resolveSubstream(sal_uInt32 nPos, Id nId) +{ + OUString aStr; + resolveSubstream(nPos, nId, aStr); +} +void RTFDocumentImpl::resolveSubstream(sal_uInt32 nPos, Id nId, OUString& rIgnoreFirst) +{ + sal_uInt32 nCurrent = Strm().Tell(); + // Seek to header position, parse, then seek back. + RTFDocumentImpl::Pointer_t pImpl(new RTFDocumentImpl(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame)); + pImpl->setSubstream(true); + pImpl->setIgnoreFirst(rIgnoreFirst); + pImpl->seek(nPos); + OSL_TRACE("substream start"); + Mapper().substream(nId, pImpl); + OSL_TRACE("substream end"); + Strm().Seek(nCurrent); + nPos = 0; +} + +void RTFDocumentImpl::parBreak() +{ + // end previous paragraph + Mapper().startCharacterGroup(); + lcl_Break(Mapper()); + Mapper().endCharacterGroup(); + Mapper().endParagraphGroup(); + + // start new one + Mapper().startParagraphGroup(); +} + +void RTFDocumentImpl::sectBreak(bool bFinal = false) +{ + while (m_nHeaderFooterPositions.size()) + { + std::pair<Id, sal_uInt32> aPair = m_nHeaderFooterPositions.front(); + m_nHeaderFooterPositions.pop_front(); + resolveSubstream(aPair.second, aPair.first); + } + + RTFValue::Pointer_t pBreak = RTFSprm::find(m_aStates.top().aSectionSprms, NS_sprm::LN_SBkc); + // In case the last section is a continous one, we don't need to output a section break. + if (bFinal && pBreak.get() && !pBreak->getInt()) + RTFSprm::erase(m_aStates.top().aSectionSprms, NS_sprm::LN_SBkc); + + // Section properties are a paragraph sprm. + RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aSectionAttributes, m_aStates.top().aSectionSprms)); + RTFSprms_t aAttributes; + RTFSprms_t aSprms; + aSprms.push_back(make_pair(NS_ooxml::LN_CT_PPr_sectPr, pValue)); + writerfilter::Reference<Properties>::Pointer_t const pProperties( + new RTFReferenceProperties(aAttributes, aSprms) + ); + // 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(); + if (!m_bIsSubstream) + Mapper().endSectionGroup(); + if (!bFinal) + { + Mapper().startSectionGroup(); + Mapper().startParagraphGroup(); + } +} + +void RTFDocumentImpl::seek(sal_uInt32 nPos) +{ + Strm().Seek(nPos); +} + +sal_uInt32 RTFDocumentImpl::getColorTable(sal_uInt32 nIndex) +{ + if (nIndex < m_aColorTable.size()) + return m_aColorTable[nIndex]; + return 0; +} + +sal_uInt32 RTFDocumentImpl::getEncodingTable(sal_uInt32 nFontIndex) +{ + if (nFontIndex < m_aFontEncodings.size()) + return m_aFontEncodings[nFontIndex]; + return 0; +} + +void RTFDocumentImpl::resolve(Stream & rMapper) +{ + m_pMapperStream = &rMapper; + switch (resolveParse()) + { + case ERROR_OK: + OSL_TRACE("%s: finished without errors", OSL_THIS_FUNC); + break; + case ERROR_GROUP_UNDER: + OSL_TRACE("%s: unmatched '}'", OSL_THIS_FUNC); + break; + case ERROR_GROUP_OVER: + OSL_TRACE("%s: unmatched '{'", OSL_THIS_FUNC); + break; + case ERROR_EOF: + OSL_TRACE("%s: unexpected end of file", OSL_THIS_FUNC); + break; + case ERROR_HEX_INVALID: + OSL_TRACE("%s: invalid hex char", OSL_THIS_FUNC); + break; + } +} + +int RTFDocumentImpl::resolvePict(char ch, bool bInline) +{ + SvMemoryStream aStream; + int b = 0, count = 2; + + // TODO this discards properties after the 'pib' property + if (!bInline) + resolveShapeProperties(m_aStates.top().aShapeProperties); + + // Read the group. + while(!Strm().IsEof() && ch != '{' && ch != '}' && ch != '\\') + { + if (ch != 0x0d && ch != 0x0a) + { + b = b << 4; + char parsed = lcl_AsHex(ch); + if (parsed == -1) + return ERROR_HEX_INVALID; + b += parsed; + count--; + if (!count) + { + aStream << (char)b; + count = 2; + b = 0; + } + } + Strm() >> ch; + } + Strm().SeekRel(-1); + + // Store, and get its URL. + aStream.Seek(0); + uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(&aStream)); + OUString aGraphicUrl = m_pGraphicHelper->importGraphicObject(xInputStream); + + // Wrap it in an XShape. + uno::Reference<drawing::XShape> xShape; + OUString aService(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.GraphicObjectShape")); + xShape.set(m_xModelFactory->createInstance(aService), uno::UNO_QUERY); + OSL_ASSERT(xShape.is()); + uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY); + OSL_ASSERT(xPropertySet.is()); + xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("GraphicURL")), uno::Any(aGraphicUrl)); + + // Send it to the dmapper. + RTFSprms_t aSprms; + RTFSprms_t aAttributes; + // shape attribute + RTFSprms_t aPicAttributes; + RTFValue::Pointer_t pShapeValue(new RTFValue(xShape)); + aPicAttributes.push_back(make_pair(NS_ooxml::LN_shape, pShapeValue)); + // pic sprm + RTFSprms_t aGraphicDataAttributes; + RTFSprms_t aGraphicDataSprms; + RTFValue::Pointer_t pPicValue(new RTFValue(aPicAttributes)); + aGraphicDataSprms.push_back(make_pair(NS_ooxml::LN_pic_pic, pPicValue)); + // graphicData sprm + RTFSprms_t aGraphicAttributes; + RTFSprms_t aGraphicSprms; + RTFValue::Pointer_t pGraphicDataValue(new RTFValue(aGraphicDataAttributes, aGraphicDataSprms)); + aGraphicSprms.push_back(make_pair(NS_ooxml::LN_CT_GraphicalObject_graphicData, pGraphicDataValue)); + // graphic sprm + RTFValue::Pointer_t pGraphicValue(new RTFValue(aGraphicAttributes, aGraphicSprms)); + // extent sprm + RTFSprms_t aExtentAttributes; + for (RTFSprms_t::iterator i = m_aStates.top().aCharacterAttributes.begin(); i != m_aStates.top().aCharacterAttributes.end(); ++i) + if (i->first == NS_rtf::LN_XEXT || i->first == NS_rtf::LN_YEXT) + aExtentAttributes.push_back(make_pair(i->first, i->second)); + RTFValue::Pointer_t pExtentValue(new RTFValue(aExtentAttributes)); + // docpr sprm + RTFSprms_t aDocprAttributes; + for (RTFSprms_t::iterator i = m_aStates.top().aCharacterAttributes.begin(); i != m_aStates.top().aCharacterAttributes.end(); ++i) + if (i->first == NS_ooxml::LN_CT_NonVisualDrawingProps_name || i->first == NS_ooxml::LN_CT_NonVisualDrawingProps_descr) + aDocprAttributes.push_back(make_pair(i->first, i->second)); + RTFValue::Pointer_t pDocprValue(new RTFValue(aDocprAttributes)); + if (bInline) + { + RTFSprms_t aInlineAttributes; + RTFSprms_t aInlineSprms; + aInlineSprms.push_back(make_pair(NS_ooxml::LN_CT_Inline_extent, pExtentValue)); + aInlineSprms.push_back(make_pair(NS_ooxml::LN_CT_Inline_docPr, pDocprValue)); + aInlineSprms.push_back(make_pair(NS_ooxml::LN_graphic_graphic, pGraphicValue)); + // inline sprm + RTFValue::Pointer_t pValue(new RTFValue(aInlineAttributes, aInlineSprms)); + aSprms.push_back(make_pair(NS_ooxml::LN_inline_inline, pValue)); + } + else // anchored + { + // wrap sprm + RTFSprms_t aAnchorWrapAttributes; + for (RTFSprms_t::iterator i = m_aStates.top().aCharacterAttributes.begin(); i != m_aStates.top().aCharacterAttributes.end(); ++i) + if (i->first == NS_ooxml::LN_CT_WrapSquare_wrapText) + aAnchorWrapAttributes.push_back(make_pair(i->first, i->second)); + RTFValue::Pointer_t pAnchorWrapValue(new RTFValue(aAnchorWrapAttributes)); + RTFSprms_t aAnchorAttributes; + RTFSprms_t aAnchorSprms; + aAnchorSprms.push_back(make_pair(NS_ooxml::LN_CT_Anchor_extent, pExtentValue)); + if (aAnchorWrapAttributes.size()) + aAnchorSprms.push_back(make_pair(NS_ooxml::LN_EG_WrapType_wrapSquare, pAnchorWrapValue)); + aAnchorSprms.push_back(make_pair(NS_ooxml::LN_CT_Anchor_docPr, pDocprValue)); + aAnchorSprms.push_back(make_pair(NS_ooxml::LN_graphic_graphic, pGraphicValue)); + // anchor sprm + RTFValue::Pointer_t pValue(new RTFValue(aAnchorAttributes, aAnchorSprms)); + aSprms.push_back(make_pair(NS_ooxml::LN_anchor_anchor, pValue)); + } + writerfilter::Reference<Properties>::Pointer_t const pProperties(new RTFReferenceProperties(aAttributes, aSprms)); + Mapper().props(pProperties); + + return 0; +} + +int RTFDocumentImpl::resolveChars(char ch) +{ + OStringBuffer aBuf; + + if (m_aStates.top().nDestinationState == DESTINATION_PICT) + return resolvePict(ch, true); + else if (m_aStates.top().nDestinationState == DESTINATION_SHAPEPROPERTYVALUEPICT) + return resolvePict(ch, false); + while(!Strm().IsEof() && ch != '{' && ch != '}' && ch != '\\') + { + if (ch != 0x0d && ch != 0x0a) + { + if (m_aStates.top().nCharsToSkip == 0) + aBuf.append(ch); + else + m_aStates.top().nCharsToSkip--; + } + // read a single char if we're in hex mode + if (m_aStates.top().nInternalState == INTERNAL_HEX) + break; + Strm() >> ch; + } + if (m_aStates.top().nInternalState != INTERNAL_HEX && !Strm().IsEof()) + Strm().SeekRel(-1); + if (m_aStates.top().nDestinationState == DESTINATION_SKIP) + return 0; + OString aStr = aBuf.makeStringAndClear(); + if (m_aStates.top().nDestinationState == DESTINATION_LEVELNUMBERS) + { + if (aStr.toChar() != ';') + m_aStates.top().aLevelNumbers.push_back(sal_Int32(ch)); + return 0; + } + OSL_TRACE("%s: collected '%s'", OSL_THIS_FUNC, aStr.getStr()); + + OUString aOUStr(OStringToOUString(aStr, m_aStates.top().nCurrentEncoding)); + + if (m_aStates.top().nDestinationState == DESTINATION_COLORTABLE) + { + // we hit a ';' at the end of each color entry + sal_uInt32 color = (m_aStates.top().aCurrentColor.nRed << 16) | ( m_aStates.top().aCurrentColor.nGreen << 8) + | m_aStates.top().aCurrentColor.nBlue; + m_aColorTable.push_back(color); + // set components back to zero + m_aStates.top().aCurrentColor = RTFColorTableEntry(); + } + else + text(aOUStr); + + return 0; +} + +void RTFDocumentImpl::text(OUString& rString) +{ + bool bRet = true; + switch (m_aStates.top().nDestinationState) + { + case DESTINATION_FONTENTRY: + case DESTINATION_STYLEENTRY: + case DESTINATION_REVISIONENTRY: + // drop the ; at the end if it's there + if (rString.endsWithAsciiL(";", 1)) + rString = rString.copy(0, rString.getLength() - 1); + case DESTINATION_LEVELTEXT: + case DESTINATION_SHAPEPROPERTYNAME: + case DESTINATION_SHAPEPROPERTYVALUE: + case DESTINATION_BOOKMARKEND: + m_aDestinationText.append(rString); + break; + default: bRet = false; break; + } + if (bRet) + return; + + if (m_aIgnoreFirst.getLength() && m_aIgnoreFirst.equals(rString)) + { + m_aIgnoreFirst = OUString(); + return; + } + + writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties( + new RTFReferenceProperties(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms) + ); + + if (m_bFirstRun) + { + // output settings table + RTFSprms_t aAttributes; + writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(aAttributes, m_aSettingsTableSprms)); + RTFReferenceTable::Entries_t aSettingsTableEntries; + aSettingsTableEntries.insert(make_pair(0, pProp)); + writerfilter::Reference<Table>::Pointer_t const pTable(new RTFReferenceTable(aSettingsTableEntries)); + Mapper().table(NS_ooxml::LN_settings_settings, pTable); + // start initial paragraph + if (!m_bIsSubstream) + Mapper().startSectionGroup(); + Mapper().startParagraphGroup(); + Mapper().props(pParagraphProperties); + m_bFirstRun = false; + } + if (m_bNeedPap) + { + if (!m_bTable && !m_bSuper) + Mapper().props(pParagraphProperties); + else + { + RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms)); + if (m_bTable) + m_aTableBuffer.push_back(make_pair(BUFFER_PROPS, pValue)); + else + m_aSuperBuffer.push_back(make_pair(BUFFER_PROPS, pValue)); + } + m_bNeedPap = false; + } + + // Don't return earlier, a bookmark start has to be in a paragraph group. + if (m_aStates.top().nDestinationState == DESTINATION_BOOKMARKSTART) + { + m_aDestinationText.append(rString); + return; + } + + if (!m_bTable && !m_bSuper && m_aStates.top().nDestinationState != DESTINATION_FOOTNOTE) + Mapper().startCharacterGroup(); + else + { + RTFValue::Pointer_t pValue; + if (m_bTable) + m_aTableBuffer.push_back(make_pair(BUFFER_STARTRUN, pValue)); + else + m_aSuperBuffer.push_back(make_pair(BUFFER_STARTRUN, pValue)); + } + if (m_aStates.top().nDestinationState == DESTINATION_NORMAL || m_aStates.top().nDestinationState == DESTINATION_FIELDRESULT) + { + if (!m_bTable && !m_bSuper) + { + writerfilter::Reference<Properties>::Pointer_t const pProperties( + new RTFReferenceProperties(m_aStates.top().aCharacterAttributes, m_aStates.top().aCharacterSprms) + ); + Mapper().props(pProperties); + } + else + { + RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aCharacterAttributes, m_aStates.top().aCharacterSprms)); + if (m_bTable) + m_aTableBuffer.push_back(make_pair(BUFFER_PROPS, pValue)); + else + m_aSuperBuffer.push_back(make_pair(BUFFER_PROPS, pValue)); + } + } + if (!m_bTable && !m_bSuper) + Mapper().utext(reinterpret_cast<sal_uInt8 const*>(rString.getStr()), rString.getLength()); + else + { + RTFValue::Pointer_t pValue(new RTFValue(rString)); + if (m_bTable) + m_aTableBuffer.push_back(make_pair(BUFFER_UTEXT, pValue)); + else + m_aSuperBuffer.push_back(make_pair(BUFFER_UTEXT, pValue)); + } + if (!m_bTable && !m_bSuper && m_aStates.top().nDestinationState != DESTINATION_FOOTNOTE) + Mapper().endCharacterGroup(); + else + { + RTFValue::Pointer_t pValue; + if (m_bTable) + m_aTableBuffer.push_back(make_pair(BUFFER_ENDRUN, pValue)); + else + m_aSuperBuffer.push_back(make_pair(BUFFER_ENDRUN, pValue)); + } +} + +void RTFDocumentImpl::replayBuffer(std::deque< std::pair<RTFBufferTypes, RTFValue::Pointer_t> >& rBuffer) +{ + while (rBuffer.size()) + { + std::pair<RTFBufferTypes, RTFValue::Pointer_t> aPair = rBuffer.front(); + rBuffer.pop_front(); + if (aPair.first == BUFFER_PROPS) + { + writerfilter::Reference<Properties>::Pointer_t const pProp( + new RTFReferenceProperties(aPair.second->getAttributes(), aPair.second->getSprms()) + ); + Mapper().props(pProp); + } + else if (aPair.first == BUFFER_CELLEND) + { + RTFValue::Pointer_t pValue(new RTFValue(1)); + m_aStates.top().aTableCellSprms.push_back(make_pair(NS_sprm::LN_PCell, pValue)); + writerfilter::Reference<Properties>::Pointer_t const pTableCellProperties( + new RTFReferenceProperties(m_aStates.top().aTableCellAttributes, m_aStates.top().aTableCellSprms) + ); + Mapper().props(pTableCellProperties); + lcl_TableBreak(Mapper()); + break; + } + else if (aPair.first == BUFFER_STARTRUN) + Mapper().startCharacterGroup(); + else if (aPair.first == BUFFER_UTEXT) + { + OUString aString(aPair.second->getString()); + Mapper().utext(reinterpret_cast<sal_uInt8 const*>(aString.getStr()), aString.getLength()); + } + else if (aPair.first == BUFFER_ENDRUN) + Mapper().endCharacterGroup(); + else if (aPair.first == BUFFER_PAR) + parBreak(); + else + OSL_FAIL("should not happen"); + } + +} + +int RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword) +{ + bool bParsed = true; + switch (nKeyword) + { + case RTF_RTF: + break; + case RTF_FONTTBL: + m_aStates.top().nDestinationState = DESTINATION_FONTTABLE; + break; + case RTF_COLORTBL: + m_aStates.top().nDestinationState = DESTINATION_COLORTABLE; + break; + case RTF_STYLESHEET: + m_aStates.top().nDestinationState = DESTINATION_STYLESHEET; + break; + case RTF_FIELD: + // A field consists of an fldinst and an fldrslt group. + break; + case RTF_FLDINST: + { + sal_uInt8 sFieldStart[] = { 0x13 }; + Mapper().startCharacterGroup(); + Mapper().text(sFieldStart, 1); + Mapper().endCharacterGroup(); + m_aStates.top().nDestinationState = DESTINATION_FIELDINSTRUCTION; + } + break; + case RTF_FLDRSLT: + m_aStates.top().nDestinationState = DESTINATION_FIELDRESULT; + break; + case RTF_LISTTABLE: + m_aStates.top().nDestinationState = DESTINATION_LISTTABLE; + break; + case RTF_LIST: + m_aStates.top().nDestinationState = DESTINATION_LISTENTRY; + break; + case RTF_LISTOVERRIDETABLE: + m_aStates.top().nDestinationState = DESTINATION_LISTOVERRIDETABLE; + break; + case RTF_LISTOVERRIDE: + m_aStates.top().nDestinationState = DESTINATION_LISTOVERRIDEENTRY; + break; + case RTF_LISTLEVEL: + m_aStates.top().nDestinationState = DESTINATION_LISTLEVEL; + break; + case RTF_LEVELTEXT: + m_aStates.top().nDestinationState = DESTINATION_LEVELTEXT; + break; + case RTF_LEVELNUMBERS: + m_aStates.top().nDestinationState = DESTINATION_LEVELNUMBERS; + break; + case RTF_SHPPICT: + m_aStates.top().nDestinationState = DESTINATION_SHPPICT; + break; + case RTF_PICT: + if (m_aStates.top().nDestinationState != DESTINATION_SHAPEPROPERTYVALUE) + m_aStates.top().nDestinationState = DESTINATION_PICT; // as character + else + m_aStates.top().nDestinationState = DESTINATION_SHAPEPROPERTYVALUEPICT; // anchored inside a shape + break; + case RTF_PICPROP: + m_aStates.top().nDestinationState = DESTINATION_PICPROP; + break; + case RTF_SP: + m_aStates.top().nDestinationState = DESTINATION_SHAPEPROPERTY; + break; + case RTF_SN: + m_aStates.top().nDestinationState = DESTINATION_SHAPEPROPERTYNAME; + break; + case RTF_SV: + m_aStates.top().nDestinationState = DESTINATION_SHAPEPROPERTYVALUE; + break; + case RTF_SHP: + m_aStates.top().nDestinationState = DESTINATION_SHAPE; + break; + case RTF_SHPINST: + m_aStates.top().nDestinationState = DESTINATION_SHAPEINSTRUCTION; + break; + case RTF_NESTTABLEPROPS: + m_aStates.top().nDestinationState = 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_bIsSubstream) + { + Id nId = 0; + sal_uInt32 nPos = m_nGroupStartPos - 1; + switch (nKeyword) + { + case RTF_HEADER: nId = NS_rtf::LN_headerr; break; + case RTF_FOOTER: nId = NS_rtf::LN_footerr; break; + case RTF_HEADERL: nId = NS_rtf::LN_headerl; break; + case RTF_HEADERR: nId = NS_rtf::LN_headerr; break; + case RTF_HEADERF: nId = NS_rtf::LN_headerr; break; // TODO figure out how to use NS_rtf::LN_headerf + case RTF_FOOTERL: nId = NS_rtf::LN_footerl; break; + case RTF_FOOTERR: nId = NS_rtf::LN_footerr; break; + case RTF_FOOTERF: nId = NS_rtf::LN_footerr; break; // same here, NS_rtf::LN_footerf could be used + default: break; + } + m_nHeaderFooterPositions.push_back(make_pair(nId, nPos)); + m_aStates.top().nDestinationState = DESTINATION_SKIP; + } + break; + case RTF_FOOTNOTE: + if (!m_bIsSubstream) + { + Id nId = NS_rtf::LN_footnote; + + // Check if this is an endnote. + OStringBuffer aBuf; + char ch; + for (int i = 0; i < 7; ++i) + { + Strm() >> ch; + aBuf.append(ch); + } + OString aKeyword = aBuf.makeStringAndClear(); + if (aKeyword.equals("\\ftnalt")) + nId = NS_rtf::LN_endnote; + + m_bHasFootnote = true; + m_bSuper = false; + bool bCustomMark = false; + OUString aCustomMark; + while (m_aSuperBuffer.size()) + { + std::pair<RTFBufferTypes, RTFValue::Pointer_t> aPair = m_aSuperBuffer.front(); + m_aSuperBuffer.pop_front(); + if (aPair.first == BUFFER_UTEXT) + { + aCustomMark = aPair.second->getString(); + bCustomMark = true; + } + } + m_aStates.top().nDestinationState = DESTINATION_FOOTNOTE; + if (bCustomMark) + Mapper().startCharacterGroup(); + resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark); + if (bCustomMark) + { + m_aStates.top().aCharacterAttributes.clear(); + m_aStates.top().aCharacterSprms.clear(); + RTFValue::Pointer_t pValue(new RTFValue(1)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue)); + text(aCustomMark); + Mapper().endCharacterGroup(); + } + m_aStates.top().nDestinationState = DESTINATION_SKIP; + } + break; + case RTF_BKMKSTART: + m_aStates.top().nDestinationState = DESTINATION_BOOKMARKSTART; + break; + case RTF_BKMKEND: + m_aStates.top().nDestinationState = DESTINATION_BOOKMARKEND; + break; + case RTF_REVTBL: + m_aStates.top().nDestinationState = DESTINATION_REVISIONTABLE; + 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().nDestinationState = DESTINATION_SKIP; + break; + default: + OSL_TRACE("%s: TODO handle destination '%s'", OSL_THIS_FUNC, lcl_RtfToString(nKeyword)); + // Make sure we skip destinations (even without \*) till we don't handle them + m_aStates.top().nDestinationState = DESTINATION_SKIP; + bParsed = false; + break; + } + + skipDestination(bParsed); + return 0; +} + +int RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword) +{ + bool bParsed = true; + sal_uInt8 cCh = 0; + + // Trivial symbols + switch (nKeyword) + { + case RTF_LINE: cCh = '\n'; break; + 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); + skipDestination(bParsed); + return 0; + } + + switch (nKeyword) + { + case RTF_IGNORE: + m_bSkipUnknown = true; + return 0; // don't reset m_bSkipUnknown after this keyword + break; + case RTF_PAR: + { + if (!m_bTable) + parBreak(); + else + { + RTFValue::Pointer_t pValue; + m_aTableBuffer.push_back(make_pair(BUFFER_PAR, pValue)); + } + // but don't emit properties yet, since they may change till the first text token arrives + m_bNeedPap = true; + } + break; + case RTF_SECT: + sectBreak(); + 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 = INTERNAL_HEX; + break; + case RTF_CELL: + case RTF_NESTCELL: + { + if (m_bNeedPap) + { + // There were no runs in the cell, so we need to send paragraph properties here. + RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms)); + m_aTableBuffer.push_back(make_pair(BUFFER_PROPS, pValue)); + } + + RTFValue::Pointer_t pValue; + m_aTableBuffer.push_back(make_pair(BUFFER_CELLEND, pValue)); + m_bNeedPap = true; + } + break; + case RTF_ROW: + case RTF_NESTROW: + { + writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties( + new RTFReferenceProperties(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms) + ); + Mapper().props(pParagraphProperties); + + // Table width. + RTFValue::Pointer_t pUnitValue(new RTFValue(3)); + lcl_putNestedAttribute(m_aStates.top().aTableRowSprms, + NS_ooxml::LN_CT_TblPrBase_tblW, NS_ooxml::LN_CT_TblWidth_type, pUnitValue); + RTFValue::Pointer_t pWidthValue(new RTFValue(m_aStates.top().nCellX)); + lcl_putNestedAttribute(m_aStates.top().aTableRowSprms, + NS_ooxml::LN_CT_TblPrBase_tblW, NS_ooxml::LN_CT_TblWidth_w, pWidthValue); + + RTFValue::Pointer_t pRowValue(new RTFValue(1)); + m_aStates.top().aTableRowSprms.push_back(make_pair(NS_sprm::LN_PRow, pRowValue)); + writerfilter::Reference<Properties>::Pointer_t const pTableRowProperties( + new RTFReferenceProperties(m_aStates.top().aTableRowAttributes, m_aStates.top().aTableRowSprms) + ); + Mapper().props(pTableRowProperties); + + lcl_TableBreak(Mapper()); + m_bNeedPap = true; + m_aTableBuffer.clear(); + } + break; + case RTF_COLUMN: + { + sal_uInt8 sBreak[] = { 0xe }; + Mapper().startCharacterGroup(); + Mapper().text(sBreak, 1); + Mapper().endCharacterGroup(); + } + break; + case RTF_CHFTN: + // Nothing to do, dmapper assumes this is the default. + break; + default: + OSL_TRACE("%s: TODO handle symbol '%s'", OSL_THIS_FUNC, lcl_RtfToString(nKeyword)); + bParsed = false; + break; + } + skipDestination(bParsed); + return 0; +} + +int RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword) +{ + bool bParsed = true; + int nParam = -1; + + // Indentation + switch (nKeyword) + { + case RTF_QC: nParam = 1; break; + case RTF_QJ: nParam = 3; break; + case RTF_QL: nParam = 0; break; + case RTF_QR: nParam = 2; break; + case RTF_QD: nParam = 4; break; + default: break; + } + if (nParam >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PJc, pValue)); + skipDestination(bParsed); + return 0; + } + + // Tab kind. + switch (nKeyword) + { + case RTF_TQR: nParam = 2; break; + case RTF_TQC: nParam = 1; break; + case RTF_TQDEC: nParam = 3; break; + default: break; + } + if (nParam >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + m_aStates.top().aTabAttributes.push_back(make_pair(NS_ooxml::LN_CT_TabStop_val, pValue)); + skipDestination(bParsed); + return 0; + } + + // Tab lead. + switch (nKeyword) + { + case RTF_TLDOT: nParam = 1; break; + case RTF_TLMDOT: nParam = NS_ooxml::LN_Value_ST_TabTlc_middleDot; break; + case RTF_TLHYPH: nParam = 2; break; + case RTF_TLUL: nParam = 3; break; + case RTF_TLTH: nParam = 2; break; // thick line is not supported by dmapper, this is just a hack + case RTF_TLEQ: nParam = 0; break; // equal sign isn't, either + default: break; + } + if (nParam >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + m_aStates.top().aTabAttributes.push_back(make_pair(NS_ooxml::LN_CT_TabStop_leader, pValue)); + skipDestination(bParsed); + return 0; + } + + // Border types + switch (nKeyword) + { + // brdrhair and brdrs are the same, brdrw will make a difference + case RTF_BRDRHAIR: nParam = editeng::SOLID; break; + case RTF_BRDRS: nParam = editeng::SOLID; break; + case RTF_BRDRDOT: nParam = editeng::DOTTED; break; + case RTF_BRDRDASH: nParam = editeng::DASHED; break; + case RTF_BRDRDB: nParam = editeng::DOUBLE; break; + case RTF_BRDRTNTHSG: nParam = editeng::THINTHICK_SMALLGAP; break; + case RTF_BRDRTNTHMG: nParam = editeng::THINTHICK_MEDIUMGAP; break; + case RTF_BRDRTNTHLG: nParam = editeng::THINTHICK_LARGEGAP; break; + case RTF_BRDRTHTNSG: nParam = editeng::THICKTHIN_SMALLGAP; break; + case RTF_BRDRTHTNMG: nParam = editeng::THICKTHIN_MEDIUMGAP; break; + case RTF_BRDRTHTNLG: nParam = editeng::THICKTHIN_LARGEGAP; break; + case RTF_BRDREMBOSS: nParam = editeng::EMBOSSED; break; + case RTF_BRDRENGRAVE: nParam = editeng::ENGRAVED; break; + case RTF_BRDROUTSET: nParam = editeng::OUTSET; break; + case RTF_BRDRINSET: nParam = editeng::INSET; break; + case RTF_BRDRNONE: nParam = editeng::NO_STYLE; break; + default: break; + } + if (nParam >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + lcl_putBorderProperty(m_aStates, NS_rtf::LN_BRCTYPE, pValue); + skipDestination(bParsed); + return 0; + } + + // Section breaks + switch (nKeyword) + { + case RTF_SBKNONE: nParam = 0; break; + case RTF_SBKCOL: nParam = 1; break; + case RTF_SBKPAGE: nParam = 2; break; + case RTF_SBKEVEN: nParam = 3; break; + case RTF_SBKODD: nParam = 4; break; + default: break; + } + if (nParam >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + m_aStates.top().aSectionSprms.push_back(make_pair(NS_sprm::LN_SBkc, pValue)); + skipDestination(bParsed); + return 0; + } + + // Trivial paragraph flags + switch (nKeyword) + { + case RTF_KEEP: nParam = NS_sprm::LN_PFKeep; break; + case RTF_KEEPN: nParam = NS_sprm::LN_PFKeepFollow; break; + case RTF_WIDCTLPAR: nParam = NS_sprm::LN_PFWidowControl; break; + case RTF_INTBL: m_bTable = true; nParam = NS_sprm::LN_PFInTable; break; + case RTF_PAGEBB: nParam = NS_sprm::LN_PFPageBreakBefore; break; + default: break; + } + if (nParam >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue(1)); + m_aStates.top().aParagraphSprms.push_back(make_pair(nParam, pValue)); + skipDestination(bParsed); + return 0; + } + + 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_PLAIN: + m_aStates.top().aCharacterSprms = m_aDefaultState.aCharacterSprms; + m_aStates.top().aCharacterAttributes = m_aDefaultState.aCharacterAttributes; + break; + case RTF_PARD: + m_aStates.top().aParagraphSprms = m_aDefaultState.aParagraphSprms; + m_aStates.top().aParagraphAttributes = m_aDefaultState.aParagraphAttributes; + m_bTable = false; + break; + case RTF_SECTD: + m_aStates.top().aSectionSprms = m_aDefaultState.aSectionSprms; + m_aStates.top().aSectionAttributes = m_aDefaultState.aSectionAttributes; + break; + case RTF_TROWD: + m_aStates.top().aTableRowSprms = m_aDefaultState.aTableRowSprms; + m_aStates.top().aTableRowAttributes = m_aDefaultState.aTableRowAttributes; + m_aStates.top().nCellX = 0; + m_aStates.top().aTableCellsSprms = m_aDefaultState.aTableCellsSprms; + m_aStates.top().aTableCellsAttributes = m_aDefaultState.aTableCellsAttributes; + break; + case RTF_NOWIDCTLPAR: + { + RTFValue::Pointer_t pValue(new RTFValue(0)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PFWidowControl, pValue)); + } + break; + case RTF_BOX: + { + RTFSprms_t aAttributes; + RTFValue::Pointer_t pValue(new RTFValue(aAttributes)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PBrcTop, pValue)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PBrcLeft, pValue)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PBrcBottom, pValue)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PBrcRight, pValue)); + m_aStates.top().nBorderState = BORDER_PARAGRAPH; + } + break; + case RTF_LTRSECT: + case RTF_RTLSECT: + { + RTFValue::Pointer_t pValue(new RTFValue(nKeyword == RTF_LTRSECT ? 0 : 1)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_STextFlow, pValue)); + } + break; + case RTF_LTRPAR: + case RTF_RTLPAR: + { + RTFValue::Pointer_t pValue(new RTFValue(nKeyword == RTF_LTRPAR ? 0 : 1)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PFrameTextFlow, pValue)); + } + break; + case RTF_LTRROW: + case RTF_RTLROW: + { + RTFValue::Pointer_t pValue(new RTFValue(nKeyword == RTF_LTRROW ? 0 : 1)); + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_TTextFlow, pValue)); + } + break; + case RTF_LTRCH: + case RTF_RTLCH: + // dmapper does not support these. + break; + case RTF_ULNONE: + { + RTFValue::Pointer_t pValue(new RTFValue(0)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_sprm::LN_CKul, pValue)); + } + break; + case RTF_NONSHPPICT: + m_aStates.top().nDestinationState = DESTINATION_SKIP; + break; + case RTF_CLBRDRT: + case RTF_CLBRDRL: + case RTF_CLBRDRB: + case RTF_CLBRDRR: + { + RTFSprms_t aAttributes; + RTFSprms_t aSprms; + RTFValue::Pointer_t pValue(new 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; + } + lcl_putNestedSprm(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcBorders, nParam, pValue); + m_aStates.top().nBorderState = BORDER_CELL; + } + break; + case RTF_PGBRDRT: + case RTF_PGBRDRL: + case RTF_PGBRDRB: + case RTF_PGBRDRR: + { + RTFSprms_t aAttributes; + RTFSprms_t aSprms; + RTFValue::Pointer_t pValue(new 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; + } + lcl_putNestedSprm(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgBorders, nParam, pValue); + m_aStates.top().nBorderState = BORDER_PAGE; + } + break; + case RTF_CLVMGF: + { + RTFValue::Pointer_t pValue(new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart)); + m_aStates.top().aTableCellSprms.push_back(make_pair(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue)); + } + break; + case RTF_CLVMRG: + { + RTFValue::Pointer_t pValue(new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue)); + m_aStates.top().aTableCellSprms.push_back(make_pair(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue)); + } + break; + case RTF_CLVERTALT: + case RTF_CLVERTALC: + case RTF_CLVERTALB: + { + switch (nKeyword) + { + case RTF_CLVERTALT: nParam = 0; break; + case RTF_CLVERTALC: nParam = 1; break; + case RTF_CLVERTALB: nParam = 3; break; + default: break; + } + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + m_aStates.top().aTableCellSprms.push_back(make_pair(NS_ooxml::LN_CT_TcPrBase_vAlign, pValue)); + } + break; + case RTF_TRKEEP: + { + RTFValue::Pointer_t pValue(new RTFValue(1)); + m_aStates.top().aTableRowSprms.push_back(make_pair(NS_sprm::LN_TCantSplit, pValue)); + } + case RTF_SECTUNLOCKED: + { + RTFValue::Pointer_t pValue(new RTFValue(!nParam)); + m_aStates.top().aSectionSprms.push_back(make_pair(NS_ooxml::LN_EG_SectPrContents_formProt, pValue)); + } + case RTF_PGNDEC: + case RTF_PGNUCRM: + case RTF_PGNLCRM: + case RTF_PGNUCLTR: + case RTF_PGNLCLTR: + case RTF_PGNBIDIA: + case RTF_PGNBIDIB: + break; + // 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: + // Noop, dmapper detects this automatically. + break; + case RTF_HICH: + m_aStates.top().bIsCjk = true; + break; + case RTF_DBCH: + m_aStates.top().bIsCjk = false; + break; + case RTF_TITLEPG: + { + RTFValue::Pointer_t pValue(new RTFValue(1)); + m_aStates.top().aSectionSprms.push_back(make_pair(NS_ooxml::LN_EG_SectPrContents_titlePg, pValue)); + } + break; + case RTF_SUPER: + { + m_bSuper = true; + OUString aValue(RTL_CONSTASCII_USTRINGPARAM("superscript")); + RTFValue::Pointer_t pValue(new RTFValue(aValue)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue)); + } + break; + case RTF_SUB: + { + OUString aValue(RTL_CONSTASCII_USTRINGPARAM("subscript")); + RTFValue::Pointer_t pValue(new RTFValue(aValue)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue)); + } + break; + case RTF_LINEPPAGE: + case RTF_LINECONT: + { + RTFValue::Pointer_t pValue(new RTFValue(nKeyword == RTF_LINEPPAGE ? 0 : 2)); + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_lnNumType, NS_ooxml::LN_CT_LineNumber_restart, pValue); + } + break; + default: + OSL_TRACE("%s: TODO handle flag '%s'", OSL_THIS_FUNC, lcl_RtfToString(nKeyword)); + bParsed = false; + break; + } + skipDestination(bParsed); + return 0; +} + +int RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) +{ + bool bParsed = true; + int nSprm = 0; + RTFValue::Pointer_t pIntValue(new RTFValue(nParam)); + // Trivial table sprms. + switch (nKeyword) + { + case RTF_FPRQ: nSprm = NS_rtf::LN_PRQ; break; + case RTF_LEVELJC: nSprm = NS_ooxml::LN_CT_Lvl_lvlJc; break; + case RTF_LEVELNFC: nSprm = NS_rtf::LN_NFC; break; + case RTF_LEVELSTARTAT: nSprm = NS_rtf::LN_ISTARTAT; break; + default: break; + } + if (nSprm > 0) + { + m_aStates.top().aTableSprms.push_back(make_pair(nSprm, pIntValue)); + skipDestination(bParsed); + return 0; + } + // Trivial character sprms. + switch (nKeyword) + { + case RTF_AF: nSprm = (m_aStates.top().bIsCjk ? NS_sprm::LN_CRgFtc1 : NS_sprm::LN_CRgFtc2); break; + case RTF_FS: nSprm = NS_sprm::LN_CHps; break; + case RTF_AFS: nSprm = NS_sprm::LN_CHpsBi; break; + case RTF_ANIMTEXT: nSprm = NS_sprm::LN_CSfxText; break; + case RTF_EXPNDTW: nSprm = NS_sprm::LN_CDxaSpace; break; + case RTF_KERNING: nSprm = NS_sprm::LN_CHpsKern; break; + case RTF_CHARSCALEX: nSprm = NS_sprm::LN_CCharScale; break; + case RTF_LANG: nSprm = NS_sprm::LN_CRgLid0; break; + case RTF_LANGFE: nSprm = NS_sprm::LN_CRgLid1; break; + default: break; + } + if (nSprm > 0) + { + m_aStates.top().aCharacterSprms.push_back(make_pair(nSprm, pIntValue)); + skipDestination(bParsed); + return 0; + } + // Trivial paragraph sprms. + switch (nKeyword) + { + case RTF_FI: nSprm = NS_sprm::LN_PDxaLeft1; break; + case RTF_LI: nSprm = NS_sprm::LN_PDxaLeft; break; + case RTF_LIN: nSprm = 0x845e; break; + case RTF_RI: nSprm = NS_sprm::LN_PDxaRight; break; + case RTF_RIN: nSprm = 0x845d; break; + case RTF_SB: nSprm = NS_sprm::LN_PDyaBefore; break; + case RTF_SA: nSprm = NS_sprm::LN_PDyaAfter; break; + case RTF_ITAP: nSprm = NS_sprm::LN_PTableDepth; break; + default: break; + } + if (nSprm > 0) + { + m_aStates.top().aParagraphSprms.push_back(make_pair(nSprm, pIntValue)); + skipDestination(bParsed); + return 0; + } + + // Trivial table attributes. + switch (nKeyword) + { + case RTF_SBASEDON: nSprm = NS_rtf::LN_ISTDBASE; break; + case RTF_SNEXT: nSprm = NS_rtf::LN_ISTDNEXT; break; + default: break; + } + if (nSprm > 0) + { + m_aStates.top().aTableAttributes.push_back(make_pair(nSprm, pIntValue)); + skipDestination(bParsed); + return 0; + } + + // Trivial paragraph attributes. + switch (nKeyword) + { + // NS_sprm::LN_PDyaLine could be used, but that won't work with slmult + case RTF_SL: nSprm = NS_ooxml::LN_CT_Spacing_line; break; + default: break; + } + if (nSprm > 0) + { + m_aStates.top().aParagraphAttributes.push_back(make_pair(nSprm, pIntValue)); + skipDestination(bParsed); + return 0; + } + + // Trivial character attributes. + switch (nKeyword) + { + case RTF_PICW: nSprm = NS_rtf::LN_XEXT; if (m_aStates.top().nPictureScaleX) nParam = m_aStates.top().nPictureScaleX * nParam; break; + case RTF_PICH: nSprm = NS_rtf::LN_YEXT; if (m_aStates.top().nPictureScaleY) nParam = m_aStates.top().nPictureScaleY * nParam; break; + default: break; + } + if (nSprm > 0) + { + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(nSprm, pValue)); + skipDestination(bParsed); + return 0; + } + + // Then check for the more complex ones. + switch (nKeyword) + { + case RTF_F: + if (m_aStates.top().nDestinationState == DESTINATION_FONTENTRY) + m_aStates.top().nCurrentFontIndex = nParam; + else + { + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_sprm::LN_CRgFtc0, pIntValue)); + m_aStates.top().nCurrentEncoding = getEncodingTable(nParam); + } + 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 0; + m_aFontEncodings[m_aStates.top().nCurrentFontIndex] = rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage); + } + break; + case RTF_CF: + { + // NS_sprm::LN_CIco won't work, that would be an index in a static table + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_Color_val, pIntValue)); + } + break; + case RTF_S: + if (m_aStates.top().nDestinationState == DESTINATION_STYLEENTRY) + { + m_aStates.top().nCurrentStyleIndex = nParam; + m_aStates.top().aTableAttributes.push_back(make_pair(NS_rtf::LN_ISTD, pIntValue)); + } + else + m_aStates.top().aParagraphAttributes.push_back(make_pair(NS_rtf::LN_ISTD, pIntValue)); + break; + case RTF_CS: + if (m_aStates.top().nDestinationState == DESTINATION_STYLEENTRY) + { + m_aStates.top().nCurrentStyleIndex = nParam; + m_aStates.top().aTableAttributes.push_back(make_pair(NS_rtf::LN_ISTD, pIntValue)); + RTFValue::Pointer_t pValue(new RTFValue(2)); + m_aStates.top().aTableAttributes.push_back(make_pair(NS_rtf::LN_SGC, pValue)); // character style + } + else + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_rtf::LN_ISTD, pIntValue)); + break; + case RTF_DEFF: + m_aDefaultState.aCharacterSprms.push_back(make_pair(NS_sprm::LN_CRgFtc0, pIntValue)); + break; + case RTF_DEFLANG: + m_aDefaultState.aCharacterSprms.push_back(make_pair(NS_sprm::LN_CRgLid0, pIntValue)); + break; + case RTF_ADEFLANG: + m_aDefaultState.aCharacterSprms.push_back(make_pair(NS_sprm::LN_CLidBi, pIntValue)); + break; + case RTF_CHCBPAT: + { + RTFValue::Pointer_t pValue(new RTFValue(getColorTable(nParam))); + lcl_putNestedAttribute(m_aStates.top().aCharacterSprms, NS_sprm::LN_CShd, NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTF_CLCBPAT: + { + RTFValue::Pointer_t pValue(new RTFValue(getColorTable(nParam))); + lcl_putNestedAttribute(m_aStates.top().aTableCellSprms, + NS_ooxml::LN_CT_TcPrBase_shd, NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTF_CBPAT: + { + RTFValue::Pointer_t pValue(new RTFValue(getColorTable(nParam))); + lcl_putNestedAttribute(m_aStates.top().aParagraphSprms, NS_sprm::LN_PShd, NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTF_ULC: + { + RTFValue::Pointer_t pValue(new RTFValue(getColorTable(nParam))); + m_aStates.top().aCharacterSprms.push_back(make_pair(0x6877, pValue)); + } + break; + case RTF_UP: // TODO handle when point size is not shrinking + { + OUString aValue(RTL_CONSTASCII_USTRINGPARAM("superscript")); + RTFValue::Pointer_t pValue(new RTFValue(aValue)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue)); + } + break; + case RTF_DN: + { + OUString aValue(RTL_CONSTASCII_USTRINGPARAM("subscript")); + RTFValue::Pointer_t pValue(new RTFValue(aValue)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue)); + } + break; + case RTF_HORZVERT: + { + RTFValue::Pointer_t pValue(new RTFValue(true)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_EastAsianLayout_vert, pValue)); + if (nParam) + // rotate fits to a single line + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue)); + } + break; + case RTF_EXPND: + { + RTFValue::Pointer_t pValue(new RTFValue(nParam/5)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_sprm::LN_CDxaSpace, pValue)); + } + break; + case RTF_TWOINONE: + { + RTFValue::Pointer_t pValue(new RTFValue(true)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_EastAsianLayout_combine, pValue)); + if (nParam > 0) + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, pIntValue)); + } + break; + case RTF_SLMULT: + if (nParam > 0) + { + RTFValue::Pointer_t pValue(new RTFValue(NS_ooxml::LN_Value_wordprocessingml_ST_LineSpacingRule_auto)); + m_aStates.top().aParagraphAttributes.push_back(make_pair(NS_ooxml::LN_CT_Spacing_lineRule, pValue)); + } + break; + case RTF_BRDRW: + { + // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0 + if (nParam > 1) + nParam = nParam * 2 / 5; + RTFValue::Pointer_t pValue(new RTFValue(nParam)); + lcl_putBorderProperty(m_aStates, NS_rtf::LN_DPTLINEWIDTH, pValue); + } + break; + case RTF_BRDRCF: + { + RTFValue::Pointer_t pValue(new RTFValue(getColorTable(nParam))); + lcl_putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue); + } + break; + case RTF_BRSP: + { + // dmapper expects it in points, we have it in twip + RTFValue::Pointer_t pValue(new RTFValue(nParam / 20)); + lcl_putBorderProperty(m_aStates, NS_rtf::LN_DPTSPACE, pValue); + } + break; + case RTF_TX: + { + m_aStates.top().aTabAttributes.push_back(make_pair(NS_ooxml::LN_CT_TabStop_pos, pIntValue)); + RTFValue::Pointer_t pValue(new RTFValue(m_aStates.top().aTabAttributes)); + lcl_putNestedSprm(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_tabs, NS_ooxml::LN_CT_Tabs_tab, pValue); + m_aStates.top().aTabAttributes.clear(); + } + break; + case RTF_ILVL: + { + RTFSprms_t& rSprms = lcl_getNumPr(m_aStates); + rSprms.push_back(make_pair(NS_sprm::LN_PIlvl, pIntValue)); + } + case RTF_LISTTEMPLATEID: + // This one is not referenced anywhere, so it's pointless to store it at the moment. + break; + case RTF_LISTID: + { + if (m_aStates.top().nDestinationState == DESTINATION_LISTENTRY) + m_aStates.top().aTableAttributes.push_back(make_pair(NS_ooxml::LN_CT_AbstractNum_abstractNumId, pIntValue)); + else if (m_aStates.top().nDestinationState == DESTINATION_LISTOVERRIDEENTRY) + m_aStates.top().aTableSprms.push_back(make_pair(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue)); + } + break; + case RTF_LS: + { + if (m_aStates.top().nDestinationState == DESTINATION_LISTOVERRIDEENTRY) + m_aStates.top().aTableAttributes.push_back(make_pair(NS_rtf::LN_LSID, pIntValue)); + else + { + RTFSprms_t& rSprms = lcl_getNumPr(m_aStates); + rSprms.push_back(make_pair(NS_sprm::LN_PIlfo, pIntValue)); + } + } + break; + case RTF_U: + if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16)) + { + OUString aStr(static_cast<sal_Unicode>(nParam)); + text(aStr); + m_aStates.top().nCharsToSkip = m_aStates.top().nUc; + } + break; + case RTF_LEVELFOLLOW: + case RTF_LISTOVERRIDECOUNT: + // Ignore these for now, the exporter always emits them with a zero parameter. + break; + case RTF_PICSCALEX: + m_aStates.top().nPictureScaleX = 0.01 * nParam; + break; + case RTF_PICSCALEY: + m_aStates.top().nPictureScaleY = 0.01 * nParam; + break; + case RTF_SHPWRK: + { + int nValue = 0; + switch (nParam) + { + case 0: nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides; break; + case 1: nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left; break; + case 2: nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right; break; + case 3: nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest; break; + default: break; + } + RTFValue::Pointer_t pValue(new RTFValue(nValue)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_WrapSquare_wrapText, pValue)); + } + break; + case RTF_CELLX: + { + int nCellX = nParam - m_aStates.top().nCellX; + m_aStates.top().nCellX = nParam; + RTFValue::Pointer_t pXValue(new RTFValue(nCellX)); + m_aStates.top().aTableRowSprms.push_back(make_pair(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue)); + + replayBuffer(m_aTableBuffer); + + // Reset cell properties. + RTFSprms::Pointer_t pTableCellSprms(new RTFSprms_t(m_aStates.top().aTableCellSprms)); + m_aStates.top().aTableCellsSprms.push_back(pTableCellSprms); + RTFSprms::Pointer_t pTableCellAttributes(new RTFSprms_t(m_aStates.top().aTableCellAttributes)); + m_aStates.top().aTableCellsAttributes.push_back(pTableCellAttributes); + m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms; + m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes; + } + break; + case RTF_TRRH: + { + lcl_putNestedAttribute(m_aStates.top().aTableRowSprms, + NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val, pIntValue); + } + break; + case RTF_COLS: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num, pIntValue); + break; + case RTF_COLSX: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space, pIntValue); + break; + case RTF_COLNO: + lcl_putNestedSprm(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_col, pIntValue); + break; + case RTF_COLW: + case RTF_COLSR: + { + RTFSprms_t& rAttributes = lcl_getLastAttributes(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_cols); + rAttributes.push_back(make_pair((nKeyword == RTF_COLW ? NS_ooxml::LN_CT_Column_w : NS_ooxml::LN_CT_Column_space), + pIntValue)); + } + break; + case RTF_PAPERH: + lcl_putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, pIntValue, true); + break; + case RTF_PAPERW: + lcl_putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, pIntValue, true); + break; + case RTF_PGHSXN: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, pIntValue, true); + break; + case RTF_PGWSXN: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, pIntValue, true); + break; + case RTF_MARGL: + lcl_putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, pIntValue, true); + break; + case RTF_MARGR: + lcl_putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, pIntValue, true); + break; + case RTF_MARGT: + lcl_putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, pIntValue, true); + break; + case RTF_MARGB: + lcl_putNestedAttribute(m_aDefaultState.aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, pIntValue, true); + break; + case RTF_MARGLSXN: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, pIntValue, true); + break; + case RTF_MARGRSXN: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, pIntValue, true); + break; + case RTF_MARGTSXN: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, pIntValue, true); + break; + case RTF_MARGBSXN: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, pIntValue, true); + break; + case RTF_HEADERY: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header, pIntValue, true); + break; + case RTF_FOOTERY: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer, pIntValue, true); + break; + case RTF_DEFTAB: + m_aSettingsTableSprms.push_back(make_pair(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue)); + break; + case RTF_LINEMOD: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_lnNumType, NS_ooxml::LN_CT_LineNumber_countBy, pIntValue); + break; + case RTF_LINEX: + if (nParam) + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_lnNumType, NS_ooxml::LN_CT_LineNumber_distance, pIntValue); + break; + case RTF_LINESTARTS: + lcl_putNestedAttribute(m_aStates.top().aSectionSprms, + NS_ooxml::LN_EG_SectPrContents_lnNumType, NS_ooxml::LN_CT_LineNumber_start, pIntValue); + break; + case RTF_REVAUTH: + case RTF_REVAUTHDEL: + { + RTFValue::Pointer_t pValue(new RTFValue(m_aAuthors[nParam])); + lcl_putNestedAttribute(m_aStates.top().aCharacterSprms, + NS_ooxml::LN_trackchange, NS_ooxml::LN_CT_TrackChange_author, pValue); + } + break; + case RTF_REVDTTM: + case RTF_REVDTTMDEL: + { + OUString aStr(OStringToOUString(lcl_DTTM22OString(nParam), m_aStates.top().nCurrentEncoding)); + RTFValue::Pointer_t pValue(new RTFValue(aStr)); + lcl_putNestedAttribute(m_aStates.top().aCharacterSprms, + NS_ooxml::LN_trackchange, NS_ooxml::LN_CT_TrackChange_date, pValue); + } + break; + default: + OSL_TRACE("%s: TODO handle value '%s'", OSL_THIS_FUNC, lcl_RtfToString(nKeyword)); + bParsed = false; + break; + } + skipDestination(bParsed); + return 0; +} + +int RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) +{ + bool bParsed = true; + int nSprm = -1; + RTFValue::Pointer_t pBoolValue(new RTFValue(!bParam || nParam != 0)); + + // Map all underline keywords to a single sprm. + switch (nKeyword) + { + case RTF_UL: nSprm = 1; break; + case RTF_ULD: nSprm = 4; break; + case RTF_ULDASH: nSprm = 7; break; + case RTF_ULDASHD: nSprm = 9; break; + case RTF_ULDASHDD: nSprm = 10; break; + case RTF_ULDB: nSprm = 3; break; + case RTF_ULHWAVE: nSprm = 27; break; + case RTF_ULLDASH: nSprm = 39; break; + case RTF_ULTH: nSprm = 6; break; + case RTF_ULTHD: nSprm = 20; break; + case RTF_ULTHDASH: nSprm = 23; break; + case RTF_ULTHDASHD: nSprm = 25; break; + case RTF_ULTHDASHDD: nSprm = 26; break; + case RTF_ULTHLDASH: nSprm = 55; break; + case RTF_ULULDBWAVE: nSprm = 43; break; + case RTF_ULW: nSprm = 2; break; + case RTF_ULWAVE: nSprm = 11; break; + default: break; + } + if (nSprm >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue((!bParam || nParam != 0) ? nSprm : 0)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_sprm::LN_CKul, pValue)); + skipDestination(bParsed); + return 0; + } + + // Accent characters (over dot / over coma). + switch (nKeyword) + { + case RTF_ACCNONE: nSprm = 0; break; + case RTF_ACCDOT: nSprm = 1; break; + case RTF_ACCCOMMA: nSprm = 2; break; + case RTF_ACCCIRCLE: nSprm = 3; break; + case RTF_ACCUNDERDOT: nSprm = 4; break; + default: break; + } + if (nSprm >= 0) + { + RTFValue::Pointer_t pValue(new RTFValue((!bParam || nParam != 0) ? nSprm : 0)); + m_aStates.top().aCharacterSprms.push_back(make_pair(NS_sprm::LN_CKcd, pValue)); + skipDestination(bParsed); + return 0; + } + + // Trivial character sprms. + switch (nKeyword) + { + case RTF_B: nSprm = NS_sprm::LN_CFBold; break; + case RTF_AB: nSprm = NS_sprm::LN_CFBoldBi; break; + case RTF_I: nSprm = NS_sprm::LN_CFItalic; break; + case RTF_AI: nSprm = NS_sprm::LN_CFItalicBi; break; + case RTF_UL: nSprm = NS_sprm::LN_CKul; break; + case RTF_OUTL: nSprm = NS_sprm::LN_CFOutline; break; + case RTF_SHAD: nSprm = NS_sprm::LN_CFShadow; break; + case RTF_V: nSprm = NS_sprm::LN_CFVanish; break; + case RTF_STRIKE: nSprm = NS_sprm::LN_CFStrike; break; + case RTF_STRIKED: nSprm = NS_sprm::LN_CFDStrike; break; + case RTF_SCAPS: nSprm = NS_sprm::LN_CFSmallCaps; break; + case RTF_IMPR: nSprm = NS_sprm::LN_CFImprint; break; + default: break; + } + if (nSprm >= 0) + { + m_aStates.top().aCharacterSprms.push_back(make_pair(nSprm, pBoolValue)); + skipDestination(bParsed); + return 0; + } + + switch (nKeyword) + { + case RTF_ASPALPHA: + m_aStates.top().aParagraphSprms.push_back(make_pair(NS_sprm::LN_PFAutoSpaceDE, pBoolValue)); + break; + case RTF_DELETED: + case RTF_REVISED: + { + RTFValue::Pointer_t pValue(new RTFValue(nKeyword == RTF_DELETED ? ooxml::OOXML_del : ooxml::OOXML_ins)); + lcl_putNestedAttribute(m_aStates.top().aCharacterSprms, + NS_ooxml::LN_trackchange, NS_ooxml::LN_token, pValue); + } + break; + default: + OSL_TRACE("%s: TODO handle toggle '%s'", OSL_THIS_FUNC, lcl_RtfToString(nKeyword)); + bParsed = false; + break; + } + skipDestination(bParsed); + return 0; +} + +void RTFDocumentImpl::skipDestination(bool bParsed) +{ + if (m_bSkipUnknown) + { + if (!bParsed) + { + OSL_TRACE("%s: skipping destination", OSL_THIS_FUNC); + m_aStates.top().nDestinationState = DESTINATION_SKIP; + } + m_bSkipUnknown = false; + } +} + +int RTFDocumentImpl::dispatchKeyword(OString& rKeyword, bool bParam, int nParam) +{ + if (m_aStates.top().nDestinationState == DESTINATION_SKIP) + return 0; + /*OSL_TRACE("%s: keyword '\\%s' with param? %d param val: '%d'", OSL_THIS_FUNC, + rKeyword.getStr(), (bParam ? 1 : 0), (bParam ? nParam : 0));*/ + int i, ret; + for (i = 0; i < nRTFControlWords; i++) + { + if (!strcmp(rKeyword.getStr(), aRTFControlWords[i].sKeyword)) + break; + } + if (i == nRTFControlWords) + { + OSL_TRACE("%s: unknown keyword '\\%s'", OSL_THIS_FUNC, rKeyword.getStr()); + skipDestination(false); + return 0; + } + + switch (aRTFControlWords[i].nControlType) + { + case CONTROL_FLAG: + // flags ignore any parameter by definition + if ((ret = dispatchFlag(aRTFControlWords[i].nIndex))) + return ret; + break; + case CONTROL_DESTINATION: + // same for destinations + if ((ret = dispatchDestination(aRTFControlWords[i].nIndex))) + return ret; + break; + case CONTROL_SYMBOL: + // and symbols + if ((ret = dispatchSymbol(aRTFControlWords[i].nIndex))) + return ret; + break; + case CONTROL_TOGGLE: + if ((ret = dispatchToggle(aRTFControlWords[i].nIndex, bParam, nParam))) + return ret; + break; + case CONTROL_VALUE: + // values require a parameter by definition + if (bParam && (ret = dispatchValue(aRTFControlWords[i].nIndex, nParam))) + return ret; + break; + } + + return 0; +} + +int RTFDocumentImpl::resolveKeyword() +{ + char ch; + OStringBuffer aBuf; + bool bNeg = false; + bool bParam = false; + int nParam = 0; + + Strm() >> ch; + if (Strm().IsEof()) + return ERROR_EOF; + + if (!isalpha(ch)) + { + aBuf.append(ch); + OString aKeyword = aBuf.makeStringAndClear(); + // control symbols aren't followed by a space, so we can return here + // without doing any SeekRel() + return dispatchKeyword(aKeyword, bParam, nParam); + } + while(isalpha(ch)) + { + aBuf.append(ch); + Strm() >> ch; + } + + if (ch == '-') + { + // in case we'll have a parameter, that will be negative + bNeg = true; + Strm() >> ch; + if (Strm().IsEof()) + return ERROR_EOF; + } + if (isdigit(ch)) + { + OStringBuffer aParameter; + + // we have a parameter + bParam = true; + while(isdigit(ch)) + { + aParameter.append(ch); + Strm() >> ch; + } + nParam = aParameter.makeStringAndClear().toInt32(); + if (bNeg) + nParam = -nParam; + } + if (ch != ' ') + Strm().SeekRel(-1); + OString aKeyword = aBuf.makeStringAndClear(); + return dispatchKeyword(aKeyword, bParam, nParam); +} + +int RTFDocumentImpl::pushState() +{ + //OSL_TRACE("%s before push: %d", OSL_THIS_FUNC, m_nGroup); + + m_nGroupStartPos = Strm().Tell(); + RTFParserState aState; + if (m_aStates.empty()) + aState = m_aDefaultState; + else + aState = m_aStates.top(); + m_aStates.push(aState); + + m_nGroup++; + + if (m_aStates.top().nDestinationState == DESTINATION_FONTTABLE) + m_aStates.top().nDestinationState = DESTINATION_FONTENTRY; + else if (m_aStates.top().nDestinationState == DESTINATION_STYLESHEET) + m_aStates.top().nDestinationState = DESTINATION_STYLEENTRY; + else if (m_aStates.top().nDestinationState == DESTINATION_FIELDRESULT) + m_aStates.top().nDestinationState = DESTINATION_NORMAL; + else if (m_aStates.top().nDestinationState == DESTINATION_REVISIONTABLE) + m_aStates.top().nDestinationState = DESTINATION_REVISIONENTRY; + + return 0; +} + +RTFSprms_t RTFDocumentImpl::mergeSprms() +{ + RTFSprms_t aSprms; + for (RTFSprms_t::iterator i = m_aStates.top().aTableSprms.begin(); + i != m_aStates.top().aTableSprms.end(); ++i) + aSprms.push_back(make_pair(i->first, i->second)); + for (RTFSprms_t::iterator i = m_aStates.top().aCharacterSprms.begin(); + i != m_aStates.top().aCharacterSprms.end(); ++i) + aSprms.push_back(make_pair(i->first, i->second)); + for (RTFSprms_t::iterator i = m_aStates.top().aParagraphSprms.begin(); + i != m_aStates.top().aParagraphSprms.end(); ++i) + aSprms.push_back(make_pair(i->first, i->second)); + return aSprms; +} + +RTFSprms_t RTFDocumentImpl::mergeAttributes() +{ + RTFSprms_t aAttributes; + for (RTFSprms_t::iterator i = m_aStates.top().aTableAttributes.begin(); + i != m_aStates.top().aTableAttributes.end(); ++i) + aAttributes.push_back(make_pair(i->first, i->second)); + for (RTFSprms_t::iterator i = m_aStates.top().aCharacterAttributes.begin(); + i != m_aStates.top().aCharacterAttributes.end(); ++i) + aAttributes.push_back(make_pair(i->first, i->second)); + for (RTFSprms_t::iterator i = m_aStates.top().aParagraphAttributes.begin(); + i != m_aStates.top().aParagraphAttributes.end(); ++i) + aAttributes.push_back(make_pair(i->first, i->second)); + return aAttributes; +} + +int RTFDocumentImpl::popState() +{ + //OSL_TRACE("%s before pop: m_nGroup %d, dest state: %d", OSL_THIS_FUNC, m_nGroup, m_aStates.top().nDestinationState); + + RTFReferenceTable::Entry_t aEntry; + bool bFontEntryEnd = false; + bool bStyleEntryEnd = false; + RTFSprms_t aSprms; + RTFSprms_t aAttributes; + bool bListEntryEnd = false; + bool bListLevelEnd = false; + bool bListOverrideEntryEnd = false; + bool bLevelTextEnd = false; + std::vector< std::pair<rtl::OUString, rtl::OUString> > aShapeProperties; + bool bPopShapeProperties = false; + bool bPicPropEnd = false; + + if (m_aStates.top().nDestinationState == DESTINATION_FONTTABLE) + { + writerfilter::Reference<Table>::Pointer_t const pTable(new RTFReferenceTable(m_aStates.top().aFontTableEntries)); + Mapper().table(NS_rtf::LN_FONTTABLE, pTable); + } + else if (m_aStates.top().nDestinationState == DESTINATION_STYLESHEET) + { + writerfilter::Reference<Table>::Pointer_t const pTable(new RTFReferenceTable(m_aStates.top().aStyleTableEntries)); + Mapper().table(NS_rtf::LN_STYLESHEET, pTable); + } + else if (m_aStates.top().nDestinationState == DESTINATION_LISTOVERRIDETABLE) + { + RTFSprms_t aListTableAttributes; + writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(aListTableAttributes, m_aListTableSprms)); + RTFReferenceTable::Entries_t aListTableEntries; + aListTableEntries.insert(make_pair(0, pProp)); + writerfilter::Reference<Table>::Pointer_t const pTable(new RTFReferenceTable(aListTableEntries)); + Mapper().table(NS_rtf::LN_LISTTABLE, pTable); + } + else if (m_aStates.top().nDestinationState == DESTINATION_FONTENTRY) + { + RTFValue::Pointer_t pValue(new RTFValue(m_aDestinationText.makeStringAndClear())); + m_aStates.top().aTableAttributes.push_back(make_pair(NS_rtf::LN_XSZFFN, pValue)); + + bFontEntryEnd = true; + writerfilter::Reference<Properties>::Pointer_t const pProp( + new RTFReferenceProperties(m_aStates.top().aTableAttributes, m_aStates.top().aTableSprms) + ); + aEntry.first = m_aStates.top().nCurrentFontIndex; + aEntry.second = pProp; + } + else if (m_aStates.top().nDestinationState == DESTINATION_STYLEENTRY) + { + RTFValue::Pointer_t pValue(new RTFValue(m_aDestinationText.makeStringAndClear())); + m_aStates.top().aTableAttributes.push_back(make_pair(NS_rtf::LN_XSTZNAME1, pValue)); + + bStyleEntryEnd = true; + writerfilter::Reference<Properties>::Pointer_t const pProp( + new RTFReferenceProperties(mergeAttributes(), mergeSprms()) + ); + aEntry.first = m_aStates.top().nCurrentStyleIndex; + aEntry.second = pProp; + } + else if (m_aStates.top().nDestinationState == DESTINATION_LISTENTRY) + { + aAttributes = m_aStates.top().aTableAttributes; + aSprms = m_aStates.top().aTableSprms; + for (RTFSprms_t::iterator i = m_aStates.top().aListLevelEntries.begin(); + i != m_aStates.top().aListLevelEntries.end(); ++i) + aSprms.push_back(make_pair(i->first, i->second)); + bListEntryEnd = true; + } + else if (m_aStates.top().nDestinationState == DESTINATION_LISTLEVEL) + { + aAttributes = m_aStates.top().aTableAttributes; + aSprms = m_aStates.top().aTableSprms; + bListLevelEnd = true; + } + else if (m_aStates.top().nDestinationState == DESTINATION_LISTOVERRIDEENTRY) + { + aAttributes = m_aStates.top().aTableAttributes; + aSprms = m_aStates.top().aTableSprms; + bListOverrideEntryEnd = true; + } + else if (m_aStates.top().nDestinationState == DESTINATION_FIELDINSTRUCTION) + { + sal_uInt8 sFieldSep[] = { 0x14 }; + Mapper().startCharacterGroup(); + Mapper().text(sFieldSep, 1); + Mapper().endCharacterGroup(); + } + else if (m_aStates.top().nDestinationState == DESTINATION_FIELDRESULT) + { + sal_uInt8 sFieldEnd[] = { 0x15 }; + Mapper().startCharacterGroup(); + Mapper().text(sFieldEnd, 1); + Mapper().endCharacterGroup(); + } + else if (m_aStates.top().nDestinationState == DESTINATION_LEVELTEXT) + { + OUString aStr = m_aDestinationText.makeStringAndClear(); + + // The first character is the length of the string (the rest should be ignored). + sal_Int32 nLength(aStr.toChar()); + OUString aValue = aStr.copy(1, nLength); + RTFValue::Pointer_t pValue(new RTFValue(aValue, true)); + m_aStates.top().aTableAttributes.push_back(make_pair(NS_ooxml::LN_CT_LevelText_val, pValue)); + + aAttributes = m_aStates.top().aTableAttributes; + bLevelTextEnd = true; + } + else if (m_aStates.top().nDestinationState == DESTINATION_LEVELNUMBERS) + { + RTFSprms_t& rAttributes = RTFSprm::find(m_aStates.top().aTableSprms, NS_ooxml::LN_CT_Lvl_lvlText)->getAttributes(); + RTFValue::Pointer_t pValue = RTFSprm::find(rAttributes, NS_ooxml::LN_CT_LevelText_val); + OUString aOrig = pValue->getString(); + + OUStringBuffer aBuf; + sal_Int32 nReplaces = 1; + for (int i = 0; i < aOrig.getLength(); i++) + { + if (std::find(m_aStates.top().aLevelNumbers.begin(), m_aStates.top().aLevelNumbers.end(), i+1) + != m_aStates.top().aLevelNumbers.end()) + { + aBuf.append(sal_Unicode('%')); + // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2. + aBuf.append(sal_Int32(nReplaces++ + m_aStates.top().nListLevelNum + 1 - m_aStates.top().aLevelNumbers.size())); + } + else + aBuf.append(aOrig.copy(i, 1)); + } + pValue->setString(aBuf.makeStringAndClear()); + } + else if (m_aStates.top().nDestinationState == DESTINATION_SHAPEPROPERTYNAME + || m_aStates.top().nDestinationState == DESTINATION_SHAPEPROPERTYVALUE + || m_aStates.top().nDestinationState == DESTINATION_SHAPEPROPERTY) + { + aShapeProperties = m_aStates.top().aShapeProperties; + if (m_aStates.top().nDestinationState == DESTINATION_SHAPEPROPERTYNAME) + aShapeProperties.push_back(make_pair(m_aDestinationText.makeStringAndClear(), OUString())); + else if (m_aStates.top().nDestinationState == DESTINATION_SHAPEPROPERTYVALUE) + aShapeProperties.back().second = m_aDestinationText.makeStringAndClear(); + bPopShapeProperties = true; + } + else if (m_aStates.top().nDestinationState == DESTINATION_PICPROP) + { + aShapeProperties = m_aStates.top().aShapeProperties; + bPicPropEnd = true; + } + else if (m_aStates.top().nDestinationState == DESTINATION_REVISIONENTRY) + m_aAuthors[m_aAuthors.size()] = m_aDestinationText.makeStringAndClear(); + else if (m_aStates.top().nDestinationState == DESTINATION_BOOKMARKSTART) + { + OUString aStr = m_aDestinationText.makeStringAndClear(); + int nPos = m_aBookmarks.size(); + m_aBookmarks[aStr] = nPos; + Mapper().props(lcl_getBookmarkProperties(nPos, aStr)); + } + else if (m_aStates.top().nDestinationState == DESTINATION_BOOKMARKEND) + Mapper().props(lcl_getBookmarkProperties(m_aBookmarks[m_aDestinationText.makeStringAndClear()])); + + // See if we need to end a track change + RTFValue::Pointer_t pTrackchange = RTFSprm::find(m_aStates.top().aCharacterSprms, NS_ooxml::LN_trackchange); + if (pTrackchange.get()) + { + RTFSprms_t aTCAttributes; + RTFValue::Pointer_t pValue(new RTFValue(0)); + aTCAttributes.push_back(make_pair(NS_ooxml::LN_endtrackchange, pValue)); + writerfilter::Reference<Properties>::Pointer_t const pProperties(new RTFReferenceProperties(aTCAttributes)); + Mapper().props(pProperties); + } + + // This is the end of the doc, see if we need to close the last section. + if (m_nGroup == 1) + sectBreak(true); + + m_aStates.pop(); + + m_nGroup--; + + if (bFontEntryEnd) + m_aStates.top().aFontTableEntries.insert(make_pair(aEntry.first, aEntry.second)); + else if (bStyleEntryEnd) + m_aStates.top().aStyleTableEntries.insert(make_pair(aEntry.first, aEntry.second)); + // list table + else if (bListEntryEnd) + { + RTFValue::Pointer_t pValue(new RTFValue(aAttributes, aSprms)); + m_aListTableSprms.push_back(make_pair(NS_ooxml::LN_CT_Numbering_abstractNum, pValue)); + } + else if (bListLevelEnd) + { + RTFValue::Pointer_t pInnerValue(new RTFValue(m_aStates.top().nListLevelNum++)); + aAttributes.push_back(make_pair(NS_ooxml::LN_CT_Lvl_ilvl, pInnerValue)); + + RTFValue::Pointer_t pValue(new RTFValue(aAttributes, aSprms)); + m_aStates.top().aListLevelEntries.push_back(make_pair(NS_ooxml::LN_CT_AbstractNum_lvl, pValue)); + } + // list override table + else if (bListOverrideEntryEnd) + { + RTFValue::Pointer_t pValue(new RTFValue(aAttributes, aSprms)); + m_aListTableSprms.push_back(make_pair(NS_ooxml::LN_CT_Numbering_num, pValue)); + } + else if (bLevelTextEnd) + { + RTFValue::Pointer_t pValue(new RTFValue(aAttributes)); + m_aStates.top().aTableSprms.push_back(make_pair(NS_ooxml::LN_CT_Lvl_lvlText, pValue)); + } + else if (bPopShapeProperties) + m_aStates.top().aShapeProperties = aShapeProperties; + else if (bPicPropEnd) + resolveShapeProperties(aShapeProperties); + if (m_bSuper) + { + if (!m_bHasFootnote) + replayBuffer(m_aSuperBuffer); + m_bSuper = m_bHasFootnote = false; + } + + return 0; +} + +void RTFDocumentImpl::resolveShapeProperties(std::vector< std::pair<rtl::OUString, rtl::OUString> >& rShapeProperties) +{ + for (std::vector< std::pair<rtl::OUString, rtl::OUString> >::iterator i = rShapeProperties.begin(); i != rShapeProperties.end(); ++i) + { + if (i->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("shapeType"))) + { + int nValue = i->second.toInt32(); + switch (nValue) + { + case 75: // picture frame + break; + default: + OSL_TRACE("%s: TODO handle shape type '%d'", OSL_THIS_FUNC, nValue); + break; + } + } + else if (i->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("wzName"))) + { + RTFValue::Pointer_t pValue(new RTFValue(i->second)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_NonVisualDrawingProps_name, pValue)); + } + else if (i->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("wzDescription"))) + { + RTFValue::Pointer_t pValue(new RTFValue(i->second)); + m_aStates.top().aCharacterAttributes.push_back(make_pair(NS_ooxml::LN_CT_NonVisualDrawingProps_descr, pValue)); + } + else + OSL_TRACE("%s: TODO handle shape property '%s':'%s'", OSL_THIS_FUNC, + OUStringToOString( i->first, RTL_TEXTENCODING_UTF8 ).getStr(), + OUStringToOString( i->second, RTL_TEXTENCODING_UTF8 ).getStr()); + } +} + +int RTFDocumentImpl::resolveParse() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + char ch; + int ret; + // for hex chars + int b = 0, count = 2; + + while ((Strm() >> ch, !Strm().IsEof())) + { + //OSL_TRACE("%s: parsing character '%c'", OSL_THIS_FUNC, ch); + if (m_nGroup < 0) + return ERROR_GROUP_UNDER; + if (!m_aStates.empty() && m_aStates.top().nInternalState == INTERNAL_BIN) + { + OSL_TRACE("%s: TODO, binary internal state", OSL_THIS_FUNC); + } + else + { + switch (ch) + { + case '{': + if ((ret = pushState())) + return ret; + break; + case '}': + if ((ret = popState())) + return ret; + if (m_bIsSubstream && m_nGroup == 0) + return 0; + break; + case '\\': + if ((ret = resolveKeyword())) + return ret; + break; + case 0x0d: + case 0x0a: + break; // ignore these + default: + if (m_aStates.top().nInternalState == INTERNAL_NORMAL) + { + if ((ret = resolveChars(ch))) + return ret; + } + else + { + OSL_TRACE("%s: hex internal state", OSL_THIS_FUNC); + b = b << 4; + char parsed = lcl_AsHex(ch); + if (parsed == -1) + return ERROR_HEX_INVALID; + b += parsed; + count--; + if (!count) + { + if ((ret = resolveChars(b))) + return ret; + count = 2; + b = 0; + m_aStates.top().nInternalState = INTERNAL_NORMAL; + } + } + break; + } + } + } + + if (m_nGroup < 0) + return ERROR_GROUP_UNDER; + else if (m_nGroup > 0) + return ERROR_GROUP_OVER; + return 0; +} + +::std::string RTFDocumentImpl::getType() const +{ + return "RTFDocumentImpl"; +} + +RTFParserState::RTFParserState() + : nInternalState(INTERNAL_NORMAL), + nDestinationState(DESTINATION_NORMAL), + nBorderState(BORDER_NONE), + aTableSprms(), + aTableAttributes(), + aCharacterSprms(), + aCharacterAttributes(), + aParagraphSprms(), + aParagraphAttributes(), + aSectionSprms(), + aSectionAttributes(), + aTableRowSprms(), + aTableRowAttributes(), + aTableCellSprms(), + aTableCellAttributes(), + aTabAttributes(), + aFontTableEntries(), + nCurrentFontIndex(0), + aCurrentColor(), + aStyleTableEntries(), + nCurrentStyleIndex(0), + nCurrentEncoding(0), + nUc(1), + nCharsToSkip(0), + nListLevelNum(0), + aListLevelEntries(), + aLevelNumbers(), + nPictureScaleX(0), + nPictureScaleY(0), + aShapeProperties(), + nCellX(0), + aTableCellsSprms(), + aTableCellsAttributes(), + bIsCjk(false) +{ +} + +RTFColorTableEntry::RTFColorTableEntry() + : nRed(0), + nGreen(0), + nBlue(0) +{ +} + +} // namespace rtftok +} // namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |