1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/xls/addressconverter.hxx" 29 30 #include <com/sun/star/container/XIndexAccess.hpp> 31 #include <com/sun/star/sheet/XCellRangeAddressable.hpp> 32 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 33 #include <osl/diagnose.h> 34 #include <rtl/strbuf.hxx> 35 #include <rtl/ustrbuf.hxx> 36 #include "oox/core/filterbase.hxx" 37 #include "oox/xls/biffinputstream.hxx" 38 #include "oox/xls/biffoutputstream.hxx" 39 40 namespace oox { 41 namespace xls { 42 43 // ============================================================================ 44 45 using namespace ::com::sun::star::container; 46 using namespace ::com::sun::star::sheet; 47 using namespace ::com::sun::star::table; 48 using namespace ::com::sun::star::uno; 49 50 using ::rtl::OStringBuffer; 51 using ::rtl::OUString; 52 using ::rtl::OUStringBuffer; 53 using ::rtl::OUStringToOString; 54 55 // ============================================================================ 56 57 namespace { 58 59 //! TODO: this limit may change, is there a way to obtain it via API? 60 const sal_Int16 API_MAXTAB = 255; 61 62 const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 ); 63 const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 ); 64 const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 ); 65 66 const sal_Int32 BIFF2_MAXCOL = 255; 67 const sal_Int32 BIFF2_MAXROW = 16383; 68 const sal_Int16 BIFF2_MAXTAB = 0; 69 70 const sal_Int32 BIFF3_MAXCOL = BIFF2_MAXCOL; 71 const sal_Int32 BIFF3_MAXROW = BIFF2_MAXROW; 72 const sal_Int16 BIFF3_MAXTAB = BIFF2_MAXTAB; 73 74 const sal_Int32 BIFF4_MAXCOL = BIFF3_MAXCOL; 75 const sal_Int32 BIFF4_MAXROW = BIFF3_MAXROW; 76 const sal_Int16 BIFF4_MAXTAB = 32767; 77 78 const sal_Int32 BIFF5_MAXCOL = BIFF4_MAXCOL; 79 const sal_Int32 BIFF5_MAXROW = BIFF4_MAXROW; 80 const sal_Int16 BIFF5_MAXTAB = BIFF4_MAXTAB; 81 82 const sal_Int32 BIFF8_MAXCOL = BIFF5_MAXCOL; 83 const sal_Int32 BIFF8_MAXROW = 65535; 84 const sal_Int16 BIFF8_MAXTAB = BIFF5_MAXTAB; 85 86 const sal_Unicode BIFF_URL_DRIVE = '\x01'; /// DOS drive letter or UNC path. 87 const sal_Unicode BIFF_URL_ROOT = '\x02'; /// Root directory of current drive. 88 const sal_Unicode BIFF_URL_SUBDIR = '\x03'; /// Subdirectory delimiter. 89 const sal_Unicode BIFF_URL_PARENT = '\x04'; /// Parent directory. 90 const sal_Unicode BIFF_URL_RAW = '\x05'; /// Unencoded URL. 91 const sal_Unicode BIFF_URL_INSTALL = '\x06'; /// Application installation directory. 92 const sal_Unicode BIFF_URL_INSTALL2 = '\x07'; /// Alternative application installation directory. 93 const sal_Unicode BIFF_URL_LIBRARY = '\x08'; /// Library directory in application installation. 94 const sal_Unicode BIFF4_URL_SHEET = '\x09'; /// BIFF4 internal sheet. 95 const sal_Unicode BIFF_URL_UNC = '@'; /// UNC path root. 96 97 const sal_Unicode BIFF_DCON_ENCODED = '\x01'; /// First character of an encoded path from DCON* records. 98 const sal_Unicode BIFF_DCON_INTERN = '\x02'; /// First character of an encoded sheet name from DCON* records. 99 100 101 inline sal_uInt8 lclGetBiffAddressSize( bool bCol16Bit, bool bRow32Bit ) 102 { 103 return (bCol16Bit ? 2 : 1) + (bRow32Bit ? 4 : 2); 104 } 105 106 inline sal_uInt8 lclGetBiffRangeSize( bool bCol16Bit, bool bRow32Bit ) 107 { 108 return 2 * lclGetBiffAddressSize( bCol16Bit, bRow32Bit ); 109 } 110 111 } // namespace 112 113 // ============================================================================ 114 // ============================================================================ 115 116 CellAddress ApiCellRangeList::getBaseAddress() const 117 { 118 if( empty() ) 119 return CellAddress(); 120 return CellAddress( front().Sheet, front().StartColumn, front().StartRow ); 121 } 122 123 // ============================================================================ 124 125 void BinAddress::read( SequenceInputStream& rStrm ) 126 { 127 rStrm >> mnRow >> mnCol; 128 } 129 130 void BinAddress::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) 131 { 132 mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16(); 133 mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8(); 134 } 135 136 void BinAddress::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const 137 { 138 if( bRow32Bit ) 139 rStrm << mnRow; 140 else 141 rStrm << static_cast< sal_uInt16 >( mnRow ); 142 if( bCol16Bit ) 143 rStrm << static_cast< sal_uInt16 >( mnCol ); 144 else 145 rStrm << static_cast< sal_uInt8 >( mnCol ); 146 } 147 148 // ============================================================================ 149 150 bool BinRange::contains( const BinAddress& rAddr ) const 151 { 152 return (maFirst.mnCol <= rAddr.mnCol) && (rAddr.mnCol <= maLast.mnCol) && 153 (maFirst.mnRow <= rAddr.mnRow) && (rAddr.mnRow <= maLast.mnRow); 154 } 155 156 void BinRange::read( SequenceInputStream& rStrm ) 157 { 158 rStrm >> maFirst.mnRow >> maLast.mnRow >> maFirst.mnCol >> maLast.mnCol; 159 } 160 161 void BinRange::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) 162 { 163 maFirst.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16(); 164 maLast.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16(); 165 maFirst.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8(); 166 maLast.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8(); 167 } 168 169 void BinRange::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const 170 { 171 if( bRow32Bit ) 172 rStrm << maFirst.mnRow << maLast.mnRow; 173 else 174 rStrm << static_cast< sal_uInt16 >( maFirst.mnRow ) << static_cast< sal_uInt16 >( maLast.mnRow ); 175 if( bCol16Bit ) 176 rStrm << static_cast< sal_uInt16 >( maFirst.mnCol ) << static_cast< sal_uInt16 >( maLast.mnCol ); 177 else 178 rStrm << static_cast< sal_uInt8 >( maFirst.mnCol ) << static_cast< sal_uInt8 >( maLast.mnCol ); 179 } 180 181 // ============================================================================ 182 183 BinRange BinRangeList::getEnclosingRange() const 184 { 185 BinRange aRange; 186 if( !empty() ) 187 { 188 const_iterator aIt = begin(), aEnd = end(); 189 aRange = *aIt; 190 for( ++aIt; aIt != aEnd; ++aIt ) 191 { 192 aRange.maFirst.mnCol = ::std::min( aRange.maFirst.mnCol, aIt->maFirst.mnCol ); 193 aRange.maFirst.mnRow = ::std::min( aRange.maFirst.mnRow, aIt->maFirst.mnRow ); 194 aRange.maLast.mnCol = ::std::max( aRange.maLast.mnCol, aIt->maLast.mnCol ); 195 aRange.maLast.mnRow = ::std::max( aRange.maLast.mnRow, aIt->maLast.mnRow ); 196 } 197 } 198 return aRange; 199 } 200 201 void BinRangeList::read( SequenceInputStream& rStrm ) 202 { 203 sal_Int32 nCount = rStrm.readInt32(); 204 resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 16 ) ); 205 for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) 206 aIt->read( rStrm ); 207 } 208 209 void BinRangeList::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) 210 { 211 sal_uInt16 nCount = rStrm.readuInt16(); 212 resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) ) ); 213 for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) 214 aIt->read( rStrm, bCol16Bit, bRow32Bit ); 215 } 216 217 void BinRangeList::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const 218 { 219 writeSubList( rStrm, 0, size(), bCol16Bit, bRow32Bit ); 220 } 221 222 void BinRangeList::writeSubList( BiffOutputStream& rStrm, size_t nBegin, size_t nCount, bool bCol16Bit, bool bRow32Bit ) const 223 { 224 OSL_ENSURE( nBegin <= size(), "BiffRangeList::writeSubList - invalid start position" ); 225 size_t nEnd = ::std::min< size_t >( nBegin + nCount, size() ); 226 sal_uInt16 nBiffCount = getLimitedValue< sal_uInt16, size_t >( nEnd - nBegin, 0, SAL_MAX_UINT16 ); 227 rStrm << nBiffCount; 228 rStrm.setPortionSize( lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) ); 229 for( const_iterator aIt = begin() + nBegin, aEnd = begin() + nEnd; aIt != aEnd; ++aIt ) 230 aIt->write( rStrm, bCol16Bit, bRow32Bit ); 231 } 232 233 // ============================================================================ 234 // ============================================================================ 235 236 AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) : 237 WorkbookHelper( rHelper ), 238 mbColOverflow( false ), 239 mbRowOverflow( false ), 240 mbTabOverflow( false ) 241 { 242 maDConChars.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF ); 243 switch( getFilterType() ) 244 { 245 case FILTER_OOXML: 246 initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW ); 247 break; 248 case FILTER_BIFF: switch( getBiff() ) 249 { 250 case BIFF2: 251 initializeMaxPos( BIFF2_MAXTAB, BIFF2_MAXCOL, BIFF2_MAXROW ); 252 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF ); 253 break; 254 case BIFF3: 255 initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW ); 256 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF ); 257 break; 258 case BIFF4: 259 initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW ); 260 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' ); 261 break; 262 case BIFF5: 263 initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW ); 264 maLinkChars.set( '\x04', '\x01', '\x02', '\x03', '\x00' ); 265 break; 266 case BIFF8: 267 initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW ); 268 maLinkChars.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' ); 269 break; 270 case BIFF_UNKNOWN: break; 271 } 272 break; 273 case FILTER_UNKNOWN: break; 274 } 275 } 276 277 // ---------------------------------------------------------------------------- 278 279 bool AddressConverter::parseOoxAddress2d( 280 sal_Int32& ornColumn, sal_Int32& ornRow, 281 const OUString& rString, sal_Int32 nStart, sal_Int32 nLength ) 282 { 283 ornColumn = ornRow = 0; 284 if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) ) 285 return false; 286 287 const sal_Unicode* pcChar = rString.getStr() + nStart; 288 const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart ); 289 290 enum { STATE_COL, STATE_ROW } eState = STATE_COL; 291 while( pcChar < pcEndChar ) 292 { 293 sal_Unicode cChar = *pcChar; 294 switch( eState ) 295 { 296 case STATE_COL: 297 { 298 if( ('a' <= cChar) && (cChar <= 'z') ) 299 (cChar -= 'a') += 'A'; 300 if( ('A' <= cChar) && (cChar <= 'Z') ) 301 { 302 /* Return, if 1-based column index is already 6 characters 303 long (12356631 is column index for column AAAAAA). */ 304 if( ornColumn >= 12356631 ) 305 return false; 306 (ornColumn *= 26) += (cChar - 'A' + 1); 307 } 308 else if( ornColumn > 0 ) 309 { 310 --pcChar; 311 eState = STATE_ROW; 312 } 313 else 314 return false; 315 } 316 break; 317 318 case STATE_ROW: 319 { 320 if( ('0' <= cChar) && (cChar <= '9') ) 321 { 322 // return, if 1-based row is already 9 digits long 323 if( ornRow >= 100000000 ) 324 return false; 325 (ornRow *= 10) += (cChar - '0'); 326 } 327 else 328 return false; 329 } 330 break; 331 } 332 ++pcChar; 333 } 334 335 --ornColumn; 336 --ornRow; 337 return (ornColumn >= 0) && (ornRow >= 0); 338 } 339 340 bool AddressConverter::parseOoxRange2d( 341 sal_Int32& ornStartColumn, sal_Int32& ornStartRow, 342 sal_Int32& ornEndColumn, sal_Int32& ornEndRow, 343 const OUString& rString, sal_Int32 nStart, sal_Int32 nLength ) 344 { 345 ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0; 346 if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) ) 347 return false; 348 349 sal_Int32 nEnd = nStart + ::std::min( nLength, rString.getLength() - nStart ); 350 sal_Int32 nColonPos = rString.indexOf( ':', nStart ); 351 if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) ) 352 { 353 return 354 parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) && 355 parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, nLength - nColonPos - 1 ); 356 } 357 358 if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nLength ) ) 359 { 360 ornEndColumn = ornStartColumn; 361 ornEndRow = ornStartRow; 362 return true; 363 } 364 365 return false; 366 } 367 368 namespace { 369 370 bool lclAppendUrlChar( OUStringBuffer& orUrl, sal_Unicode cChar, bool bEncodeSpecial ) 371 { 372 // #126855# encode special characters 373 if( bEncodeSpecial ) switch( cChar ) 374 { 375 case '#': orUrl.appendAscii( "%23" ); return true; 376 case '%': orUrl.appendAscii( "%25" ); return true; 377 } 378 orUrl.append( cChar ); 379 return cChar >= ' '; 380 } 381 382 } // namespace 383 384 BiffTargetType AddressConverter::parseBiffTargetUrl( 385 OUString& orClassName, OUString& orTargetUrl, OUString& orSheetName, 386 const OUString& rBiffTargetUrl, bool bFromDConRec ) 387 { 388 OUStringBuffer aTargetUrl; 389 OUStringBuffer aSheetName; 390 // default target type: some URL with/without sheet name, may be overridden below 391 BiffTargetType eTargetType = BIFF_TARGETTYPE_URL; 392 const ControlCharacters& rCChars = bFromDConRec ? maDConChars : maLinkChars; 393 394 enum 395 { 396 STATE_START, 397 STATE_ENCODED_PATH_START, /// Start of encoded file path. 398 STATE_ENCODED_PATH, /// Inside encoded file path. 399 STATE_ENCODED_DRIVE, /// DOS drive letter or start of UNC path. 400 STATE_ENCODED_URL, /// Encoded URL, e.g. http links. 401 STATE_UNENCODED, /// Unencoded URL, could be DDE or OLE. 402 STATE_DDE_OLE, /// Second part of DDE or OLE link. 403 STATE_FILENAME, /// File name enclosed in brackets. 404 STATE_SHEETNAME, /// Sheet name following enclosed file name. 405 STATE_UNSUPPORTED, /// Unsupported special paths. 406 STATE_ERROR 407 } 408 eState = STATE_START; 409 410 const sal_Unicode* pcChar = rBiffTargetUrl.getStr(); 411 const sal_Unicode* pcEnd = pcChar + rBiffTargetUrl.getLength(); 412 for( ; (eState != STATE_ERROR) && (pcChar < pcEnd); ++pcChar ) 413 { 414 sal_Unicode cChar = *pcChar; 415 switch( eState ) 416 { 417 case STATE_START: 418 if( (cChar == rCChars.mcThisWorkbook) || (cChar == rCChars.mcThisSheet) || (cChar == rCChars.mcSameSheet) ) 419 { 420 if( pcChar + 1 < pcEnd ) 421 eState = STATE_ERROR; 422 if( cChar == rCChars.mcSameSheet ) 423 eTargetType = BIFF_TARGETTYPE_SAMESHEET; 424 } 425 else if( cChar == rCChars.mcExternal ) 426 eState = (pcChar + 1 < pcEnd) ? STATE_ENCODED_PATH_START : STATE_ERROR; 427 else if( cChar == rCChars.mcInternal ) 428 eState = (pcChar + 1 < pcEnd) ? STATE_SHEETNAME : STATE_ERROR; 429 else 430 eState = lclAppendUrlChar( aTargetUrl, cChar, true ) ? STATE_UNENCODED : STATE_ERROR; 431 break; 432 433 case STATE_ENCODED_PATH_START: 434 if( cChar == BIFF_URL_DRIVE ) 435 eState = STATE_ENCODED_DRIVE; 436 else if( cChar == BIFF_URL_ROOT ) 437 { 438 aTargetUrl.append( sal_Unicode( '/' ) ); 439 eState = STATE_ENCODED_PATH; 440 } 441 else if( cChar == BIFF_URL_PARENT ) 442 aTargetUrl.appendAscii( "../" ); 443 else if( cChar == BIFF_URL_RAW ) 444 eState = STATE_ENCODED_URL; 445 else if( cChar == BIFF_URL_INSTALL ) 446 eState = STATE_UNSUPPORTED; 447 else if( cChar == BIFF_URL_INSTALL2 ) 448 eState = STATE_UNSUPPORTED; 449 else if( cChar == BIFF_URL_LIBRARY ) 450 { 451 eState = STATE_ENCODED_PATH; 452 eTargetType = BIFF_TARGETTYPE_LIBRARY; 453 } 454 else if( (getBiff() == BIFF4) && (cChar == BIFF4_URL_SHEET) ) 455 eState = STATE_SHEETNAME; 456 else if( cChar == '[' ) 457 eState = STATE_FILENAME; 458 else if( lclAppendUrlChar( aTargetUrl, cChar, true ) ) 459 eState = STATE_ENCODED_PATH; 460 else 461 eState = STATE_ERROR; 462 break; 463 464 case STATE_ENCODED_PATH: 465 if( cChar == BIFF_URL_SUBDIR ) 466 aTargetUrl.append( sal_Unicode( '/' ) ); 467 else if( cChar == '[' ) 468 eState = STATE_FILENAME; 469 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) ) 470 eState = STATE_ERROR; 471 break; 472 473 case STATE_ENCODED_DRIVE: 474 if( cChar == BIFF_URL_UNC ) 475 { 476 aTargetUrl.appendAscii( "file://" ); 477 eState = STATE_ENCODED_PATH; 478 } 479 else 480 { 481 aTargetUrl.appendAscii( "file:///" ); 482 eState = lclAppendUrlChar( aTargetUrl, cChar, false ) ? STATE_ENCODED_PATH : STATE_ERROR; 483 aTargetUrl.appendAscii( ":/" ); 484 } 485 break; 486 487 case STATE_ENCODED_URL: 488 { 489 sal_Int32 nLength = cChar; 490 if( nLength + 1 == pcEnd - pcChar ) 491 aTargetUrl.append( pcChar + 1, nLength ); 492 else 493 eState = STATE_ERROR; 494 } 495 break; 496 497 case STATE_UNENCODED: 498 if( cChar == BIFF_URL_SUBDIR ) 499 { 500 orClassName = aTargetUrl.makeStringAndClear(); 501 eState = bFromDConRec ? STATE_ERROR : STATE_DDE_OLE; 502 eTargetType = BIFF_TARGETTYPE_DDE_OLE; 503 } 504 else if( cChar == '[' ) 505 eState = STATE_FILENAME; 506 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) ) 507 eState = STATE_ERROR; 508 break; 509 510 case STATE_DDE_OLE: 511 if( !lclAppendUrlChar( aTargetUrl, cChar, true ) ) 512 eState = STATE_ERROR; 513 break; 514 515 case STATE_FILENAME: 516 if( cChar == ']' ) 517 eState = STATE_SHEETNAME; 518 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) ) 519 eState = STATE_ERROR; 520 break; 521 522 case STATE_SHEETNAME: 523 if( !lclAppendUrlChar( aSheetName, cChar, false ) ) 524 eState = STATE_ERROR; 525 break; 526 527 case STATE_UNSUPPORTED: 528 pcChar = pcEnd - 1; 529 break; 530 531 case STATE_ERROR: 532 break; 533 } 534 } 535 536 OSL_ENSURE( (eState != STATE_ERROR) && (pcChar == pcEnd), 537 OStringBuffer( "AddressConverter::parseBiffTargetUrl - parser error in target \"" ). 538 append( OUStringToOString( rBiffTargetUrl, RTL_TEXTENCODING_UTF8 ) ).append( '"' ).getStr() ); 539 bool bParserOk = (eState != STATE_ERROR) && (eState != STATE_UNSUPPORTED) && (pcChar == pcEnd); 540 541 if( bParserOk ) 542 { 543 orTargetUrl = aTargetUrl.makeStringAndClear(); 544 orSheetName = aSheetName.makeStringAndClear(); 545 } 546 else 547 { 548 orClassName = orTargetUrl = orSheetName = OUString(); 549 } 550 551 return bParserOk ? eTargetType : BIFF_TARGETTYPE_UNKNOWN; 552 } 553 554 // ---------------------------------------------------------------------------- 555 556 bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow ) 557 { 558 bool bValid = (0 <= nCol) && (nCol <= maMaxPos.Column); 559 if( !bValid && bTrackOverflow ) 560 mbColOverflow = true; 561 return bValid; 562 } 563 564 bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow ) 565 { 566 bool bValid = (0 <= nRow) && (nRow <= maMaxPos.Row); 567 if( !bValid && bTrackOverflow ) 568 mbRowOverflow = true; 569 return bValid; 570 } 571 572 bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow ) 573 { 574 bool bValid = (0 <= nSheet) && (nSheet <= maMaxPos.Sheet); 575 if( !bValid && bTrackOverflow ) 576 mbTabOverflow |= (nSheet > maMaxPos.Sheet); // do not warn for deleted refs (-1) 577 return bValid; 578 } 579 580 // ---------------------------------------------------------------------------- 581 582 bool AddressConverter::checkCellAddress( const CellAddress& rAddress, bool bTrackOverflow ) 583 { 584 return 585 checkTab( rAddress.Sheet, bTrackOverflow ) && 586 checkCol( rAddress.Column, bTrackOverflow ) && 587 checkRow( rAddress.Row, bTrackOverflow ); 588 } 589 590 bool AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress, 591 const OUString& rString, sal_Int16 nSheet ) 592 { 593 orAddress.Sheet = nSheet; 594 return parseOoxAddress2d( orAddress.Column, orAddress.Row, rString ); 595 } 596 597 bool AddressConverter::convertToCellAddress( CellAddress& orAddress, 598 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow ) 599 { 600 return 601 convertToCellAddressUnchecked( orAddress, rString, nSheet ) && 602 checkCellAddress( orAddress, bTrackOverflow ); 603 } 604 605 CellAddress AddressConverter::createValidCellAddress( 606 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow ) 607 { 608 CellAddress aAddress; 609 if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) ) 610 { 611 aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet ); 612 aAddress.Column = ::std::min( aAddress.Column, maMaxPos.Column ); 613 aAddress.Row = ::std::min( aAddress.Row, maMaxPos.Row ); 614 } 615 return aAddress; 616 } 617 618 void AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress, 619 const BinAddress& rBinAddress, sal_Int16 nSheet ) 620 { 621 orAddress.Sheet = nSheet; 622 orAddress.Column = rBinAddress.mnCol; 623 orAddress.Row = rBinAddress.mnRow; 624 } 625 626 bool AddressConverter::convertToCellAddress( CellAddress& orAddress, 627 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow ) 628 { 629 convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet ); 630 return checkCellAddress( orAddress, bTrackOverflow ); 631 } 632 633 CellAddress AddressConverter::createValidCellAddress( 634 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow ) 635 { 636 CellAddress aAddress; 637 if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) ) 638 { 639 aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet ); 640 aAddress.Column = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, maMaxPos.Column ); 641 aAddress.Row = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, maMaxPos.Row ); 642 } 643 return aAddress; 644 } 645 646 // ---------------------------------------------------------------------------- 647 648 bool AddressConverter::checkCellRange( const CellRangeAddress& rRange, bool bAllowOverflow, bool bTrackOverflow ) 649 { 650 return 651 (checkCol( rRange.EndColumn, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow! 652 (checkRow( rRange.EndRow, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow! 653 checkTab( rRange.Sheet, bTrackOverflow ) && 654 checkCol( rRange.StartColumn, bTrackOverflow ) && 655 checkRow( rRange.StartRow, bTrackOverflow ); 656 } 657 658 bool AddressConverter::validateCellRange( CellRangeAddress& orRange, bool bAllowOverflow, bool bTrackOverflow ) 659 { 660 if( orRange.StartColumn > orRange.EndColumn ) 661 ::std::swap( orRange.StartColumn, orRange.EndColumn ); 662 if( orRange.StartRow > orRange.EndRow ) 663 ::std::swap( orRange.StartRow, orRange.EndRow ); 664 if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) ) 665 return false; 666 if( orRange.EndColumn > maMaxPos.Column ) 667 orRange.EndColumn = maMaxPos.Column; 668 if( orRange.EndRow > maMaxPos.Row ) 669 orRange.EndRow = maMaxPos.Row; 670 return true; 671 } 672 673 bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange, 674 const OUString& rString, sal_Int16 nSheet ) 675 { 676 orRange.Sheet = nSheet; 677 return parseOoxRange2d( orRange.StartColumn, orRange.StartRow, orRange.EndColumn, orRange.EndRow, rString ); 678 } 679 680 bool AddressConverter::convertToCellRange( CellRangeAddress& orRange, 681 const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow ) 682 { 683 return 684 convertToCellRangeUnchecked( orRange, rString, nSheet ) && 685 validateCellRange( orRange, bAllowOverflow, bTrackOverflow ); 686 } 687 688 void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange, 689 const BinRange& rBinRange, sal_Int16 nSheet ) 690 { 691 orRange.Sheet = nSheet; 692 orRange.StartColumn = rBinRange.maFirst.mnCol; 693 orRange.StartRow = rBinRange.maFirst.mnRow; 694 orRange.EndColumn = rBinRange.maLast.mnCol; 695 orRange.EndRow = rBinRange.maLast.mnRow; 696 } 697 698 bool AddressConverter::convertToCellRange( CellRangeAddress& orRange, 699 const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow ) 700 { 701 convertToCellRangeUnchecked( orRange, rBinRange, nSheet ); 702 return validateCellRange( orRange, bAllowOverflow, bTrackOverflow ); 703 } 704 705 // ---------------------------------------------------------------------------- 706 707 bool AddressConverter::checkCellRangeList( const ApiCellRangeList& rRanges, bool bAllowOverflow, bool bTrackOverflow ) 708 { 709 for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt ) 710 if( !checkCellRange( *aIt, bAllowOverflow, bTrackOverflow ) ) 711 return false; 712 return true; 713 } 714 715 void AddressConverter::validateCellRangeList( ApiCellRangeList& orRanges, bool bTrackOverflow ) 716 { 717 for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex ) 718 if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) ) 719 orRanges.erase( orRanges.begin() + nIndex - 1 ); 720 } 721 722 void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges, 723 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow ) 724 { 725 sal_Int32 nPos = 0; 726 sal_Int32 nLen = rString.getLength(); 727 CellRangeAddress aRange; 728 while( (0 <= nPos) && (nPos < nLen) ) 729 { 730 OUString aToken = rString.getToken( 0, ' ', nPos ); 731 if( (aToken.getLength() > 0) && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) ) 732 orRanges.push_back( aRange ); 733 } 734 } 735 736 void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges, 737 const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow ) 738 { 739 CellRangeAddress aRange; 740 for( BinRangeList::const_iterator aIt = rBinRanges.begin(), aEnd = rBinRanges.end(); aIt != aEnd; ++aIt ) 741 if( convertToCellRange( aRange, *aIt, nSheet, true, bTrackOverflow ) ) 742 orRanges.push_back( aRange ); 743 } 744 745 // private -------------------------------------------------------------------- 746 747 void AddressConverter::ControlCharacters::set( 748 sal_Unicode cThisWorkbook, sal_Unicode cExternal, 749 sal_Unicode cThisSheet, sal_Unicode cInternal, sal_Unicode cSameSheet ) 750 { 751 mcThisWorkbook = cThisWorkbook; 752 mcExternal = cExternal; 753 mcThisSheet = cThisSheet; 754 mcInternal = cInternal; 755 mcSameSheet = cSameSheet; 756 } 757 758 void AddressConverter::initializeMaxPos( 759 sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow ) 760 { 761 maMaxXlsPos.Sheet = nMaxXlsTab; 762 maMaxXlsPos.Column = nMaxXlsCol; 763 maMaxXlsPos.Row = nMaxXlsRow; 764 765 // maximum cell position in Calc 766 try 767 { 768 Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW ); 769 Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW ); 770 CellRangeAddress aRange = xAddressable->getRangeAddress(); 771 maMaxApiPos = CellAddress( API_MAXTAB, aRange.EndColumn, aRange.EndRow ); 772 maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos; 773 } 774 catch( Exception& ) 775 { 776 OSL_ENSURE( false, "AddressConverter::AddressConverter - cannot get sheet limits" ); 777 } 778 } 779 780 // ============================================================================ 781 782 } // namespace xls 783 } // namespace oox 784