LCOV - code coverage report
Current view: top level - sc/source/core/tool - address.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 696 977 71.2 %
Date: 2012-08-25 Functions: 44 45 97.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 604 1253 48.2 %

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

Generated by: LCOV version 1.10