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 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 #include "address.hxx" 28 #include "global.hxx" 29 #include "compiler.hxx" 30 #include "document.hxx" 31 #include "externalrefmgr.hxx" 32 33 #include "globstr.hrc" 34 #include <sal/alloca.h> 35 36 #include <com/sun/star/frame/XModel.hpp> 37 #include <com/sun/star/beans/XPropertySet.hpp> 38 #include <com/sun/star/sheet/ExternalLinkInfo.hpp> 39 #include <com/sun/star/sheet/ExternalLinkType.hpp> 40 #include <sfx2/objsh.hxx> 41 #include <tools/urlobj.hxx> 42 using namespace ::com::sun::star; 43 44 //////////////////////////////////////////////////////////////////////////// 45 const ScAddress::Details ScAddress::detailsOOOa1( formula::FormulaGrammar::CONV_OOO, 0, 0 ); 46 47 ScAddress::Details::Details ( const ScDocument* pDoc, 48 const ScAddress & rAddr ) : 49 eConv( pDoc->GetAddressConvention() ), 50 nRow( rAddr.Row() ), 51 nCol( rAddr.Col() ) 52 { 53 } 54 55 //UNUSED2009-05 void ScAddress::Details::SetPos ( const ScDocument* pDoc, 56 //UNUSED2009-05 const ScAddress & rAddr ) 57 //UNUSED2009-05 { 58 //UNUSED2009-05 nRow = rAddr.Row(); 59 //UNUSED2009-05 nCol = rAddr.Col(); 60 //UNUSED2009-05 eConv = pDoc->GetAddressConvention(); 61 //UNUSED2009-05 } 62 63 //////////////////////////////////////////////////////////////////////////// 64 65 #include <iostream> 66 67 /** 68 * Parse from the opening single quote to the closing single quote. Inside 69 * the quotes, a single quote character is encoded by double single-quote 70 * characters. 71 * 72 * @param p pointer to the first character to begin parsing. 73 * @param rName (reference) parsed name within the quotes. If the name is 74 * empty, either the parsing failed or it's an empty quote. 75 * 76 * @return pointer to the character immediately after the closing single 77 * quote. 78 */ 79 static const sal_Unicode* lcl_ParseQuotedName( const sal_Unicode* p, String& rName ) 80 { 81 rName.Erase(); 82 if (*p != '\'') 83 return p; 84 85 const sal_Unicode* pStart = p; 86 sal_Unicode cPrev = 0; 87 for (++p; *p; ++p) 88 { 89 if (*p == '\'') 90 { 91 if (cPrev == '\'') 92 { 93 // double single-quote equals one single quote. 94 rName += *p; 95 cPrev = 0; 96 continue; 97 } 98 } 99 else if (cPrev == '\'') 100 // We are past the closing quote. We're done! 101 return p; 102 else 103 rName += *p; 104 cPrev = *p; 105 } 106 rName.Erase(); 107 return pStart; 108 } 109 110 static long int 111 sal_Unicode_strtol ( const sal_Unicode* p, 112 const sal_Unicode** pEnd ) 113 { 114 long int accum = 0, prev = 0; 115 bool is_neg = false; 116 117 if( *p == '-' ) 118 { 119 is_neg = true; 120 p++; 121 } 122 else if( *p == '+' ) 123 p++; 124 125 while (CharClass::isAsciiDigit( *p )) 126 { 127 accum = accum * 10 + *p - '0'; 128 if( accum < prev ) 129 { 130 *pEnd = NULL; 131 return 0; 132 } 133 prev = accum; 134 p++; 135 } 136 137 *pEnd = p; 138 return is_neg ? -accum : accum; 139 } 140 141 const sal_Unicode* lcl_eatWhiteSpace( const sal_Unicode* p ) 142 { 143 if ( p ) 144 { 145 while( *p == ' ' ) 146 ++p; 147 } 148 return p; 149 } 150 151 /** Determines the number of sheets an external reference spans and sets 152 rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding 153 bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in 154 cached order rStartTabName comes after rEndTabName, pExtInfo->maTabName 155 is set to rEndTabName. 156 @returns <FALSE/> if pExtInfo is already filled and rExternDocName does not 157 result in the identical file ID. Else <TRUE/>. 158 */ 159 static bool lcl_ScRange_External_TabSpan( 160 ScRange & rRange, 161 sal_uInt16 & rFlags, 162 ScAddress::ExternalInfo* pExtInfo, 163 const String & rExternDocName, 164 const String & rStartTabName, 165 const String & rEndTabName, 166 ScDocument* pDoc ) 167 { 168 if (!rExternDocName.Len()) 169 return !pExtInfo || !pExtInfo->mbExternal; 170 171 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 172 if (pRefMgr->isOwnDocument( rExternDocName)) 173 return !pExtInfo || !pExtInfo->mbExternal; 174 175 sal_uInt16 nFileId = pRefMgr->getExternalFileId( rExternDocName); 176 177 if (pExtInfo) 178 { 179 if (pExtInfo->mbExternal) 180 { 181 if (pExtInfo->mnFileId != nFileId) 182 return false; 183 } 184 else 185 { 186 pExtInfo->mbExternal = true; 187 pExtInfo->maTabName = rStartTabName; 188 pExtInfo->mnFileId = nFileId; 189 } 190 } 191 192 if (!rEndTabName.Len() || rStartTabName == rEndTabName) 193 { 194 rRange.aEnd.SetTab( rRange.aStart.Tab()); 195 return true; 196 } 197 198 SCsTAB nSpan = pRefMgr->getCachedTabSpan( nFileId, rStartTabName, rEndTabName); 199 if (nSpan == -1) 200 rFlags &= ~(SCA_VALID_TAB | SCA_VALID_TAB2); 201 else if (nSpan == 0) 202 rFlags &= ~SCA_VALID_TAB2; 203 else if (nSpan >= 1) 204 rRange.aEnd.SetTab( rRange.aStart.Tab() + nSpan - 1); 205 else // (nSpan < -1) 206 { 207 rRange.aEnd.SetTab( rRange.aStart.Tab() - nSpan - 1); 208 if (pExtInfo) 209 pExtInfo->maTabName = rEndTabName; 210 } 211 return true; 212 } 213 214 /** Returns NULL if the string should be a sheet name, but is invalid. 215 Returns a pointer to the first character after the sheet name, if there was 216 any, else pointer to start. 217 @param pMsoxlQuoteStop 218 Starting _within_ a quoted name, but still may be 3D; quoted name stops 219 at pMsoxlQuoteStop 220 */ 221 static const sal_Unicode * 222 lcl_XL_ParseSheetRef( const sal_Unicode* start, 223 String& rExternTabName, 224 bool allow_3d, 225 const sal_Unicode* pMsoxlQuoteStop ) 226 { 227 String aTabName; 228 const sal_Unicode *p = start; 229 230 // XL only seems to use single quotes for sheet names. 231 if (pMsoxlQuoteStop) 232 { 233 const sal_Unicode* pCurrentStart = p; 234 while (p < pMsoxlQuoteStop) 235 { 236 if (*p == '\'') 237 { 238 // We pre-analyzed the quoting, no checks needed here. 239 if (*++p == '\'') 240 { 241 aTabName.Append( pCurrentStart, 242 sal::static_int_cast<xub_StrLen>( p - pCurrentStart)); 243 pCurrentStart = ++p; 244 } 245 } 246 else if (*p == ':') 247 { 248 break; // while 249 } 250 else 251 ++p; 252 } 253 if (pCurrentStart < p) 254 aTabName.Append( pCurrentStart, sal::static_int_cast<xub_StrLen>( p - pCurrentStart)); 255 if (!aTabName.Len()) 256 return NULL; 257 if (p == pMsoxlQuoteStop) 258 ++p; // position on ! of ...'!... 259 if( *p != '!' && ( !allow_3d || *p != ':' ) ) 260 return (!allow_3d && *p == ':') ? p : start; 261 } 262 else if( *p == '\'') 263 { 264 p = lcl_ParseQuotedName(p, aTabName); 265 if (!aTabName.Len()) 266 return NULL; 267 } 268 else 269 { 270 bool only_digits = sal_True; 271 272 /* 273 * Valid: Normal!a1 274 * Valid: x.y!a1 275 * Invalid: .y!a1 276 * 277 * Some names starting with digits are actually valid, but 278 * unparse quoted. Things are quite tricky: most sheet names 279 * starting with a digit are ok, but not those starting with 280 * "[0-9]*\." or "[0-9]+[eE]". 281 * 282 * Valid: 42!a1 283 * Valid: 4x!a1 284 * Invalid: 1.!a1 285 * Invalid: 1e!a1 286 */ 287 while( 1 ) 288 { 289 const sal_Unicode uc = *p; 290 if( CharClass::isAsciiAlpha( uc ) || uc == '_' ) 291 { 292 if( only_digits && p != start && 293 (uc == 'e' || uc == 'E' ) ) 294 { 295 p = start; 296 break; 297 } 298 only_digits = sal_False; 299 p++; 300 } 301 else if( CharClass::isAsciiDigit( uc )) 302 { 303 p++; 304 } 305 else if( uc == '.' ) 306 { 307 if( only_digits ) // Valid, except after only digits. 308 { 309 p = start; 310 break; 311 } 312 p++; 313 } 314 else if (uc > 127) 315 { 316 // non ASCII character is allowed. 317 ++p; 318 } 319 else 320 break; 321 } 322 323 if( *p != '!' && ( !allow_3d || *p != ':' ) ) 324 return (!allow_3d && *p == ':') ? p : start; 325 326 aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) ); 327 } 328 329 rExternTabName = aTabName; 330 return p; 331 } 332 333 334 const sal_Unicode* ScRange::Parse_XL_Header( 335 const sal_Unicode* p, 336 const ScDocument* pDoc, 337 String& rExternDocName, 338 String& rStartTabName, 339 String& rEndTabName, 340 sal_uInt16& nFlags, 341 bool bOnlyAcceptSingle, 342 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 343 { 344 const sal_Unicode* startTabs, *start = p; 345 sal_uInt16 nSaveFlags = nFlags; 346 347 // Is this an external reference ? 348 rStartTabName.Erase(); 349 rEndTabName.Erase(); 350 rExternDocName.Erase(); 351 const sal_Unicode* pMsoxlQuoteStop = NULL; 352 if (*p == '[') 353 { 354 ++p; 355 // Only single quotes are correct, and a double single quote escapes a 356 // single quote text inside the quoted text. 357 if (*p == '\'') 358 { 359 p = lcl_ParseQuotedName(p, rExternDocName); 360 if (!*p || *p != ']' || !rExternDocName.Len()) 361 { 362 rExternDocName.Erase(); 363 return start; 364 } 365 } 366 else 367 { 368 // non-quoted file name. 369 p = ScGlobal::UnicodeStrChr( start+1, ']' ); 370 if( p == NULL ) 371 return start; 372 rExternDocName.Append( start+1, sal::static_int_cast<xub_StrLen>( p-(start+1) ) ); 373 } 374 ++p; 375 376 if (pExternalLinks && pExternalLinks->hasElements()) 377 { 378 // A numeric "document name" is an index into the sequence. 379 if (CharClass::isAsciiNumeric( rExternDocName)) 380 { 381 sal_Int32 i = rExternDocName.ToInt32(); 382 if (i < 0 || i >= pExternalLinks->getLength()) 383 return start; 384 const sheet::ExternalLinkInfo & rInfo = (*pExternalLinks)[i]; 385 switch (rInfo.Type) 386 { 387 case sheet::ExternalLinkType::DOCUMENT : 388 { 389 rtl::OUString aStr; 390 if (!(rInfo.Data >>= aStr)) 391 { 392 DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i); 393 return NULL; 394 } 395 rExternDocName = aStr; 396 } 397 break; 398 case sheet::ExternalLinkType::SELF : 399 return start; // ??? 400 case sheet::ExternalLinkType::SPECIAL : 401 // silently return nothing (do not assert), caller has to handle this 402 return NULL; 403 default: 404 DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d", 405 rInfo.Type, i); 406 return NULL; 407 } 408 } 409 } 410 rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell()); 411 } 412 else if (*p == '\'') 413 { 414 // Sickness in Excel's ODF msoxl namespace: 415 // 'E:\[EXTDATA8.XLS]Sheet1'!$A$7 or 416 // 'E:\[EXTDATA12B.XLSB]Sheet1:Sheet3'!$A$11 417 // But, 'Sheet1'!B3 would also be a valid! 418 // Excel does not allow [ and ] characters in sheet names though. 419 p = lcl_ParseQuotedName(p, rExternDocName); 420 if (!*p || *p != '!') 421 { 422 rExternDocName.Erase(); 423 return start; 424 } 425 if (rExternDocName.Len()) 426 { 427 xub_StrLen nOpen = rExternDocName.Search( '['); 428 if (nOpen == STRING_NOTFOUND) 429 rExternDocName.Erase(); 430 else 431 { 432 xub_StrLen nClose = rExternDocName.Search( ']', nOpen+1); 433 if (nClose == STRING_NOTFOUND) 434 rExternDocName.Erase(); 435 else 436 { 437 rExternDocName.Erase( nClose); 438 rExternDocName.Erase( nOpen, 1); 439 pMsoxlQuoteStop = p - 1; // the ' quote char 440 // There may be embedded escaped quotes, just matching the 441 // doc name's length may not work. 442 for (p = start; *p != '['; ++p) 443 ; 444 for ( ; *p != ']'; ++p) 445 ; 446 ++p; 447 } 448 } 449 } 450 if (!rExternDocName.Len()) 451 p = start; 452 } 453 454 startTabs = p; 455 p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop); 456 if( NULL == p ) 457 return start; // invalid tab 458 if (bOnlyAcceptSingle && *p == ':') 459 return NULL; // 3D 460 if( p != startTabs ) 461 { 462 nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE; 463 if( *p == ':' ) // 3d ref 464 { 465 p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false, pMsoxlQuoteStop); 466 if( p == NULL ) 467 { 468 nFlags = nSaveFlags; 469 return start; // invalid tab 470 } 471 nFlags |= SCA_VALID_TAB2 | SCA_TAB2_3D | SCA_TAB2_ABSOLUTE; 472 } 473 else 474 { 475 // If only one sheet is given, the full reference is still valid, 476 // only the second 3D flag is not set. 477 nFlags |= SCA_VALID_TAB2 | SCA_TAB2_ABSOLUTE; 478 aEnd.SetTab( aStart.Tab() ); 479 } 480 481 if( *p++ != '!' ) 482 { 483 nFlags = nSaveFlags; 484 return start; // syntax error 485 } 486 else 487 p = lcl_eatWhiteSpace( p ); 488 } 489 else 490 { 491 nFlags |= SCA_VALID_TAB | SCA_VALID_TAB2; 492 // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. ); 493 } 494 495 if (rExternDocName.Len()) 496 { 497 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 498 pRefMgr->convertToAbsName( rExternDocName); 499 } 500 else 501 { 502 // Internal reference. 503 if (!rStartTabName.Len()) 504 { 505 nFlags = nSaveFlags; 506 return start; 507 } 508 509 SCTAB nTab; 510 if (!pDoc->GetTable(rStartTabName, nTab)) 511 { 512 // invalid table name. 513 nFlags &= ~SCA_VALID_TAB; 514 nTab = -1; 515 } 516 517 aStart.SetTab(nTab); 518 aEnd.SetTab(nTab); 519 520 if (rEndTabName.Len()) 521 { 522 if (!pDoc->GetTable(rEndTabName, nTab)) 523 { 524 // invalid table name. 525 nFlags &= ~SCA_VALID_TAB2; 526 nTab = -1; 527 } 528 529 aEnd.SetTab(nTab); 530 } 531 } 532 return p; 533 } 534 535 536 static const sal_Unicode* 537 lcl_r1c1_get_col( const sal_Unicode* p, 538 const ScAddress::Details& rDetails, 539 ScAddress* pAddr, sal_uInt16* nFlags ) 540 { 541 const sal_Unicode *pEnd; 542 long int n; 543 bool isRelative; 544 545 if( p[0] == '\0' ) 546 return NULL; 547 548 p++; 549 if( (isRelative = (*p == '[') ) != false ) 550 p++; 551 n = sal_Unicode_strtol( p, &pEnd ); 552 if( NULL == pEnd ) 553 return NULL; 554 555 if( p == pEnd ) // C is a relative ref with offset 0 556 { 557 if( isRelative ) 558 return NULL; 559 n = rDetails.nCol; 560 } 561 else if( isRelative ) 562 { 563 if( *pEnd != ']' ) 564 return NULL; 565 n += rDetails.nCol; 566 pEnd++; 567 } 568 else 569 { 570 *nFlags |= SCA_COL_ABSOLUTE; 571 n--; 572 } 573 574 if( n < 0 || n >= MAXCOLCOUNT ) 575 return NULL; 576 pAddr->SetCol( static_cast<SCCOL>( n ) ); 577 *nFlags |= SCA_VALID_COL; 578 579 return pEnd; 580 } 581 static inline const sal_Unicode* 582 lcl_r1c1_get_row( const sal_Unicode* p, 583 const ScAddress::Details& rDetails, 584 ScAddress* pAddr, sal_uInt16* nFlags ) 585 { 586 const sal_Unicode *pEnd; 587 long int n; 588 bool isRelative; 589 590 if( p[0] == '\0' ) 591 return NULL; 592 593 p++; 594 if( (isRelative = (*p == '[') ) != false ) 595 p++; 596 n = sal_Unicode_strtol( p, &pEnd ); 597 if( NULL == pEnd ) 598 return NULL; 599 600 if( p == pEnd ) // R is a relative ref with offset 0 601 { 602 if( isRelative ) 603 return NULL; 604 n = rDetails.nRow; 605 } 606 else if( isRelative ) 607 { 608 if( *pEnd != ']' ) 609 return NULL; 610 n += rDetails.nRow; 611 pEnd++; 612 } 613 else 614 { 615 *nFlags |= SCA_ROW_ABSOLUTE; 616 n--; 617 } 618 619 if( n < 0 || n >= MAXROWCOUNT ) 620 return NULL; 621 pAddr->SetRow( static_cast<SCROW>( n ) ); 622 *nFlags |= SCA_VALID_ROW; 623 624 return pEnd; 625 } 626 627 static sal_uInt16 628 lcl_ScRange_Parse_XL_R1C1( ScRange& r, 629 const sal_Unicode* p, 630 ScDocument* pDoc, 631 const ScAddress::Details& rDetails, 632 bool bOnlyAcceptSingle, 633 ScAddress::ExternalInfo* pExtInfo ) 634 { 635 const sal_Unicode* pTmp = NULL; 636 String aExternDocName, aStartTabName, aEndTabName; 637 sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB; 638 // Keep in mind that nFlags2 gets left-shifted by 4 bits before being merged. 639 sal_uInt16 nFlags2 = SCA_VALID_TAB; 640 641 #if 0 642 { 643 ByteString aStr(p, RTL_TEXTENCODING_UTF8); 644 aStr.Append(static_cast< char >(0)); 645 std::cerr << "parse::XL::R1C1 \'" << aStr.GetBuffer() << '\'' << std::endl; 646 } 647 #endif 648 p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName, 649 aEndTabName, nFlags, bOnlyAcceptSingle, NULL ); 650 651 if (aExternDocName.Len() > 0) 652 lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName, 653 aStartTabName, aEndTabName, pDoc); 654 655 if( NULL == p ) 656 return 0; 657 658 if( *p == 'R' || *p == 'r' ) 659 { 660 if( NULL == (p = lcl_r1c1_get_row( p, rDetails, &r.aStart, &nFlags )) ) 661 goto failed; 662 663 if( *p != 'C' && *p != 'c' ) // full row R# 664 { 665 if( p[0] != ':' || (p[1] != 'R' && p[1] != 'r' ) || 666 NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 ))) 667 { 668 // Only the initial row number is given, or the second row 669 // number is invalid. Fallback to just the initial R 670 nFlags |= (nFlags << 4); 671 r.aEnd.SetRow( r.aStart.Row() ); 672 } 673 else 674 { 675 // Full row range successfully parsed. 676 nFlags |= (nFlags2 << 4); 677 p = pTmp; 678 } 679 680 if (p && p[0] != 0) 681 { 682 // any trailing invalid character must invalidate the whole address. 683 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 684 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 685 return nFlags; 686 } 687 688 nFlags |= 689 SCA_VALID_COL | SCA_VALID_COL2 | 690 SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE; 691 r.aStart.SetCol( 0 ); 692 r.aEnd.SetCol( MAXCOL ); 693 694 return bOnlyAcceptSingle ? 0 : nFlags; 695 } 696 else if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags ))) 697 goto failed; 698 699 if( p[0] != ':' || 700 (p[1] != 'R' && p[1] != 'r') || 701 NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 )) || 702 (*pTmp != 'C' && *pTmp != 'c') || 703 NULL == (pTmp = lcl_r1c1_get_col( pTmp, rDetails, &r.aEnd, &nFlags2 ))) 704 { 705 // single cell reference 706 707 if (p && p[0] != 0) 708 { 709 // any trailing invalid character must invalidate the whole address. 710 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB); 711 return nFlags; 712 } 713 714 return bOnlyAcceptSingle ? nFlags : 0; 715 } 716 p = pTmp; 717 718 // double reference 719 720 if (p && p[0] != 0) 721 { 722 // any trailing invalid character must invalidate the whole range. 723 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 724 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 725 return nFlags; 726 } 727 728 nFlags |= (nFlags2 << 4); 729 return bOnlyAcceptSingle ? 0 : nFlags; 730 } 731 else if( *p == 'C' || *p == 'c' ) // full col C# 732 { 733 if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags ))) 734 goto failed; 735 736 if( p[0] != ':' || (p[1] != 'C' && p[1] != 'c') || 737 NULL == (pTmp = lcl_r1c1_get_col( p+1, rDetails, &r.aEnd, &nFlags2 ))) 738 { // Fallback to just the initial C 739 nFlags |= (nFlags << 4); 740 r.aEnd.SetCol( r.aStart.Col() ); 741 } 742 else 743 { 744 nFlags |= (nFlags2 << 4); 745 p = pTmp; 746 } 747 748 if (p && p[0] != 0) 749 { 750 // any trailing invalid character must invalidate the whole address. 751 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 752 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 753 return nFlags; 754 } 755 756 nFlags |= 757 SCA_VALID_ROW | SCA_VALID_ROW2 | 758 SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE; 759 r.aStart.SetRow( 0 ); 760 r.aEnd.SetRow( MAXROW ); 761 762 return bOnlyAcceptSingle ? 0 : nFlags; 763 } 764 765 failed : 766 return 0; 767 } 768 769 static inline const sal_Unicode* 770 lcl_a1_get_col( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags ) 771 { 772 SCCOL nCol; 773 774 if( *p == '$' ) 775 *nFlags |= SCA_COL_ABSOLUTE, p++; 776 777 if( !CharClass::isAsciiAlpha( *p ) ) 778 return NULL; 779 780 nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' ); 781 while (nCol <= MAXCOL && CharClass::isAsciiAlpha(*p)) 782 nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' ); 783 if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) ) 784 return NULL; 785 786 *nFlags |= SCA_VALID_COL; 787 pAddr->SetCol( nCol ); 788 789 return p; 790 } 791 792 static inline const sal_Unicode* 793 lcl_a1_get_row( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags ) 794 { 795 const sal_Unicode *pEnd; 796 long int n; 797 798 if( *p == '$' ) 799 *nFlags |= SCA_ROW_ABSOLUTE, p++; 800 801 n = sal_Unicode_strtol( p, &pEnd ) - 1; 802 if( NULL == pEnd || p == pEnd || n < 0 || n > MAXROW ) 803 return NULL; 804 805 *nFlags |= SCA_VALID_ROW; 806 pAddr->SetRow( static_cast<SCROW>(n) ); 807 808 return pEnd; 809 } 810 811 static sal_uInt16 812 lcl_ScRange_Parse_XL_A1( ScRange& r, 813 const sal_Unicode* p, 814 ScDocument* pDoc, 815 bool bOnlyAcceptSingle, 816 ScAddress::ExternalInfo* pExtInfo, 817 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 818 { 819 const sal_Unicode* tmp1, *tmp2; 820 String aExternDocName, aStartTabName, aEndTabName; // for external link table 821 sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB; 822 823 #if 0 824 { 825 ByteString aStr(p, RTL_TEXTENCODING_UTF8); 826 aStr.Append(static_cast< char >(0)); 827 std::cerr << "parse::XL::A1 \'" << aStr.GetBuffer() << '\'' << std::endl; 828 } 829 #endif 830 p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName, 831 aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks ); 832 833 if (aExternDocName.Len() > 0) 834 lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName, 835 aStartTabName, aEndTabName, pDoc); 836 837 if( NULL == p ) 838 return 0; 839 840 tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags ); 841 if( tmp1 == NULL ) // Is it a row only reference 3:5 842 { 843 if( bOnlyAcceptSingle ) // by definition full row refs are ranges 844 return 0; 845 846 tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags ); 847 848 tmp1 = lcl_eatWhiteSpace( tmp1 ); 849 if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2) 850 return 0; 851 852 tmp1 = lcl_eatWhiteSpace( tmp1 ); 853 tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 ); 854 if( !tmp2 ) 855 return 0; 856 857 r.aStart.SetCol( 0 ); r.aEnd.SetCol( MAXCOL ); 858 nFlags |= 859 SCA_VALID_COL | SCA_VALID_COL2 | 860 SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE; 861 nFlags |= (nFlags2 << 4); 862 return nFlags; 863 } 864 865 tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags ); 866 if( tmp2 == NULL ) // check for col only reference F:H 867 { 868 if( bOnlyAcceptSingle ) // by definition full col refs are ranges 869 return 0; 870 871 tmp1 = lcl_eatWhiteSpace( tmp1 ); 872 if( *tmp1++ != ':' ) // Even a singleton requires ':' (eg F:F) 873 return 0; 874 875 tmp1 = lcl_eatWhiteSpace( tmp1 ); 876 tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 ); 877 if( !tmp2 ) 878 return 0; 879 880 r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW ); 881 nFlags |= 882 SCA_VALID_ROW | SCA_VALID_ROW2 | 883 SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE; 884 nFlags |= (nFlags2 << 4); 885 return nFlags; 886 } 887 888 // prepare as if it's a singleton, in case we want to fall back */ 889 r.aEnd.SetCol( r.aStart.Col() ); 890 r.aEnd.SetRow( r.aStart.Row() ); // don't overwrite sheet number as parsed in Parse_XL_Header() 891 892 if ( bOnlyAcceptSingle ) 893 { 894 if ( *tmp2 == 0 ) 895 return nFlags; 896 else 897 { 898 // any trailing invalid character must invalidate the address. 899 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB); 900 return nFlags; 901 } 902 } 903 904 tmp2 = lcl_eatWhiteSpace( tmp2 ); 905 if( *tmp2 != ':' ) 906 { 907 // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is 908 // not. Any trailing invalid character invalidates the range. 909 if (*tmp2 == 0 && (nFlags & SCA_TAB2_3D)) 910 { 911 if (nFlags & SCA_COL_ABSOLUTE) 912 nFlags |= SCA_COL2_ABSOLUTE; 913 if (nFlags & SCA_ROW_ABSOLUTE) 914 nFlags |= SCA_ROW2_ABSOLUTE; 915 } 916 else 917 nFlags &= ~(SCA_VALID | 918 SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 919 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 920 return nFlags; 921 } 922 923 p = tmp2; 924 p = lcl_eatWhiteSpace( p+1 ); 925 tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 ); 926 if( !tmp1 ) // strange, but valid singleton 927 return nFlags; 928 929 tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 ); 930 if( !tmp2 ) // strange, but valid singleton 931 return nFlags; 932 933 if ( *tmp2 != 0 ) 934 { 935 // any trailing invalid character must invalidate the range. 936 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 937 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 938 return nFlags; 939 } 940 941 nFlags |= (nFlags2 << 4); 942 return nFlags; 943 } 944 945 /** 946 @param pRange pointer to range where rAddr effectively is *pRange->aEnd, 947 used in conjunction with pExtInfo to determine the tab span 948 of a 3D reference. 949 */ 950 static sal_uInt16 951 lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, 952 ScAddress::ExternalInfo* pExtInfo = NULL, ScRange* pRange = NULL ) 953 { 954 sal_uInt16 nRes = 0; 955 String aDocName; // der pure Dokumentenname 956 String aTab; 957 bool bExtDoc = false; 958 bool bExtDocInherited = false; 959 const ScAddress aCurPos(rAddr); 960 961 // Lets see if this is a reference to something in an external file. A 962 // document name is always quoted and has a trailing #. 963 if (*p == '\'') 964 { 965 const sal_Unicode* pStart = p; 966 p = lcl_ParseQuotedName(p, aDocName); 967 if (*p++ == SC_COMPILER_FILE_TAB_SEP) 968 bExtDoc = true; 969 else 970 // This is not a document name. Perhaps a quoted relative table 971 // name. 972 p = pStart; 973 } 974 else if (pExtInfo && pExtInfo->mbExternal) 975 { 976 // This is an external reference. 977 bExtDoc = bExtDocInherited = true; 978 } 979 980 SCCOL nCol = 0; 981 SCROW nRow = 0; 982 SCTAB nTab = 0; 983 sal_uInt16 nBits = SCA_VALID_TAB; 984 const sal_Unicode* q; 985 if ( ScGlobal::FindUnquoted( p, '.') ) 986 { 987 nRes |= SCA_TAB_3D; 988 if ( bExtDoc ) 989 nRes |= SCA_TAB_ABSOLUTE; 990 if (*p == '$') 991 nRes |= SCA_TAB_ABSOLUTE, p++; 992 993 if (*p == '\'') 994 { 995 // Tokens that start at ' can have anything in them until a final 996 // ' but '' marks an escaped '. We've earlier guaranteed that a 997 // string containing '' will be surrounded by '. 998 p = lcl_ParseQuotedName(p, aTab); 999 } 1000 else 1001 { 1002 while (*p) 1003 { 1004 if( *p == '.') 1005 break; 1006 1007 if( *p == '\'' ) 1008 { 1009 p++; break; 1010 } 1011 aTab += *p++; 1012 } 1013 } 1014 if( *p++ != '.' ) 1015 nBits = 0; 1016 1017 if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab ))) 1018 nBits = 0; 1019 } 1020 else 1021 { 1022 if (bExtDoc && !bExtDocInherited) 1023 return nRes; // After a document a sheet must follow. 1024 nTab = rAddr.Tab(); 1025 } 1026 nRes |= nBits; 1027 1028 q = p; 1029 if (*p) 1030 { 1031 nBits = SCA_VALID_COL; 1032 if (*p == '$') 1033 nBits |= SCA_COL_ABSOLUTE, p++; 1034 1035 if (CharClass::isAsciiAlpha( *p )) 1036 { 1037 nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' ); 1038 while (nCol < MAXCOL && CharClass::isAsciiAlpha(*p)) 1039 nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' ); 1040 } 1041 else 1042 nBits = 0; 1043 1044 if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) ) 1045 nBits = 0; 1046 nRes |= nBits; 1047 if( !nBits ) 1048 p = q; 1049 } 1050 1051 q = p; 1052 if (*p) 1053 { 1054 nBits = SCA_VALID_ROW; 1055 if (*p == '$') 1056 nBits |= SCA_ROW_ABSOLUTE, p++; 1057 if( !CharClass::isAsciiDigit( *p ) ) 1058 { 1059 nBits = 0; 1060 nRow = SCROW(-1); 1061 } 1062 else 1063 { 1064 String aTmp( p ); 1065 long n = aTmp.ToInt32() - 1; 1066 while (CharClass::isAsciiDigit( *p )) 1067 p++; 1068 if( n < 0 || n > MAXROW ) 1069 nBits = 0; 1070 nRow = static_cast<SCROW>(n); 1071 } 1072 nRes |= nBits; 1073 if( !nBits ) 1074 p = q; 1075 } 1076 1077 rAddr.Set( nCol, nRow, nTab ); 1078 1079 if (!*p && bExtDoc) 1080 { 1081 if (!pDoc) 1082 nRes = 0; 1083 else 1084 { 1085 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 1086 1087 // Need document name if inherited. 1088 if (bExtDocInherited) 1089 { 1090 const String* pFileName = pRefMgr->getExternalFileName( pExtInfo->mnFileId); 1091 if (pFileName) 1092 aDocName = *pFileName; 1093 else 1094 nRes = 0; 1095 } 1096 pRefMgr->convertToAbsName(aDocName); 1097 1098 if ((!pExtInfo || !pExtInfo->mbExternal) && pRefMgr->isOwnDocument(aDocName)) 1099 { 1100 if (!pDoc->GetTable( aTab, nTab )) 1101 nRes = 0; 1102 else 1103 { 1104 rAddr.SetTab( nTab); 1105 nRes |= SCA_VALID_TAB; 1106 } 1107 } 1108 else 1109 { 1110 if (!pExtInfo) 1111 nRes = 0; 1112 else 1113 { 1114 if (!pExtInfo->mbExternal) 1115 { 1116 sal_uInt16 nFileId = pRefMgr->getExternalFileId(aDocName); 1117 1118 pExtInfo->mbExternal = true; 1119 pExtInfo->maTabName = aTab; 1120 pExtInfo->mnFileId = nFileId; 1121 1122 if (pRefMgr->getSingleRefToken(nFileId, aTab, 1123 ScAddress(nCol, nRow, 0), NULL, 1124 &nTab).get()) 1125 { 1126 rAddr.SetTab( nTab); 1127 nRes |= SCA_VALID_TAB; 1128 } 1129 else 1130 nRes = 0; 1131 } 1132 else 1133 { 1134 // This is a call for the second part of the reference, 1135 // we must have the range to adapt tab span. 1136 if (!pRange) 1137 nRes = 0; 1138 else 1139 { 1140 sal_uInt16 nFlags = nRes | SCA_VALID_TAB2; 1141 if (!lcl_ScRange_External_TabSpan( *pRange, nFlags, 1142 pExtInfo, aDocName, 1143 pExtInfo->maTabName, aTab, pDoc)) 1144 nRes &= ~SCA_VALID_TAB; 1145 else 1146 { 1147 if (nFlags & SCA_VALID_TAB2) 1148 { 1149 rAddr.SetTab( pRange->aEnd.Tab()); 1150 nRes |= SCA_VALID_TAB; 1151 } 1152 else 1153 nRes &= ~SCA_VALID_TAB; 1154 } 1155 } 1156 } 1157 } 1158 } 1159 } 1160 } 1161 1162 if ( !(nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL) 1163 && !( (nRes & SCA_TAB_3D) && (nRes & SCA_VALID_TAB)) ) 1164 { // no Row, no Tab, but Col => DM (...), B (...) et al 1165 nRes = 0; 1166 } 1167 if( !*p ) 1168 { 1169 sal_uInt16 nMask = nRes & ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ); 1170 if( nMask == ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ) ) 1171 nRes |= SCA_VALID; 1172 } 1173 else 1174 nRes = 0; 1175 return nRes; 1176 } 1177 1178 static sal_uInt16 1179 lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, 1180 const ScAddress::Details& rDetails, 1181 ScAddress::ExternalInfo* pExtInfo = NULL, 1182 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL ) 1183 { 1184 if( !*p ) 1185 return 0; 1186 1187 switch (rDetails.eConv) 1188 { 1189 default : 1190 case formula::FormulaGrammar::CONV_OOO: 1191 { 1192 return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, pExtInfo, NULL ); 1193 } 1194 1195 case formula::FormulaGrammar::CONV_XL_A1: 1196 case formula::FormulaGrammar::CONV_XL_OOX: 1197 { 1198 ScRange r = rAddr; 1199 sal_uInt16 nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, true, pExtInfo, 1200 (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) ); 1201 rAddr = r.aStart; 1202 return nFlags; 1203 } 1204 case formula::FormulaGrammar::CONV_XL_R1C1: 1205 { 1206 ScRange r = rAddr; 1207 sal_uInt16 nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, true, pExtInfo ); 1208 rAddr = r.aStart; 1209 return nFlags; 1210 } 1211 } 1212 } 1213 1214 1215 bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString, 1216 SCTAB nDefTab, ScRefAddress& rRefAddress, 1217 const ScAddress::Details& rDetails, 1218 ScAddress::ExternalInfo* pExtInfo /* = NULL */ ) 1219 { 1220 bool bRet = false; 1221 if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND)) 1222 { 1223 ScAddress aAddr( 0, 0, nDefTab ); 1224 sal_uInt16 nRes = aAddr.Parse( rRefString, pDoc, rDetails, pExtInfo); 1225 if ( nRes & SCA_VALID ) 1226 { 1227 rRefAddress.Set( aAddr, 1228 ((nRes & SCA_COL_ABSOLUTE) == 0), 1229 ((nRes & SCA_ROW_ABSOLUTE) == 0), 1230 ((nRes & SCA_TAB_ABSOLUTE) == 0)); 1231 bRet = true; 1232 } 1233 } 1234 return bRet; 1235 } 1236 1237 1238 bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, 1239 ScRefAddress& rStartRefAddress, ScRefAddress& rEndRefAddress, 1240 const ScAddress::Details& rDetails, 1241 ScAddress::ExternalInfo* pExtInfo /* = NULL */ ) 1242 { 1243 bool bRet = false; 1244 if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND)) 1245 { 1246 ScRange aRange( ScAddress( 0, 0, nDefTab)); 1247 sal_uInt16 nRes = aRange.Parse( rRefString, pDoc, rDetails, pExtInfo); 1248 if ( nRes & SCA_VALID ) 1249 { 1250 rStartRefAddress.Set( aRange.aStart, 1251 ((nRes & SCA_COL_ABSOLUTE) == 0), 1252 ((nRes & SCA_ROW_ABSOLUTE) == 0), 1253 ((nRes & SCA_TAB_ABSOLUTE) == 0)); 1254 rEndRefAddress.Set( aRange.aEnd, 1255 ((nRes & SCA_COL2_ABSOLUTE) == 0), 1256 ((nRes & SCA_ROW2_ABSOLUTE) == 0), 1257 ((nRes & SCA_TAB2_ABSOLUTE) == 0)); 1258 bRet = true; 1259 } 1260 } 1261 return bRet; 1262 } 1263 1264 1265 sal_uInt16 ScAddress::Parse( const String& r, ScDocument* pDoc, 1266 const Details& rDetails, 1267 ExternalInfo* pExtInfo, 1268 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 1269 { 1270 return lcl_ScAddress_Parse( r.GetBuffer(), pDoc, *this, rDetails, pExtInfo, pExternalLinks ); 1271 } 1272 1273 1274 bool ScRange::Intersects( const ScRange& r ) const 1275 { 1276 return !( 1277 Min( aEnd.Col(), r.aEnd.Col() ) < Max( aStart.Col(), r.aStart.Col() ) 1278 || Min( aEnd.Row(), r.aEnd.Row() ) < Max( aStart.Row(), r.aStart.Row() ) 1279 || Min( aEnd.Tab(), r.aEnd.Tab() ) < Max( aStart.Tab(), r.aStart.Tab() ) 1280 ); 1281 } 1282 1283 1284 void ScRange::Justify() 1285 { 1286 SCCOL nTempCol; 1287 if ( aEnd.Col() < (nTempCol = aStart.Col()) ) 1288 { 1289 aStart.SetCol(aEnd.Col()); aEnd.SetCol(nTempCol); 1290 } 1291 SCROW nTempRow; 1292 if ( aEnd.Row() < (nTempRow = aStart.Row()) ) 1293 { 1294 aStart.SetRow(aEnd.Row()); aEnd.SetRow(nTempRow); 1295 } 1296 SCTAB nTempTab; 1297 if ( aEnd.Tab() < (nTempTab = aStart.Tab()) ) 1298 { 1299 aStart.SetTab(aEnd.Tab()); aEnd.SetTab(nTempTab); 1300 } 1301 } 1302 1303 void ScRange::ExtendTo( const ScRange& rRange ) 1304 { 1305 DBG_ASSERT( rRange.IsValid(), "ScRange::ExtendTo - cannot extend to invalid range" ); 1306 if( IsValid() ) 1307 { 1308 aStart.SetCol( ::std::min( aStart.Col(), rRange.aStart.Col() ) ); 1309 aStart.SetRow( ::std::min( aStart.Row(), rRange.aStart.Row() ) ); 1310 aStart.SetTab( ::std::min( aStart.Tab(), rRange.aStart.Tab() ) ); 1311 aEnd.SetCol( ::std::max( aEnd.Col(), rRange.aEnd.Col() ) ); 1312 aEnd.SetRow( ::std::max( aEnd.Row(), rRange.aEnd.Row() ) ); 1313 aEnd.SetTab( ::std::max( aEnd.Tab(), rRange.aEnd.Tab() ) ); 1314 } 1315 else 1316 *this = rRange; 1317 } 1318 1319 static sal_uInt16 1320 lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL ) 1321 { 1322 sal_uInt16 nRes1 = 0, nRes2 = 0; 1323 xub_StrLen nPos = ScGlobal::FindUnquoted( r, ':'); 1324 if (nPos != STRING_NOTFOUND) 1325 { 1326 String aTmp( r ); 1327 sal_Unicode* p = aTmp.GetBufferAccess(); 1328 p[ nPos ] = 0; 1329 if( (nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, aRange.aStart, pExtInfo, NULL ) ) != 0 ) 1330 { 1331 aRange.aEnd = aRange.aStart; // sheet must be initialized identical to first sheet 1332 if ( (nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, aRange.aEnd, pExtInfo, &aRange ) ) != 0 ) 1333 { 1334 // PutInOrder / Justify 1335 sal_uInt16 nMask, nBits1, nBits2; 1336 SCCOL nTempCol; 1337 if ( aRange.aEnd.Col() < (nTempCol = aRange.aStart.Col()) ) 1338 { 1339 aRange.aStart.SetCol(aRange.aEnd.Col()); aRange.aEnd.SetCol(nTempCol); 1340 nMask = (SCA_VALID_COL | SCA_COL_ABSOLUTE); 1341 nBits1 = nRes1 & nMask; 1342 nBits2 = nRes2 & nMask; 1343 nRes1 = (nRes1 & ~nMask) | nBits2; 1344 nRes2 = (nRes2 & ~nMask) | nBits1; 1345 } 1346 SCROW nTempRow; 1347 if ( aRange.aEnd.Row() < (nTempRow = aRange.aStart.Row()) ) 1348 { 1349 aRange.aStart.SetRow(aRange.aEnd.Row()); aRange.aEnd.SetRow(nTempRow); 1350 nMask = (SCA_VALID_ROW | SCA_ROW_ABSOLUTE); 1351 nBits1 = nRes1 & nMask; 1352 nBits2 = nRes2 & nMask; 1353 nRes1 = (nRes1 & ~nMask) | nBits2; 1354 nRes2 = (nRes2 & ~nMask) | nBits1; 1355 } 1356 SCTAB nTempTab; 1357 if ( aRange.aEnd.Tab() < (nTempTab = aRange.aStart.Tab()) ) 1358 { 1359 aRange.aStart.SetTab(aRange.aEnd.Tab()); aRange.aEnd.SetTab(nTempTab); 1360 nMask = (SCA_VALID_TAB | SCA_TAB_ABSOLUTE | SCA_TAB_3D); 1361 nBits1 = nRes1 & nMask; 1362 nBits2 = nRes2 & nMask; 1363 nRes1 = (nRes1 & ~nMask) | nBits2; 1364 nRes2 = (nRes2 & ~nMask) | nBits1; 1365 } 1366 if ( ((nRes1 & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) 1367 == ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) 1368 && !(nRes2 & SCA_TAB_3D) ) 1369 nRes2 |= SCA_TAB_ABSOLUTE; 1370 } 1371 else 1372 nRes1 = 0; // #38840# keine Tokens aus halben Sachen 1373 } 1374 } 1375 nRes1 = ( ( nRes1 | nRes2 ) & SCA_VALID ) 1376 | nRes1 1377 | ( ( nRes2 & 0x070F ) << 4 ); 1378 return nRes1; 1379 } 1380 1381 sal_uInt16 ScRange::Parse( const String& r, ScDocument* pDoc, 1382 const ScAddress::Details& rDetails, 1383 ScAddress::ExternalInfo* pExtInfo, 1384 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 1385 { 1386 if ( r.Len() <= 0 ) 1387 return 0; 1388 1389 switch (rDetails.eConv) 1390 { 1391 default : 1392 case formula::FormulaGrammar::CONV_OOO: 1393 return lcl_ScRange_Parse_OOo( *this, r, pDoc, pExtInfo ); 1394 1395 case formula::FormulaGrammar::CONV_XL_A1: 1396 case formula::FormulaGrammar::CONV_XL_OOX: 1397 return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, false, pExtInfo, 1398 (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) ); 1399 1400 case formula::FormulaGrammar::CONV_XL_R1C1: 1401 return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, false, pExtInfo ); 1402 } 1403 } 1404 1405 1406 // Accept a full range, or an address 1407 sal_uInt16 ScRange::ParseAny( const String& r, ScDocument* pDoc, 1408 const ScAddress::Details& rDetails ) 1409 { 1410 sal_uInt16 nRet = Parse( r, pDoc, rDetails ); 1411 const sal_uInt16 nValid = SCA_VALID | SCA_VALID_COL2 | SCA_VALID_ROW2 | 1412 SCA_VALID_TAB2; 1413 1414 if ( (nRet & nValid) != nValid ) 1415 { 1416 ScAddress aAdr; 1417 nRet = aAdr.Parse( r, pDoc, rDetails ); 1418 if ( nRet & SCA_VALID ) 1419 aStart = aEnd = aAdr; 1420 } 1421 return nRet; 1422 } 1423 1424 // Parse only full row references 1425 sal_uInt16 ScRange::ParseCols( const String& rStr, ScDocument* pDoc, 1426 const ScAddress::Details& rDetails ) 1427 { 1428 const sal_Unicode* p = rStr.GetBuffer(); 1429 sal_uInt16 nRes = 0, ignored = 0; 1430 1431 if( NULL == p ) 1432 return 0; 1433 1434 pDoc = NULL; // make compiler shutup we may need this later 1435 1436 switch (rDetails.eConv) 1437 { 1438 default : 1439 case formula::FormulaGrammar::CONV_OOO: // No full col refs in OOO yet, assume XL notation 1440 case formula::FormulaGrammar::CONV_XL_A1: 1441 case formula::FormulaGrammar::CONV_XL_OOX: 1442 if (NULL != (p = lcl_a1_get_col( p, &aStart, &ignored ) ) ) 1443 { 1444 if( p[0] == ':') 1445 { 1446 if( NULL != (p = lcl_a1_get_col( p+1, &aEnd, &ignored ))) 1447 { 1448 nRes = SCA_VALID_COL; 1449 } 1450 } 1451 else 1452 { 1453 aEnd = aStart; 1454 nRes = SCA_VALID_COL; 1455 } 1456 } 1457 break; 1458 1459 case formula::FormulaGrammar::CONV_XL_R1C1: 1460 if ((p[0] == 'C' || p[0] != 'c') && 1461 NULL != (p = lcl_r1c1_get_col( p, rDetails, &aStart, &ignored ))) 1462 { 1463 if( p[0] == ':') 1464 { 1465 if( (p[1] == 'C' || p[1] == 'c') && 1466 NULL != (p = lcl_r1c1_get_col( p+1, rDetails, &aEnd, &ignored ))) 1467 { 1468 nRes = SCA_VALID_COL; 1469 } 1470 } 1471 else 1472 { 1473 aEnd = aStart; 1474 nRes = SCA_VALID_COL; 1475 } 1476 } 1477 break; 1478 } 1479 1480 return (p != NULL && *p == '\0') ? nRes : 0; 1481 } 1482 1483 // Parse only full row references 1484 sal_uInt16 ScRange::ParseRows( const String& rStr, ScDocument* pDoc, 1485 const ScAddress::Details& rDetails ) 1486 { 1487 const sal_Unicode* p = rStr.GetBuffer(); 1488 sal_uInt16 nRes = 0, ignored = 0; 1489 1490 if( NULL == p ) 1491 return 0; 1492 1493 pDoc = NULL; // make compiler shutup we may need this later 1494 1495 switch (rDetails.eConv) 1496 { 1497 default : 1498 case formula::FormulaGrammar::CONV_OOO: // No full row refs in OOO yet, assume XL notation 1499 case formula::FormulaGrammar::CONV_XL_A1: 1500 case formula::FormulaGrammar::CONV_XL_OOX: 1501 if (NULL != (p = lcl_a1_get_row( p, &aStart, &ignored ) ) ) 1502 { 1503 if( p[0] == ':') 1504 { 1505 if( NULL != (p = lcl_a1_get_row( p+1, &aEnd, &ignored ))) 1506 { 1507 nRes = SCA_VALID_COL; 1508 } 1509 } 1510 else 1511 { 1512 aEnd = aStart; 1513 nRes = SCA_VALID_COL; 1514 } 1515 } 1516 break; 1517 1518 case formula::FormulaGrammar::CONV_XL_R1C1: 1519 if ((p[0] == 'R' || p[0] != 'r') && 1520 NULL != (p = lcl_r1c1_get_row( p, rDetails, &aStart, &ignored ))) 1521 { 1522 if( p[0] == ':') 1523 { 1524 if( (p[1] == 'R' || p[1] == 'r') && 1525 NULL != (p = lcl_r1c1_get_row( p+1, rDetails, &aEnd, &ignored ))) 1526 { 1527 nRes = SCA_VALID_COL; 1528 } 1529 } 1530 else 1531 { 1532 aEnd = aStart; 1533 nRes = SCA_VALID_COL; 1534 } 1535 } 1536 break; 1537 } 1538 1539 return (p != NULL && *p == '\0') ? nRes : 0; 1540 } 1541 1542 static inline void 1543 lcl_a1_append_c ( String &r, int nCol, bool bIsAbs ) 1544 { 1545 if( bIsAbs ) 1546 r += '$'; 1547 ScColToAlpha( r, sal::static_int_cast<SCCOL>(nCol) ); 1548 } 1549 1550 static inline void 1551 lcl_a1_append_r ( String &r, int nRow, bool bIsAbs ) 1552 { 1553 if ( bIsAbs ) 1554 r += '$'; 1555 r += String::CreateFromInt32( nRow+1 ); 1556 } 1557 1558 static inline void 1559 lcl_r1c1_append_c ( String &r, int nCol, bool bIsAbs, 1560 const ScAddress::Details& rDetails ) 1561 { 1562 r += 'C'; 1563 if (bIsAbs) 1564 { 1565 r += String::CreateFromInt32( nCol + 1 ); 1566 } 1567 else 1568 { 1569 nCol -= rDetails.nCol; 1570 if (nCol != 0) { 1571 r += '['; 1572 r += String::CreateFromInt32( nCol ); 1573 r += ']'; 1574 } 1575 } 1576 } 1577 static inline void 1578 lcl_r1c1_append_r ( String &r, int nRow, bool bIsAbs, 1579 const ScAddress::Details& rDetails ) 1580 { 1581 r += 'R'; 1582 if (bIsAbs) 1583 { 1584 r += String::CreateFromInt32( nRow + 1 ); 1585 } 1586 else 1587 { 1588 nRow -= rDetails.nRow; 1589 if (nRow != 0) { 1590 r += '['; 1591 r += String::CreateFromInt32( nRow ); 1592 r += ']'; 1593 } 1594 } 1595 } 1596 1597 static String 1598 getFileNameFromDoc( const ScDocument* pDoc ) 1599 { 1600 // TODO : er points at ScGlobal::GetAbsDocName() 1601 // as a better template. Look into it 1602 String sFileName; 1603 SfxObjectShell* pShell; 1604 1605 if( NULL != pDoc && 1606 NULL != (pShell = pDoc->GetDocumentShell() ) ) 1607 { 1608 uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY ); 1609 if( xModel.is() ) 1610 { 1611 if( xModel->getURL().getLength() ) 1612 { 1613 INetURLObject aURL( xModel->getURL() ); 1614 sFileName = aURL.GetLastName(); 1615 } 1616 else 1617 sFileName = pShell->GetTitle(); 1618 } 1619 } 1620 #if 0 1621 { 1622 ByteString aStr( sFileName, RTL_TEXTENCODING_UTF8 ); 1623 aStr.Append(static_cast< char >(0)); 1624 std::cerr << "docname \'" << aStr.GetBuffer() << '\'' << std::endl; 1625 } 1626 #endif 1627 return sFileName; 1628 } 1629 1630 void ScAddress::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc, 1631 const Details& rDetails) const 1632 { 1633 r.Erase(); 1634 if( nFlags & SCA_VALID ) 1635 nFlags |= ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ); 1636 if( pDoc && (nFlags & SCA_VALID_TAB ) ) 1637 { 1638 if ( nTab >= pDoc->GetTableCount() ) 1639 { 1640 r = ScGlobal::GetRscString( STR_NOREF_STR ); 1641 return; 1642 } 1643 // if( nFlags & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ) ) 1644 if( nFlags & SCA_TAB_3D ) 1645 { 1646 String aTabName, aDocName; 1647 pDoc->GetName( nTab, aTabName ); 1648 // External Reference, same as in ScCompiler::MakeTabStr() 1649 if( aTabName.GetChar(0) == '\'' ) 1650 { // "'Doc'#Tab" 1651 xub_StrLen nPos = ScCompiler::GetDocTabPos( aTabName); 1652 if (nPos != STRING_NOTFOUND) 1653 { 1654 aDocName = aTabName.Copy( 0, nPos + 1 ); 1655 aTabName.Erase( 0, nPos + 1 ); 1656 } 1657 } 1658 else if( nFlags & SCA_FORCE_DOC ) 1659 { 1660 // VBA has an 'external' flag that forces the addition of the 1661 // tab name _and_ the doc name. The VBA code would be 1662 // needlessly complicated if it constructed an actual external 1663 // reference so we add this somewhat cheesy kludge to force the 1664 // addition of the document name even for non-external references 1665 aDocName = getFileNameFromDoc( pDoc ); 1666 } 1667 ScCompiler::CheckTabQuotes( aTabName, rDetails.eConv); 1668 1669 switch( rDetails.eConv ) 1670 { 1671 default : 1672 case formula::FormulaGrammar::CONV_OOO: 1673 r += aDocName; 1674 if( nFlags & SCA_TAB_ABSOLUTE ) 1675 r += '$'; 1676 r += aTabName; 1677 r += '.'; 1678 break; 1679 1680 case formula::FormulaGrammar::CONV_XL_A1: 1681 case formula::FormulaGrammar::CONV_XL_R1C1: 1682 case formula::FormulaGrammar::CONV_XL_OOX: 1683 if (aDocName.Len() > 0) 1684 { 1685 r += '['; 1686 r += aDocName; 1687 r += ']'; 1688 } 1689 r += aTabName; 1690 r += '!'; 1691 break; 1692 } 1693 } 1694 } 1695 switch( rDetails.eConv ) 1696 { 1697 default : 1698 case formula::FormulaGrammar::CONV_OOO: 1699 case formula::FormulaGrammar::CONV_XL_A1: 1700 case formula::FormulaGrammar::CONV_XL_OOX: 1701 if( nFlags & SCA_VALID_COL ) 1702 lcl_a1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE ); 1703 if( nFlags & SCA_VALID_ROW ) 1704 lcl_a1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE ); 1705 break; 1706 1707 case formula::FormulaGrammar::CONV_XL_R1C1: 1708 if( nFlags & SCA_VALID_ROW ) 1709 lcl_r1c1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE, rDetails ); 1710 if( nFlags & SCA_VALID_COL ) 1711 lcl_r1c1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE, rDetails ); 1712 break; 1713 } 1714 } 1715 1716 static void 1717 lcl_Split_DocTab( const ScDocument* pDoc, SCTAB nTab, 1718 const ScAddress::Details& rDetails, 1719 sal_uInt16 nFlags, 1720 String& rTabName, String& rDocName ) 1721 { 1722 pDoc->GetName( nTab, rTabName ); 1723 rDocName.Erase(); 1724 #if 0 1725 { 1726 ByteString aStr(rTabName, RTL_TEXTENCODING_UTF8); 1727 aStr.Append(static_cast< char >(0)); 1728 std::cerr << "tabname \'" << aStr.GetBuffer() << '\'' << std::endl; 1729 } 1730 #endif 1731 // External reference, same as in ScCompiler::MakeTabStr() 1732 if ( rTabName.GetChar(0) == '\'' ) 1733 { // "'Doc'#Tab" 1734 xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); 1735 if (nPos != STRING_NOTFOUND) 1736 { 1737 rDocName = rTabName.Copy( 0, nPos + 1 ); 1738 rTabName.Erase( 0, nPos + 1 ); 1739 } 1740 } 1741 else if( nFlags & SCA_FORCE_DOC ) 1742 { 1743 // VBA has an 'external' flag that forces the addition of the 1744 // tab name _and_ the doc name. The VBA code would be 1745 // needlessly complicated if it constructed an actual external 1746 // reference so we add this somewhat cheesy kludge to force the 1747 // addition of the document name even for non-external references 1748 rDocName = getFileNameFromDoc( pDoc ); 1749 } 1750 ScCompiler::CheckTabQuotes( rTabName, rDetails.eConv); 1751 } 1752 1753 static void 1754 lcl_ScRange_Format_XL_Header( String& r, const ScRange& rRange, 1755 sal_uInt16 nFlags, ScDocument* pDoc, 1756 const ScAddress::Details& rDetails ) 1757 { 1758 if( nFlags & SCA_TAB_3D ) 1759 { 1760 String aTabName, aDocName; 1761 lcl_Split_DocTab( pDoc, rRange.aStart.Tab(), rDetails, nFlags, 1762 aTabName, aDocName ); 1763 if( aDocName.Len() > 0 ) 1764 { 1765 r += '['; 1766 r += aDocName; 1767 r += ']'; 1768 } 1769 r += aTabName; 1770 1771 if( nFlags & SCA_TAB2_3D ) 1772 { 1773 lcl_Split_DocTab( pDoc, rRange.aEnd.Tab(), rDetails, nFlags, 1774 aTabName, aDocName ); 1775 r += ':'; 1776 r += aTabName; 1777 } 1778 r += '!'; 1779 } 1780 } 1781 1782 void ScRange::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc, 1783 const ScAddress::Details& rDetails ) const 1784 { 1785 r.Erase(); 1786 if( !( nFlags & SCA_VALID ) ) 1787 { 1788 r = ScGlobal::GetRscString( STR_NOREF_STR ); 1789 return; 1790 } 1791 1792 #define absrel_differ(nFlags, mask) (((nFlags) & (mask)) ^ (((nFlags) >> 4) & (mask))) 1793 switch( rDetails.eConv ) { 1794 default : 1795 case formula::FormulaGrammar::CONV_OOO: { 1796 sal_Bool bOneTab = (aStart.Tab() == aEnd.Tab()); 1797 if ( !bOneTab ) 1798 nFlags |= SCA_TAB_3D; 1799 aStart.Format( r, nFlags, pDoc, rDetails ); 1800 if( aStart != aEnd || 1801 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) || 1802 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) 1803 { 1804 String aName; 1805 nFlags = ( nFlags & SCA_VALID ) | ( ( nFlags >> 4 ) & 0x070F ); 1806 if ( bOneTab ) 1807 pDoc = NULL; 1808 else 1809 nFlags |= SCA_TAB_3D; 1810 aEnd.Format( aName, nFlags, pDoc, rDetails ); 1811 r += ':'; 1812 r += aName; 1813 } 1814 } 1815 break; 1816 1817 case formula::FormulaGrammar::CONV_XL_A1: 1818 case formula::FormulaGrammar::CONV_XL_OOX: 1819 lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails ); 1820 if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL ) 1821 { 1822 // Full col refs always require 2 rows (2:2) 1823 lcl_a1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE ); 1824 r += ':'; 1825 lcl_a1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE ); 1826 } 1827 else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW ) 1828 { 1829 // Full row refs always require 2 cols (A:A) 1830 lcl_a1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE ); 1831 r += ':'; 1832 lcl_a1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE ); 1833 } 1834 else 1835 { 1836 lcl_a1_append_c ( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE ); 1837 lcl_a1_append_r ( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE ); 1838 if( aStart.Col() != aEnd.Col() || 1839 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) || 1840 aStart.Row() != aEnd.Row() || 1841 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) { 1842 r += ':'; 1843 lcl_a1_append_c ( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE ); 1844 lcl_a1_append_r ( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE ); 1845 } 1846 } 1847 break; 1848 1849 case formula::FormulaGrammar::CONV_XL_R1C1: 1850 lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails ); 1851 if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL ) 1852 { 1853 lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails ); 1854 if( aStart.Row() != aEnd.Row() || 1855 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) { 1856 r += ':'; 1857 lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails ); 1858 } 1859 } 1860 else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW ) 1861 { 1862 lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails ); 1863 if( aStart.Col() != aEnd.Col() || 1864 absrel_differ( nFlags, SCA_COL_ABSOLUTE )) { 1865 r += ':'; 1866 lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails ); 1867 } 1868 } 1869 else 1870 { 1871 lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails ); 1872 lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails ); 1873 if( aStart.Col() != aEnd.Col() || 1874 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) || 1875 aStart.Row() != aEnd.Row() || 1876 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) { 1877 r += ':'; 1878 lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails ); 1879 lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails ); 1880 } 1881 } 1882 } 1883 #undef absrel_differ 1884 } 1885 1886 bool ScAddress::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc ) 1887 { 1888 SCsTAB nMaxTab = pDoc ? pDoc->GetTableCount() : MAXTAB+1; 1889 dx = Col() + dx; 1890 dy = Row() + dy; 1891 dz = Tab() + dz; 1892 sal_Bool bValid = sal_True; 1893 if( dx < 0 ) 1894 dx = 0, bValid = sal_False; 1895 else if( dx > MAXCOL ) 1896 dx = MAXCOL, bValid =sal_False; 1897 if( dy < 0 ) 1898 dy = 0, bValid = sal_False; 1899 else if( dy > MAXROW ) 1900 dy = MAXROW, bValid =sal_False; 1901 if( dz < 0 ) 1902 dz = 0, bValid = sal_False; 1903 else if( dz >= nMaxTab ) 1904 dz = nMaxTab-1, bValid =sal_False; 1905 Set( dx, dy, dz ); 1906 return bValid; 1907 } 1908 1909 1910 bool ScRange::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc ) 1911 { 1912 // Einfahces &, damit beides ausgefuehrt wird!! 1913 return aStart.Move( dx, dy, dz, pDoc ) & aEnd.Move( dx, dy, dz, pDoc ); 1914 } 1915 1916 1917 String ScAddress::GetColRowString( bool bAbsolute, 1918 const Details& rDetails ) const 1919 { 1920 String aString; 1921 1922 switch( rDetails.eConv ) 1923 { 1924 default : 1925 case formula::FormulaGrammar::CONV_OOO: 1926 case formula::FormulaGrammar::CONV_XL_A1: 1927 case formula::FormulaGrammar::CONV_XL_OOX: 1928 if (bAbsolute) 1929 aString.Append( '$' ); 1930 1931 ScColToAlpha( aString, nCol); 1932 1933 if ( bAbsolute ) 1934 aString.Append( '$' ); 1935 1936 aString += String::CreateFromInt32(nRow+1); 1937 break; 1938 1939 case formula::FormulaGrammar::CONV_XL_R1C1: 1940 lcl_r1c1_append_r ( aString, nRow, bAbsolute, rDetails ); 1941 lcl_r1c1_append_c ( aString, nCol, bAbsolute, rDetails ); 1942 break; 1943 } 1944 1945 return aString; 1946 } 1947 1948 1949 String ScRefAddress::GetRefString( ScDocument* pDoc, SCTAB nActTab, 1950 const ScAddress::Details& rDetails ) const 1951 { 1952 if ( !pDoc ) 1953 return EMPTY_STRING; 1954 if ( Tab()+1 > pDoc->GetTableCount() ) 1955 return ScGlobal::GetRscString( STR_NOREF_STR ); 1956 1957 String aString; 1958 sal_uInt16 nFlags = SCA_VALID; 1959 if ( nActTab != Tab() ) 1960 { 1961 nFlags |= SCA_TAB_3D; 1962 if ( !bRelTab ) 1963 nFlags |= SCA_TAB_ABSOLUTE; 1964 } 1965 if ( !bRelCol ) 1966 nFlags |= SCA_COL_ABSOLUTE; 1967 if ( !bRelRow ) 1968 nFlags |= SCA_ROW_ABSOLUTE; 1969 1970 aAdr.Format( aString, nFlags, pDoc, rDetails ); 1971 1972 return aString; 1973 } 1974 1975 //------------------------------------------------------------------------ 1976 1977 void ScColToAlpha( rtl::OUStringBuffer& rBuf, SCCOL nCol ) 1978 { 1979 if (nCol < 26*26) 1980 { 1981 if (nCol < 26) 1982 rBuf.append( static_cast<sal_Unicode>( 'A' + 1983 static_cast<sal_uInt16>(nCol))); 1984 else 1985 { 1986 rBuf.append( static_cast<sal_Unicode>( 'A' + 1987 (static_cast<sal_uInt16>(nCol) / 26) - 1)); 1988 rBuf.append( static_cast<sal_Unicode>( 'A' + 1989 (static_cast<sal_uInt16>(nCol) % 26))); 1990 } 1991 } 1992 else 1993 { 1994 String aStr; 1995 while (nCol >= 26) 1996 { 1997 SCCOL nC = nCol % 26; 1998 aStr += static_cast<sal_Unicode>( 'A' + 1999 static_cast<sal_uInt16>(nC)); 2000 nCol = sal::static_int_cast<SCCOL>( nCol - nC ); 2001 nCol = nCol / 26 - 1; 2002 } 2003 aStr += static_cast<sal_Unicode>( 'A' + 2004 static_cast<sal_uInt16>(nCol)); 2005 aStr.Reverse(); 2006 rBuf.append( aStr); 2007 } 2008 } 2009 2010 2011 bool AlphaToCol( SCCOL& rCol, const String& rStr) 2012 { 2013 SCCOL nResult = 0; 2014 xub_StrLen nStop = rStr.Len(); 2015 xub_StrLen nPos = 0; 2016 sal_Unicode c; 2017 while (nResult <= MAXCOL && nPos < nStop && (c = rStr.GetChar( nPos)) != 0 && 2018 CharClass::isAsciiAlpha(c)) 2019 { 2020 if (nPos > 0) 2021 nResult = (nResult + 1) * 26; 2022 nResult += ScGlobal::ToUpperAlpha(c) - 'A'; 2023 ++nPos; 2024 } 2025 bool bOk = (ValidCol(nResult) && nPos > 0); 2026 if (bOk) 2027 rCol = nResult; 2028 return bOk; 2029 } 2030