LCOV - code coverage report
Current view: top level - sc/source/core/tool - address.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 1020 0.0 %
Date: 2014-04-14 Functions: 0 46 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10