/* -*- 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/io/WrongFormatException.hpp>#include <svl/lngmisc.hxx>#include <ooxml/resourceids.hxx>#include <sal/log.hxx>#include "rtfreferenceproperties.hxx"#include "rtfskipdestination.hxx"usingnamespacecom::sun::star;namespacewriterfilter{namespacertftok{RTFErrorRTFDocumentImpl::dispatchSymbol(RTFKeywordnKeyword){setNeedSect(true);if(nKeyword!=RTF_HEXCHAR)checkUnicode(/*bUnicode =*/true,/*bHex =*/true);elsecheckUnicode(/*bUnicode =*/true,/*bHex =*/false);RTFSkipDestinationaSkip(*this);if(RTF_LINE==nKeyword){// very special handling since text() will eat lone '\n'singleChar('\n');returnRTFError::OK;}// Trivial symbolssal_uInt8cCh=0;switch(nKeyword){caseRTF_TAB:
cCh='\t';break;caseRTF_BACKSLASH:
cCh='\\';break;caseRTF_LBRACE:
cCh='{';break;caseRTF_RBRACE:
cCh='}';break;caseRTF_EMDASH:
cCh=151;break;caseRTF_ENDASH:
cCh=150;break;caseRTF_BULLET:
cCh=149;break;caseRTF_LQUOTE:
cCh=145;break;caseRTF_RQUOTE:
cCh=146;break;caseRTF_LDBLQUOTE:
cCh=147;break;caseRTF_RDBLQUOTE:
cCh=148;break;default:break;}if(cCh>0){OUStringaStr(OStringToOUString(OString(cCh),RTL_TEXTENCODING_MS_1252));text(aStr);returnRTFError::OK;}switch(nKeyword){caseRTF_IGNORE:
{m_bSkipUnknown=true;aSkip.setReset(false);returnRTFError::OK;}break;caseRTF_PAR:
{if(m_aStates.top().eDestination==Destination::FOOTNOTESEPARATOR)break;// just ignore it - only thing we read in here is CHFTNSEPcheckFirstRun();boolbNeedPap=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.RTFSprmsaAttributes;RTFSprmsaSprms;aSprms.set(NS_ooxml::LN_tblEnd,newRTFValue(1));writerfilter::Reference<Properties>::Pointer_tpProperties=newRTFReferenceProperties(aAttributes,aSprms);Mapper().props(pProperties);}m_nCellxMax=0;}elseif(m_aStates.top().eDestination!=Destination::SHAPETEXT){RTFValue::Pointer_tpValue;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 arrivesm_bNeedPap=true;if(!m_aStates.top().aFrame.inFrame())m_bNeedPar=false;m_bNeedFinalPar=false;}break;caseRTF_SECT:
{m_bHadSect=true;if(m_bIgnoreNextContSectBreak)m_bIgnoreNextContSectBreak=false;else{sectBreak();if(m_nResetBreakOnSectBreak!=RTF_invalid){// this should run on _second_ \sect after \pagedispatchSymbol(m_nResetBreakOnSectBreak);// lazy resetm_nResetBreakOnSectBreak=RTF_invalid;m_bNeedSect=false;// dispatchSymbol set it}}}break;caseRTF_NOBREAK:
{OUStringaStr(SVT_HARD_SPACE);text(aStr);}break;caseRTF_NOBRKHYPH:
{OUStringaStr(SVT_HARD_HYPHEN);text(aStr);}break;caseRTF_OPTHYPH:
{OUStringaStr(SVT_SOFT_HYPHEN);text(aStr);}break;caseRTF_HEXCHAR:
m_aStates.top().nInternalState=RTFInternalState::HEX;break;caseRTF_CELL:
caseRTF_NESTCELL:
{if(nKeyword==RTF_CELL)m_bAfterCellBeforeRow=true;checkFirstRun();if(m_bNeedPap){// There were no runs in the cell, so we need to send paragraph and character properties here.autopPValue=newRTFValue(m_aStates.top().aParagraphAttributes,m_aStates.top().aParagraphSprms);m_aTableBufferStack.back().emplace_back(Buf_t(BUFFER_PROPS,pPValue,nullptr));autopCValue=newRTFValue(m_aStates.top().aCharacterAttributes,m_aStates.top().aCharacterSprms);m_aTableBufferStack.back().emplace_back(Buf_t(BUFFER_PROPS,pCValue,nullptr));}RTFValue::Pointer_tpValue;m_aTableBufferStack.back().emplace_back(Buf_t(BUFFER_CELLEND,pValue,nullptr));m_bNeedPap=true;}break;caseRTF_NESTROW:
{tools::SvRef<TableRowBuffer>constpBuffer(newTableRowBuffer(m_aTableBufferStack.back(),m_aNestedTableCellsSprms,m_aNestedTableCellsAttributes,m_nNestedCells));prepareProperties(m_aStates.top(),pBuffer->pParaProperties,pBuffer->pFrameProperties,pBuffer->pRowProperties,m_nNestedCells,m_nNestedCurrentCellX-m_nNestedTRLeft);if(m_aTableBufferStack.size()==1||!m_aStates.top().pCurrentBuffer){throwio::WrongFormatException("mismatch between \\itap and number of \\nestrow",nullptr);}assert(m_aStates.top().pCurrentBuffer==&m_aTableBufferStack.back());

<--- Assert statement calls a function which may have desired side effects: 'top'. [+]

Non-pure function: 'top' is called inside assert statement. Assert statements are removed from release builds so the code inside assert statement is not executed. If the code is needed also in release builds, this is a bug.

// note: there may be several states pointing to table buffer!for(std::size_ti=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().emplace_back(Buf_t(BUFFER_NESTROW,RTFValue::Pointer_t(),pBuffer));m_aNestedTableCellsSprms.clear();m_aNestedTableCellsAttributes.clear();m_nNestedCells=0;m_bNeedPap=true;}break;caseRTF_ROW:
{m_bAfterCellBeforeRow=false;if(m_aStates.top().nTableRowWidthAfter>0){// Add fake cellx / cell, RTF equivalent of// OOXMLFastContextHandlerTextTableRow::handleGridAfter().autopXValue=newRTFValue(m_aStates.top().nTableRowWidthAfter);m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblGridBase_gridCol,pXValue,RTFOverwrite::NO_APPEND);dispatchSymbol(RTF_CELL);// Adjust total width, which is done in the \cellx handler for normal cells.m_nTopLevelCurrentCellX+=m_aStates.top().nTableRowWidthAfter;m_aStates.top().nTableRowWidthAfter=0;}boolbRestored=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 cellconstintMINLAY=23;// sw/inc/swtypes.hxx, minimal possible size of frames.if((m_nCellxMax-m_nTopLevelCurrentCellX)>=MINLAY){autopXValueLast=m_aStates.top().aTableRowSprms.find(NS_ooxml::LN_CT_TblGridBase_gridCol,false);constintnXValueLast=pXValueLast?pXValueLast->getInt():0;autopXValue=newRTFValue(nXValueLast+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 elementsm_aTableInheritingCellsSprms=m_aTopLevelTableCellsSprms;m_aTableInheritingCellsAttributes=m_aTopLevelTableCellsAttributes;m_nInheritingCells=m_nTopLevelCells;}else{// No table definition? Then inherit from the previous rowm_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_ti=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);// The scope of the table cell defaults is one row.m_aDefaultState.aTableCellSprms.clear();m_aStates.top().aTableCellSprms=m_aDefaultState.aTableCellSprms;m_aStates.top().aTableCellAttributes=m_aDefaultState.aTableCellAttributes;writerfilter::Reference<Properties>::Pointer_tparaProperties;writerfilter::Reference<Properties>::Pointer_tframeProperties;writerfilter::Reference<Properties>::Pointer_trowProperties;prepareProperties(m_aStates.top(),paraProperties,frameProperties,rowProperties,m_nTopLevelCells,m_nTopLevelCurrentCellX-m_nTopLevelTRLeft);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;caseRTF_COLUMN:
{boolbColumns=false;// If we have multiple columnsRTFValue::Pointer_tpCols=m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_cols);if(pCols){RTFValue::Pointer_tpNum=pCols->getAttributes().find(NS_ooxml::LN_CT_Columns_num);if(pNum.get()&&pNum->getInt()>1)bColumns=true;}checkFirstRun();if(bColumns){sal_uInt8constsBreak[]={0xe};Mapper().startCharacterGroup();Mapper().text(sBreak,1);Mapper().endCharacterGroup();}elsedispatchSymbol(RTF_PAGE);}break;caseRTF_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;}caseRTF_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_tpBreak=m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_type);// Unless we're on a title page.RTFValue::Pointer_tpTitlePg=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 pusheddispatchFlag(RTF_SBKPAGE);if(m_bNeedPar)dispatchSymbol(RTF_PAR);m_bIgnoreNextContSectBreak=true;// arrange to clean up the synthetic RTF_SBKPAGEm_nResetBreakOnSectBreak=RTF_SBKNONE;}else{checkFirstRun();checkNeedPap();sal_uInt8constsBreak[]={0xc};Mapper().text(sBreak,1);if(!m_bNeedPap){parBreak();m_bNeedPap=true;}m_bNeedCr=true;}}break;caseRTF_CHPGN:
{OUStringaStr("PAGE");singleChar(cFieldStart);text(aStr);singleChar(cFieldSep,true);singleChar(cFieldEnd);}break;caseRTF_CHFTNSEP:
{staticconstsal_UnicodeuFtnEdnSep=0x3;Mapper().utext(reinterpret_cast<constsal_uInt8*>(&uFtnEdnSep),1);}break;default:{SAL_INFO("writerfilter.rtf","TODO handle symbol '"<<keywordToString(nKeyword)<<"'");aSkip.setParsed(false);}break;}returnRTFError::OK;}}// namespace rtftok}// namespace writerfilter/* vim:set shiftwidth=4 softtabstop=4 expandtab: */