LCOV - code coverage report
Current view: top level - sc/source/core/tool - address.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 765 1024 74.7 %
Date: 2014-11-03 Functions: 46 47 97.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10