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