Update ooo320-m1
[ooovba.git] / oox / source / xls / addressconverter.cxx
blob06bce7716967bb63667dfc4bb02224ca9a65f89b
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;
55 namespace oox {
56 namespace xls {
58 // ============================================================================
60 namespace {
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 );
114 } // namespace
116 // ============================================================================
117 // ============================================================================
119 CellAddress ApiCellRangeList::getBaseAddress() const
121 if( empty() )
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
141 if( bRow32Bit )
142 rStrm << mnRow;
143 else
144 rStrm << static_cast< sal_uInt16 >( mnRow );
145 if( bCol16Bit )
146 rStrm << static_cast< sal_uInt16 >( mnCol );
147 else
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
174 if( bRow32Bit )
175 rStrm << maFirst.mnRow << maLast.mnRow;
176 else
177 rStrm << static_cast< sal_uInt16 >( maFirst.mnRow ) << static_cast< sal_uInt16 >( maLast.mnRow );
178 if( bCol16Bit )
179 rStrm << static_cast< sal_uInt16 >( maFirst.mnCol ) << static_cast< sal_uInt16 >( maLast.mnCol );
180 else
181 rStrm << static_cast< sal_uInt8 >( maFirst.mnCol ) << static_cast< sal_uInt8 >( maLast.mnCol );
184 // ============================================================================
186 BinRange BinRangeList::getEnclosingRange() const
188 BinRange aRange;
189 if( !empty() )
191 const_iterator aIt = begin(), aEnd = end();
192 aRange = *aIt;
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 );
201 return aRange;
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 )
209 aIt->read( rStrm );
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 );
230 rStrm << nBiffCount;
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() )
248 case FILTER_OOX:
249 initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
250 break;
251 case FILTER_BIFF: switch( getBiff() )
253 case BIFF2:
254 initializeMaxPos( BIFF2_MAXTAB, BIFF2_MAXCOL, BIFF2_MAXROW );
255 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
256 break;
257 case BIFF3:
258 initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW );
259 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
260 break;
261 case BIFF4:
262 initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW );
263 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
264 break;
265 case BIFF5:
266 initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW );
267 maLinkChars.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
268 break;
269 case BIFF8:
270 initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW );
271 maLinkChars.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
272 break;
273 case BIFF_UNKNOWN: break;
275 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) )
288 return false;
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;
297 switch( eState )
299 case STATE_COL:
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 )
308 return false;
309 (ornColumn *= 26) += (cChar - 'A' + 1);
311 else if( ornColumn > 0 )
313 --pcChar;
314 eState = STATE_ROW;
316 else
317 return false;
319 break;
321 case STATE_ROW:
323 if( ('0' <= cChar) && (cChar <= '9') )
325 // return, if 1-based row is already 9 digits long
326 if( ornRow >= 100000000 )
327 return false;
328 (ornRow *= 10) += (cChar - '0');
330 else
331 return false;
333 break;
335 ++pcChar;
338 --ornColumn;
339 --ornRow;
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) )
350 return false;
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) )
356 return
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;
365 return true;
368 return false;
371 namespace {
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 );
382 return cChar >= ' ';
385 } // namespace
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;
397 enum
399 STATE_START,
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.
409 STATE_ERROR
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;
418 switch( eState )
420 case STATE_START:
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;
432 else
433 eState = lclAppendUrlChar( aTargetUrl, cChar, true ) ? STATE_UNENCODED : STATE_ERROR;
434 break;
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;
463 else
464 eState = STATE_ERROR;
465 break;
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;
474 break;
476 case STATE_ENCODED_DRIVE:
477 if( cChar == BIFF_URL_UNC )
479 aTargetUrl.appendAscii( "file://" );
480 eState = STATE_ENCODED_PATH;
482 else
484 aTargetUrl.appendAscii( "file:///" );
485 eState = lclAppendUrlChar( aTargetUrl, cChar, false ) ? STATE_ENCODED_PATH : STATE_ERROR;
486 aTargetUrl.appendAscii( ":/" );
488 break;
490 case STATE_ENCODED_URL:
492 sal_Int32 nLength = cChar;
493 if( nLength + 1 == pcEnd - pcChar )
494 aTargetUrl.append( pcChar + 1, nLength );
495 else
496 eState = STATE_ERROR;
498 break;
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;
511 break;
513 case STATE_DDE_OLE:
514 if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
515 eState = STATE_ERROR;
516 break;
518 case STATE_FILENAME:
519 if( cChar == ']' )
520 eState = STATE_SHEETNAME;
521 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
522 eState = STATE_ERROR;
523 break;
525 case STATE_SHEETNAME:
526 if( !lclAppendUrlChar( aSheetName, cChar, false ) )
527 eState = STATE_ERROR;
528 break;
530 case STATE_UNSUPPORTED:
531 pcChar = pcEnd - 1;
532 break;
534 case STATE_ERROR:
535 break;
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);
544 if( bParserOk )
546 orTargetUrl = aTargetUrl.makeStringAndClear();
547 orSheetName = aSheetName.makeStringAndClear();
549 else
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;
564 return bValid;
567 bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
569 bool bValid = (0 <= nRow) && (nRow <= maMaxPos.Row);
570 if( !bValid && bTrackOverflow )
571 mbRowOverflow = true;
572 return bValid;
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)
580 return bValid;
583 // ----------------------------------------------------------------------------
585 bool AddressConverter::checkCellAddress( const CellAddress& rAddress, bool bTrackOverflow )
587 return
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 )
603 return
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 );
618 return aAddress;
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 );
646 return aAddress;
649 // ----------------------------------------------------------------------------
651 bool AddressConverter::checkCellRange( const CellRangeAddress& rRange, bool bAllowOverflow, bool bTrackOverflow )
653 return
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 ) )
668 return false;
669 if( orRange.EndColumn > maMaxPos.Column )
670 orRange.EndColumn = maMaxPos.Column;
671 if( orRange.EndRow > maMaxPos.Row )
672 orRange.EndRow = maMaxPos.Row;
673 return true;
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 )
686 return
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 ) )
714 return false;
715 return true;
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 )
728 sal_Int32 nPos = 0;
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;
777 catch( Exception& )
779 OSL_ENSURE( false, "AddressConverter::AddressConverter - cannot get sheet limits" );
783 // ============================================================================
785 } // namespace xls
786 } // namespace oox