| /************************************************************** |
| * |
| * 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 |