1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: addressconverter.cxx,v $
10 * $Revision: 1.4.20.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/addressconverter.hxx"
32 #include <osl/diagnose.h>
33 #include <rtl/ustrbuf.hxx>
34 #include <rtl/strbuf.hxx>
35 #include <com/sun/star/container/XIndexAccess.hpp>
36 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
37 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
38 #include "oox/helper/recordinputstream.hxx"
39 #include "oox/core/filterbase.hxx"
40 #include "oox/xls/biffinputstream.hxx"
41 #include "oox/xls/biffoutputstream.hxx"
43 using ::rtl::OUString
;
44 using ::rtl::OUStringBuffer
;
45 using ::rtl::OStringBuffer
;
46 using ::rtl::OUStringToOString
;
47 using ::com::sun::star::uno::UNO_QUERY_THROW
;
48 using ::com::sun::star::uno::Reference
;
49 using ::com::sun::star::uno::Exception
;
50 using ::com::sun::star::container::XIndexAccess
;
51 using ::com::sun::star::table::CellAddress
;
52 using ::com::sun::star::table::CellRangeAddress
;
53 using ::com::sun::star::sheet::XCellRangeAddressable
;
58 // ============================================================================
62 //! TODO: this limit may be changed
63 const sal_Int16 API_MAXTAB
= 255;
65 const sal_Int32 OOX_MAXCOL
= static_cast< sal_Int32
>( (1 << 14) - 1 );
66 const sal_Int32 OOX_MAXROW
= static_cast< sal_Int32
>( (1 << 20) - 1 );
67 const sal_Int16 OOX_MAXTAB
= static_cast< sal_Int16
>( (1 << 15) - 1 );
69 const sal_Int32 BIFF2_MAXCOL
= 255;
70 const sal_Int32 BIFF2_MAXROW
= 16383;
71 const sal_Int16 BIFF2_MAXTAB
= 0;
73 const sal_Int32 BIFF3_MAXCOL
= BIFF2_MAXCOL
;
74 const sal_Int32 BIFF3_MAXROW
= BIFF2_MAXROW
;
75 const sal_Int16 BIFF3_MAXTAB
= BIFF2_MAXTAB
;
77 const sal_Int32 BIFF4_MAXCOL
= BIFF3_MAXCOL
;
78 const sal_Int32 BIFF4_MAXROW
= BIFF3_MAXROW
;
79 const sal_Int16 BIFF4_MAXTAB
= 32767;
81 const sal_Int32 BIFF5_MAXCOL
= BIFF4_MAXCOL
;
82 const sal_Int32 BIFF5_MAXROW
= BIFF4_MAXROW
;
83 const sal_Int16 BIFF5_MAXTAB
= BIFF4_MAXTAB
;
85 const sal_Int32 BIFF8_MAXCOL
= BIFF5_MAXCOL
;
86 const sal_Int32 BIFF8_MAXROW
= 65535;
87 const sal_Int16 BIFF8_MAXTAB
= BIFF5_MAXTAB
;
89 const sal_Unicode BIFF_URL_DRIVE
= '\x01'; /// DOS drive letter or UNC path.
90 const sal_Unicode BIFF_URL_ROOT
= '\x02'; /// Root directory of current drive.
91 const sal_Unicode BIFF_URL_SUBDIR
= '\x03'; /// Subdirectory delimiter.
92 const sal_Unicode BIFF_URL_PARENT
= '\x04'; /// Parent directory.
93 const sal_Unicode BIFF_URL_RAW
= '\x05'; /// Unencoded URL.
94 const sal_Unicode BIFF_URL_INSTALL
= '\x06'; /// Application installation directory.
95 const sal_Unicode BIFF_URL_INSTALL2
= '\x07'; /// Alternative application installation directory.
96 const sal_Unicode BIFF_URL_LIBRARY
= '\x08'; /// Library directory in application installation.
97 const sal_Unicode BIFF4_URL_SHEET
= '\x09'; /// BIFF4 internal sheet.
98 const sal_Unicode BIFF_URL_UNC
= '@'; /// UNC path root.
100 const sal_Unicode BIFF_DCON_ENCODED
= '\x01'; /// First character of an encoded path from DCON* records.
101 const sal_Unicode BIFF_DCON_INTERN
= '\x02'; /// First character of an encoded sheet name from DCON* records.
104 inline sal_uInt16
lclGetBiffAddressSize( bool bCol16Bit
, bool bRow32Bit
)
106 return (bCol16Bit
? 2 : 1) + (bRow32Bit
? 4 : 2);
109 inline sal_uInt16
lclGetBiffRangeSize( bool bCol16Bit
, bool bRow32Bit
)
111 return 2 * lclGetBiffAddressSize( bCol16Bit
, bRow32Bit
);
116 // ============================================================================
117 // ============================================================================
119 CellAddress
ApiCellRangeList::getBaseAddress() const
122 return CellAddress();
123 return CellAddress( front().Sheet
, front().StartColumn
, front().StartRow
);
126 // ============================================================================
128 void BinAddress::read( RecordInputStream
& rStrm
)
130 rStrm
>> mnRow
>> mnCol
;
133 void BinAddress::read( BiffInputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
)
135 mnRow
= bRow32Bit
? rStrm
.readInt32() : rStrm
.readuInt16();
136 mnCol
= bCol16Bit
? rStrm
.readuInt16() : rStrm
.readuInt8();
139 void BinAddress::write( BiffOutputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
) const
144 rStrm
<< static_cast< sal_uInt16
>( mnRow
);
146 rStrm
<< static_cast< sal_uInt16
>( mnCol
);
148 rStrm
<< static_cast< sal_uInt8
>( mnCol
);
151 // ============================================================================
153 bool BinRange::contains( const BinAddress
& rAddr
) const
155 return (maFirst
.mnCol
<= rAddr
.mnCol
) && (rAddr
.mnCol
<= maLast
.mnCol
) &&
156 (maFirst
.mnRow
<= rAddr
.mnRow
) && (rAddr
.mnRow
<= maLast
.mnRow
);
159 void BinRange::read( RecordInputStream
& rStrm
)
161 rStrm
>> maFirst
.mnRow
>> maLast
.mnRow
>> maFirst
.mnCol
>> maLast
.mnCol
;
164 void BinRange::read( BiffInputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
)
166 maFirst
.mnRow
= bRow32Bit
? rStrm
.readInt32() : rStrm
.readuInt16();
167 maLast
.mnRow
= bRow32Bit
? rStrm
.readInt32() : rStrm
.readuInt16();
168 maFirst
.mnCol
= bCol16Bit
? rStrm
.readuInt16() : rStrm
.readuInt8();
169 maLast
.mnCol
= bCol16Bit
? rStrm
.readuInt16() : rStrm
.readuInt8();
172 void BinRange::write( BiffOutputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
) const
175 rStrm
<< maFirst
.mnRow
<< maLast
.mnRow
;
177 rStrm
<< static_cast< sal_uInt16
>( maFirst
.mnRow
) << static_cast< sal_uInt16
>( maLast
.mnRow
);
179 rStrm
<< static_cast< sal_uInt16
>( maFirst
.mnCol
) << static_cast< sal_uInt16
>( maLast
.mnCol
);
181 rStrm
<< static_cast< sal_uInt8
>( maFirst
.mnCol
) << static_cast< sal_uInt8
>( maLast
.mnCol
);
184 // ============================================================================
186 BinRange
BinRangeList::getEnclosingRange() const
191 const_iterator aIt
= begin(), aEnd
= end();
193 for( ++aIt
; aIt
!= aEnd
; ++aIt
)
195 aRange
.maFirst
.mnCol
= ::std::min( aRange
.maFirst
.mnCol
, aIt
->maFirst
.mnCol
);
196 aRange
.maFirst
.mnRow
= ::std::min( aRange
.maFirst
.mnRow
, aIt
->maFirst
.mnRow
);
197 aRange
.maLast
.mnCol
= ::std::max( aRange
.maLast
.mnCol
, aIt
->maLast
.mnCol
);
198 aRange
.maLast
.mnRow
= ::std::max( aRange
.maLast
.mnRow
, aIt
->maLast
.mnRow
);
204 void BinRangeList::read( RecordInputStream
& rStrm
)
206 sal_Int32 nCount
= rStrm
.readInt32();
207 resize( getLimitedValue
< size_t, sal_Int64
>( nCount
, 0, rStrm
.getRemaining() / 16 ) );
208 for( iterator aIt
= begin(), aEnd
= end(); aIt
!= aEnd
; ++aIt
)
212 void BinRangeList::read( BiffInputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
)
214 sal_uInt16 nCount
= rStrm
.readuInt16();
215 resize( getLimitedValue
< size_t, sal_Int64
>( nCount
, 0, rStrm
.getRemaining() / lclGetBiffRangeSize( bCol16Bit
, bRow32Bit
) ) );
216 for( iterator aIt
= begin(), aEnd
= end(); aIt
!= aEnd
; ++aIt
)
217 aIt
->read( rStrm
, bCol16Bit
, bRow32Bit
);
220 void BinRangeList::write( BiffOutputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
) const
222 writeSubList( rStrm
, 0, size(), bCol16Bit
, bRow32Bit
);
225 void BinRangeList::writeSubList( BiffOutputStream
& rStrm
, size_t nBegin
, size_t nCount
, bool bCol16Bit
, bool bRow32Bit
) const
227 OSL_ENSURE( nBegin
<= size(), "BiffRangeList::writeSubList - invalid start position" );
228 size_t nEnd
= ::std::min
< size_t >( nBegin
+ nCount
, size() );
229 sal_uInt16 nBiffCount
= getLimitedValue
< sal_uInt16
, size_t >( nEnd
- nBegin
, 0, SAL_MAX_UINT16
);
231 rStrm
.setPortionSize( lclGetBiffRangeSize( bCol16Bit
, bRow32Bit
) );
232 for( const_iterator aIt
= begin() + nBegin
, aEnd
= begin() + nEnd
; aIt
!= aEnd
; ++aIt
)
233 aIt
->write( rStrm
, bCol16Bit
, bRow32Bit
);
236 // ============================================================================
237 // ============================================================================
239 AddressConverter::AddressConverter( const WorkbookHelper
& rHelper
) :
240 WorkbookHelper( rHelper
),
241 mbColOverflow( false ),
242 mbRowOverflow( false ),
243 mbTabOverflow( false )
245 maDConChars
.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF );
246 switch( getFilterType() )
249 initializeMaxPos( OOX_MAXTAB
, OOX_MAXCOL
, OOX_MAXROW
);
251 case FILTER_BIFF
: switch( getBiff() )
254 initializeMaxPos( BIFF2_MAXTAB
, BIFF2_MAXCOL
, BIFF2_MAXROW
);
255 maLinkChars
.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
258 initializeMaxPos( BIFF3_MAXTAB
, BIFF3_MAXCOL
, BIFF3_MAXROW
);
259 maLinkChars
.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
262 initializeMaxPos( BIFF4_MAXTAB
, BIFF4_MAXCOL
, BIFF4_MAXROW
);
263 maLinkChars
.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
266 initializeMaxPos( BIFF5_MAXTAB
, BIFF5_MAXCOL
, BIFF5_MAXROW
);
267 maLinkChars
.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
270 initializeMaxPos( BIFF8_MAXTAB
, BIFF8_MAXCOL
, BIFF8_MAXROW
);
271 maLinkChars
.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
273 case BIFF_UNKNOWN
: break;
276 case FILTER_UNKNOWN
: break;
280 // ----------------------------------------------------------------------------
282 bool AddressConverter::parseOoxAddress2d(
283 sal_Int32
& ornColumn
, sal_Int32
& ornRow
,
284 const OUString
& rString
, sal_Int32 nStart
, sal_Int32 nLength
)
286 ornColumn
= ornRow
= 0;
287 if( (nStart
< 0) || (nStart
>= rString
.getLength()) || (nLength
< 2) )
290 const sal_Unicode
* pcChar
= rString
.getStr() + nStart
;
291 const sal_Unicode
* pcEndChar
= pcChar
+ ::std::min( nLength
, rString
.getLength() - nStart
);
293 enum { STATE_COL
, STATE_ROW
} eState
= STATE_COL
;
294 while( pcChar
< pcEndChar
)
296 sal_Unicode cChar
= *pcChar
;
301 if( ('a' <= cChar
) && (cChar
<= 'z') )
302 (cChar
-= 'a') += 'A';
303 if( ('A' <= cChar
) && (cChar
<= 'Z') )
305 /* Return, if 1-based column index is already 6 characters
306 long (12356631 is column index for column AAAAAA). */
307 if( ornColumn
>= 12356631 )
309 (ornColumn
*= 26) += (cChar
- 'A' + 1);
311 else if( ornColumn
> 0 )
323 if( ('0' <= cChar
) && (cChar
<= '9') )
325 // return, if 1-based row is already 9 digits long
326 if( ornRow
>= 100000000 )
328 (ornRow
*= 10) += (cChar
- '0');
340 return (ornColumn
>= 0) && (ornRow
>= 0);
343 bool AddressConverter::parseOoxRange2d(
344 sal_Int32
& ornStartColumn
, sal_Int32
& ornStartRow
,
345 sal_Int32
& ornEndColumn
, sal_Int32
& ornEndRow
,
346 const OUString
& rString
, sal_Int32 nStart
, sal_Int32 nLength
)
348 ornStartColumn
= ornStartRow
= ornEndColumn
= ornEndRow
= 0;
349 if( (nStart
< 0) || (nStart
>= rString
.getLength()) || (nLength
< 2) )
352 sal_Int32 nEnd
= nStart
+ ::std::min( nLength
, rString
.getLength() - nStart
);
353 sal_Int32 nColonPos
= rString
.indexOf( ':', nStart
);
354 if( (nStart
< nColonPos
) && (nColonPos
+ 1 < nEnd
) )
357 parseOoxAddress2d( ornStartColumn
, ornStartRow
, rString
, nStart
, nColonPos
- nStart
) &&
358 parseOoxAddress2d( ornEndColumn
, ornEndRow
, rString
, nColonPos
+ 1, nLength
- nColonPos
- 1 );
361 if( parseOoxAddress2d( ornStartColumn
, ornStartRow
, rString
, nStart
, nLength
) )
363 ornEndColumn
= ornStartColumn
;
364 ornEndRow
= ornStartRow
;
373 bool lclAppendUrlChar( OUStringBuffer
& orUrl
, sal_Unicode cChar
, bool bEncodeSpecial
)
375 // #126855# encode special characters
376 if( bEncodeSpecial
) switch( cChar
)
378 case '#': orUrl
.appendAscii( "%23" ); return true;
379 case '%': orUrl
.appendAscii( "%25" ); return true;
381 orUrl
.append( cChar
);
387 BiffTargetType
AddressConverter::parseBiffTargetUrl(
388 OUString
& orClassName
, OUString
& orTargetUrl
, OUString
& orSheetName
,
389 const OUString
& rBiffTargetUrl
, bool bFromDConRec
)
391 OUStringBuffer aTargetUrl
;
392 OUStringBuffer aSheetName
;
393 // default target type: some URL with/without sheet name, may be overridden below
394 BiffTargetType eTargetType
= BIFF_TARGETTYPE_URL
;
395 const ControlCharacters
& rCChars
= bFromDConRec
? maDConChars
: maLinkChars
;
400 STATE_ENCODED_PATH_START
, /// Start of encoded file path.
401 STATE_ENCODED_PATH
, /// Inside encoded file path.
402 STATE_ENCODED_DRIVE
, /// DOS drive letter or start of UNC path.
403 STATE_ENCODED_URL
, /// Encoded URL, e.g. http links.
404 STATE_UNENCODED
, /// Unencoded URL, could be DDE or OLE.
405 STATE_DDE_OLE
, /// Second part of DDE or OLE link.
406 STATE_FILENAME
, /// File name enclosed in brackets.
407 STATE_SHEETNAME
, /// Sheet name following enclosed file name.
408 STATE_UNSUPPORTED
, /// Unsupported special paths.
411 eState
= STATE_START
;
413 const sal_Unicode
* pcChar
= rBiffTargetUrl
.getStr();
414 const sal_Unicode
* pcEnd
= pcChar
+ rBiffTargetUrl
.getLength();
415 for( ; (eState
!= STATE_ERROR
) && (pcChar
< pcEnd
); ++pcChar
)
417 sal_Unicode cChar
= *pcChar
;
421 if( (cChar
== rCChars
.mcThisWorkbook
) || (cChar
== rCChars
.mcThisSheet
) || (cChar
== rCChars
.mcSameSheet
) )
423 if( pcChar
+ 1 < pcEnd
)
424 eState
= STATE_ERROR
;
425 if( cChar
== rCChars
.mcSameSheet
)
426 eTargetType
= BIFF_TARGETTYPE_SAMESHEET
;
428 else if( cChar
== rCChars
.mcExternal
)
429 eState
= (pcChar
+ 1 < pcEnd
) ? STATE_ENCODED_PATH_START
: STATE_ERROR
;
430 else if( cChar
== rCChars
.mcInternal
)
431 eState
= (pcChar
+ 1 < pcEnd
) ? STATE_SHEETNAME
: STATE_ERROR
;
433 eState
= lclAppendUrlChar( aTargetUrl
, cChar
, true ) ? STATE_UNENCODED
: STATE_ERROR
;
436 case STATE_ENCODED_PATH_START
:
437 if( cChar
== BIFF_URL_DRIVE
)
438 eState
= STATE_ENCODED_DRIVE
;
439 else if( cChar
== BIFF_URL_ROOT
)
441 aTargetUrl
.append( sal_Unicode( '/' ) );
442 eState
= STATE_ENCODED_PATH
;
444 else if( cChar
== BIFF_URL_PARENT
)
445 aTargetUrl
.appendAscii( "../" );
446 else if( cChar
== BIFF_URL_RAW
)
447 eState
= STATE_ENCODED_URL
;
448 else if( cChar
== BIFF_URL_INSTALL
)
449 eState
= STATE_UNSUPPORTED
;
450 else if( cChar
== BIFF_URL_INSTALL2
)
451 eState
= STATE_UNSUPPORTED
;
452 else if( cChar
== BIFF_URL_LIBRARY
)
454 eState
= STATE_ENCODED_PATH
;
455 eTargetType
= BIFF_TARGETTYPE_LIBRARY
;
457 else if( (getBiff() == BIFF4
) && (cChar
== BIFF4_URL_SHEET
) )
458 eState
= STATE_SHEETNAME
;
459 else if( cChar
== '[' )
460 eState
= STATE_FILENAME
;
461 else if( lclAppendUrlChar( aTargetUrl
, cChar
, true ) )
462 eState
= STATE_ENCODED_PATH
;
464 eState
= STATE_ERROR
;
467 case STATE_ENCODED_PATH
:
468 if( cChar
== BIFF_URL_SUBDIR
)
469 aTargetUrl
.append( sal_Unicode( '/' ) );
470 else if( cChar
== '[' )
471 eState
= STATE_FILENAME
;
472 else if( !lclAppendUrlChar( aTargetUrl
, cChar
, true ) )
473 eState
= STATE_ERROR
;
476 case STATE_ENCODED_DRIVE
:
477 if( cChar
== BIFF_URL_UNC
)
479 aTargetUrl
.appendAscii( "file://" );
480 eState
= STATE_ENCODED_PATH
;
484 aTargetUrl
.appendAscii( "file:///" );
485 eState
= lclAppendUrlChar( aTargetUrl
, cChar
, false ) ? STATE_ENCODED_PATH
: STATE_ERROR
;
486 aTargetUrl
.appendAscii( ":/" );
490 case STATE_ENCODED_URL
:
492 sal_Int32 nLength
= cChar
;
493 if( nLength
+ 1 == pcEnd
- pcChar
)
494 aTargetUrl
.append( pcChar
+ 1, nLength
);
496 eState
= STATE_ERROR
;
500 case STATE_UNENCODED
:
501 if( cChar
== BIFF_URL_SUBDIR
)
503 orClassName
= aTargetUrl
.makeStringAndClear();
504 eState
= bFromDConRec
? STATE_ERROR
: STATE_DDE_OLE
;
505 eTargetType
= BIFF_TARGETTYPE_DDE_OLE
;
507 else if( cChar
== '[' )
508 eState
= STATE_FILENAME
;
509 else if( !lclAppendUrlChar( aTargetUrl
, cChar
, true ) )
510 eState
= STATE_ERROR
;
514 if( !lclAppendUrlChar( aTargetUrl
, cChar
, true ) )
515 eState
= STATE_ERROR
;
520 eState
= STATE_SHEETNAME
;
521 else if( !lclAppendUrlChar( aTargetUrl
, cChar
, true ) )
522 eState
= STATE_ERROR
;
525 case STATE_SHEETNAME
:
526 if( !lclAppendUrlChar( aSheetName
, cChar
, false ) )
527 eState
= STATE_ERROR
;
530 case STATE_UNSUPPORTED
:
539 OSL_ENSURE( (eState
!= STATE_ERROR
) && (pcChar
== pcEnd
),
540 OStringBuffer( "AddressConverter::parseBiffTargetUrl - parser error in target \"" ).
541 append( OUStringToOString( rBiffTargetUrl
, RTL_TEXTENCODING_UTF8
) ).append( '"' ).getStr() );
542 bool bParserOk
= (eState
!= STATE_ERROR
) && (eState
!= STATE_UNSUPPORTED
) && (pcChar
== pcEnd
);
546 orTargetUrl
= aTargetUrl
.makeStringAndClear();
547 orSheetName
= aSheetName
.makeStringAndClear();
551 orClassName
= orTargetUrl
= orSheetName
= OUString();
554 return bParserOk
? eTargetType
: BIFF_TARGETTYPE_UNKNOWN
;
557 // ----------------------------------------------------------------------------
559 bool AddressConverter::checkCol( sal_Int32 nCol
, bool bTrackOverflow
)
561 bool bValid
= (0 <= nCol
) && (nCol
<= maMaxPos
.Column
);
562 if( !bValid
&& bTrackOverflow
)
563 mbColOverflow
= true;
567 bool AddressConverter::checkRow( sal_Int32 nRow
, bool bTrackOverflow
)
569 bool bValid
= (0 <= nRow
) && (nRow
<= maMaxPos
.Row
);
570 if( !bValid
&& bTrackOverflow
)
571 mbRowOverflow
= true;
575 bool AddressConverter::checkTab( sal_Int16 nSheet
, bool bTrackOverflow
)
577 bool bValid
= (0 <= nSheet
) && (nSheet
<= maMaxPos
.Sheet
);
578 if( !bValid
&& bTrackOverflow
)
579 mbTabOverflow
|= (nSheet
> maMaxPos
.Sheet
); // do not warn for deleted refs (-1)
583 // ----------------------------------------------------------------------------
585 bool AddressConverter::checkCellAddress( const CellAddress
& rAddress
, bool bTrackOverflow
)
588 checkTab( rAddress
.Sheet
, bTrackOverflow
) &&
589 checkCol( rAddress
.Column
, bTrackOverflow
) &&
590 checkRow( rAddress
.Row
, bTrackOverflow
);
593 bool AddressConverter::convertToCellAddressUnchecked( CellAddress
& orAddress
,
594 const OUString
& rString
, sal_Int16 nSheet
)
596 orAddress
.Sheet
= nSheet
;
597 return parseOoxAddress2d( orAddress
.Column
, orAddress
.Row
, rString
);
600 bool AddressConverter::convertToCellAddress( CellAddress
& orAddress
,
601 const OUString
& rString
, sal_Int16 nSheet
, bool bTrackOverflow
)
604 convertToCellAddressUnchecked( orAddress
, rString
, nSheet
) &&
605 checkCellAddress( orAddress
, bTrackOverflow
);
608 CellAddress
AddressConverter::createValidCellAddress(
609 const OUString
& rString
, sal_Int16 nSheet
, bool bTrackOverflow
)
611 CellAddress aAddress
;
612 if( !convertToCellAddress( aAddress
, rString
, nSheet
, bTrackOverflow
) )
614 aAddress
.Sheet
= getLimitedValue
< sal_Int16
, sal_Int16
>( nSheet
, 0, maMaxPos
.Sheet
);
615 aAddress
.Column
= ::std::min( aAddress
.Column
, maMaxPos
.Column
);
616 aAddress
.Row
= ::std::min( aAddress
.Row
, maMaxPos
.Row
);
621 void AddressConverter::convertToCellAddressUnchecked( CellAddress
& orAddress
,
622 const BinAddress
& rBinAddress
, sal_Int16 nSheet
)
624 orAddress
.Sheet
= nSheet
;
625 orAddress
.Column
= rBinAddress
.mnCol
;
626 orAddress
.Row
= rBinAddress
.mnRow
;
629 bool AddressConverter::convertToCellAddress( CellAddress
& orAddress
,
630 const BinAddress
& rBinAddress
, sal_Int16 nSheet
, bool bTrackOverflow
)
632 convertToCellAddressUnchecked( orAddress
, rBinAddress
, nSheet
);
633 return checkCellAddress( orAddress
, bTrackOverflow
);
636 CellAddress
AddressConverter::createValidCellAddress(
637 const BinAddress
& rBinAddress
, sal_Int16 nSheet
, bool bTrackOverflow
)
639 CellAddress aAddress
;
640 if( !convertToCellAddress( aAddress
, rBinAddress
, nSheet
, bTrackOverflow
) )
642 aAddress
.Sheet
= getLimitedValue
< sal_Int16
, sal_Int16
>( nSheet
, 0, maMaxPos
.Sheet
);
643 aAddress
.Column
= getLimitedValue
< sal_Int32
, sal_Int32
>( rBinAddress
.mnCol
, 0, maMaxPos
.Column
);
644 aAddress
.Row
= getLimitedValue
< sal_Int32
, sal_Int32
>( rBinAddress
.mnRow
, 0, maMaxPos
.Row
);
649 // ----------------------------------------------------------------------------
651 bool AddressConverter::checkCellRange( const CellRangeAddress
& rRange
, bool bAllowOverflow
, bool bTrackOverflow
)
654 (checkCol( rRange
.EndColumn
, bTrackOverflow
) || bAllowOverflow
) && // bAllowOverflow after checkCol to track overflow!
655 (checkRow( rRange
.EndRow
, bTrackOverflow
) || bAllowOverflow
) && // bAllowOverflow after checkRow to track overflow!
656 checkTab( rRange
.Sheet
, bTrackOverflow
) &&
657 checkCol( rRange
.StartColumn
, bTrackOverflow
) &&
658 checkRow( rRange
.StartRow
, bTrackOverflow
);
661 bool AddressConverter::validateCellRange( CellRangeAddress
& orRange
, bool bAllowOverflow
, bool bTrackOverflow
)
663 if( orRange
.StartColumn
> orRange
.EndColumn
)
664 ::std::swap( orRange
.StartColumn
, orRange
.EndColumn
);
665 if( orRange
.StartRow
> orRange
.EndRow
)
666 ::std::swap( orRange
.StartRow
, orRange
.EndRow
);
667 if( !checkCellRange( orRange
, bAllowOverflow
, bTrackOverflow
) )
669 if( orRange
.EndColumn
> maMaxPos
.Column
)
670 orRange
.EndColumn
= maMaxPos
.Column
;
671 if( orRange
.EndRow
> maMaxPos
.Row
)
672 orRange
.EndRow
= maMaxPos
.Row
;
676 bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress
& orRange
,
677 const OUString
& rString
, sal_Int16 nSheet
)
679 orRange
.Sheet
= nSheet
;
680 return parseOoxRange2d( orRange
.StartColumn
, orRange
.StartRow
, orRange
.EndColumn
, orRange
.EndRow
, rString
);
683 bool AddressConverter::convertToCellRange( CellRangeAddress
& orRange
,
684 const OUString
& rString
, sal_Int16 nSheet
, bool bAllowOverflow
, bool bTrackOverflow
)
687 convertToCellRangeUnchecked( orRange
, rString
, nSheet
) &&
688 validateCellRange( orRange
, bAllowOverflow
, bTrackOverflow
);
691 void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress
& orRange
,
692 const BinRange
& rBinRange
, sal_Int16 nSheet
)
694 orRange
.Sheet
= nSheet
;
695 orRange
.StartColumn
= rBinRange
.maFirst
.mnCol
;
696 orRange
.StartRow
= rBinRange
.maFirst
.mnRow
;
697 orRange
.EndColumn
= rBinRange
.maLast
.mnCol
;
698 orRange
.EndRow
= rBinRange
.maLast
.mnRow
;
701 bool AddressConverter::convertToCellRange( CellRangeAddress
& orRange
,
702 const BinRange
& rBinRange
, sal_Int16 nSheet
, bool bAllowOverflow
, bool bTrackOverflow
)
704 convertToCellRangeUnchecked( orRange
, rBinRange
, nSheet
);
705 return validateCellRange( orRange
, bAllowOverflow
, bTrackOverflow
);
708 // ----------------------------------------------------------------------------
710 bool AddressConverter::checkCellRangeList( const ApiCellRangeList
& rRanges
, bool bAllowOverflow
, bool bTrackOverflow
)
712 for( ApiCellRangeList::const_iterator aIt
= rRanges
.begin(), aEnd
= rRanges
.end(); aIt
!= aEnd
; ++aIt
)
713 if( !checkCellRange( *aIt
, bAllowOverflow
, bTrackOverflow
) )
718 void AddressConverter::validateCellRangeList( ApiCellRangeList
& orRanges
, bool bTrackOverflow
)
720 for( size_t nIndex
= orRanges
.size(); nIndex
> 0; --nIndex
)
721 if( !validateCellRange( orRanges
[ nIndex
- 1 ], true, bTrackOverflow
) )
722 orRanges
.erase( orRanges
.begin() + nIndex
- 1 );
725 void AddressConverter::convertToCellRangeList( ApiCellRangeList
& orRanges
,
726 const OUString
& rString
, sal_Int16 nSheet
, bool bTrackOverflow
)
729 sal_Int32 nLen
= rString
.getLength();
730 CellRangeAddress aRange
;
731 while( (0 <= nPos
) && (nPos
< nLen
) )
733 OUString aToken
= rString
.getToken( 0, ' ', nPos
);
734 if( (aToken
.getLength() > 0) && convertToCellRange( aRange
, aToken
, nSheet
, true, bTrackOverflow
) )
735 orRanges
.push_back( aRange
);
739 void AddressConverter::convertToCellRangeList( ApiCellRangeList
& orRanges
,
740 const BinRangeList
& rBinRanges
, sal_Int16 nSheet
, bool bTrackOverflow
)
742 CellRangeAddress aRange
;
743 for( BinRangeList::const_iterator aIt
= rBinRanges
.begin(), aEnd
= rBinRanges
.end(); aIt
!= aEnd
; ++aIt
)
744 if( convertToCellRange( aRange
, *aIt
, nSheet
, true, bTrackOverflow
) )
745 orRanges
.push_back( aRange
);
748 // private --------------------------------------------------------------------
750 void AddressConverter::ControlCharacters::set(
751 sal_Unicode cThisWorkbook
, sal_Unicode cExternal
,
752 sal_Unicode cThisSheet
, sal_Unicode cInternal
, sal_Unicode cSameSheet
)
754 mcThisWorkbook
= cThisWorkbook
;
755 mcExternal
= cExternal
;
756 mcThisSheet
= cThisSheet
;
757 mcInternal
= cInternal
;
758 mcSameSheet
= cSameSheet
;
761 void AddressConverter::initializeMaxPos(
762 sal_Int16 nMaxXlsTab
, sal_Int32 nMaxXlsCol
, sal_Int32 nMaxXlsRow
)
764 maMaxXlsPos
.Sheet
= nMaxXlsTab
;
765 maMaxXlsPos
.Column
= nMaxXlsCol
;
766 maMaxXlsPos
.Row
= nMaxXlsRow
;
768 // maximum cell position in Calc
771 Reference
< XIndexAccess
> xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW
);
772 Reference
< XCellRangeAddressable
> xAddressable( xSheetsIA
->getByIndex( 0 ), UNO_QUERY_THROW
);
773 CellRangeAddress aRange
= xAddressable
->getRangeAddress();
774 maMaxApiPos
= CellAddress( API_MAXTAB
, aRange
.EndColumn
, aRange
.EndRow
);
775 maMaxPos
= getBaseFilter().isImportFilter() ? maMaxApiPos
: maMaxXlsPos
;
779 OSL_ENSURE( false, "AddressConverter::AddressConverter - cannot get sheet limits" );
783 // ============================================================================