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

Generated by: LCOV version 1.10