/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source 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.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: IBM Corporation
*
* Copyright: 2008 by IBM Corporation
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
/**
* @file
* For LWP filter architecture prototype - table cell numerics format
*/
#include "lwptblcell.hxx"
#include "lwppara.hxx"
#include "lwptblformula.hxx"
#include "lwptablelayout.hxx"
#include <osl/thread.h>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <memory>
#include <utility>
LwpFormulaArg::~LwpFormulaArg()
{
}
LwpFormulaInfo::LwpFormulaInfo(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
: LwpCellList(objHdr, pStrm)
, m_bSupported(true)
, m_nFormulaRow(0)
{}
LwpFormulaInfo::~LwpFormulaInfo()
{
}
void LwpFormulaInfo::ReadConst()
{
double Constant = m_pObjStrm->QuickReadDouble();
m_aStack.push_back( std::make_unique<LwpFormulaConst>(Constant) );
}
/**
* Need more effort for unicode.
*/
void LwpFormulaInfo::ReadText()
{
m_pObjStrm->QuickReadInt16(); //Disk Size
sal_uInt16 nStrLen = m_pObjStrm->QuickReadInt16();
std::vector<char> aBuf(nStrLen + 1);
m_pObjStrm->QuickRead(aBuf.data(), nStrLen);
aBuf[nStrLen]= '\0';
OUString aText = "\"" +
OUString(aBuf.data(), nStrLen, osl_getThreadTextEncoding()) +
"\"";
m_aStack.push_back(std::make_unique<LwpFormulaText>(aText));
}
void LwpFormulaInfo::ReadCellID()
{
LwpRowSpecifier RowSpecifier;
LwpColumnSpecifier ColumnSpecifier;
RowSpecifier.QuickRead(m_pObjStrm.get());
ColumnSpecifier.QuickRead(m_pObjStrm.get());
m_aStack.push_back( std::make_unique<LwpFormulaCellAddr>(ColumnSpecifier.ColumnID(cColumn),
RowSpecifier.RowID(m_nFormulaRow)) );
}
void LwpFormulaInfo::ReadCellRange()
{
ReadCellID( ); // start
std::unique_ptr<LwpFormulaCellAddr> pStartCellAddr( static_cast<LwpFormulaCellAddr*>(m_aStack.back().release()));
m_aStack.pop_back();
ReadCellID(); // end
std::unique_ptr<LwpFormulaCellAddr> pEndCellAddr(static_cast<LwpFormulaCellAddr*>(m_aStack.back().release()));
m_aStack.pop_back();
m_aStack.push_back( std::make_unique<LwpFormulaCellRangeAddr>(pStartCellAddr->GetCol(),
pStartCellAddr->GetRow(),
pEndCellAddr->GetCol(),
pEndCellAddr->GetRow()) );
}
/**
* Read expression from wordpro file
*/
void LwpFormulaInfo::ReadExpression()
{
sal_uInt16 TokenType, DiskLength;
/* Read the compiled expression length */
m_pObjStrm->SeekRel(2);
bool bError = false;
while ((TokenType = m_pObjStrm->QuickReaduInt16(&bError)) != TK_END)
{
if (bError)
throw std::runtime_error("error reading expression");
// Get the disk length of this token
DiskLength = m_pObjStrm->QuickReaduInt16();
switch (TokenType)
{
case TK_CONSTANT:
{
ReadConst();
break;
}
case TK_CELLID:
ReadCellID();
break;
case TK_CELLRANGE:
ReadCellRange();
break;
case TK_SUM:
case TK_IF:
case TK_COUNT:
case TK_MINIMUM:
case TK_MAXIMUM:
case TK_AVERAGE:
{
std::unique_ptr<LwpFormulaFunc> xFunc(new LwpFormulaFunc(TokenType));
ReadArguments(*xFunc);
m_aStack.push_back(std::move(xFunc));
}
break;
case TK_ADD://7
case TK_SUBTRACT:
case TK_MULTIPLY:
case TK_DIVIDE:
case TK_LESS:
case TK_LESS_OR_EQUAL:
case TK_GREATER:
case TK_GREATER_OR_EQUAL:
case TK_EQUAL:
case TK_NOT_EQUAL:
case TK_AND:
case TK_OR:
case TK_NOT:
m_pObjStrm->SeekRel(DiskLength); // extensible for future
if (m_aStack.size() >= 2)
{//binary operator
std::unique_ptr<LwpFormulaOp> pOp(new LwpFormulaOp(TokenType));
pOp->AddArg(std::move(m_aStack.back())); m_aStack.pop_back();
pOp->AddArg(std::move(m_aStack.back())); m_aStack.pop_back();
m_aStack.push_back(std::move(pOp));
}
break;
case TK_UNARY_MINUS:
if (!m_aStack.empty())
{
std::unique_ptr<LwpFormulaUnaryOp> pOp(new LwpFormulaUnaryOp(TokenType));
pOp->AddArg(std::move(m_aStack.back())); m_aStack.pop_back();
m_aStack.push_back(std::move(pOp));
}
break;
default:
// We don't know what to do with this token, so eat it.
m_pObjStrm->SeekRel(DiskLength);
break;
}
MarkUnsupported(TokenType);
}
}
void LwpFormulaInfo::MarkUnsupported(sal_uInt16 TokenType)
{
switch(TokenType)
{
case TK_IF:
case TK_COUNT:
case TK_NOT:
{
m_bSupported = false;//Not supported formulas
}
break;
default:
break;
}
}
/**
* Read arguments of functions from wordpro file
* @param LwpFormulaFunc& aFunc, functions object
*/
void LwpFormulaInfo::ReadArguments(LwpFormulaFunc& aFunc)
{
sal_uInt16 NumberOfArguments = m_pObjStrm->QuickReaduInt16();
for (sal_uInt16 Count = 0; Count < NumberOfArguments; Count++)
{
sal_uInt8 ArgumentType = static_cast<sal_uInt8>(m_pObjStrm->QuickReaduInt16()); // written as lushort
sal_uInt16 ArgumentDiskLength = m_pObjStrm->QuickReaduInt16();
bool bArgument = true;
switch(ArgumentType)
{
case TK_CELLID:
ReadCellID();
break;
case TK_CELLRANGE:
ReadCellRange();
break;
case TK_CONSTANT:
ReadConst();
break;
case TK_TEXT:
ReadText();
break;
case TK_EXPRESSION:
ReadExpression();
break;
default:
bArgument = false;
m_pObjStrm->SeekRel(ArgumentDiskLength);
break;
}
if (bArgument && !m_aStack.empty())
{
aFunc.AddArg(std::move(m_aStack.back()));
m_aStack.pop_back();
}
}
}
void LwpFormulaInfo::Read()
{
LwpCellList::Read();
{
LwpRowList* pRowList = dynamic_cast<LwpRowList*>(cParent.obj().get());
if (pRowList)
{
m_nFormulaRow = pRowList->GetRowID();
}
else
{
SAL_WARN("lwp", "missing row list");
}
}
m_pObjStrm->SeekRel(2);//flags, size in file: sal_uInt16
LwpNotifyListPersistent cNotifyList;
cNotifyList.Read(m_pObjStrm.get());
ReadExpression();
m_pObjStrm->SkipExtra();
}
/**
* Make the formula string.
*/
OUString LwpFormulaInfo::Convert(LwpTableLayout* pCellsMap)
{
OUString aFormula;
if (m_bSupported)
{
if(1==m_aStack.size())
{
aFormula = m_aStack[0]->ToString(pCellsMap);
}
else
{
assert(false);
}
}
return aFormula;
}
/**
* Fill the XFCell content
*/
void LwpFormulaInfo::Convert(XFCell * pCell,LwpTableLayout* pCellsMap)
{
OUString aFormula = Convert(pCellsMap);
if (!aFormula.isEmpty())
{
pCell->SetFormula(aFormula);
}
LwpCellList::Convert(pCell);
}
LwpFormulaConst::LwpFormulaConst(double dVal)
{
m_dVal = dVal;
}
OUString LwpFormulaConst::ToString(LwpTableLayout* /*pCellsMap*/)
{
return OUString::number(m_dVal);
}
LwpFormulaText::LwpFormulaText( OUString aText) : m_aText(std::move(aText))
{
}
LwpFormulaCellAddr::LwpFormulaCellAddr(sal_Int16 aCol, sal_Int16 aRow)
: m_aCol(aCol), m_aRow(aRow)
{
}
OUString LwpFormulaCellAddr::ToString(LwpTableLayout* pCellsMap)
{
OUString aCellAddr = "<" + LwpFormulaTools::GetCellAddr(m_aRow,m_aCol,pCellsMap) + ">";
return aCellAddr;
}
LwpFormulaCellRangeAddr::LwpFormulaCellRangeAddr(sal_Int16 aStartCol,
sal_Int16 aStartRow,
sal_Int16 aEndCol,
sal_Int16 aEndRow)
: m_aStartCol(aStartCol), m_aStartRow(aStartRow),
m_aEndCol(aEndCol), m_aEndRow(aEndRow)
{
}
/**
* Convert the cell range into a string
*/
OUString LwpFormulaCellRangeAddr::ToString(LwpTableLayout* pCellsMap)
{
OUString aCellAddr = "<"
+ LwpFormulaTools::GetCellAddr(m_aStartRow,m_aStartCol,pCellsMap) + ":"
+ LwpFormulaTools::GetCellAddr(m_aEndRow,m_aEndCol,pCellsMap) + ">";
return aCellAddr;
}
LwpFormulaFunc::LwpFormulaFunc(sal_uInt16 nTokenType) : m_nTokenType(nTokenType)
{
}
LwpFormulaFunc::~LwpFormulaFunc()
{
}
void LwpFormulaFunc::AddArg(std::unique_ptr<LwpFormulaArg> pArg)
{
m_aArgs.push_back(std::move(pArg));
}
/**
* Convert the functions to a string, which is an argument of other formula
*/
OUString LwpFormulaFunc::ToArgString(LwpTableLayout* pCellsMap)
{
return "(" + ToString(pCellsMap) + ")";
}
/**
* Convert the function to a formula string.
*/
OUString LwpFormulaFunc::ToString(LwpTableLayout* pCellsMap)
{
OUStringBuffer aFormula;
OUString aFuncName = LwpFormulaTools::GetName(m_nTokenType);
aFormula.append(aFuncName +
" ");//Append a blank space
//Append args
for (auto const& elem : m_aArgs)
{
aFormula.append(elem->ToArgString(pCellsMap) + "|"); //separator
}
//erase the last "|"
if (!m_aArgs.empty())
{
aFormula.setLength(aFormula.getLength()-1);
}
else
{
assert(false);
}
return aFormula.makeStringAndClear();
}
/**
* Convert the formula in operators to a string : e.g. 1+2+3
*/
OUString LwpFormulaOp::ToString(LwpTableLayout* pCellsMap)
{
OUString aFormula;
if (2==m_aArgs.size())
{
aFormula += m_aArgs[1]->ToArgString(pCellsMap) + " ";
OUString aFuncName = LwpFormulaTools::GetName(m_nTokenType);
aFormula += aFuncName + " " +
m_aArgs[0]->ToArgString(pCellsMap);
}
else
{
assert(false);
}
return aFormula;
}
/**
* convert the formula in unary operators into string : e.g. -2
*/
OUString LwpFormulaUnaryOp::ToString(LwpTableLayout* pCellsMap)
{
OUString aFormula;
if (1==m_aArgs.size())
{
OUString aFuncName = LwpFormulaTools::GetName(m_nTokenType);
aFormula += aFuncName +
m_aArgs[0]->ToArgString(pCellsMap);
}
else
{
assert(false);
}
return aFormula;
}
/**
* Get token name
*/
OUString LwpFormulaTools::GetName(sal_uInt16 nTokenType)
{
OUString aName;
switch(nTokenType)
{
case TK_SUM:
aName = "SUM";
break;
case TK_IF:
aName = "IF";//Not supported by SODC
break;
case TK_COUNT:
aName = "COUNT";//Not supported by SODC
break;
case TK_MINIMUM:
aName = "MIN";
break;
case TK_MAXIMUM:
aName = "MAX";
break;
case TK_AVERAGE:
aName = "MEAN";
break;
case TK_ADD:
aName = "+";
break;
case TK_SUBTRACT:
aName = "-";
break;
case TK_MULTIPLY:
aName = "*";
break;
case TK_DIVIDE:
aName = "/";
break;
case TK_UNARY_MINUS:
aName = "-";
break;
case TK_LESS:
aName = "L";
break;
case TK_LESS_OR_EQUAL:
aName = "LEQ";
break;
case TK_GREATER:
aName = "G";
break;
case TK_GREATER_OR_EQUAL:
aName = "GEQ";
break;
case TK_EQUAL:
aName = "EQ";
break;
case TK_NOT_EQUAL:
aName = "NEQ";
break;
case TK_NOT:
aName = "NOT";
break;
case TK_AND:
aName = "AND";
break;
case TK_OR:
aName = "OR";
break;
default:
assert(false);
break;
}
return aName;
}
/**
* Get cell address in String
*/
OUString LwpFormulaTools::GetCellAddr(sal_Int16 nRow, sal_Int16 nCol, LwpTableLayout* pCellsMap)
{
OUString aCellAddr;
XFCell* pCell = pCellsMap->GetCellsMap(nRow,static_cast<sal_uInt8>(nCol));
if (pCell)
{
aCellAddr = pCell->GetCellName();
}
else
{
assert( -1==nRow || -1==static_cast<sal_Int8>(nCol));
}
return aCellAddr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1037 Two or more case-branches perform the same actions. Check lines: 513, 522