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

Generated by: LCOV version 1.11