/* -*- 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 layouts
*/
#include <lwpglobalmgr.hxx>
#include "lwptablelayout.hxx"
#include <lwpfoundry.hxx>
#include "lwpholder.hxx"
#include "lwptable.hxx"
#include "lwptblcell.hxx"
#include "lwprowlayout.hxx"
#include <lwpfilehdr.hxx>
#include <xfilter/xfstylemanager.hxx>
#include <xfilter/xftablestyle.hxx>
#include <xfilter/xfrow.hxx>
#include <xfilter/xfrowstyle.hxx>
#include <xfilter/xfcell.hxx>
#include <xfilter/xfcolstyle.hxx>
#include <xfilter/xfframestyle.hxx>
#include <xfilter/xfframe.hxx>
#include <xfilter/xffloatframe.hxx>
#include "lwpframelayout.hxx"
#include <xfilter/xfnumberstyle.hxx>
#include <xfilter/xfparastyle.hxx>
#include <o3tl/sorted_vector.hxx>
#include <sal/log.hxx>
#include <comphelper/configuration.hxx>
#include <algorithm>
#include <memory>
LwpSuperTableLayout::LwpSuperTableLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
: LwpPlacableLayout(objHdr, pStrm)
{
m_pFrame.reset(new LwpFrame(this) );
}
LwpSuperTableLayout::~LwpSuperTableLayout()
{
}
/**
* @short Read super table layout record
*/
void LwpSuperTableLayout::Read()
{
LwpPlacableLayout::Read();
m_pObjStrm->SkipExtra();
}
/**
* @short Get child table layout
* @return pointer to table layout
*/
LwpTableLayout* LwpSuperTableLayout::GetTableLayout()
{
LwpObjectID *pID = &GetChildTail();
o3tl::sorted_vector<LwpObjectID*> aSeen;
while (pID && !pID->IsNull())
{
bool bAlreadySeen = !aSeen.insert(pID).second;
if (bAlreadySeen)
throw std::runtime_error("loop in conversion");
LwpLayout* pLayout = dynamic_cast<LwpLayout*>(pID->obj().get());
if (!pLayout)
break;
if (pLayout->GetLayoutType() == LWP_TABLE_LAYOUT)
return dynamic_cast<LwpTableLayout *>(pLayout);
pID = &pLayout->GetPrevious();
}
return nullptr;
}
/**
* @short Get effective heading table layout, the one just before table layout is the only one which is effective
* @return LwpTableHeadingLayout* - pointer to table heading layout
*/
LwpTableHeadingLayout* LwpSuperTableLayout::GetTableHeadingLayout()
{
LwpObjectID *pID = &GetChildTail();
o3tl::sorted_vector<LwpObjectID*> aSeen;
while (pID && !pID->IsNull())
{
bool bAlreadySeen = !aSeen.insert(pID).second;
if (bAlreadySeen)
throw std::runtime_error("loop in conversion");
LwpLayout * pLayout = dynamic_cast<LwpLayout *>(pID->obj().get());
if (!pLayout)
break;
if (pLayout->GetLayoutType() == LWP_TABLE_HEADING_LAYOUT)
return dynamic_cast<LwpTableHeadingLayout *>(pLayout);
pID = &pLayout->GetPrevious();
}
return nullptr;
}
/**
* @short Register super table layout style
*/
void LwpSuperTableLayout::RegisterNewStyle()
{
// if this layout is style of real table entry
LwpTableLayout* pTableLayout = GetTableLayout();
if (pTableLayout != nullptr)
{
pTableLayout->SetFoundry(m_pFoundry);
pTableLayout->RegisterStyle();
}
}
/**
* @short Judge whether table size is according to content, borrowed from Word Pro code
* @param
* @return sal_Bool
*/
bool LwpSuperTableLayout::IsSizeRightToContent()
{
/* Only "with paragraph above" tables can size right to content. */
if (GetRelativeType() == LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE)
return LwpPlacableLayout::IsSizeRightToContent();
return false;
}
/**
* @short Judge whether table is justifiable, borrowed from Word Pro code
* @param
* @return sal_Bool
*/
bool LwpSuperTableLayout::IsJustifiable()
{
return (GetRelativeType() != LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE || IsSizeRightToContent());
}
/**
* @short Get width of frame outside table
* @param pTableStyle - pointer of XFTableStyle
* @return double - table width
*/
double LwpSuperTableLayout::GetWidth()
{
double dWidth = GetTableWidth();
double dLeft = GetMarginsValue(MARGIN_LEFT);
double dRight = GetMarginsValue(MARGIN_RIGHT);
return (dWidth + dLeft + dRight);
}
/**
* @short Get width of table
* @param pTableStyle - pointer of XFTableStyle
* @return double - table width
*/
double LwpSuperTableLayout::GetTableWidth()
{
sal_Int32 nWidth = 0;
if(!IsJustifiable() || ((nWidth = LwpMiddleLayout::GetMinimumWidth()) <= 0))
{
LwpTableLayout* pTableLayout = GetTableLayout();
if(!pTableLayout)
{
SAL_WARN("lwp", "missing table layout, early return");
return 0;
}
LwpTable *pTable = pTableLayout->GetTable();
if(!pTable)
{
SAL_WARN("lwp", "missing table, early return");
return 0;
}
double dDefaultWidth = pTable->GetWidth();
sal_uInt16 nCol = pTable->GetColumn();
double dWidth = 0;
for(sal_uInt16 i =0; i< nCol; i++)
{
LwpObjectID *pColumnID = &pTableLayout->GetColumnLayoutHead();
LwpColumnLayout * pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
double dColumnWidth = dDefaultWidth;
o3tl::sorted_vector<LwpColumnLayout*> aSeen;
while (pColumnLayout)
{
bool bAlreadySeen = !aSeen.insert(pColumnLayout).second;
if (bAlreadySeen)
throw std::runtime_error("loop in conversion");
if(pColumnLayout->GetColumnID() == i)
{
dColumnWidth = pColumnLayout->GetWidth();
break;
}
pColumnID = &pColumnLayout->GetNext();
pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
}
dWidth += dColumnWidth;
}
return dWidth;
}
double dLeft = GetMarginsValue(MARGIN_LEFT);
double dRight = GetMarginsValue(MARGIN_RIGHT);
return LwpTools::ConvertFromUnits(nWidth) - dLeft - dRight;
}
/**
* @short Apply shadow to table
* @param pTableStyle - pointer of XFTableStyle
* @return
*/
void LwpSuperTableLayout::ApplyShadow(XFTableStyle *pTableStyle)
{
// use shadow property of supertable
std::unique_ptr<XFShadow> pXFShadow(GetXFShadow());
if(pXFShadow)
{
pTableStyle->SetShadow(pXFShadow->GetPosition(), pXFShadow->GetOffset(), pXFShadow->GetColor());
}
}
/**
* @short Apply pattern fill to table style
* @param pTableStyle - pointer of XFTableStyle
* @return
*/
void LwpSuperTableLayout::ApplyPatternFill(XFTableStyle* pTableStyle)
{
std::unique_ptr<XFBGImage> xXFBGImage(GetFillPattern());
if (xXFBGImage)
{
pTableStyle->SetBackImage(xXFBGImage);
}
}
/**
* @short Apply background to table style
* @param pTableStyle - pointer of XFTableStyle
* @return
*/
void LwpSuperTableLayout::ApplyBackGround(XFTableStyle* pTableStyle)
{
if (IsPatternFill())
{
ApplyPatternFill(pTableStyle);
}
else
{
ApplyBackColor(pTableStyle);
}
}
/**
* @short Apply back color to table
* @param pTableStyle - pointer of XFTableStyle
* @return
*/
void LwpSuperTableLayout::ApplyBackColor(XFTableStyle *pTableStyle)
{
LwpColor* pColor = GetBackColor();
if(pColor && pColor->IsValidColor())
{
XFColor aColor(pColor->To24Color());
pTableStyle->SetBackColor(aColor);
}
}
/**
* @short Apply watermark to table
* @param pTableStyle - pointer of XFTableStyle
* @return
*/
void LwpSuperTableLayout::ApplyWatermark(XFTableStyle *pTableStyle)
{
std::unique_ptr<XFBGImage> xBGImage(GetXFBGImage());
if (xBGImage)
{
pTableStyle->SetBackImage(xBGImage);
}
}
/**
* @short Apply alignment to table
* @param pTableStyle - pointer of XFTableStyle
* @return
*/
void LwpSuperTableLayout::ApplyAlignment(XFTableStyle * pTableStyle)
{
LwpPoint aPoint;
if (LwpLayoutGeometry* pGeometry = GetGeometry())
aPoint = pGeometry->GetOrigin();
double dXOffset = LwpTools::ConvertFromUnits(aPoint.GetX());
// add left padding to alignment distance
double dLeft = GetMarginsValue(MARGIN_LEFT);
pTableStyle->SetAlign(enumXFAlignStart, dXOffset+ dLeft);
}
/**
* @short Add table to container
* @param pCont - pointer of container
* @return pCont
*/
void LwpSuperTableLayout::XFConvert(XFContentContainer* pCont)
{
if ( LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE == GetRelativeType()
&& (!GetContainerLayout().is() || !GetContainerLayout()->IsCell()) )
{
LwpTableLayout * pTableLayout = GetTableLayout();
if (pTableLayout)
{
pTableLayout->XFConvert(pCont);
}
}
else if(IsRelativeAnchored())
{
//anchor to paragraph except "with paragraph above"
XFConvertFrame(pCont);
}
else if(m_pFrame)
{
//anchor to page, frame, cell
m_pFrame->XFConvert(pCont);
}
}
/**
* @short convert frame which anchor to page
* @param
* @return
*/
void LwpSuperTableLayout::XFConvertFrame(XFContentContainer* pCont, sal_Int32 nStart, sal_Int32 nEnd, bool bAll)
{
if(!m_pFrame)
return;
rtl::Reference<XFFrame> xXFFrame;
if(nEnd < nStart)
{
xXFFrame.set(new XFFrame);
}
else
{
xXFFrame.set(new XFFloatFrame(nStart, nEnd, bAll));
}
m_pFrame->Parse(xXFFrame.get(), static_cast<sal_uInt16>(nStart));
//parse table, and add table to frame
LwpTableLayout * pTableLayout = GetTableLayout();
if (pTableLayout)
{
pTableLayout->XFConvert(xXFFrame.get());
}
//add frame to the container
pCont->Add(xXFFrame.get());
}
/**
* @short register frame style
* @param
* @return
*/
void LwpSuperTableLayout::RegisterFrameStyle()
{
std::unique_ptr<XFFrameStyle> xFrameStyle(new XFFrameStyle);
m_pFrame->RegisterStyle(xFrameStyle);
}
LwpTableLayout::LwpTableLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
: LwpLayout(objHdr, pStrm)
, m_nRows(0)
, m_nCols(0)
, m_pDefaultCellLayout(nullptr)
, m_bConverted(false)
{
}
/**
* @short Get neighbour cell by specifying ROW+COL
* @param nRow
* @param nCol
* @return LwpCellLayout *
*/
LwpCellLayout * LwpTableLayout::GetCellByRowCol(sal_uInt16 nRow, sal_uInt16 nCol)
{
if (nRow >= m_nRows || nCol >= m_nCols)
return nullptr;
return m_WordProCellsMap[static_cast<size_t>(nRow)*m_nCols + nCol];
}
/**
* @short traverse all table cells
* @param
* @param
* @param
*/
void LwpTableLayout::TraverseTable()
{
sal_uInt32 nCount = m_nRows*m_nCols;
// new cell map nRow*nCOl and initialize
m_WordProCellsMap.insert(m_WordProCellsMap.end(), nCount, m_pDefaultCellLayout);
// set value
LwpObjectID* pRowID = &GetChildHead();
LwpRowLayout * pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
o3tl::sorted_vector<LwpRowLayout*> aSeen;
while (pRowLayout)
{
bool bAlreadySeen = !aSeen.insert(pRowLayout).second;
if (bAlreadySeen)
throw std::runtime_error("loop in conversion");
pRowLayout->SetRowMap();
// for 's analysis job
m_RowsMap[pRowLayout->GetRowID()] = pRowLayout;
pRowLayout->CollectMergeInfo();
// end for 's analysis
pRowID = &pRowLayout->GetNext();
pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
}
}
/**
* @short search the cell map
* @param nRow - row id (0 based)
* @param nRow - row id (0 based)
* @return LwpObjectID * - pointer to cell story object ID
*/
LwpObjectID * LwpTableLayout::SearchCellStoryMap(sal_uInt16 nRow, sal_uInt16 nCol)
{
if (nRow >= m_nRows || nCol >= m_nCols )
{
return nullptr;
}
LwpCellLayout * pCell = GetCellByRowCol(nRow, nCol);
if (pCell)
{
// maybe connected cell layout
// maybe default cell layout
if (nRow != pCell->GetRowID() || nCol != pCell->GetColID())
{
return nullptr;
}
return &pCell->GetContent();
}
return nullptr;
}
/**
* @short Get parent super table layout of table layout
* @return LwpSuperTableLayout * - pointer of parent super table layout
*/
LwpSuperTableLayout * LwpTableLayout::GetSuperTableLayout()
{
return dynamic_cast<LwpSuperTableLayout *>(GetParent().obj().get());
}
/**
* @short Get table pointer
* @return LwpTable * - content table pointer
*/
LwpTable * LwpTableLayout::GetTable()
{
return dynamic_cast<LwpTable *>(m_Content.obj().get());
}
/**
* @short Get column style name by column ID
* @param sal_uInt16 -- col id(0 based)
* @return OUString - name of column style
*/
OUString LwpTableLayout::GetColumnWidth(sal_uInt16 nCol)
{
if (nCol >= m_nCols)
{
assert(false);
return m_DefaultColumnStyleName;
}
LwpColumnLayout * pCol = m_aColumns[nCol];
if (pCol)
{
return pCol->GetStyleName();
}
return m_DefaultColumnStyleName;
}
/**
* @short analyze all columns to get whole table width and width of all columns
* @short and register all column styles
* @param none
*/
void LwpTableLayout::RegisterColumns()
{
LwpTable* pTable = GetTable();
if (!pTable)
throw std::range_error("corrupt LwpTableLayout");
LwpSuperTableLayout* pSuper = GetSuperTableLayout();
if (!pSuper)
throw std::range_error("corrupt LwpTableLayout");
sal_uInt16 nCols = m_nCols;
m_aColumns.resize(nCols);
std::unique_ptr<bool[]> pWidthCalculated( new bool[nCols] );
for(sal_uInt16 i=0;i<nCols; i++)
{
pWidthCalculated[i] = false;
m_aColumns[i] = nullptr;
}
double dDefaultColumn = pTable->GetWidth();
sal_uInt16 nJustifiableColumn = nCols;
double dTableWidth = pSuper->GetTableWidth();
// Get total width of justifiable columns
// NOTICE: all default columns are regarded as justifiable columns
LwpObjectID* pColumnID = &GetColumnLayoutHead();
LwpColumnLayout * pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
o3tl::sorted_vector<LwpColumnLayout*> aSeen;
while (pColumnLayout)
{
bool bAlreadySeen = !aSeen.insert(pColumnLayout).second;
if (bAlreadySeen)
throw std::runtime_error("loop in conversion");
auto nColId = pColumnLayout->GetColumnID();
if (nColId >= nCols)
{
throw std::range_error("corrupt LwpTableLayout");
}
m_aColumns[nColId] = pColumnLayout;
if (!pColumnLayout->IsJustifiable())
{
pWidthCalculated[nColId] = true;
dTableWidth -= pColumnLayout->GetWidth();
nJustifiableColumn --;
}
pColumnID = &pColumnLayout->GetNext();
pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColumnID->obj().get());
}
// if all columns are not justifiable, the rightmost column will be changed to justifiable
if (nJustifiableColumn == 0 && nCols != 0)
{
nJustifiableColumn ++;
if (m_aColumns[nCols - 1])
{
pWidthCalculated[nCols-1] = false;
dTableWidth += m_aColumns[nCols-1]->GetWidth();
}
else
{
// this can't happen
dTableWidth = dDefaultColumn;
assert(false);
}
}
// justifiable columns will share the remain width averagely
dDefaultColumn = nJustifiableColumn ? dTableWidth/nJustifiableColumn : 0;
// register default column style
std::unique_ptr<XFColStyle> xColStyle(new XFColStyle);
xColStyle->SetWidth(static_cast<float>(dDefaultColumn));
XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
m_DefaultColumnStyleName = pXFStyleManager->AddStyle(std::move(xColStyle)).m_pStyle->GetStyleName();
// register existed column style
sal_uInt16 i=0;
for( i=0;i<nCols; i++)
{
if (m_aColumns[i])
{
m_aColumns[i]->SetFoundry(m_pFoundry);
if(!pWidthCalculated[i])
{
// justifiable ----register style with calculated value
m_aColumns[i]->SetStyleName(m_DefaultColumnStyleName);
}
else
{
// not justifiable ---- register style with original value
m_aColumns[i]->RegisterStyle(m_aColumns[i]->GetWidth());
}
}
}
}
/**
* @short register all row styles
* @param none
*/
void LwpTableLayout::RegisterRows()
{
LwpTable * pTable = GetTable();
if (pTable == nullptr)
{
assert(false);
return;
}
// register default row style
std::unique_ptr<XFRowStyle> xRowStyle(new XFRowStyle);
if (m_nDirection & 0x0030)
{
xRowStyle->SetMinRowHeight(static_cast<float>(pTable->GetHeight()));
}
else
{
xRowStyle->SetRowHeight(static_cast<float>(pTable->GetHeight()));
}
XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
m_DefaultRowStyleName = pXFStyleManager->AddStyle(std::move(xRowStyle)).m_pStyle->GetStyleName();
// register style of rows
LwpObjectID * pRowID = &GetChildHead();
LwpRowLayout * pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
while (pRowLayout)
{
pRowLayout->SetFoundry(m_pFoundry);
pRowLayout->RegisterStyle();
pRowID = &pRowLayout->GetNext();
pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
}
}
/**
* @short register table style, if needed, including frame style
* @param none
*/
void LwpTableLayout::RegisterStyle()
{
// get super table layout
LwpSuperTableLayout * pSuper = GetSuperTableLayout();
if (!pSuper)
return;
// get table
LwpTable * pTable = GetTable();
if (pTable == nullptr)
{
SAL_WARN("lwp", "missing table, early return");
return;
}
// get row/column number of this table
m_nRows = pTable->GetRow();
m_nCols = pTable->GetColumn();
//http://www.danielsays.com/ss-gallery-win1x2x3x-lotus-word-pro-96.html
//tables with up to 255 rows and 8192 columns
//the row limit tallies with the casting of m_nCols to an unsigned char
//elsewhere
if (m_nRows > MAX_NUM_ROWS)
throw std::runtime_error("max legal row exceeded");
if (m_nCols > MAX_NUM_COLS)
throw std::runtime_error("max legal column exceeded");
// get default cell layout of current table
LwpObjectID& rID= pTable->GetDefaultCellStyle();
m_pDefaultCellLayout = dynamic_cast<LwpCellLayout *>(rID.obj().get());
// register columns styles
RegisterColumns();
// register style of whole table
std::unique_ptr<XFTableStyle> xTableStyle(new XFTableStyle);
sal_uInt8 nType = pSuper->GetRelativeType();
// If the table is not "with paragraph above" placement, create an frame style
// by supertable layout
if ( LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE == nType
&& (!pSuper->GetContainerLayout().is() || !pSuper->GetContainerLayout()->IsCell()) )
{
//with para above
pSuper->ApplyBackGround(xTableStyle.get());
pSuper->ApplyWatermark(xTableStyle.get());
pSuper->ApplyShadow(xTableStyle.get());
pSuper->ApplyAlignment(xTableStyle.get());
xTableStyle->SetWidth(pSuper->GetTableWidth());
}
else
{
pSuper->RegisterFrameStyle();
xTableStyle->SetAlign(enumXFAlignCenter);
xTableStyle->SetWidth(pSuper->GetTableWidth());
}
XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
m_StyleName = pXFStyleManager->AddStyle(std::move(xTableStyle)).m_pStyle->GetStyleName();
//convert to OO table now and register row style traverse
TraverseTable();
SplitConflictCells();
// Register rows layouts, it must be after SplitConflictCells
RegisterRows();
// Parse table
ParseTable();
// the old code doesn't check if the LwpFoundry pointer is NULL,
// so the NULL pointer cause sodc freeze. Add code to check the pointer.
if (GetFoundry())
PutCellVals(GetFoundry(), pTable->GetObjectID());
}
/**
* @short read table layout
* @param none
*/
void LwpTableLayout::ParseTable()
{
// get super table layout
LwpSuperTableLayout* pSuper = GetSuperTableLayout();
if (!pSuper)
{
throw std::runtime_error("missing super table");
}
if (m_pXFTable)
{
throw std::runtime_error("this table is already parsed");
}
// set name of object
m_pXFTable.set(new XFTable);
m_pXFTable->SetTableName(pSuper->GetName().str());
// set table style
m_pXFTable->SetStyleName(m_StyleName);
sal_uInt16 nRow = m_nRows;
sal_uInt8 nCol = static_cast<sal_uInt8>(m_nCols);
sal_uInt16 nContentRow = 0;
//process header rows
LwpTableHeadingLayout* pTableHeading;
pTableHeading = pSuper->GetTableHeadingLayout();
if (pTableHeading)
{
sal_uInt16 nStartHeadRow;
sal_uInt16 nEndHeadRow;
pTableHeading->GetStartEndRow(nStartHeadRow, nEndHeadRow);
SAL_WARN_IF(nEndHeadRow == SAL_MAX_UINT16, "lwp", "invalid End Head Row of: " << nEndHeadRow);
if (nStartHeadRow == 0 && nEndHeadRow != SAL_MAX_UINT16)
{
if (comphelper::IsFuzzing() && nEndHeadRow - nStartHeadRow > 128)
{
SAL_WARN("lwp", "truncating HeadingRow for fuzzing performance");
nEndHeadRow = nStartHeadRow + 128;
}
nContentRow = ConvertHeadingRow(m_pXFTable, nStartHeadRow, o3tl::sanitizing_inc(nEndHeadRow));
}
}
ConvertTable(m_pXFTable, nContentRow, nRow, 0, nCol);
}
/**
* @short read table layout
* @param none
*/
void LwpTableLayout::Read()
{
LwpLayout::Read();
// before layout hierarchy rework!
if(LwpFileHeader::m_nFileRevision < 0x000b)
{
assert(false);
}
m_ColumnLayout.ReadIndexed(m_pObjStrm.get());
m_pObjStrm->SkipExtra();
}
/**
* @short Convert table
* @param
* @return pCont - container which will contain table
*/
void LwpTableLayout::XFConvert(XFContentContainer* pCont)
{
if (!m_pXFTable)
return;
if (m_bConverted)
throw std::runtime_error("already added to a container");
pCont->Add(m_pXFTable.get());
m_bConverted = true;
}
/**
* @short convert heading row
* @param pXFTable - pointer of table
* @param nStartRow - start heading row ID
* @param nEndRow - end heading row ID
*/
sal_uInt16 LwpTableLayout::ConvertHeadingRow(
rtl::Reference<XFTable> const & pXFTable, sal_uInt16 nStartHeadRow, sal_uInt16 nEndHeadRow)
{
sal_uInt16 nContentRow;
LwpTable* pTable = GetTable();
assert(pTable);
sal_uInt8 nCol = static_cast<sal_uInt8>(pTable->GetColumn());
rtl::Reference<XFTable> pTmpTable( new XFTable );
ConvertTable(pTmpTable,nStartHeadRow,nEndHeadRow,0,nCol);
sal_uInt16 nRowNum = pTmpTable->GetRowCount();
std::vector<sal_uInt8> CellMark(nRowNum);
if (nRowNum == 1)
{
XFRow* pXFRow = pTmpTable->GetRow(1);
pXFTable->AddHeaderRow(pXFRow);
pTmpTable->RemoveRow(1);
nContentRow = nEndHeadRow;
}
else
{
sal_uInt8 nFirstColSpann = 1;
const bool bFindFlag = FindSplitColMark(pTmpTable.get(), CellMark, nFirstColSpann);
if (bFindFlag)//split to 2 cells
{
SplitRowToCells(pTmpTable.get(), pXFTable, nFirstColSpann, CellMark.data());
nContentRow = nEndHeadRow;
}
else//can not split,the first row will be the heading row,the rest will be content row
{
XFRow* pXFRow = pTmpTable->GetRow(1);
pXFTable->AddHeaderRow(pXFRow);
pTmpTable->RemoveRow(1);
auto iter = m_RowsMap.find(0);
if (iter == m_RowsMap.end())
{
SAL_WARN("lwp", "row 0 is unknown");
nContentRow = 0;
}
else
nContentRow = iter->second->GetCurMaxSpannedRows(0,nCol);
}
}
return nContentRow;
}
void LwpTableLayout::SplitRowToCells(XFTable* pTmpTable, rtl::Reference<XFTable> const & pXFTable,
sal_uInt8 nFirstColSpann,const sal_uInt8* pCellMark)
{
sal_uInt16 i;
sal_uInt16 nRowNum = pTmpTable->GetRowCount();
LwpTable* pTable = GetTable();
assert(pTable);
sal_uInt8 nCol = static_cast<sal_uInt8>(pTable->GetColumn());
rtl::Reference<XFRow> xXFRow(new XFRow);
//register style for heading row
double fHeight = 0;
std::unique_ptr<XFRowStyle> xRowStyle(new XFRowStyle);
XFRow* pRow = pTmpTable->GetRow(1);
if (!pRow)
throw std::runtime_error("missing row");
OUString styleName = pRow->GetStyleName();
// get settings of the row and assign them to new row style
XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
XFRowStyle *pTempRowStyle = static_cast<XFRowStyle*>(pXFStyleManager->FindStyle(styleName));
if (pTempRowStyle)
*xRowStyle = *pTempRowStyle;
for (i=1;i<=nRowNum;i++)
{
styleName = pTmpTable->GetRow(i)->GetStyleName();
if (XFRowStyle* pRowStyle = static_cast<XFRowStyle*>(pXFStyleManager->FindStyle(styleName)))
fHeight+=pRowStyle->GetRowHeight();
}
if (m_nDirection & 0x0030)
{
xRowStyle->SetMinRowHeight(static_cast<float>(fHeight));
}
else
{
xRowStyle->SetRowHeight(static_cast<float>(fHeight));
}
xXFRow->SetStyleName(pXFStyleManager->AddStyle(std::move(xRowStyle)).m_pStyle->GetStyleName());
//construct heading row
rtl::Reference<XFCell> xXFCell1(new XFCell);
rtl::Reference<XFCell> xXFCell2(new XFCell);
rtl::Reference<XFTable> xSubTable1(new XFTable);
rtl::Reference<XFTable> xSubTable2(new XFTable);
rtl::Reference<XFCell> xNewCell;
for (i=1;i<=nRowNum;i++)
{
XFRow* pOldRow = pTmpTable->GetRow(i);
rtl::Reference<XFRow> xNewRow(new XFRow);
xNewRow->SetStyleName(pOldRow->GetStyleName());
for (sal_uInt8 j=1;j<=pCellMark[i];j++)
{
xNewCell = pOldRow->GetCell(j);
xNewRow->AddCell(xNewCell);
}
xSubTable1->AddRow(xNewRow);
}
ConvertColumn(xSubTable1, 0, nFirstColSpann);//add column info
xXFCell1->Add(xSubTable1.get());
xXFCell1->SetColumnSpaned(nFirstColSpann);
xXFRow->AddCell(xXFCell1);
for (i=1;i<=nRowNum;i++)
{
XFRow* pOldRow = pTmpTable->GetRow(i);
rtl::Reference<XFRow> xNewRow(new XFRow);
xNewRow->SetStyleName(pOldRow->GetStyleName());
for(sal_Int32 j=pCellMark[i]+1;j<=pOldRow->GetCellCount();j++)
{
xNewCell = pOldRow->GetCell(j);
xNewRow->AddCell(xNewCell);
}
xSubTable2->AddRow(xNewRow);
}
ConvertColumn(xSubTable2, nFirstColSpann, nCol);//add column info
xXFCell2->Add(xSubTable2.get());
xXFCell2->SetColumnSpaned(nCol-nFirstColSpann);
xXFRow->AddCell(xXFCell2);
pXFTable->AddHeaderRow(xXFRow.get());
//remove tmp table
for (i=1;i<=nRowNum;i++)
{
pTmpTable->RemoveRow(i);
}
}
/**
* @short find if the heading rows can be split to 2 cells
* @param pXFTable - pointer of tmp XFtable
* @param CellMark - pointer of cell mark array
*/
bool LwpTableLayout::FindSplitColMark(XFTable* pXFTable, std::vector<sal_uInt8>& rCellMark,
sal_uInt8& nMaxColSpan)
{
sal_uInt16 nRowNum = pXFTable->GetRowCount();
sal_uInt8 nColNum = static_cast<sal_uInt8>(pXFTable->GetColumnCount());
sal_uInt8 nCount;
sal_uInt8 nColSpan;
bool bFindFlag = false;
XFRow* pTmpRow;
for(sal_uInt8 i=1;i<=nColNum;i++)
{
sal_uInt16 nRowLoop;
//find current max column span
nMaxColSpan = 1;
for (nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)
{
nColSpan = 0;
for(sal_uInt8 nCellLoop=1; nCellLoop<i+1; nCellLoop++)
{
pTmpRow = pXFTable->GetRow(nRowLoop);
XFCell* pCell = pTmpRow->GetCell(nCellLoop);
if (pCell)
nColSpan += static_cast<sal_uInt8>(pCell->GetColSpaned());
else
return false;
}
if (nColSpan > nMaxColSpan)
nMaxColSpan = nColSpan;
rCellMark.at(nRowLoop) = 0;//reset all cell mark to zero
}
//find if other row has the same column
for (nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)
{
pTmpRow = pXFTable->GetRow(nRowLoop);
nCount = 0;
sal_Int32 nCellMark = 0;
for (sal_Int32 nCellLoop=1; nCellLoop<=pTmpRow->GetCellCount(); nCellLoop++)
{
if (nCount>nMaxColSpan)
break;
nCount+= static_cast<sal_uInt8>(pTmpRow->GetCell(nCellLoop)->GetColSpaned());
if (nCount == nMaxColSpan)
{
nCellMark = nCellLoop;
break;
}
}
if (nCellMark == 0)
break;
else
rCellMark.at(nRowLoop) = nCellMark;
}
for(nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)//check if all ==0,break
{
if (rCellMark.at(nRowLoop) == 0)
break;
}
if (nRowLoop == nRowNum+1)
{
bFindFlag = true;
return bFindFlag;
}
}
return bFindFlag;
}
static bool operator==(const TableConvertAttempt& a, const TableConvertAttempt& b)
{
return a.mnStartRow == b.mnStartRow &&
a.mnEndRow == b.mnEndRow &&
a.mnStartCol== b.mnStartCol &&
a.mnEndCol == b.mnEndCol;
}
/**
* @short convert word pro table to SODC table
* @param pXFTable - pointer of table
* @param nStartRow - start row ID
* @param nEndRow - end row ID
* @param nStartCol - start column ID
* @param nEndCol - end column ID
*/
void LwpTableLayout::ConvertTable(rtl::Reference<XFTable> const & pXFTable, sal_uInt16 nStartRow,
sal_uInt16 nEndRow,sal_uInt8 nStartCol,sal_uInt8 nEndCol)
{
TableConvertAttempt aConversionAttempt(nStartRow, nEndRow, nStartCol, nEndCol);
auto itr = std::find(m_aConvertingStack.begin(), m_aConvertingStack.end(), aConversionAttempt);
if (itr != m_aConvertingStack.end())
{
SAL_WARN("lwp", "already trying to convert this range");
return;
}
m_aConvertingStack.push_back(aConversionAttempt);
//out put column info TO BE CHANGED
ConvertColumn(pXFTable,nStartCol,nEndCol);
std::map<sal_uInt16,LwpRowLayout*>::iterator iter;
for (sal_uInt16 i=nStartRow; i<nEndRow;)
{
iter = m_RowsMap.find(i);
if (iter == m_RowsMap.end())
{
ConvertDefaultRow(pXFTable,nStartCol,nEndCol,i);
i++;
}
else
{
LwpRowLayout* pRow = iter->second;
if (pRow->GetCurMaxSpannedRows(nStartCol,nEndCol) == 1)
{
pRow->ConvertCommonRow(pXFTable,nStartCol,nEndCol);
i++;
}
else
{
pRow->ConvertRow(pXFTable,nStartCol,nEndCol);
i += pRow->GetCurMaxSpannedRows(nStartCol,nEndCol);
}
}
}
m_aConvertingStack.pop_back();
}
/**
* @short apply numeric value and formula to cell
* @param pFoundry - pointer of foundry
* @param aTableID - table ID
*/
void LwpTableLayout::PutCellVals(LwpFoundry* pFoundry, LwpObjectID aTableID)
{
// The old code doesn't check if the LwpFoundry pointer is NULL, so the NULL
// pointer cause sodc frozen. Add code to check the pointer.
if( !pFoundry ) return;
try{
LwpDLVListHeadHolder* pHolder = dynamic_cast<LwpDLVListHeadHolder*>(pFoundry->GetNumberManager().GetTableRangeID().obj().get());
LwpTableRange* pTableRange = pHolder ? dynamic_cast<LwpTableRange*>(pHolder->GetHeadID().obj().get()) : nullptr;
//Look up the table
o3tl::sorted_vector<LwpTableRange*> aTableSeen;
while (pTableRange)
{
bool bAlreadySeenTable = !aTableSeen.insert(pTableRange).second;
if (bAlreadySeenTable)
throw std::runtime_error("loop in conversion");
LwpObjectID aID = pTableRange->GetTableID();
if (aID == aTableID)
{
break;
}
pTableRange = pTableRange->GetNext();
}
if (!pTableRange)
return;
LwpCellRange* pRange = dynamic_cast<LwpCellRange*>(pTableRange->GetCellRangeID().obj().get());
if (!pRange)
return;
LwpFolder* pFolder = dynamic_cast<LwpFolder*>(pRange->GetFolderID().obj().get());
if (!pFolder)
return;
LwpObjectID aRowListID = pFolder->GetChildHeadID();
LwpRowList* pRowList = dynamic_cast<LwpRowList*>(aRowListID.obj().get());
//loop the rowlist
o3tl::sorted_vector<LwpRowList*> aOuterSeen;
while (pRowList)
{
bool bAlreadySeenOuter = !aOuterSeen.insert(pRowList).second;
if (bAlreadySeenOuter)
throw std::runtime_error("loop in conversion");
sal_uInt16 nRowID = pRowList->GetRowID();
{
LwpCellList* pCellList = dynamic_cast<LwpCellList*>(pRowList->GetChildHeadID().obj().get());
//loop the cellList
o3tl::sorted_vector<LwpCellList*> aSeen;
while (pCellList)
{
bool bAlreadySeen = !aSeen.insert(pCellList).second;
if (bAlreadySeen)
throw std::runtime_error("loop in conversion");
{//put cell
sal_uInt16 nColID = pCellList->GetColumnID();
XFCell* pCell = GetCellsMap(nRowID,static_cast<sal_uInt8>(nColID));
if (!pCell)
{
throw std::runtime_error("Hidden cell would not be in cellsmap");
}
pCellList->Convert(pCell, this);
//process paragraph
PostProcessParagraph(pCell, nRowID, nColID);
}
pCellList = dynamic_cast<LwpCellList*>(pCellList->GetNextID().obj().get());
}
}
pRowList = dynamic_cast<LwpRowList*>(pRowList->GetNextID().obj().get());
}
}catch (...) {
SAL_WARN("lwp", "bad PutCellVals");
}
}
/**
* @short 1. set number right alignment to right if number 2. remove tab added before if number
* @param pCell - cell which to be process
* @param nRowID - row number in Word Pro file
* @param nColID - column number in Word Pro file
*/
void LwpTableLayout::PostProcessParagraph(XFCell *pCell, sal_uInt16 nRowID, sal_uInt16 nColID)
{
// if number right, set alignment to right
LwpCellLayout * pCellLayout = GetCellByRowCol(nRowID, nColID);
if(!pCellLayout)
return;
rtl::Reference<XFContent> first(
pCell->FindFirstContent(enumXFContentPara));
XFParagraph * pXFPara = static_cast<XFParagraph*>(first.get());
if (!pXFPara)
return;
XFColor aNullColor;
OUString sNumfmt = pCellLayout->GetNumfmtName();
bool bColorMod = false;
XFNumberStyle* pNumStyle = nullptr;
XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
if (!sNumfmt.isEmpty())
{
pNumStyle = static_cast<XFNumberStyle*>(pXFStyleManager->FindStyle(sNumfmt));
XFColor aColor = pNumStyle->GetColor();
if ( aColor != aNullColor )
bColorMod = true;//end
}
XFParaStyle * pStyle = pXFStyleManager->FindParaStyle(pXFPara->GetStyleName());
if (!((pStyle && pStyle->GetNumberRight()) || bColorMod))
return;
std::unique_ptr<XFParaStyle> xOverStyle(new XFParaStyle);
if (pStyle)
{
*xOverStyle = *pStyle;
if (pStyle->GetNumberRight())
xOverStyle->SetAlignType(enumXFAlignEnd);
}
if (bColorMod)
{
rtl::Reference<XFFont> xFont = xOverStyle->GetFont();
if (xFont.is())
{
XFColor aColor = xFont->GetColor();
if (aColor == aNullColor)
{
rtl::Reference<XFFont> pNewFont(new XFFont);
aColor = pNumStyle->GetColor();
pNewFont->SetColor(aColor);
xOverStyle->SetFont(pNewFont);
}
}
}
xOverStyle->SetStyleName(u""_ustr);
OUString StyleName
= pXFStyleManager->AddStyle(std::move(xOverStyle)).m_pStyle->GetStyleName();
pXFPara->SetStyleName(StyleName);
}
/**
* @short Parse all cols of table
* @param pXFTable - pointer to created XFTable
*/
void LwpTableLayout::ConvertColumn(rtl::Reference<XFTable> const & pXFTable, sal_uInt8 nStartCol, sal_uInt8 nEndCol)
{
LwpTable * pTable = GetTable();
if (!pTable)
{
assert(false);
return;
}
for (sal_uInt32 iLoop = 0; iLoop < static_cast<sal_uInt32>(nEndCol)-nStartCol; ++iLoop)
{
// add row to table
LwpObjectID *pColID = &GetColumnLayoutHead();
LwpColumnLayout * pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColID->obj().get());
while (pColumnLayout)
{
if (pColumnLayout->GetColumnID() == (iLoop+nStartCol))
{
pXFTable->SetColumnStyle(iLoop+1, pColumnLayout->GetStyleName());
break;
}
pColID = &pColumnLayout->GetNext();
pColumnLayout = dynamic_cast<LwpColumnLayout *>(pColID->obj().get());
}
if (!pColumnLayout)
{
pXFTable->SetColumnStyle(iLoop+1, m_DefaultColumnStyleName);
}
}
}
/**
* @short split conflict merged cells
*/
void LwpTableLayout::SplitConflictCells()
{
LwpTable * pTable = GetTable();
if (!pTable)
return;
sal_uInt16 nCol = pTable->GetColumn();
sal_uInt16 nRow = pTable->GetRow();
sal_uInt16 nEffectRows;
std::map<sal_uInt16,LwpRowLayout*>::iterator iter1;
std::map<sal_uInt16,LwpRowLayout*>::iterator iter2;
LwpRowLayout* pRowLayout;
LwpRowLayout* pEffectRow;
for (sal_uInt16 i=0; i<nRow; )
{
iter1 = m_RowsMap.find(i);
if (iter1 == m_RowsMap.end())//default rows
{
i++;
continue;
}
pRowLayout= iter1->second;
if (!pRowLayout->GetMergeCellFlag())
{
i++;
continue;
}
else
{
nEffectRows = i + pRowLayout->GetCurMaxSpannedRows(0,static_cast<sal_uInt8>(nCol));
for (sal_uInt16 j = i+1; j<nEffectRows; j++)
{
iter2 = m_RowsMap.find(j);
if (iter2 == m_RowsMap.end())
continue;
pEffectRow = iter2->second;
if (!pEffectRow->GetMergeCellFlag())
continue;
else
pEffectRow->SetCellSplit(nEffectRows);
}
i = nEffectRows;
}
}//end for
}
/**
* @short add default row which are missing in the file
* @param pXFTable - pointer to new created table
* @param nStartCol - starting column
* @param nEndCol - end column
* @return pXFTable
*/
void LwpTableLayout::ConvertDefaultRow(rtl::Reference<XFTable> const & pXFTable, sal_uInt8 nStartCol,
sal_uInt8 nEndCol, sal_uInt16 nRowID)
{
// current row doesn't exist in the file
rtl::Reference<XFRow> xRow(new XFRow);
xRow->SetStyleName(m_DefaultRowStyleName);
for (sal_uInt16 j =0;j < nEndCol-nStartCol; j++)
{
// if table has default cell layout, use it to ConvertCell
// otherwise use blank cell
rtl::Reference<XFCell> xCell;
if (m_pDefaultCellLayout)
{
LwpTable* pTable = GetTable();
assert(pTable);
xCell = m_pDefaultCellLayout->DoConvertCell(
pTable->GetObjectID(),nRowID,j+nStartCol);
}
else
{
xCell.set(new XFCell);
}
xRow->AddCell(xCell);
}
pXFTable->AddRow(xRow);
}
/**
* @short set cell map info
* @param pXFCell - pointer to xfcell
* @param nRow - row id
* @param nCol - column id
*/
void LwpTableLayout::SetCellsMap(sal_uInt16 nRow1, sal_uInt8 nCol1,
sal_uInt16 nRow2, sal_uInt8 nCol2, XFCell* pXFCell)
{
m_CellsMap.insert({{nRow1, nCol1}, {nRow2, nCol2}}, XFCellListener(pXFCell));
}
/**
* @short get cell map info
* @param nRow - row id
* @param nCol - column id
* @return pXFCell
*/
XFCell* LwpTableLayout::GetCellsMap(sal_uInt16 nRow, sal_uInt8 nCol)
{
auto results = m_CellsMap.search({{nRow, nCol}, {nRow, nCol}}, rt_type::search_type::overlap);
if (results.begin() == results.end())
return nullptr;
// return the last thing inserted for this position
return std::prev(results.end())->GetCell();
}
/**
* @descr Get row layout by row id
* @param nRow - row id
*/
LwpRowLayout* LwpTableLayout::GetRowLayout(sal_uInt16 nRow)
{
LwpObjectID *pRowID = &GetChildHead();
LwpRowLayout * pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
while (pRowLayout)
{
if(pRowLayout->GetRowID() == nRow)
return pRowLayout;
pRowID = &pRowLayout->GetNext();
pRowLayout = dynamic_cast<LwpRowLayout *>(pRowID->obj().get());
}
return nullptr;
}
//add end by
LwpColumnLayout::LwpColumnLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
: LwpVirtualLayout(objHdr, pStrm)
, ccolid(0)
, cwidth(0)
{}
LwpColumnLayout::~LwpColumnLayout()
{}
void LwpColumnLayout::Read()
{
LwpObjectStream* pStrm = m_pObjStrm.get();
LwpVirtualLayout::Read();
sal_uInt16 colid;
colid = pStrm->QuickReaduInt16(); // forced to lushort
ccolid = static_cast<sal_uInt8>(colid);
cwidth = pStrm->QuickReadInt32();
pStrm->SkipExtra();
}
void LwpColumnLayout::RegisterStyle(double dCalculatedWidth)
{
std::unique_ptr<XFColStyle> xColStyle(new XFColStyle);
xColStyle->SetWidth(static_cast<float>(dCalculatedWidth));
XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager();
m_StyleName = pXFStyleManager->AddStyle(std::move(xColStyle)).m_pStyle->GetStyleName();
}
LwpTableHeadingLayout::LwpTableHeadingLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm)
: LwpTableLayout(objHdr, pStrm)
, cStartRow(0)
, cEndRow(0)
{}
LwpTableHeadingLayout::~LwpTableHeadingLayout()
{}
/**
* @short read table heading layout
* @param
* @return
*/
void LwpTableHeadingLayout::Read()
{
LwpTableLayout::Read();
cStartRow = m_pObjStrm->QuickReaduInt16();
cEndRow = m_pObjStrm->QuickReaduInt16();
m_pObjStrm->SkipExtra();
}
/**
* @short get start and end row number of table heading
* @param
* @return *pStartRow - starting row number
* @return *pEndRow - end row number
*/
void LwpTableHeadingLayout::GetStartEndRow(sal_uInt16& nStartRow, sal_uInt16& nEndRow)
{
nStartRow = cStartRow;
nEndRow = cEndRow;
}
LwpSuperParallelColumnLayout::LwpSuperParallelColumnLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpSuperTableLayout(objHdr, pStrm)
{
}
LwpSuperParallelColumnLayout::~LwpSuperParallelColumnLayout()
{}
void LwpSuperParallelColumnLayout::Read()
{
LwpSuperTableLayout::Read();
m_pObjStrm->SkipExtra();
}
LwpSuperGlossaryLayout::LwpSuperGlossaryLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpSuperTableLayout(objHdr, pStrm)
{
}
LwpSuperGlossaryLayout::~LwpSuperGlossaryLayout()
{
}
void LwpSuperGlossaryLayout::Read()
{
LwpSuperTableLayout::Read();
m_pObjStrm->SkipExtra();
}
LwpParallelColumnsLayout::LwpParallelColumnsLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpTableLayout(objHdr, pStrm)
{
}
LwpParallelColumnsLayout::~LwpParallelColumnsLayout()
{
}
void LwpParallelColumnsLayout::Read()
{
LwpTableLayout::Read();
m_pObjStrm->SkipExtra();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V522 There might be dereferencing of a potential null pointer 'pTable'.
↑ V522 There might be dereferencing of a potential null pointer 'pTable'.
↑ V522 There might be dereferencing of a potential null pointer 'pTable'.