blob: b3b1616653dec051d77bbdc35dd6333d6f57dc95 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "oox/xls/addressconverter.hxx"
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <osl/diagnose.h>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include "oox/core/filterbase.hxx"
#include "oox/xls/biffinputstream.hxx"
#include "oox/xls/biffoutputstream.hxx"
namespace oox {
namespace xls {
// ============================================================================
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::table;
using namespace ::com::sun::star::uno;
using ::rtl::OStringBuffer;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using ::rtl::OUStringToOString;
// ============================================================================
namespace {
//! TODO: this limit may change, is there a way to obtain it via API?
const sal_Int16 API_MAXTAB = 255;
const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
const sal_Int32 BIFF2_MAXCOL = 255;
const sal_Int32 BIFF2_MAXROW = 16383;
const sal_Int16 BIFF2_MAXTAB = 0;
const sal_Int32 BIFF3_MAXCOL = BIFF2_MAXCOL;
const sal_Int32 BIFF3_MAXROW = BIFF2_MAXROW;
const sal_Int16 BIFF3_MAXTAB = BIFF2_MAXTAB;
const sal_Int32 BIFF4_MAXCOL = BIFF3_MAXCOL;
const sal_Int32 BIFF4_MAXROW = BIFF3_MAXROW;
const sal_Int16 BIFF4_MAXTAB = 32767;
const sal_Int32 BIFF5_MAXCOL = BIFF4_MAXCOL;
const sal_Int32 BIFF5_MAXROW = BIFF4_MAXROW;
const sal_Int16 BIFF5_MAXTAB = BIFF4_MAXTAB;
const sal_Int32 BIFF8_MAXCOL = BIFF5_MAXCOL;
const sal_Int32 BIFF8_MAXROW = 65535;
const sal_Int16 BIFF8_MAXTAB = BIFF5_MAXTAB;
const sal_Unicode BIFF_URL_DRIVE = '\x01'; /// DOS drive letter or UNC path.
const sal_Unicode BIFF_URL_ROOT = '\x02'; /// Root directory of current drive.
const sal_Unicode BIFF_URL_SUBDIR = '\x03'; /// Subdirectory delimiter.
const sal_Unicode BIFF_URL_PARENT = '\x04'; /// Parent directory.
const sal_Unicode BIFF_URL_RAW = '\x05'; /// Unencoded URL.
const sal_Unicode BIFF_URL_INSTALL = '\x06'; /// Application installation directory.
const sal_Unicode BIFF_URL_INSTALL2 = '\x07'; /// Alternative application installation directory.
const sal_Unicode BIFF_URL_LIBRARY = '\x08'; /// Library directory in application installation.
const sal_Unicode BIFF4_URL_SHEET = '\x09'; /// BIFF4 internal sheet.
const sal_Unicode BIFF_URL_UNC = '@'; /// UNC path root.
const sal_Unicode BIFF_DCON_ENCODED = '\x01'; /// First character of an encoded path from DCON* records.
const sal_Unicode BIFF_DCON_INTERN = '\x02'; /// First character of an encoded sheet name from DCON* records.
inline sal_uInt8 lclGetBiffAddressSize( bool bCol16Bit, bool bRow32Bit )
{
return (bCol16Bit ? 2 : 1) + (bRow32Bit ? 4 : 2);
}
inline sal_uInt8 lclGetBiffRangeSize( bool bCol16Bit, bool bRow32Bit )
{
return 2 * lclGetBiffAddressSize( bCol16Bit, bRow32Bit );
}
} // namespace
// ============================================================================
// ============================================================================
CellAddress ApiCellRangeList::getBaseAddress() const
{
if( empty() )
return CellAddress();
return CellAddress( front().Sheet, front().StartColumn, front().StartRow );
}
// ============================================================================
void BinAddress::read( SequenceInputStream& rStrm )
{
rStrm >> mnRow >> mnCol;
}
void BinAddress::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
{
mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
}
void BinAddress::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
{
if( bRow32Bit )
rStrm << mnRow;
else
rStrm << static_cast< sal_uInt16 >( mnRow );
if( bCol16Bit )
rStrm << static_cast< sal_uInt16 >( mnCol );
else
rStrm << static_cast< sal_uInt8 >( mnCol );
}
// ============================================================================
bool BinRange::contains( const BinAddress& rAddr ) const
{
return (maFirst.mnCol <= rAddr.mnCol) && (rAddr.mnCol <= maLast.mnCol) &&
(maFirst.mnRow <= rAddr.mnRow) && (rAddr.mnRow <= maLast.mnRow);
}
void BinRange::read( SequenceInputStream& rStrm )
{
rStrm >> maFirst.mnRow >> maLast.mnRow >> maFirst.mnCol >> maLast.mnCol;
}
void BinRange::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
{
maFirst.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
maLast.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
maFirst.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
maLast.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
}
void BinRange::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
{
if( bRow32Bit )
rStrm << maFirst.mnRow << maLast.mnRow;
else
rStrm << static_cast< sal_uInt16 >( maFirst.mnRow ) << static_cast< sal_uInt16 >( maLast.mnRow );
if( bCol16Bit )
rStrm << static_cast< sal_uInt16 >( maFirst.mnCol ) << static_cast< sal_uInt16 >( maLast.mnCol );
else
rStrm << static_cast< sal_uInt8 >( maFirst.mnCol ) << static_cast< sal_uInt8 >( maLast.mnCol );
}
// ============================================================================
BinRange BinRangeList::getEnclosingRange() const
{
BinRange aRange;
if( !empty() )
{
const_iterator aIt = begin(), aEnd = end();
aRange = *aIt;
for( ++aIt; aIt != aEnd; ++aIt )
{
aRange.maFirst.mnCol = ::std::min( aRange.maFirst.mnCol, aIt->maFirst.mnCol );
aRange.maFirst.mnRow = ::std::min( aRange.maFirst.mnRow, aIt->maFirst.mnRow );
aRange.maLast.mnCol = ::std::max( aRange.maLast.mnCol, aIt->maLast.mnCol );
aRange.maLast.mnRow = ::std::max( aRange.maLast.mnRow, aIt->maLast.mnRow );
}
}
return aRange;
}
void BinRangeList::read( SequenceInputStream& rStrm )
{
sal_Int32 nCount = rStrm.readInt32();
resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 16 ) );
for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
aIt->read( rStrm );
}
void BinRangeList::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
{
sal_uInt16 nCount = rStrm.readuInt16();
resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) ) );
for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
aIt->read( rStrm, bCol16Bit, bRow32Bit );
}
void BinRangeList::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
{
writeSubList( rStrm, 0, size(), bCol16Bit, bRow32Bit );
}
void BinRangeList::writeSubList( BiffOutputStream& rStrm, size_t nBegin, size_t nCount, bool bCol16Bit, bool bRow32Bit ) const
{
OSL_ENSURE( nBegin <= size(), "BiffRangeList::writeSubList - invalid start position" );
size_t nEnd = ::std::min< size_t >( nBegin + nCount, size() );
sal_uInt16 nBiffCount = getLimitedValue< sal_uInt16, size_t >( nEnd - nBegin, 0, SAL_MAX_UINT16 );
rStrm << nBiffCount;
rStrm.setPortionSize( lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) );
for( const_iterator aIt = begin() + nBegin, aEnd = begin() + nEnd; aIt != aEnd; ++aIt )
aIt->write( rStrm, bCol16Bit, bRow32Bit );
}
// ============================================================================
// ============================================================================
AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) :
WorkbookHelper( rHelper ),
mbColOverflow( false ),
mbRowOverflow( false ),
mbTabOverflow( false )
{
maDConChars.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF );
switch( getFilterType() )
{
case FILTER_OOXML:
initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
break;
case FILTER_BIFF: switch( getBiff() )
{
case BIFF2:
initializeMaxPos( BIFF2_MAXTAB, BIFF2_MAXCOL, BIFF2_MAXROW );
maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
break;
case BIFF3:
initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW );
maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
break;
case BIFF4:
initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW );
maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
break;
case BIFF5:
initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW );
maLinkChars.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
break;
case BIFF8:
initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW );
maLinkChars.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
break;
case BIFF_UNKNOWN: break;
}
break;
case FILTER_UNKNOWN: break;
}
}
// ----------------------------------------------------------------------------
bool AddressConverter::parseOoxAddress2d(
sal_Int32& ornColumn, sal_Int32& ornRow,
const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
{
ornColumn = ornRow = 0;
if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
return false;
const sal_Unicode* pcChar = rString.getStr() + nStart;
const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
enum { STATE_COL, STATE_ROW } eState = STATE_COL;
while( pcChar < pcEndChar )
{
sal_Unicode cChar = *pcChar;
switch( eState )
{
case STATE_COL:
{
if( ('a' <= cChar) && (cChar <= 'z') )
(cChar -= 'a') += 'A';
if( ('A' <= cChar) && (cChar <= 'Z') )
{
/* Return, if 1-based column index is already 6 characters
long (12356631 is column index for column AAAAAA). */
if( ornColumn >= 12356631 )
return false;
(ornColumn *= 26) += (cChar - 'A' + 1);
}
else if( ornColumn > 0 )
{
--pcChar;
eState = STATE_ROW;
}
else
return false;
}
break;
case STATE_ROW:
{
if( ('0' <= cChar) && (cChar <= '9') )
{
// return, if 1-based row is already 9 digits long
if( ornRow >= 100000000 )
return false;
(ornRow *= 10) += (cChar - '0');
}
else
return false;
}
break;
}
++pcChar;
}
--ornColumn;
--ornRow;
return (ornColumn >= 0) && (ornRow >= 0);
}
bool AddressConverter::parseOoxRange2d(
sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
{
ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
return false;
sal_Int32 nEnd = nStart + ::std::min( nLength, rString.getLength() - nStart );
sal_Int32 nColonPos = rString.indexOf( ':', nStart );
if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
{
return
parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, nLength - nColonPos - 1 );
}
if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nLength ) )
{
ornEndColumn = ornStartColumn;
ornEndRow = ornStartRow;
return true;
}
return false;
}
namespace {
bool lclAppendUrlChar( OUStringBuffer& orUrl, sal_Unicode cChar, bool bEncodeSpecial )
{
// #126855# encode special characters
if( bEncodeSpecial ) switch( cChar )
{
case '#': orUrl.appendAscii( "%23" ); return true;
case '%': orUrl.appendAscii( "%25" ); return true;
}
orUrl.append( cChar );
return cChar >= ' ';
}
} // namespace
BiffTargetType AddressConverter::parseBiffTargetUrl(
OUString& orClassName, OUString& orTargetUrl, OUString& orSheetName,
const OUString& rBiffTargetUrl, bool bFromDConRec )
{
OUStringBuffer aTargetUrl;
OUStringBuffer aSheetName;
// default target type: some URL with/without sheet name, may be overridden below
BiffTargetType eTargetType = BIFF_TARGETTYPE_URL;
const ControlCharacters& rCChars = bFromDConRec ? maDConChars : maLinkChars;
enum
{
STATE_START,
STATE_ENCODED_PATH_START, /// Start of encoded file path.
STATE_ENCODED_PATH, /// Inside encoded file path.
STATE_ENCODED_DRIVE, /// DOS drive letter or start of UNC path.
STATE_ENCODED_URL, /// Encoded URL, e.g. http links.
STATE_UNENCODED, /// Unencoded URL, could be DDE or OLE.
STATE_DDE_OLE, /// Second part of DDE or OLE link.
STATE_FILENAME, /// File name enclosed in brackets.
STATE_SHEETNAME, /// Sheet name following enclosed file name.
STATE_UNSUPPORTED, /// Unsupported special paths.
STATE_ERROR
}
eState = STATE_START;
const sal_Unicode* pcChar = rBiffTargetUrl.getStr();
const sal_Unicode* pcEnd = pcChar + rBiffTargetUrl.getLength();
for( ; (eState != STATE_ERROR) && (pcChar < pcEnd); ++pcChar )
{
sal_Unicode cChar = *pcChar;
switch( eState )
{
case STATE_START:
if( (cChar == rCChars.mcThisWorkbook) || (cChar == rCChars.mcThisSheet) || (cChar == rCChars.mcSameSheet) )
{
if( pcChar + 1 < pcEnd )
eState = STATE_ERROR;
if( cChar == rCChars.mcSameSheet )
eTargetType = BIFF_TARGETTYPE_SAMESHEET;
}
else if( cChar == rCChars.mcExternal )
eState = (pcChar + 1 < pcEnd) ? STATE_ENCODED_PATH_START : STATE_ERROR;
else if( cChar == rCChars.mcInternal )
eState = (pcChar + 1 < pcEnd) ? STATE_SHEETNAME : STATE_ERROR;
else
eState = lclAppendUrlChar( aTargetUrl, cChar, true ) ? STATE_UNENCODED : STATE_ERROR;
break;
case STATE_ENCODED_PATH_START:
if( cChar == BIFF_URL_DRIVE )
eState = STATE_ENCODED_DRIVE;
else if( cChar == BIFF_URL_ROOT )
{
aTargetUrl.append( sal_Unicode( '/' ) );
eState = STATE_ENCODED_PATH;
}
else if( cChar == BIFF_URL_PARENT )
aTargetUrl.appendAscii( "../" );
else if( cChar == BIFF_URL_RAW )
eState = STATE_ENCODED_URL;
else if( cChar == BIFF_URL_INSTALL )
eState = STATE_UNSUPPORTED;
else if( cChar == BIFF_URL_INSTALL2 )
eState = STATE_UNSUPPORTED;
else if( cChar == BIFF_URL_LIBRARY )
{
eState = STATE_ENCODED_PATH;
eTargetType = BIFF_TARGETTYPE_LIBRARY;
}
else if( (getBiff() == BIFF4) && (cChar == BIFF4_URL_SHEET) )
eState = STATE_SHEETNAME;
else if( cChar == '[' )
eState = STATE_FILENAME;
else if( lclAppendUrlChar( aTargetUrl, cChar, true ) )
eState = STATE_ENCODED_PATH;
else
eState = STATE_ERROR;
break;
case STATE_ENCODED_PATH:
if( cChar == BIFF_URL_SUBDIR )
aTargetUrl.append( sal_Unicode( '/' ) );
else if( cChar == '[' )
eState = STATE_FILENAME;
else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
eState = STATE_ERROR;
break;
case STATE_ENCODED_DRIVE:
if( cChar == BIFF_URL_UNC )
{
aTargetUrl.appendAscii( "file://" );
eState = STATE_ENCODED_PATH;
}
else
{
aTargetUrl.appendAscii( "file:///" );
eState = lclAppendUrlChar( aTargetUrl, cChar, false ) ? STATE_ENCODED_PATH : STATE_ERROR;
aTargetUrl.appendAscii( ":/" );
}
break;
case STATE_ENCODED_URL:
{
sal_Int32 nLength = cChar;
if( nLength + 1 == pcEnd - pcChar )
aTargetUrl.append( pcChar + 1, nLength );
else
eState = STATE_ERROR;
}
break;
case STATE_UNENCODED:
if( cChar == BIFF_URL_SUBDIR )
{
orClassName = aTargetUrl.makeStringAndClear();
eState = bFromDConRec ? STATE_ERROR : STATE_DDE_OLE;
eTargetType = BIFF_TARGETTYPE_DDE_OLE;
}
else if( cChar == '[' )
eState = STATE_FILENAME;
else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
eState = STATE_ERROR;
break;
case STATE_DDE_OLE:
if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
eState = STATE_ERROR;
break;
case STATE_FILENAME:
if( cChar == ']' )
eState = STATE_SHEETNAME;
else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
eState = STATE_ERROR;
break;
case STATE_SHEETNAME:
if( !lclAppendUrlChar( aSheetName, cChar, false ) )
eState = STATE_ERROR;
break;
case STATE_UNSUPPORTED:
pcChar = pcEnd - 1;
break;
case STATE_ERROR:
break;
}
}
OSL_ENSURE( (eState != STATE_ERROR) && (pcChar == pcEnd),
OStringBuffer( "AddressConverter::parseBiffTargetUrl - parser error in target \"" ).
append( OUStringToOString( rBiffTargetUrl, RTL_TEXTENCODING_UTF8 ) ).append( '"' ).getStr() );
bool bParserOk = (eState != STATE_ERROR) && (eState != STATE_UNSUPPORTED) && (pcChar == pcEnd);
if( bParserOk )
{
orTargetUrl = aTargetUrl.makeStringAndClear();
orSheetName = aSheetName.makeStringAndClear();
}
else
{
orClassName = orTargetUrl = orSheetName = OUString();
}
return bParserOk ? eTargetType : BIFF_TARGETTYPE_UNKNOWN;
}
// ----------------------------------------------------------------------------
bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
{
bool bValid = (0 <= nCol) && (nCol <= maMaxPos.Column);
if( !bValid && bTrackOverflow )
mbColOverflow = true;
return bValid;
}
bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
{
bool bValid = (0 <= nRow) && (nRow <= maMaxPos.Row);
if( !bValid && bTrackOverflow )
mbRowOverflow = true;
return bValid;
}
bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
{
bool bValid = (0 <= nSheet) && (nSheet <= maMaxPos.Sheet);
if( !bValid && bTrackOverflow )
mbTabOverflow |= (nSheet > maMaxPos.Sheet); // do not warn for deleted refs (-1)
return bValid;
}
// ----------------------------------------------------------------------------
bool AddressConverter::checkCellAddress( const CellAddress& rAddress, bool bTrackOverflow )
{
return
checkTab( rAddress.Sheet, bTrackOverflow ) &&
checkCol( rAddress.Column, bTrackOverflow ) &&
checkRow( rAddress.Row, bTrackOverflow );
}
bool AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress,
const OUString& rString, sal_Int16 nSheet )
{
orAddress.Sheet = nSheet;
return parseOoxAddress2d( orAddress.Column, orAddress.Row, rString );
}
bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
{
return
convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
checkCellAddress( orAddress, bTrackOverflow );
}
CellAddress AddressConverter::createValidCellAddress(
const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
{
CellAddress aAddress;
if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
{
aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
aAddress.Column = ::std::min( aAddress.Column, maMaxPos.Column );
aAddress.Row = ::std::min( aAddress.Row, maMaxPos.Row );
}
return aAddress;
}
void AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress,
const BinAddress& rBinAddress, sal_Int16 nSheet )
{
orAddress.Sheet = nSheet;
orAddress.Column = rBinAddress.mnCol;
orAddress.Row = rBinAddress.mnRow;
}
bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
{
convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
return checkCellAddress( orAddress, bTrackOverflow );
}
CellAddress AddressConverter::createValidCellAddress(
const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
{
CellAddress aAddress;
if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
{
aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
aAddress.Column = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, maMaxPos.Column );
aAddress.Row = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, maMaxPos.Row );
}
return aAddress;
}
// ----------------------------------------------------------------------------
bool AddressConverter::checkCellRange( const CellRangeAddress& rRange, bool bAllowOverflow, bool bTrackOverflow )
{
return
(checkCol( rRange.EndColumn, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow!
(checkRow( rRange.EndRow, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow!
checkTab( rRange.Sheet, bTrackOverflow ) &&
checkCol( rRange.StartColumn, bTrackOverflow ) &&
checkRow( rRange.StartRow, bTrackOverflow );
}
bool AddressConverter::validateCellRange( CellRangeAddress& orRange, bool bAllowOverflow, bool bTrackOverflow )
{
if( orRange.StartColumn > orRange.EndColumn )
::std::swap( orRange.StartColumn, orRange.EndColumn );
if( orRange.StartRow > orRange.EndRow )
::std::swap( orRange.StartRow, orRange.EndRow );
if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) )
return false;
if( orRange.EndColumn > maMaxPos.Column )
orRange.EndColumn = maMaxPos.Column;
if( orRange.EndRow > maMaxPos.Row )
orRange.EndRow = maMaxPos.Row;
return true;
}
bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
const OUString& rString, sal_Int16 nSheet )
{
orRange.Sheet = nSheet;
return parseOoxRange2d( orRange.StartColumn, orRange.StartRow, orRange.EndColumn, orRange.EndRow, rString );
}
bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
{
return
convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
}
void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
const BinRange& rBinRange, sal_Int16 nSheet )
{
orRange.Sheet = nSheet;
orRange.StartColumn = rBinRange.maFirst.mnCol;
orRange.StartRow = rBinRange.maFirst.mnRow;
orRange.EndColumn = rBinRange.maLast.mnCol;
orRange.EndRow = rBinRange.maLast.mnRow;
}
bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
{
convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
}
// ----------------------------------------------------------------------------
bool AddressConverter::checkCellRangeList( const ApiCellRangeList& rRanges, bool bAllowOverflow, bool bTrackOverflow )
{
for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
if( !checkCellRange( *aIt, bAllowOverflow, bTrackOverflow ) )
return false;
return true;
}
void AddressConverter::validateCellRangeList( ApiCellRangeList& orRanges, bool bTrackOverflow )
{
for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
orRanges.erase( orRanges.begin() + nIndex - 1 );
}
void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
{
sal_Int32 nPos = 0;
sal_Int32 nLen = rString.getLength();
CellRangeAddress aRange;
while( (0 <= nPos) && (nPos < nLen) )
{
OUString aToken = rString.getToken( 0, ' ', nPos );
if( (aToken.getLength() > 0) && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
orRanges.push_back( aRange );
}
}
void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
{
CellRangeAddress aRange;
for( BinRangeList::const_iterator aIt = rBinRanges.begin(), aEnd = rBinRanges.end(); aIt != aEnd; ++aIt )
if( convertToCellRange( aRange, *aIt, nSheet, true, bTrackOverflow ) )
orRanges.push_back( aRange );
}
// private --------------------------------------------------------------------
void AddressConverter::ControlCharacters::set(
sal_Unicode cThisWorkbook, sal_Unicode cExternal,
sal_Unicode cThisSheet, sal_Unicode cInternal, sal_Unicode cSameSheet )
{
mcThisWorkbook = cThisWorkbook;
mcExternal = cExternal;
mcThisSheet = cThisSheet;
mcInternal = cInternal;
mcSameSheet = cSameSheet;
}
void AddressConverter::initializeMaxPos(
sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
{
maMaxXlsPos.Sheet = nMaxXlsTab;
maMaxXlsPos.Column = nMaxXlsCol;
maMaxXlsPos.Row = nMaxXlsRow;
// maximum cell position in Calc
try
{
Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
CellRangeAddress aRange = xAddressable->getRangeAddress();
maMaxApiPos = CellAddress( API_MAXTAB, aRange.EndColumn, aRange.EndRow );
maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos;
}
catch( Exception& )
{
OSL_ENSURE( false, "AddressConverter::AddressConverter - cannot get sheet limits" );
}
}
// ============================================================================
} // namespace xls
} // namespace oox