LCOV - code coverage report
Current view: top level - sc/source/core/tool - compiler.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1327 2279 58.2 %
Date: 2014-11-03 Functions: 115 149 77.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <config_features.h>
      21             : 
      22             : #include "compiler.hxx"
      23             : 
      24             : #include <sfx2/app.hxx>
      25             : #include <sfx2/objsh.hxx>
      26             : #include <basic/sbmeth.hxx>
      27             : #include <basic/sbstar.hxx>
      28             : #include <svl/zforlist.hxx>
      29             : #include <svl/sharedstringpool.hxx>
      30             : #include <sal/macros.h>
      31             : #include <tools/rcid.h>
      32             : #include <tools/solar.h>
      33             : #include <unotools/charclass.hxx>
      34             : #include <com/sun/star/lang/Locale.hpp>
      35             : #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
      36             : #include <com/sun/star/sheet/FormulaLanguage.hpp>
      37             : #include <com/sun/star/sheet/FormulaMapGroup.hpp>
      38             : #include <comphelper/processfactory.hxx>
      39             : #include <comphelper/string.hxx>
      40             : #include <unotools/transliterationwrapper.hxx>
      41             : #include <tools/urlobj.hxx>
      42             : #include <rtl/math.hxx>
      43             : #include <rtl/ustring.hxx>
      44             : #include <svtools/miscopt.hxx>
      45             : #include <ctype.h>
      46             : #include <stdio.h>
      47             : #include <stdlib.h>
      48             : #include <string.h>
      49             : #include <math.h>
      50             : #include "rangenam.hxx"
      51             : #include "dbdata.hxx"
      52             : #include "document.hxx"
      53             : #include "callform.hxx"
      54             : #include "addincol.hxx"
      55             : #include "refupdat.hxx"
      56             : #include "scresid.hxx"
      57             : #include "sc.hrc"
      58             : #include "globstr.hrc"
      59             : #include "formulacell.hxx"
      60             : #include "dociter.hxx"
      61             : #include "docoptio.hxx"
      62             : #include <formula/errorcodes.hxx>
      63             : #include "parclass.hxx"
      64             : #include "autonamecache.hxx"
      65             : #include "externalrefmgr.hxx"
      66             : #include "rangeutl.hxx"
      67             : #include "convuno.hxx"
      68             : #include "tokenuno.hxx"
      69             : #include "formulaparserpool.hxx"
      70             : #include "tokenarray.hxx"
      71             : #include "scmatrix.hxx"
      72             : #include <tokenstringcontext.hxx>
      73             : 
      74             : using namespace formula;
      75             : using namespace ::com::sun::star;
      76             : using ::std::vector;
      77             : 
      78             : CharClass*                          ScCompiler::pCharClassEnglish = NULL;
      79             : const ScCompiler::Convention*       ScCompiler::pConventions[ ]   = { NULL, NULL, NULL, NULL, NULL, NULL };
      80             : 
      81             : enum ScanState
      82             : {
      83             :     ssGetChar,
      84             :     ssGetBool,
      85             :     ssGetValue,
      86             :     ssGetString,
      87             :     ssSkipString,
      88             :     ssGetIdent,
      89             :     ssGetReference,
      90             :     ssSkipReference,
      91             :     ssGetErrorConstant,
      92             :     ssStop
      93             : };
      94             : 
      95             : static const sal_Char* pInternal[2] = { "TTT", "__DEBUG_VAR" };
      96             : 
      97             : using namespace ::com::sun::star::i18n;
      98             : 
      99          82 : void ScCompiler::fillFromAddInMap( NonConstOpCodeMapPtr xMap,FormulaGrammar::Grammar _eGrammar  ) const
     100             : {
     101             :     size_t nSymbolOffset;
     102          82 :     switch( _eGrammar )
     103             :     {
     104             :         case FormulaGrammar::GRAM_PODF:
     105          14 :             nSymbolOffset = offsetof( AddInMap, pUpper);
     106          14 :             break;
     107             :         default:
     108             :         case FormulaGrammar::GRAM_ODFF:
     109          56 :             nSymbolOffset = offsetof( AddInMap, pODFF);
     110          56 :             break;
     111             :         case FormulaGrammar::GRAM_ENGLISH:
     112          12 :             nSymbolOffset = offsetof( AddInMap, pEnglish);
     113          12 :             break;
     114             :     }
     115          82 :     const AddInMap* pMap = GetAddInMap();
     116          82 :     const AddInMap* const pStop = pMap + GetAddInMapCount();
     117        9020 :     for ( ; pMap < pStop; ++pMap)
     118             :     {
     119             :         char const * const * ppSymbol =
     120             :             reinterpret_cast< char const * const * >(
     121        8938 :                     reinterpret_cast< char const * >(pMap) + nSymbolOffset);
     122             :         xMap->putExternal( OUString::createFromAscii( *ppSymbol),
     123        8938 :                 OUString::createFromAscii( pMap->pOriginal));
     124             :     }
     125          82 : }
     126             : 
     127          70 : void ScCompiler::fillFromAddInCollectionUpperName( NonConstOpCodeMapPtr xMap ) const
     128             : {
     129          70 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
     130          70 :     long nCount = pColl->GetFuncCount();
     131        4634 :     for (long i=0; i < nCount; ++i)
     132             :     {
     133        4564 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
     134        4564 :         if (pFuncData)
     135        3124 :             xMap->putExternalSoftly( pFuncData->GetUpperName(),
     136        6248 :                     pFuncData->GetOriginalName());
     137             :     }
     138          70 : }
     139             : 
     140          12 : void ScCompiler::fillFromAddInCollectionEnglishName( NonConstOpCodeMapPtr xMap ) const
     141             : {
     142          12 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
     143          12 :     long nCount = pColl->GetFuncCount();
     144        1460 :     for (long i=0; i < nCount; ++i)
     145             :     {
     146        1448 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
     147        1448 :         if (pFuncData)
     148             :         {
     149         928 :             OUString aName;
     150         928 :             if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
     151         928 :                 xMap->putExternalSoftly( aName, pFuncData->GetOriginalName());
     152             :             else
     153           0 :                 xMap->putExternalSoftly( pFuncData->GetUpperName(),
     154           0 :                         pFuncData->GetOriginalName());
     155             :         }
     156             :     }
     157          12 : }
     158             : 
     159          20 : void ScCompiler::DeInit()
     160             : {
     161          20 :     if (pCharClassEnglish)
     162             :     {
     163          10 :         delete pCharClassEnglish;
     164          10 :         pCharClassEnglish = NULL;
     165             :     }
     166          20 : }
     167             : 
     168           0 : bool ScCompiler::IsEnglishSymbol( const OUString& rName )
     169             : {
     170             :     // function names are always case-insensitive
     171           0 :     OUString aUpper = ScGlobal::pCharClass->uppercase(rName);
     172             : 
     173             :     // 1. built-in function name
     174           0 :     OpCode eOp = ScCompiler::GetEnglishOpCode( aUpper );
     175           0 :     if ( eOp != ocNone )
     176             :     {
     177           0 :         return true;
     178             :     }
     179             :     // 2. old add in functions
     180           0 :     if (ScGlobal::GetFuncCollection()->findByName(aUpper))
     181             :     {
     182           0 :         return true;
     183             :     }
     184             : 
     185             :     // 3. new (uno) add in functions
     186           0 :     OUString aIntName = ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
     187           0 :     if (!aIntName.isEmpty())
     188             :     {
     189           0 :         return true;
     190             :     }
     191           0 :     return false;       // no valid function name
     192             : }
     193             : 
     194          54 : void ScCompiler::InitCharClassEnglish()
     195             : {
     196          54 :     ::com::sun::star::lang::Locale aLocale( "en", "US", "");
     197             :     pCharClassEnglish = new CharClass(
     198          54 :             ::comphelper::getProcessComponentContext(), LanguageTag( aLocale));
     199          54 : }
     200             : 
     201       82494 : void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
     202             : {
     203             :     OSL_ENSURE( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED");
     204       82494 :     if (eGrammar == GetGrammar())
     205       82686 :         return;     // nothing to be done
     206             : 
     207       82302 :     if( eGrammar == FormulaGrammar::GRAM_EXTERNAL )
     208             :     {
     209           0 :         meGrammar = eGrammar;
     210           0 :         mxSymbols = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
     211             :     }
     212             :     else
     213             :     {
     214       82302 :         FormulaGrammar::Grammar eMyGrammar = eGrammar;
     215       82302 :         const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar);
     216       82302 :         OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage);
     217             :         OSL_ENSURE( xMap, "ScCompiler::SetGrammar: unknown formula language");
     218       82302 :         if (!xMap)
     219             :         {
     220           0 :             xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE);
     221           0 :             eMyGrammar = xMap->getGrammar();
     222             :         }
     223             : 
     224             :         // Save old grammar for call to SetGrammarAndRefConvention().
     225       82302 :         FormulaGrammar::Grammar eOldGrammar = GetGrammar();
     226             :         // This also sets the grammar associated with the map!
     227       82302 :         SetFormulaLanguage( xMap);
     228             : 
     229             :         // Override if necessary.
     230       82302 :         if (eMyGrammar != GetGrammar())
     231       10952 :             SetGrammarAndRefConvention( eMyGrammar, eOldGrammar);
     232             :     }
     233             : }
     234             : 
     235             : // Unclear how this was intended to be refreshed when the
     236             : // grammer or sheet count is changed ? Ideally this would be
     237             : // a method on Document that would globally cache these.
     238       55216 : std::vector<OUString> &ScCompiler::GetSetupTabNames() const
     239             : {
     240       55216 :     std::vector<OUString> &rTabNames = const_cast<ScCompiler *>(this)->maTabNames;
     241             : 
     242       55216 :     if (pDoc && rTabNames.empty())
     243             :     {
     244       51760 :         rTabNames = pDoc->GetAllTableNames();
     245       51760 :         std::vector<OUString>::iterator it = rTabNames.begin(), itEnd = rTabNames.end();
     246      106362 :         for (; it != itEnd; ++it)
     247       54602 :             ScCompiler::CheckTabQuotes(*it, formula::FormulaGrammar::extractRefConvention(meGrammar));
     248             :     }
     249             : 
     250       55216 :     return rTabNames;
     251             : }
     252             : 
     253        1446 : void ScCompiler::SetNumberFormatter( SvNumberFormatter* pFormatter )
     254             : {
     255        1446 :     mpFormatter = pFormatter;
     256        1446 : }
     257             : 
     258       82536 : void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap )
     259             : {
     260       82536 :     if (xMap.get())
     261             :     {
     262       82536 :         mxSymbols = xMap;
     263       82536 :         if (mxSymbols->isEnglish())
     264             :         {
     265       10648 :             if (!pCharClassEnglish)
     266          54 :                 InitCharClassEnglish();
     267       10648 :             pCharClass = pCharClassEnglish;
     268             :         }
     269             :         else
     270       71888 :             pCharClass = ScGlobal::pCharClass;
     271       82536 :         SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar());
     272             :     }
     273       82536 : }
     274             : 
     275       93488 : void ScCompiler::SetGrammarAndRefConvention(
     276             :         const FormulaGrammar::Grammar eNewGrammar, const FormulaGrammar::Grammar eOldGrammar )
     277             : {
     278       93488 :     meGrammar = eNewGrammar;    //! SetRefConvention needs the new grammar set!
     279       93488 :     FormulaGrammar::AddressConvention eConv = FormulaGrammar::extractRefConvention( meGrammar);
     280       93488 :     if (eConv == FormulaGrammar::CONV_UNSPECIFIED && eOldGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
     281             :     {
     282      162232 :         if (pDoc)
     283       81116 :             SetRefConvention( pDoc->GetAddressConvention());
     284             :         else
     285           0 :             SetRefConvention( GetRefConvention( FormulaGrammar::CONV_OOO ) );
     286             :     }
     287             :     else
     288       12372 :         SetRefConvention( eConv );
     289       93488 : }
     290             : 
     291           0 : OUString ScCompiler::FindAddInFunction( const OUString& rUpperName, bool bLocalFirst ) const
     292             : {
     293           0 :     return ScGlobal::GetAddInCollection()->FindFunction(rUpperName, bLocalFirst);    // bLocalFirst=false for english
     294             : }
     295             : 
     296         132 : ScCompiler::Convention::~Convention()
     297             : {
     298         132 :     delete [] mpCharTable;
     299         132 :     mpCharTable = NULL;
     300         132 : }
     301             : 
     302         132 : ScCompiler::Convention::Convention( FormulaGrammar::AddressConvention eConv )
     303             :         :
     304         132 :     meConv( eConv )
     305             : {
     306             :     int i;
     307         132 :     sal_uLong *t= new sal_uLong [128];
     308             : 
     309         132 :     ScCompiler::pConventions[ meConv ] = this;
     310         132 :     mpCharTable = t;
     311             : 
     312       17028 :     for (i = 0; i < 128; i++)
     313       16896 :         t[i] = SC_COMPILER_C_ILLEGAL;
     314             : 
     315         132 : /*   */     t[32] = SC_COMPILER_C_CHAR_DONTCARE | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     316         132 : /* ! */     t[33] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     317         132 :             if (FormulaGrammar::CONV_ODF == meConv)
     318          54 : /* ! */         t[33] |= SC_COMPILER_C_ODF_LABEL_OP;
     319         132 : /* " */     t[34] = SC_COMPILER_C_CHAR_STRING | SC_COMPILER_C_STRING_SEP;
     320         132 : /* # */     t[35] = SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_CHAR_ERRCONST;
     321         132 : /* $ */     t[36] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT;
     322         132 :             if (FormulaGrammar::CONV_ODF == meConv)
     323          54 : /* $ */         t[36] |= SC_COMPILER_C_ODF_NAME_MARKER;
     324         132 : /* % */     t[37] = SC_COMPILER_C_VALUE;
     325         132 : /* & */     t[38] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     326         132 : /* ' */     t[39] = SC_COMPILER_C_NAME_SEP;
     327         132 : /* ( */     t[40] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     328         132 : /* ) */     t[41] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     329         132 : /* * */     t[42] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     330         132 : /* + */     t[43] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
     331         132 : /* , */     t[44] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE;
     332         132 : /* - */     t[45] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_SIGN;
     333         132 : /* . */     t[46] = SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
     334         132 : /* / */     t[47] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     335             : 
     336        1452 :             for (i = 48; i < 58; i++)
     337        1320 : /* 0-9 */       t[i] = SC_COMPILER_C_CHAR_VALUE | SC_COMPILER_C_WORD | SC_COMPILER_C_VALUE | SC_COMPILER_C_VALUE_EXP | SC_COMPILER_C_VALUE_VALUE | SC_COMPILER_C_IDENT | SC_COMPILER_C_NAME;
     338             : 
     339         132 : /* : */     t[58] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD;
     340         132 : /* ; */     t[59] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     341         132 : /* < */     t[60] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     342         132 : /* = */     t[61] = SC_COMPILER_C_CHAR | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     343         132 : /* > */     t[62] = SC_COMPILER_C_CHAR_BOOL | SC_COMPILER_C_BOOL | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     344         132 : /* ? */     t[63] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_NAME;
     345             : /* @ */     // FREE
     346             : 
     347        3564 :     for (i = 65; i < 91; i++)
     348        3432 : /* A-Z */   t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
     349             : 
     350         132 :     if (FormulaGrammar::CONV_ODF == meConv)
     351             :     {
     352          54 : /* [ */     t[91] = SC_COMPILER_C_ODF_LBRACKET;
     353             : /* \ */     // FREE
     354          54 : /* ] */     t[93] = SC_COMPILER_C_ODF_RBRACKET;
     355             :     }
     356             :     else
     357             :     {
     358             : /* [ */     // FREE
     359             : /* \ */     // FREE
     360             : /* ] */     // FREE
     361             :     }
     362         132 : /* ^ */     t[94] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     363         132 : /* _ */     t[95] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
     364             : /* ` */     // FREE
     365             : 
     366        3564 :             for (i = 97; i < 123; i++)
     367        3432 : /* a-z */       t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT | SC_COMPILER_C_CHAR_NAME | SC_COMPILER_C_NAME;
     368             : 
     369         132 : /* { */     t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open
     370         132 : /* | */     t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific)
     371         132 : /* } */     t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close
     372         132 : /* ~ */     t[126] = SC_COMPILER_C_CHAR;        // OOo specific
     373             : /* 127 */   // FREE
     374             : 
     375         132 :     if( FormulaGrammar::CONV_XL_A1 == meConv || FormulaGrammar::CONV_XL_R1C1 == meConv || FormulaGrammar::CONV_XL_OOX == meConv )
     376             :     {
     377          24 : /*   */     t[32] |=   SC_COMPILER_C_WORD;
     378          24 : /* ! */     t[33] |=   SC_COMPILER_C_IDENT | SC_COMPILER_C_WORD;
     379          24 : /* " */     t[34] |=   SC_COMPILER_C_WORD;
     380          24 : /* # */     t[35] &= (~SC_COMPILER_C_WORD_SEP);
     381          24 : /* # */     t[35] |=   SC_COMPILER_C_WORD;
     382          24 : /* % */     t[37] |=   SC_COMPILER_C_WORD;
     383          24 : /* ' */     t[39] |=   SC_COMPILER_C_WORD;
     384             : 
     385          24 : /* % */     t[37] |=   SC_COMPILER_C_WORD;
     386          24 : /* & */     t[38] |=   SC_COMPILER_C_WORD;
     387          24 : /* ' */     t[39] |=   SC_COMPILER_C_WORD;
     388          24 : /* ( */     t[40] |=   SC_COMPILER_C_WORD;
     389          24 : /* ) */     t[41] |=   SC_COMPILER_C_WORD;
     390          24 : /* * */     t[42] |=   SC_COMPILER_C_WORD;
     391          24 : /* + */     t[43] |=   SC_COMPILER_C_WORD;
     392             : #if 0 /* this really needs to be locale specific. */
     393             : /* , */     t[44]  =   SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP;
     394             : #else
     395          24 : /* , */     t[44] |=   SC_COMPILER_C_WORD;
     396             : #endif
     397          24 : /* - */     t[45] |=   SC_COMPILER_C_WORD;
     398             : 
     399          24 : /* ; */     t[59] |=   SC_COMPILER_C_WORD;
     400          24 : /* < */     t[60] |=   SC_COMPILER_C_WORD;
     401          24 : /* = */     t[61] |=   SC_COMPILER_C_WORD;
     402          24 : /* > */     t[62] |=   SC_COMPILER_C_WORD;
     403             : /* ? */     // question really is not permitted in sheet name
     404          24 : /* @ */     t[64] |=   SC_COMPILER_C_WORD;
     405          24 : /* [ */     t[91] |=   SC_COMPILER_C_WORD;
     406          24 : /* ] */     t[93] |=   SC_COMPILER_C_WORD;
     407          24 : /* { */     t[123]|=   SC_COMPILER_C_WORD;
     408          24 : /* | */     t[124]|=   SC_COMPILER_C_WORD;
     409          24 : /* } */     t[125]|=   SC_COMPILER_C_WORD;
     410          24 : /* ~ */     t[126]|=   SC_COMPILER_C_WORD;
     411             : 
     412          24 :         if( FormulaGrammar::CONV_XL_R1C1 == meConv )
     413             :         {
     414           6 : /* [ */     t[91] |= SC_COMPILER_C_IDENT;
     415           6 : /* ] */     t[93] |= SC_COMPILER_C_IDENT;
     416             :         }
     417          24 :         if( FormulaGrammar::CONV_XL_OOX == meConv )
     418             :         {
     419          10 : /* [ */     t[91] |= SC_COMPILER_C_CHAR_IDENT;
     420          10 : /* ] */     t[93] |= SC_COMPILER_C_IDENT;
     421             :         }
     422             :     }
     423         132 : }
     424             : 
     425         906 : static bool lcl_isValidQuotedText( const OUString& rFormula, sal_Int32 nSrcPos, ParseResult& rRes )
     426             : {
     427             :     // Tokens that start at ' can have anything in them until a final '
     428             :     // but '' marks an escaped '
     429             :     // We've earlier guaranteed that a string containing '' will be
     430             :     // surrounded by '
     431         906 :     if (nSrcPos < rFormula.getLength() && rFormula[nSrcPos] == '\'')
     432             :     {
     433         344 :         sal_Int32 nPos = nSrcPos+1;
     434        5176 :         while (nPos < rFormula.getLength())
     435             :         {
     436        4832 :             if (rFormula[nPos] == '\'')
     437             :             {
     438         352 :                 if ( (nPos+1 == rFormula.getLength()) || (rFormula[nPos+1] != '\'') )
     439             :                 {
     440         344 :                     rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
     441         344 :                     rRes.EndPos = nPos+1;
     442         344 :                     return true;
     443             :                 }
     444           8 :                 ++nPos;
     445             :             }
     446        4488 :             ++nPos;
     447             :         }
     448             :     }
     449             : 
     450         562 :     return false;
     451             : }
     452             : 
     453          50 : static bool lcl_parseExternalName(
     454             :         const OUString& rSymbol,
     455             :         OUString& rFile,
     456             :         OUString& rName,
     457             :         const sal_Unicode cSep,
     458             :         const ScDocument* pDoc = NULL,
     459             :         const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks = NULL )
     460             : {
     461             :     /* TODO: future versions will have to support sheet-local names too, thus
     462             :      * return a possible sheet name as well. */
     463          50 :     const sal_Unicode* const pStart = rSymbol.getStr();
     464          50 :     const sal_Unicode* p = pStart;
     465          50 :     sal_Int32 nLen = rSymbol.getLength();
     466         100 :     OUString aTmpFile, aTmpName;
     467          50 :     sal_Int32 i = 0;
     468          50 :     bool bInName = false;
     469          50 :     if (cSep == '!')
     470             :     {
     471             :         // For XL use existing parser that resolves bracketed and quoted and
     472             :         // indexed external document names.
     473           6 :         ScRange aRange;
     474           6 :         OUString aStartTabName, aEndTabName;
     475           6 :         sal_uInt16 nFlags = 0;
     476             :         p = aRange.Parse_XL_Header( p, pDoc, aTmpFile, aStartTabName,
     477           6 :                 aEndTabName, nFlags, true, pExternalLinks );
     478           6 :         if (!p || p == pStart)
     479           6 :             return false;
     480           0 :         i = sal_Int32(p - pStart);
     481             :     }
     482         254 :     for ( ; i < nLen; ++i, ++p)
     483             :     {
     484         212 :         sal_Unicode c = *p;
     485         212 :         if (i == 0)
     486             :         {
     487          44 :             if (c == '.' || c == cSep)
     488           0 :                 return false;
     489             : 
     490          44 :             if (c == '\'')
     491             :             {
     492             :                 // Move to the next char and loop until the second single
     493             :                 // quote.
     494           0 :                 sal_Unicode cPrev = c;
     495           0 :                 ++i; ++p;
     496           0 :                 for (sal_Int32 j = i; j < nLen; ++j, ++p)
     497             :                 {
     498           0 :                     c = *p;
     499           0 :                     if (c == '\'')
     500             :                     {
     501           0 :                         if (j == i)
     502             :                         {
     503             :                             // empty quote e.g. (=''!Name)
     504           0 :                             return false;
     505             :                         }
     506             : 
     507           0 :                         if (cPrev == '\'')
     508             :                         {
     509             :                             // two consecutive quotes equal a single quote in
     510             :                             // the file name.
     511           0 :                             aTmpFile += OUString(c);
     512           0 :                             cPrev = 'a';
     513             :                         }
     514             :                         else
     515           0 :                             cPrev = c;
     516             : 
     517           0 :                         continue;
     518             :                     }
     519             : 
     520           0 :                     if (cPrev == '\'' && j != i)
     521             :                     {
     522             :                         // this is not a quote but the previous one is.  This
     523             :                         // ends the parsing of the quoted segment.  At this
     524             :                         // point, the current char must equal the separator
     525             :                         // char.
     526             : 
     527           0 :                         i = j;
     528           0 :                         bInName = true;
     529           0 :                         aTmpName += OUString(c); // Keep the separator as part of the name.
     530           0 :                         break;
     531             :                     }
     532           0 :                     aTmpFile += OUString(c);
     533           0 :                     cPrev = c;
     534             :                 }
     535             : 
     536           0 :                 if (!bInName)
     537             :                 {
     538             :                     // premature ending of the quoted segment.
     539           0 :                     return false;
     540             :                 }
     541             : 
     542           0 :                 if (c != cSep)
     543             :                 {
     544             :                     // only the separator is allowed after the closing quote.
     545           0 :                     return false;
     546             :                 }
     547             : 
     548           0 :                 continue;
     549             :             }
     550             :         }
     551             : 
     552         212 :         if (bInName)
     553             :         {
     554           0 :             if (c == cSep)
     555             :             {
     556             :                 // A second separator ?  Not a valid external name.
     557           0 :                 return false;
     558             :             }
     559           0 :             aTmpName += OUString(c);
     560             :         }
     561             :         else
     562             :         {
     563         212 :             if (c == cSep)
     564             :             {
     565           0 :                 bInName = true;
     566           0 :                 aTmpName += OUString(c); // Keep the separator as part of the name.
     567             :             }
     568             :             else
     569             :             {
     570             :                 do
     571             :                 {
     572         212 :                     if (rtl::isAsciiAlphanumeric(c))
     573             :                         // allowed.
     574         210 :                         break;
     575             : 
     576           2 :                     if (c > 128)
     577             :                         // non-ASCII character is allowed.
     578           0 :                         break;
     579             : 
     580           2 :                     bool bValid = false;
     581           2 :                     switch (c)
     582             :                     {
     583             :                         case '_':
     584             :                         case '-':
     585             :                         case '.':
     586             :                             // these special characters are allowed.
     587           0 :                             bValid = true;
     588           0 :                             break;
     589             :                     }
     590           2 :                     if (bValid)
     591           0 :                         break;
     592             : 
     593           2 :                     return false;
     594             :                 }
     595             :                 while (false);
     596         210 :                 aTmpFile += OUString(c);
     597             :             }
     598             :         }
     599             :     }
     600             : 
     601          42 :     if (!bInName)
     602             :     {
     603             :         // No name found - most likely the symbol has no '!'s.
     604          42 :         return false;
     605             :     }
     606             : 
     607           0 :     sal_Int32 nNameLen = aTmpName.getLength();
     608           0 :     if (nNameLen < 2)
     609             :     {
     610             :         // Name must be at least 2-char long (separator plus name).
     611           0 :         return false;
     612             :     }
     613             : 
     614           0 :     if (aTmpName[0] != cSep)
     615             :     {
     616             :         // 1st char of the name must equal the separator.
     617           0 :         return false;
     618             :     }
     619             : 
     620           0 :     if (aTmpName[nNameLen-1] == '!')
     621             :     {
     622             :         // Check against #REF!.
     623           0 :         if (aTmpName.equalsAscii("#REF!"))
     624           0 :             return false;
     625             :     }
     626             : 
     627           0 :     rFile = aTmpFile;
     628           0 :     rName = aTmpName.copy(1); // Skip the first char as it is always the separator.
     629          50 :     return true;
     630             : }
     631             : 
     632           0 : static OUString lcl_makeExternalNameStr(const OUString& rFile, const OUString& rName,
     633             :         const sal_Unicode cSep, bool bODF )
     634             : {
     635           0 :     OUString aEscQuote("''");
     636           0 :     OUString aFile(rFile.replaceAll("'", aEscQuote));
     637           0 :     OUString aName(rName);
     638           0 :     if (bODF)
     639           0 :         aName = aName.replaceAll("'", aEscQuote);
     640           0 :     OUStringBuffer aBuf(aFile.getLength() + aName.getLength() + 9);
     641           0 :     if (bODF)
     642           0 :         aBuf.append( '[');
     643           0 :     aBuf.append( "'" + aFile + "'" + OUString(cSep));
     644           0 :     if (bODF)
     645           0 :         aBuf.append( "$$'" );
     646           0 :     aBuf.append( aName);
     647           0 :     if (bODF)
     648           0 :         aBuf.append( "']" );
     649           0 :     return aBuf.makeStringAndClear();
     650             : }
     651             : 
     652           0 : static bool lcl_getLastTabName( OUString& rTabName2, const OUString& rTabName1,
     653             :                                 const vector<OUString>& rTabNames, const ScRange& rRef )
     654             : {
     655           0 :     SCsTAB nTabSpan = rRef.aEnd.Tab() - rRef.aStart.Tab();
     656           0 :     if (nTabSpan > 0)
     657             :     {
     658           0 :         size_t nCount = rTabNames.size();
     659           0 :         vector<OUString>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end();
     660           0 :         vector<OUString>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1);
     661           0 :         if (itr == rTabNames.end())
     662             :         {
     663           0 :             rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     664           0 :             return false;
     665             :         }
     666             : 
     667           0 :         size_t nDist = ::std::distance(itrBeg, itr);
     668           0 :         if (nDist + static_cast<size_t>(nTabSpan) >= nCount)
     669             :         {
     670           0 :             rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
     671           0 :             return false;
     672             :         }
     673             : 
     674           0 :         rTabName2 = rTabNames[nDist+nTabSpan];
     675             :     }
     676             :     else
     677           0 :         rTabName2 = rTabName1;
     678             : 
     679           0 :     return true;
     680             : }
     681             : 
     682         126 : struct Convention_A1 : public ScCompiler::Convention
     683             : {
     684         126 :     Convention_A1( FormulaGrammar::AddressConvention eConv ) : ScCompiler::Convention( eConv ) { }
     685             :     static void MakeColStr( OUStringBuffer& rBuffer, SCCOL nCol );
     686             :     static void MakeRowStr( OUStringBuffer& rBuffer, SCROW nRow );
     687             : 
     688         898 :     ParseResult parseAnyToken( const OUString& rFormula,
     689             :                                sal_Int32 nSrcPos,
     690             :                                const CharClass* pCharClass) const SAL_OVERRIDE
     691             :     {
     692         898 :         ParseResult aRet;
     693         898 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
     694         344 :             return aRet;
     695             : 
     696             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
     697             :             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
     698             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
     699             :         // '?' allowed in range names because of Xcl :-/
     700         554 :         static const OUString aAddAllowed("?#");
     701             :         return pCharClass->parseAnyToken( rFormula,
     702         554 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
     703             :     }
     704             : 
     705      192640 :     virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode /*cLast*/ ) const SAL_OVERRIDE
     706             :     {
     707      192640 :         return mpCharTable[static_cast<sal_uInt8>(c)];
     708             :     }
     709             : };
     710             : 
     711       86652 : void Convention_A1::MakeColStr( OUStringBuffer& rBuffer, SCCOL nCol )
     712             : {
     713       86652 :     if ( !ValidCol( nCol) )
     714           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     715             :     else
     716       86652 :         ::ScColToAlpha( rBuffer, nCol);
     717       86652 : }
     718             : 
     719       86658 : void Convention_A1::MakeRowStr( OUStringBuffer& rBuffer, SCROW nRow )
     720             : {
     721       86658 :     if ( !ValidRow(nRow) )
     722           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     723             :     else
     724       86658 :         rBuffer.append(sal_Int32(nRow + 1));
     725       86658 : }
     726             : 
     727         108 : struct ConventionOOO_A1 : public Convention_A1
     728             : {
     729          54 :     ConventionOOO_A1() : Convention_A1 (FormulaGrammar::CONV_OOO) { }
     730          54 :     ConventionOOO_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1 (eConv) { }
     731             : 
     732       51130 :     static void MakeTabStr( OUStringBuffer &rBuf, const std::vector<OUString>& rTabNames, SCTAB nTab )
     733             :     {
     734       51130 :         if (static_cast<size_t>(nTab) >= rTabNames.size())
     735           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
     736             :         else
     737       51130 :             rBuf.append(rTabNames[nTab]);
     738       51130 :         rBuf.append('.');
     739       51130 :     }
     740             : 
     741       78266 :     void MakeOneRefStrImpl(
     742             :         OUStringBuffer& rBuffer,
     743             :         const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     744             :         const ScSingleRefData& rRef, const ScAddress& rAbsRef,
     745             :         bool bForceTab, bool bODF ) const
     746             :     {
     747       78266 :         if( rRef.IsFlag3D() || bForceTab )
     748             :         {
     749       51140 :             if (!ValidTab(rAbsRef.Tab()) || rRef.IsTabDeleted())
     750             :             {
     751          10 :                 if (!rRef.IsTabRel())
     752           2 :                     rBuffer.append('$');
     753          10 :                 rBuffer.append(rErrRef);
     754          10 :                 rBuffer.append('.');
     755             :             }
     756             :             else
     757             :             {
     758       51130 :                 if (!rRef.IsTabRel())
     759       50460 :                     rBuffer.append('$');
     760       51130 :                 MakeTabStr(rBuffer, rTabNames, rAbsRef.Tab());
     761             :             }
     762             :         }
     763       27126 :         else if (bODF)
     764         508 :             rBuffer.append('.');
     765       78266 :         if (!rRef.IsColRel())
     766       76144 :             rBuffer.append('$');
     767       78266 :         if (!ValidCol(rAbsRef.Col()) || rRef.IsColDeleted())
     768           6 :             rBuffer.append(rErrRef);
     769             :         else
     770       78260 :             MakeColStr(rBuffer, rAbsRef.Col());
     771       78266 :         if (!rRef.IsRowRel())
     772       76194 :             rBuffer.append('$');
     773       78266 :         if (!ValidRow(rAbsRef.Row()) || rRef.IsRowDeleted())
     774           0 :             rBuffer.append(rErrRef);
     775             :         else
     776       78266 :             MakeRowStr(rBuffer, rAbsRef.Row());
     777       78266 :     }
     778             : 
     779       52076 :     void makeRefStr( OUStringBuffer&   rBuffer,
     780             :                      formula::FormulaGrammar::Grammar /*eGram*/,
     781             :                      const ScAddress& rPos,
     782             :                      const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     783             :                      const ScComplexRefData& rRef,
     784             :                      bool bSingleRef ) const SAL_OVERRIDE
     785             :     {
     786       52076 :         ScComplexRefData aRef( rRef );
     787             :         // In case absolute/relative positions weren't separately available:
     788             :         // transform relative to absolute!
     789       52076 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
     790       52076 :         if( !bSingleRef )
     791       25610 :             aAbs2 = aRef.Ref2.toAbs(rPos);
     792             : 
     793       52076 :         MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref1, aAbs1, false, false);
     794       52076 :         if (!bSingleRef)
     795             :         {
     796       25610 :             rBuffer.append(':');
     797       25610 :             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref2, aAbs2, aAbs1.Tab() != aAbs2.Tab(), false);
     798             :         }
     799       52076 :     }
     800             : 
     801       64524 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
     802             :     {
     803       64524 :         switch (eSymType)
     804             :         {
     805             :             case ScCompiler::Convention::ABS_SHEET_PREFIX:
     806       32262 :                 return '$';
     807             :             case ScCompiler::Convention::SHEET_SEPARATOR:
     808       32262 :                 return '.';
     809             :         }
     810             : 
     811           0 :         return sal_Unicode(0);
     812             :     }
     813             : 
     814          44 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
     815             :             const ScDocument* pDoc,
     816             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
     817             :     {
     818          44 :         return lcl_parseExternalName(rSymbol, rFile, rName, '#', pDoc, pExternalLinks);
     819             :     }
     820             : 
     821           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
     822             :             const OUString& rName ) const SAL_OVERRIDE
     823             :     {
     824           0 :         return lcl_makeExternalNameStr( rFile, rName, '#', false);
     825             :     }
     826             : 
     827          74 :     bool makeExternalSingleRefStr(
     828             :         OUStringBuffer& rBuffer, const OUString& rFileName, const OUString& rTabName,
     829             :         const ScSingleRefData& rRef, const ScAddress& rPos, bool bDisplayTabName, bool bEncodeUrl ) const
     830             :     {
     831          74 :         ScAddress aAbsRef = rRef.toAbs(rPos);
     832          74 :         if (bDisplayTabName)
     833             :         {
     834          62 :             OUString aFile;
     835          62 :             if (bEncodeUrl)
     836          20 :                 aFile = rFileName;
     837             :             else
     838          42 :                 aFile = INetURLObject::decode(rFileName, '%', INetURLObject::DECODE_UNAMBIGUOUS);
     839             : 
     840          62 :             rBuffer.append("'" + aFile.replaceAll("'", "''") + "'#");
     841             : 
     842          62 :             if (!rRef.IsTabRel())
     843          62 :                 rBuffer.append('$');
     844          62 :             ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
     845             : 
     846          62 :             rBuffer.append('.');
     847             :         }
     848             : 
     849          74 :         if (!rRef.IsColRel())
     850           4 :             rBuffer.append('$');
     851          74 :         MakeColStr( rBuffer, aAbsRef.Col());
     852          74 :         if (!rRef.IsRowRel())
     853          14 :             rBuffer.append('$');
     854          74 :         MakeRowStr( rBuffer, aAbsRef.Row());
     855             : 
     856          74 :         return true;
     857             :     }
     858             : 
     859          50 :     void makeExternalRefStrImpl(
     860             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     861             :         const OUString& rTabName, const ScSingleRefData& rRef, bool bODF ) const
     862             :     {
     863          50 :         if (bODF)
     864          16 :             rBuffer.append( '[');
     865             : 
     866          50 :         bool bEncodeUrl = bODF;
     867          50 :         makeExternalSingleRefStr(rBuffer, rFileName, rTabName, rRef, rPos, true, bEncodeUrl);
     868          50 :         if (bODF)
     869          16 :             rBuffer.append( ']');
     870          50 :     }
     871             : 
     872          34 :     virtual void makeExternalRefStr(
     873             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     874             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
     875             :     {
     876          34 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, false);
     877          34 :     }
     878             : 
     879          12 :     void makeExternalRefStrImpl(
     880             :         OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& rFileName,
     881             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
     882             :         const ScComplexRefData& rRef, bool bODF ) const
     883             :     {
     884          12 :         ScRange aAbsRange = rRef.toAbs(rPos);
     885             : 
     886          12 :         if (bODF)
     887           4 :             rBuffer.append( '[');
     888             :         // Ensure that there's always a closing bracket, no premature returns.
     889          12 :         bool bEncodeUrl = bODF;
     890             : 
     891             :         do
     892             :         {
     893          12 :             if (!makeExternalSingleRefStr(rBuffer, rFileName, rTabName, rRef.Ref1, rPos, true, bEncodeUrl))
     894           0 :                 break;
     895             : 
     896          12 :             rBuffer.append(':');
     897             : 
     898          12 :             OUString aLastTabName;
     899          12 :             bool bDisplayTabName = (aAbsRange.aStart.Tab() != aAbsRange.aEnd.Tab());
     900          12 :             if (bDisplayTabName)
     901             :             {
     902             :                 // Get the name of the last table.
     903           0 :                 if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, aAbsRange))
     904             :                 {
     905             :                     OSL_FAIL( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found");
     906             :                     // aLastTabName contains #REF!, proceed.
     907             :                 }
     908             :             }
     909          12 :             else if (bODF)
     910           4 :                 rBuffer.append( '.');      // need at least the sheet separator in ODF
     911             :             makeExternalSingleRefStr(
     912          12 :                 rBuffer, rFileName, aLastTabName, rRef.Ref2, rPos, bDisplayTabName, bEncodeUrl);
     913             :         } while (false);
     914             : 
     915          12 :         if (bODF)
     916           4 :             rBuffer.append( ']');
     917          12 :     }
     918             : 
     919           8 :     virtual void makeExternalRefStr(
     920             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     921             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
     922             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
     923             :     {
     924           8 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabNames, rTabName, rRef, false);
     925           8 :     }
     926             : };
     927             : 
     928          54 : struct ConventionOOO_A1_ODF : public ConventionOOO_A1
     929             : {
     930          54 :     ConventionOOO_A1_ODF() : ConventionOOO_A1 (FormulaGrammar::CONV_ODF) { }
     931         454 :     void makeRefStr( OUStringBuffer&   rBuffer,
     932             :                      formula::FormulaGrammar::Grammar eGram,
     933             :                      const ScAddress& rPos,
     934             :                      const OUString& rErrRef, const std::vector<OUString>& rTabNames,
     935             :                      const ScComplexRefData& rRef,
     936             :                      bool bSingleRef ) const SAL_OVERRIDE
     937             :     {
     938         454 :         rBuffer.append('[');
     939         454 :         ScComplexRefData aRef( rRef );
     940             :         // In case absolute/relative positions weren't separately available:
     941             :         // transform relative to absolute!
     942         454 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
     943         454 :         if( !bSingleRef )
     944         126 :             aAbs2 = aRef.Ref2.toAbs(rPos);
     945             : 
     946         454 :         if (FormulaGrammar::isODFF(eGram) && (!ValidAddress(aAbs1) || !ValidAddress(aAbs2)))
     947             :         {
     948           0 :             rBuffer.append(rErrRef);
     949             :             // For ODFF write [#REF!], but not for PODF so apps reading ODF
     950             :             // 1.0/1.1 may have a better chance if they implemented the old
     951             :             // form.
     952             :         }
     953             :         else
     954             :         {
     955         454 :             MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref1, aAbs1, false, true);
     956         454 :             if (!bSingleRef)
     957             :             {
     958         126 :                 rBuffer.append(':');
     959         126 :                 MakeOneRefStrImpl(rBuffer, rErrRef, rTabNames, aRef.Ref2, aAbs2, aAbs1.Tab() != aAbs2.Tab(), true);
     960             :             }
     961             :         }
     962         454 :         rBuffer.append(']');
     963         454 :     }
     964             : 
     965           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
     966             :             const OUString& rName ) const SAL_OVERRIDE
     967             :     {
     968           0 :         return lcl_makeExternalNameStr( rFile, rName, '#', true);
     969             :     }
     970             : 
     971          16 :     virtual void makeExternalRefStr(
     972             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     973             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
     974             :     {
     975          16 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, true);
     976          16 :     }
     977             : 
     978           4 :     virtual void makeExternalRefStr(
     979             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
     980             :         const std::vector<OUString>& rTabNames,
     981             :         const OUString& rTabName, const ScComplexRefData& rRef ) const SAL_OVERRIDE
     982             :     {
     983           4 :         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabNames, rTabName, rRef, true);
     984           4 :     }
     985             : };
     986             : 
     987          24 : struct ConventionXL
     988             : {
     989         254 :     static void GetTab(
     990             :         const ScAddress& rPos, const std::vector<OUString>& rTabNames,
     991             :         const ScSingleRefData& rRef, OUString& rTabName )
     992             :     {
     993         254 :         ScAddress aAbs = rRef.toAbs(rPos);
     994         254 :         if (rRef.IsTabDeleted() || static_cast<size_t>(aAbs.Tab()) >= rTabNames.size())
     995             :         {
     996           0 :             rTabName = ScGlobal::GetRscString( STR_NO_REF_TABLE );
     997         254 :             return;
     998             :         }
     999         254 :         rTabName = rTabNames[aAbs.Tab()];
    1000             :     }
    1001             : 
    1002        7116 :     static void MakeTabStr( OUStringBuffer& rBuf,
    1003             :                             const ScAddress& rPos,
    1004             :                             const std::vector<OUString>& rTabNames,
    1005             :                             const ScComplexRefData& rRef,
    1006             :                             bool bSingleRef )
    1007             :     {
    1008        7116 :         if( rRef.Ref1.IsFlag3D() )
    1009             :         {
    1010         508 :             OUString aStartTabName, aEndTabName;
    1011             : 
    1012         254 :             GetTab(rPos, rTabNames, rRef.Ref1, aStartTabName);
    1013             : 
    1014         254 :             if( !bSingleRef && rRef.Ref2.IsFlag3D() )
    1015             :             {
    1016           0 :                 GetTab(rPos, rTabNames, rRef.Ref2, aEndTabName);
    1017             :             }
    1018             : 
    1019         254 :             rBuf.append( aStartTabName );
    1020         254 :             if( !bSingleRef && rRef.Ref2.IsFlag3D() && aStartTabName != aEndTabName )
    1021             :             {
    1022           0 :                 rBuf.append( ':' );
    1023           0 :                 rBuf.append( aEndTabName );
    1024             :             }
    1025             : 
    1026         508 :             rBuf.append( '!' );
    1027             :         }
    1028        7116 :     }
    1029             : 
    1030       30300 :     static sal_Unicode getSpecialSymbol( ScCompiler::Convention::SpecialSymbolType eSymType )
    1031             :     {
    1032       30300 :         switch (eSymType)
    1033             :         {
    1034             :             case ScCompiler::Convention::ABS_SHEET_PREFIX:
    1035       15150 :                 return sal_Unicode(0);
    1036             :             case ScCompiler::Convention::SHEET_SEPARATOR:
    1037       15150 :                 return '!';
    1038             :         }
    1039           0 :         return sal_Unicode(0);
    1040             :     }
    1041             : 
    1042           6 :     static bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1043             :             const ScDocument* pDoc,
    1044             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
    1045             :     {
    1046           6 :         return lcl_parseExternalName( rSymbol, rFile, rName, '!', pDoc, pExternalLinks);
    1047             :     }
    1048             : 
    1049           0 :     static OUString makeExternalNameStr( const OUString& rFile, const OUString& rName )
    1050             :     {
    1051           0 :         return lcl_makeExternalNameStr( rFile, rName, '!', false);
    1052             :     }
    1053             : 
    1054           0 :     static void makeExternalDocStr( OUStringBuffer& rBuffer, const OUString& rFullName, bool bEncodeUrl )
    1055             :     {
    1056             :         // Format that is easier to deal with inside OOo, because we use file
    1057             :         // URL, and all characetrs are allowed.  Check if it makes sense to do
    1058             :         // it the way Gnumeric does it.  Gnumeric doesn't use the URL form
    1059             :         // and allows relative file path.
    1060             :         //
    1061             :         //   ['file:///path/to/source/filename.xls']
    1062             : 
    1063           0 :         rBuffer.append('[');
    1064           0 :         rBuffer.append('\'');
    1065           0 :         OUString aFullName;
    1066           0 :         if (bEncodeUrl)
    1067           0 :             aFullName = rFullName;
    1068             :         else
    1069           0 :             aFullName = INetURLObject::decode(rFullName, '%', INetURLObject::DECODE_UNAMBIGUOUS);
    1070             : 
    1071           0 :         const sal_Unicode* pBuf = aFullName.getStr();
    1072           0 :         sal_Int32 nLen = aFullName.getLength();
    1073           0 :         for (sal_Int32 i = 0; i < nLen; ++i)
    1074             :         {
    1075           0 :             const sal_Unicode c = pBuf[i];
    1076           0 :             if (c == '\'')
    1077           0 :                 rBuffer.append(c);
    1078           0 :             rBuffer.append(c);
    1079             :         }
    1080           0 :         rBuffer.append('\'');
    1081           0 :         rBuffer.append(']');
    1082           0 :     }
    1083             : 
    1084           0 :     static void makeExternalTabNameRange( OUStringBuffer& rBuf, const OUString& rTabName,
    1085             :                                           const vector<OUString>& rTabNames,
    1086             :                                           const ScRange& rRef )
    1087             :     {
    1088           0 :         OUString aLastTabName;
    1089           0 :         if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef))
    1090             :         {
    1091           0 :             ScRangeStringConverter::AppendTableName(rBuf, aLastTabName);
    1092           0 :             return;
    1093             :         }
    1094             : 
    1095           0 :         ScRangeStringConverter::AppendTableName(rBuf, rTabName);
    1096           0 :         if (rTabName != aLastTabName)
    1097             :         {
    1098           0 :             rBuf.append(':');
    1099           0 :             ScRangeStringConverter::AppendTableName(rBuf, rTabName);
    1100           0 :         }
    1101             :     }
    1102             : 
    1103           8 :     static void parseExternalDocName( const OUString& rFormula, sal_Int32& rSrcPos )
    1104             :     {
    1105           8 :         sal_Int32 nLen = rFormula.getLength();
    1106           8 :         const sal_Unicode* p = rFormula.getStr();
    1107           8 :         sal_Unicode cPrev = 0;
    1108           8 :         for (sal_Int32 i = rSrcPos; i < nLen; ++i)
    1109             :         {
    1110           8 :             sal_Unicode c = p[i];
    1111           8 :             if (i == rSrcPos)
    1112             :             {
    1113             :                 // first character must be '['.
    1114           8 :                 if (c != '[')
    1115           8 :                     return;
    1116             :             }
    1117           0 :             else if (i == rSrcPos + 1)
    1118             :             {
    1119             :                 // second character must be a single quote.
    1120           0 :                 if (c != '\'')
    1121           0 :                     return;
    1122             :             }
    1123           0 :             else if (c == '\'')
    1124             :             {
    1125           0 :                 if (cPrev == '\'')
    1126             :                     // two successive single quote is treated as a single
    1127             :                     // valid character.
    1128           0 :                     c = 'a';
    1129             :             }
    1130           0 :             else if (c == ']')
    1131             :             {
    1132           0 :                 if (cPrev == '\'')
    1133             :                 {
    1134             :                     // valid source document path found.  Increment the
    1135             :                     // current position to skip the source path.
    1136           0 :                     rSrcPos = i + 1;
    1137           0 :                     if (rSrcPos >= nLen)
    1138           0 :                         rSrcPos = nLen - 1;
    1139           0 :                     return;
    1140             :                 }
    1141             :                 else
    1142           0 :                     return;
    1143             :             }
    1144             :             else
    1145             :             {
    1146             :                 // any other character
    1147           0 :                 if (i > rSrcPos + 2 && cPrev == '\'')
    1148             :                     // unless it's the 3rd character, a normal character
    1149             :                     // following immediately a single quote is invalid.
    1150           0 :                     return;
    1151             :             }
    1152           0 :             cPrev = c;
    1153             :         }
    1154             :     }
    1155             : };
    1156             : 
    1157          18 : struct ConventionXL_A1 : public Convention_A1, public ConventionXL
    1158             : {
    1159           8 :     ConventionXL_A1() : Convention_A1( FormulaGrammar::CONV_XL_A1 ) { }
    1160          10 :     ConventionXL_A1( FormulaGrammar::AddressConvention eConv ) : Convention_A1( eConv ) { }
    1161             : 
    1162        8318 :     void makeSingleCellStr( OUStringBuffer& rBuf, const ScSingleRefData& rRef, const ScAddress& rAbs ) const
    1163             :     {
    1164        8318 :         if (!rRef.IsColRel())
    1165        2966 :             rBuf.append('$');
    1166        8318 :         MakeColStr(rBuf, rAbs.Col());
    1167        8318 :         if (!rRef.IsRowRel())
    1168        2966 :             rBuf.append('$');
    1169        8318 :         MakeRowStr(rBuf, rAbs.Row());
    1170        8318 :     }
    1171             : 
    1172        6970 :     void makeRefStr( OUStringBuffer&   rBuf,
    1173             :                      formula::FormulaGrammar::Grammar /*eGram*/,
    1174             :                      const ScAddress& rPos,
    1175             :                      const OUString& /*rErrRef*/, const std::vector<OUString>& rTabNames,
    1176             :                      const ScComplexRefData& rRef,
    1177             :                      bool bSingleRef ) const SAL_OVERRIDE
    1178             :     {
    1179        6970 :         ScComplexRefData aRef( rRef );
    1180             : 
    1181             :         // Play fast and loose with invalid refs.  There is not much point in producing
    1182             :         // Foo!A1:#REF! versus #REF! at this point
    1183        6970 :         ScAddress aAbs1 = aRef.Ref1.toAbs(rPos), aAbs2;
    1184             : 
    1185        6970 :         MakeTabStr(rBuf, rPos, rTabNames, aRef, bSingleRef);
    1186             : 
    1187        6970 :         if (!ValidAddress(aAbs1))
    1188             :         {
    1189           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1190           0 :             return;
    1191             :         }
    1192             : 
    1193        6970 :         if( !bSingleRef )
    1194             :         {
    1195        1342 :             aAbs2 = aRef.Ref2.toAbs(rPos);
    1196        1342 :             if (!ValidAddress(aAbs2))
    1197             :             {
    1198           0 :                 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1199           0 :                 return;
    1200             :             }
    1201             : 
    1202        1342 :             if (aAbs1.Col() == 0 && aAbs2.Col() >= MAXCOL)
    1203             :             {
    1204           0 :                 if (!aRef.Ref1.IsRowRel())
    1205           0 :                     rBuf.append( '$' );
    1206           0 :                 MakeRowStr(rBuf, aAbs1.Row());
    1207           0 :                 rBuf.append( ':' );
    1208           0 :                 if (!aRef.Ref2.IsRowRel())
    1209           0 :                     rBuf.append( '$' );
    1210           0 :                 MakeRowStr(rBuf, aAbs2.Row());
    1211           0 :                 return;
    1212             :             }
    1213             : 
    1214        1342 :             if (aAbs1.Row() == 0 && aAbs2.Row() >= MAXROW)
    1215             :             {
    1216           0 :                 if (!aRef.Ref1.IsColRel())
    1217           0 :                     rBuf.append( '$' );
    1218           0 :                 MakeColStr(rBuf, aAbs1.Col());
    1219           0 :                 rBuf.append( ':' );
    1220           0 :                 if (!aRef.Ref2.IsColRel())
    1221           0 :                     rBuf.append( '$' );
    1222           0 :                 MakeColStr(rBuf, aAbs2.Col());
    1223           0 :                 return;
    1224             :             }
    1225             :         }
    1226             : 
    1227        6970 :         makeSingleCellStr(rBuf, aRef.Ref1, aAbs1);
    1228        6970 :         if (!bSingleRef)
    1229             :         {
    1230        1342 :             rBuf.append( ':' );
    1231        1342 :             makeSingleCellStr(rBuf, aRef.Ref2, aAbs2);
    1232             :         }
    1233             :     }
    1234             : 
    1235           8 :     virtual ParseResult parseAnyToken( const OUString& rFormula,
    1236             :                                        sal_Int32 nSrcPos,
    1237             :                                        const CharClass* pCharClass) const SAL_OVERRIDE
    1238             :     {
    1239           8 :         ConventionXL::parseExternalDocName(rFormula, nSrcPos);
    1240             : 
    1241           8 :         ParseResult aRet;
    1242           8 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
    1243           0 :             return aRet;
    1244             : 
    1245             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
    1246             :             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
    1247             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
    1248             :         // '?' allowed in range names
    1249          16 :         const OUString aAddAllowed("?!");
    1250             :         return pCharClass->parseAnyToken( rFormula,
    1251          16 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
    1252             :     }
    1253             : 
    1254       27596 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
    1255             :     {
    1256       27596 :         return ConventionXL::getSpecialSymbol(eSymType);
    1257             :     }
    1258             : 
    1259           6 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1260             :             const ScDocument* pDoc,
    1261             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
    1262             :     {
    1263           6 :         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
    1264             :     }
    1265             : 
    1266           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
    1267             :             const OUString& rName ) const SAL_OVERRIDE
    1268             :     {
    1269           0 :         return ConventionXL::makeExternalNameStr(rFile, rName);
    1270             :     }
    1271             : 
    1272           0 :     virtual void makeExternalRefStr(
    1273             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1274             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1275             :     {
    1276             :         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
    1277             :         // This is a little different from the format Excel uses, as Excel
    1278             :         // puts [] only around the file name.  But we need to enclose the
    1279             :         // whole file path with [] because the file name can contain any
    1280             :         // characters.
    1281             : 
    1282           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1283           0 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1284           0 :         rBuffer.append('!');
    1285             : 
    1286           0 :         makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
    1287           0 :     }
    1288             : 
    1289           0 :     virtual void makeExternalRefStr(
    1290             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1291             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1292             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1293             :     {
    1294           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1295             : 
    1296           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1297           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1298           0 :         rBuffer.append('!');
    1299             : 
    1300           0 :         makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1301           0 :         if (aAbsRef.aStart != aAbsRef.aEnd)
    1302             :         {
    1303           0 :             rBuffer.append(':');
    1304           0 :             makeSingleCellStr(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1305             :         }
    1306           0 :     }
    1307             : };
    1308             : 
    1309          10 : struct ConventionXL_OOX : public ConventionXL_A1
    1310             : {
    1311          10 :     ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
    1312             : 
    1313           0 :     virtual OUString makeExternalNameStr( sal_uInt16 nFileId, const OUString& /*rFile*/,
    1314             :             const OUString& rName ) const SAL_OVERRIDE
    1315             :     {
    1316             :         // [N]!DefinedName is a workbook global name.
    1317           0 :         return OUString( "[" + OUString::number(nFileId+1) + "]!" + rName );
    1318             : 
    1319             :         /* TODO: add support for sheet local names, would be
    1320             :          * [N]'Sheet Name'!DefinedName
    1321             :          * Similar to makeExternalRefStr() but with DefinedName instead of
    1322             :          * CellStr. */
    1323             :     }
    1324             : 
    1325           6 :     virtual void makeExternalRefStr(
    1326             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/,
    1327             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1328             :     {
    1329             :         // [N]'Sheet Name'!$A$1
    1330             :         // Where N is a 1-based positive integer number of a file name in OOXML
    1331             :         // xl/externalLinks/externalLinkN.xml
    1332             : 
    1333           6 :         ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
    1334           6 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1335           6 :         rBuffer.append('!');
    1336             : 
    1337           6 :         makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
    1338           6 :     }
    1339             : 
    1340           0 :     virtual void makeExternalRefStr(
    1341             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/,
    1342             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1343             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1344             :     {
    1345           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1346             : 
    1347           0 :         ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
    1348           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1349           0 :         rBuffer.append('!');
    1350             : 
    1351           0 :         makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1352           0 :         if (aAbsRef.aStart != aAbsRef.aEnd)
    1353             :         {
    1354           0 :             rBuffer.append(':');
    1355           0 :             makeSingleCellStr(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1356             :         }
    1357           0 :     }
    1358             : 
    1359           6 :     static void makeExternalDocStr( OUStringBuffer& rBuffer, sal_uInt16 nFileId )
    1360             :     {
    1361           6 :         rBuffer.append('[').append( OUString::number( nFileId+1)).append(']');
    1362           6 :     }
    1363             : };
    1364             : 
    1365             : static void
    1366         152 : r1c1_add_col( OUStringBuffer &rBuf, const ScSingleRefData& rRef, const ScAddress& rAbsRef )
    1367             : {
    1368         152 :     rBuf.append( 'C' );
    1369         152 :     if( rRef.IsColRel() )
    1370             :     {
    1371         134 :         SCCOL nCol = rRef.Col();
    1372         134 :         if (nCol != 0)
    1373          86 :             rBuf.append("[").append(OUString::number(nCol)).append("]");
    1374             :     }
    1375             :     else
    1376          18 :         rBuf.append( OUString::number( rAbsRef.Col() + 1 ) );
    1377         152 : }
    1378             : static void
    1379         152 : r1c1_add_row( OUStringBuffer &rBuf, const ScSingleRefData& rRef, const ScAddress& rAbsRef )
    1380             : {
    1381         152 :     rBuf.append( 'R' );
    1382         152 :     if( rRef.IsRowRel() )
    1383             :     {
    1384         134 :         if (rRef.Row() != 0)
    1385             :         {
    1386          20 :             rBuf.append("[").append( OUString::number(rRef.Row()) ).append("]");
    1387             :         }
    1388             :     }
    1389             :     else
    1390          18 :         rBuf.append( OUString::number( rAbsRef.Row() + 1 ) );
    1391         152 : }
    1392             : 
    1393           6 : struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
    1394             : {
    1395           6 :     ConventionXL_R1C1() : ScCompiler::Convention( FormulaGrammar::CONV_XL_R1C1 ) { }
    1396         146 :     void makeRefStr( OUStringBuffer&   rBuf,
    1397             :                      formula::FormulaGrammar::Grammar /*eGram*/,
    1398             :                      const ScAddress& rPos,
    1399             :                      const OUString& /*rErrRef*/, const std::vector<OUString>& rTabNames,
    1400             :                      const ScComplexRefData& rRef,
    1401             :                      bool bSingleRef ) const SAL_OVERRIDE
    1402             :     {
    1403         146 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1404         146 :         ScComplexRefData aRef( rRef );
    1405             : 
    1406         146 :         MakeTabStr(rBuf, rPos, rTabNames, aRef, bSingleRef);
    1407             : 
    1408             :         // Play fast and loose with invalid refs.  There is not much point in producing
    1409             :         // Foo!A1:#REF! versus #REF! at this point
    1410         146 :         if (!ValidCol(aAbsRef.aStart.Col()) || !ValidRow(aAbsRef.aStart.Row()))
    1411             :         {
    1412           0 :             rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1413           0 :             return;
    1414             :         }
    1415             : 
    1416         146 :         if( !bSingleRef )
    1417             :         {
    1418           6 :             if (!ValidCol(aAbsRef.aEnd.Col()) || !ValidRow(aAbsRef.aEnd.Row()))
    1419             :             {
    1420           0 :                 rBuf.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1421           0 :                 return;
    1422             :             }
    1423             : 
    1424           6 :             if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= MAXCOL)
    1425             :             {
    1426           0 :                 r1c1_add_row(rBuf,  rRef.Ref1, aAbsRef.aStart);
    1427           0 :                 if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() ||
    1428           0 :                     rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel() )
    1429             :                 {
    1430           0 :                     rBuf.append( ':' );
    1431           0 :                     r1c1_add_row(rBuf,  rRef.Ref2, aAbsRef.aEnd);
    1432             :                 }
    1433           0 :                 return;
    1434             : 
    1435             :             }
    1436             : 
    1437           6 :             if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= MAXROW)
    1438             :             {
    1439           0 :                 r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
    1440           0 :                 if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() ||
    1441           0 :                     rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
    1442             :                 {
    1443           0 :                     rBuf.append( ':' );
    1444           0 :                     r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1445             :                 }
    1446           0 :                 return;
    1447             :             }
    1448             :         }
    1449             : 
    1450         146 :         r1c1_add_row(rBuf, rRef.Ref1, aAbsRef.aStart);
    1451         146 :         r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart);
    1452         146 :         if (!bSingleRef)
    1453             :         {
    1454           6 :             rBuf.append( ':' );
    1455           6 :             r1c1_add_row(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1456           6 :             r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
    1457             :         }
    1458             :     }
    1459             : 
    1460           0 :     ParseResult parseAnyToken( const OUString& rFormula,
    1461             :                                sal_Int32 nSrcPos,
    1462             :                                const CharClass* pCharClass) const SAL_OVERRIDE
    1463             :     {
    1464           0 :         ConventionXL::parseExternalDocName(rFormula, nSrcPos);
    1465             : 
    1466           0 :         ParseResult aRet;
    1467           0 :         if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
    1468           0 :             return aRet;
    1469             : 
    1470             :         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
    1471             :             KParseTokens::ASC_UNDERSCORE ;
    1472             :         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
    1473             :         // '?' allowed in range names
    1474           0 :         const OUString aAddAllowed("?-[]!");
    1475             : 
    1476             :         return pCharClass->parseAnyToken( rFormula,
    1477           0 :                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
    1478             :     }
    1479             : 
    1480        2704 :     virtual sal_Unicode getSpecialSymbol( SpecialSymbolType eSymType ) const SAL_OVERRIDE
    1481             :     {
    1482        2704 :         return ConventionXL::getSpecialSymbol(eSymType);
    1483             :     }
    1484             : 
    1485           0 :     virtual bool parseExternalName( const OUString& rSymbol, OUString& rFile, OUString& rName,
    1486             :             const ScDocument* pDoc,
    1487             :             const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks ) const SAL_OVERRIDE
    1488             :     {
    1489           0 :         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, pExternalLinks);
    1490             :     }
    1491             : 
    1492           0 :     virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const OUString& rFile,
    1493             :             const OUString& rName ) const SAL_OVERRIDE
    1494             :     {
    1495           0 :         return ConventionXL::makeExternalNameStr(rFile, rName);
    1496             :     }
    1497             : 
    1498           0 :     virtual void makeExternalRefStr(
    1499             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1500             :         const OUString& rTabName, const ScSingleRefData& rRef ) const SAL_OVERRIDE
    1501             :     {
    1502             :         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
    1503             :         // This is a little different from the format Excel uses, as Excel
    1504             :         // puts [] only around the file name.  But we need to enclose the
    1505             :         // whole file path with [] because the file name can contain any
    1506             :         // characters.
    1507             : 
    1508           0 :         ScAddress aAbsRef = rRef.toAbs(rPos);
    1509           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1510           0 :         ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
    1511           0 :         rBuffer.append('!');
    1512             : 
    1513           0 :         r1c1_add_row(rBuffer, rRef, aAbsRef);
    1514           0 :         r1c1_add_col(rBuffer, rRef, aAbsRef);
    1515           0 :     }
    1516             : 
    1517           0 :     virtual void makeExternalRefStr(
    1518             :         OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName,
    1519             :         const std::vector<OUString>& rTabNames, const OUString& rTabName,
    1520             :         const ScComplexRefData& rRef ) const SAL_OVERRIDE
    1521             :     {
    1522           0 :         ScRange aAbsRef = rRef.toAbs(rPos);
    1523             : 
    1524           0 :         ConventionXL::makeExternalDocStr(rBuffer, rFileName, false);
    1525           0 :         ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, aAbsRef);
    1526           0 :         rBuffer.append('!');
    1527             : 
    1528           0 :         if (!ValidCol(aAbsRef.aEnd.Col()) || !ValidRow(aAbsRef.aEnd.Row()))
    1529             :         {
    1530           0 :             rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
    1531           0 :             return;
    1532             :         }
    1533             : 
    1534           0 :         if (aAbsRef.aStart.Col() == 0 && aAbsRef.aEnd.Col() >= MAXCOL)
    1535             :         {
    1536           0 :             r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1537           0 :             if (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel())
    1538             :             {
    1539           0 :                 rBuffer.append(':');
    1540           0 :                 r1c1_add_row(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1541             :             }
    1542           0 :             return;
    1543             :         }
    1544             : 
    1545           0 :         if (aAbsRef.aStart.Row() == 0 && aAbsRef.aEnd.Row() >= MAXROW)
    1546             :         {
    1547           0 :             r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1548           0 :             if (aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() || rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel())
    1549             :             {
    1550           0 :                 rBuffer.append(':');
    1551           0 :                 r1c1_add_col(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1552             :             }
    1553           0 :             return;
    1554             :         }
    1555             : 
    1556           0 :         r1c1_add_row(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1557           0 :         r1c1_add_col(rBuffer, rRef.Ref1, aAbsRef.aStart);
    1558           0 :         rBuffer.append(':');
    1559           0 :         r1c1_add_row(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1560           0 :         r1c1_add_col(rBuffer, rRef.Ref2, aAbsRef.aEnd);
    1561             :     }
    1562             : 
    1563        6626 :     virtual sal_uLong getCharTableFlags( sal_Unicode c, sal_Unicode cLast ) const SAL_OVERRIDE
    1564             :     {
    1565        6626 :         sal_uLong nFlags = mpCharTable[static_cast<sal_uInt8>(c)];
    1566        6626 :         if (c == '-' && cLast == '[')
    1567             :             // '-' can occur within a reference string only after '[' e.g. R[-1]C.
    1568         394 :             nFlags |= SC_COMPILER_C_IDENT;
    1569        6626 :         return nFlags;
    1570             :     }
    1571             : };
    1572             : 
    1573        4122 : ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, ScTokenArray& rArr ) :
    1574             :     FormulaCompiler(rArr),
    1575        4122 :     pDoc(rCxt.getDoc()),
    1576             :     aPos(rPos),
    1577        4122 :     mpFormatter(pDoc->GetFormatTable()),
    1578             :     pCharClass(ScGlobal::pCharClass),
    1579             :     mnPredetectedReference(0),
    1580             :     mnRangeOpPosInSymbol(-1),
    1581        4122 :     pConv(GetRefConvention(FormulaGrammar::CONV_OOO)),
    1582             :     meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
    1583             :     mbCloseBrackets(true),
    1584             :     mbRewind(false),
    1585       16488 :     maTabNames(rCxt.getTabNames())
    1586             : {
    1587        4122 :     nMaxTab = pDoc->GetTableCount() - 1;
    1588        4122 :     SetGrammar(rCxt.getGrammar());
    1589        4122 : }
    1590             : 
    1591       15066 : ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArray& rArr)
    1592             :         : FormulaCompiler(rArr),
    1593             :         pDoc( pDocument ),
    1594             :         aPos( rPos ),
    1595       15066 :         mpFormatter(pDoc->GetFormatTable()),
    1596             :         nSrcPos(0),
    1597             :         pCharClass( ScGlobal::pCharClass ),
    1598             :         mnPredetectedReference(0),
    1599             :         mnRangeOpPosInSymbol(-1),
    1600       15066 :         pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
    1601             :         meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
    1602             :         mbCloseBrackets( true ),
    1603       45198 :         mbRewind( false )
    1604             : {
    1605       15066 :     nMaxTab = pDoc->GetTableCount() - 1;
    1606       15066 : }
    1607             : 
    1608          10 : ScCompiler::ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos ) :
    1609          10 :     pDoc(rCxt.getDoc()),
    1610             :     aPos(rPos),
    1611          10 :     mpFormatter(pDoc ? pDoc->GetFormatTable() : NULL),
    1612             :     pCharClass(ScGlobal::pCharClass),
    1613             :     mnPredetectedReference(0),
    1614             :     mnRangeOpPosInSymbol(-1),
    1615          10 :     pConv(GetRefConvention(FormulaGrammar::CONV_OOO)),
    1616             :     meExtendedErrorDetection(EXTENDED_ERROR_DETECTION_NONE),
    1617             :     mbCloseBrackets(true),
    1618             :     mbRewind(false),
    1619          40 :     maTabNames(rCxt.getTabNames())
    1620             : {
    1621          10 :     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
    1622          10 :     SetGrammar(rCxt.getGrammar());
    1623          10 : }
    1624             : 
    1625       61868 : ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos)
    1626             :         :
    1627             :         pDoc( pDocument ),
    1628             :         aPos( rPos ),
    1629       61810 :         mpFormatter(pDoc ? pDoc->GetFormatTable() : NULL),
    1630             :         nSrcPos(0),
    1631             :         pCharClass( ScGlobal::pCharClass ),
    1632             :         mnPredetectedReference(0),
    1633             :         mnRangeOpPosInSymbol(-1),
    1634       61868 :         pConv( GetRefConvention( FormulaGrammar::CONV_OOO ) ),
    1635             :         meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
    1636             :         mbCloseBrackets( true ),
    1637      185546 :         mbRewind( false )
    1638             : {
    1639       61868 :     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
    1640       61868 : }
    1641             : 
    1642       82592 : ScCompiler::~ScCompiler()
    1643             : {
    1644       82592 : }
    1645             : 
    1646       57556 : void ScCompiler::CheckTabQuotes( OUString& rString,
    1647             :                                  const FormulaGrammar::AddressConvention eConv )
    1648             : {
    1649             :     using namespace ::com::sun::star::i18n;
    1650       57556 :     sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER | KParseTokens::ASC_UNDERSCORE;
    1651       57556 :     sal_Int32 nContFlags = nStartFlags;
    1652             :     ParseResult aRes = ScGlobal::pCharClass->parsePredefinedToken(
    1653       57556 :         KParseType::IDENTNAME, rString, 0, nStartFlags, EMPTY_OUSTRING, nContFlags, EMPTY_OUSTRING);
    1654       57556 :     bool bNeedsQuote = !((aRes.TokenType & KParseType::IDENTNAME) && aRes.EndPos == rString.getLength());
    1655             : 
    1656       57556 :     switch ( eConv )
    1657             :     {
    1658             :         default :
    1659             :         case FormulaGrammar::CONV_UNSPECIFIED :
    1660           0 :             break;
    1661             :         case FormulaGrammar::CONV_OOO :
    1662             :         case FormulaGrammar::CONV_XL_A1 :
    1663             :         case FormulaGrammar::CONV_XL_R1C1 :
    1664             :         case FormulaGrammar::CONV_XL_OOX :
    1665             :         case FormulaGrammar::CONV_ODF :
    1666       57556 :             if( bNeedsQuote )
    1667             :             {
    1668        1866 :                 const OUString one_quote('\'');
    1669        3732 :                 const OUString two_quote("''");
    1670             :                 // escape embedded quotes
    1671        3732 :                 rString = rString.replaceAll( one_quote, two_quote );
    1672             :             }
    1673       57556 :             break;
    1674             :     }
    1675             : 
    1676       57556 :     if ( !bNeedsQuote && CharClass::isAsciiNumeric( rString ) )
    1677             :     {
    1678             :         // Prevent any possible confusion resulting from pure numeric sheet names.
    1679           2 :         bNeedsQuote = true;
    1680             :     }
    1681             : 
    1682       57556 :     if( bNeedsQuote )
    1683             :     {
    1684        1868 :         rString = "'" + rString + "'";
    1685       57556 :     }
    1686       57556 : }
    1687             : 
    1688           2 : sal_Int32 ScCompiler::GetDocTabPos( const OUString& rString )
    1689             : {
    1690           2 :     if (rString[0] != '\'')
    1691           2 :         return -1;
    1692           0 :     sal_Int32 nPos = ScGlobal::FindUnquoted( rString, SC_COMPILER_FILE_TAB_SEP);
    1693             :     // it must be 'Doc'#
    1694           0 :     if (nPos != -1 && rString[nPos-1] != '\'')
    1695           0 :         nPos = -1;
    1696           0 :     return nPos;
    1697             : }
    1698             : 
    1699       93722 : void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv )
    1700             : {
    1701       93722 :     const Convention* p = GetRefConvention(eConv);
    1702       93722 :     if (p)
    1703       93436 :         SetRefConvention(p);
    1704       93722 : }
    1705             : 
    1706      174846 : const ScCompiler::Convention* ScCompiler::GetRefConvention( FormulaGrammar::AddressConvention eConv )
    1707             : {
    1708             : 
    1709      174846 :     switch (eConv)
    1710             :     {
    1711             :         case FormulaGrammar::CONV_OOO:
    1712             :         {
    1713      163554 :             static const ConventionOOO_A1 ConvOOO_A1;
    1714      163554 :             return &ConvOOO_A1;
    1715             :         }
    1716             :         case FormulaGrammar::CONV_ODF:
    1717             :         {
    1718        7006 :             static const ConventionOOO_A1_ODF ConvOOO_A1_ODF;
    1719        7006 :             return &ConvOOO_A1_ODF;
    1720             :         }
    1721             :         case FormulaGrammar::CONV_XL_A1:
    1722             :         {
    1723         288 :             static const ConventionXL_A1 ConvXL_A1;
    1724         288 :             return &ConvXL_A1;
    1725             :         }
    1726             :         case FormulaGrammar::CONV_XL_R1C1:
    1727             :         {
    1728         902 :             static const ConventionXL_R1C1 ConvXL_R1C1;
    1729         902 :             return &ConvXL_R1C1;
    1730             :         }
    1731             :         case FormulaGrammar::CONV_XL_OOX:
    1732             :         {
    1733        2810 :             static const ConventionXL_OOX ConvXL_OOX;
    1734        2810 :             return &ConvXL_OOX;
    1735             :         }
    1736             :         case FormulaGrammar::CONV_UNSPECIFIED:
    1737             :         default:
    1738             :             ;
    1739             :     }
    1740             : 
    1741         286 :     return NULL;
    1742             : }
    1743             : 
    1744       93436 : void ScCompiler::SetRefConvention( const ScCompiler::Convention *pConvP )
    1745             : {
    1746       93436 :     pConv = pConvP;
    1747       93436 :     meGrammar = FormulaGrammar::mergeToGrammar( meGrammar, pConv->meConv);
    1748             :     OSL_ENSURE( FormulaGrammar::isSupported( meGrammar),
    1749             :             "ScCompiler::SetRefConvention: unsupported grammar resulting");
    1750       93436 : }
    1751             : 
    1752        3424 : void ScCompiler::SetError(sal_uInt16 nError)
    1753             : {
    1754        3424 :     if( !pArr->GetCodeError() )
    1755        1714 :         pArr->SetCodeError( nError);
    1756        3424 : }
    1757             : 
    1758         362 : static sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, sal_Int32 nMax )
    1759             : {
    1760         362 :     const sal_Unicode* const pStop = pDst + nMax;
    1761        9316 :     while ( *pSrc && pDst < pStop )
    1762             :     {
    1763        8592 :         *pDst++ = *pSrc++;
    1764             :     }
    1765         362 :     *pDst = 0;
    1766         362 :     return pDst;
    1767             : }
    1768             : 
    1769             : // NextSymbol
    1770             : 
    1771             : // Zerlegt die Formel in einzelne Symbole fuer die weitere
    1772             : // Verarbeitung (Turing-Maschine).
    1773             : 
    1774             : // Ausgangs Zustand = GetChar
    1775             : 
    1776             : // Alter Zustand | gelesenes Zeichen | Aktion                | Neuer Zustand
    1777             : //---------------+-------------------+-----------------------+---------------
    1778             : // GetChar       | ;()+-*/^=&        | Symbol=Zeichen        | Stop
    1779             : //               | <>                | Symbol=Zeichen        | GetBool
    1780             : //               | $ Buchstabe       | Symbol=Zeichen        | GetWord
    1781             : //               | Ziffer            | Symbol=Zeichen        | GetValue
    1782             : //               | "                 | Keine                 | GetString
    1783             : //               | Sonst             | Keine                 | GetChar
    1784             : //---------------+-------------------+-----------------------+---------------
    1785             : // GetBool       | =>                | Symbol=Symbol+Zeichen | Stop
    1786             : //               | Sonst             | Dec(CharPos)          | Stop
    1787             : //---------------+-------------------+-----------------------+---------------
    1788             : // GetWord       | SepSymbol         | Dec(CharPos)          | Stop
    1789             : //               | ()+-*/^=<>&~      |                       |
    1790             : //               | Leerzeichen       | Dec(CharPos)          | Stop
    1791             : //               | $_:.              |                       |
    1792             : //               | Buchstabe,Ziffer  | Symbol=Symbol+Zeichen | GetWord
    1793             : //               | Sonst             | Fehler                | Stop
    1794             : //---------------+-------------------+-----------------------+---------------
    1795             : // GetValue      | ;()*/^=<>&        |                       |
    1796             : //               | Leerzeichen       | Dec(CharPos)          | Stop
    1797             : //               | Ziffer E+-%,.     | Symbol=Symbol+Zeichen | GetValue
    1798             : //               | Sonst             | Fehler                | Stop
    1799             : //---------------+-------------------+-----------------------+---------------
    1800             : // GetString     | "                 | Keine                 | Stop
    1801             : //               | Sonst             | Symbol=Symbol+Zeichen | GetString
    1802             : //---------------+-------------------+-----------------------+---------------
    1803             : 
    1804       47412 : sal_Int32 ScCompiler::NextSymbol(bool bInArray)
    1805             : {
    1806       47412 :     cSymbol[MAXSTRLEN-1] = 0;       // Stopper
    1807       47412 :     sal_Unicode* pSym = cSymbol;
    1808       47412 :     const sal_Unicode* const pStart = aFormula.getStr();
    1809       47412 :     const sal_Unicode* pSrc = pStart + nSrcPos;
    1810       47412 :     bool bi18n = false;
    1811       47412 :     sal_Unicode c = *pSrc;
    1812       47412 :     sal_Unicode cLast = 0;
    1813       47412 :     bool bQuote = false;
    1814       47412 :     mnRangeOpPosInSymbol = -1;
    1815       47412 :     ScanState eState = ssGetChar;
    1816       47412 :     sal_Int32 nSpaces = 0;
    1817       47412 :     sal_Unicode cSep = mxSymbols->getSymbolChar( ocSep);
    1818       47412 :     sal_Unicode cArrayColSep = mxSymbols->getSymbolChar( ocArrayColSep);
    1819       47412 :     sal_Unicode cArrayRowSep = mxSymbols->getSymbolChar( ocArrayRowSep);
    1820       47412 :     sal_Unicode cDecSep = (mxSymbols->isEnglish() ? '.' :
    1821       47412 :             ScGlobal::pLocaleData->getNumDecimalSep()[0]);
    1822             : 
    1823             :     // special symbols specific to address convention used
    1824       47412 :     sal_Unicode cSheetPrefix = pConv->getSpecialSymbol(ScCompiler::Convention::ABS_SHEET_PREFIX);
    1825       47412 :     sal_Unicode cSheetSep    = pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
    1826             : 
    1827       47412 :     int nDecSeps = 0;
    1828       47412 :     bool bAutoIntersection = false;
    1829       47412 :     int nRefInName = 0;
    1830       47412 :     bool bErrorConstantHadSlash = false;
    1831       47412 :     mnPredetectedReference = 0;
    1832             :     // try to parse simple tokens before calling i18n parser
    1833      281250 :     while ((c != 0) && (eState != ssStop) )
    1834             :     {
    1835      186426 :         pSrc++;
    1836      186426 :         sal_uLong nMask = GetCharTableFlags( c, cLast );
    1837             : 
    1838             :         // The parameter separator and the array column and row separators end
    1839             :         // things unconditionally if not in string or reference.
    1840      186426 :         if (c == cSep || (bInArray && (c == cArrayColSep || c == cArrayRowSep)))
    1841             :         {
    1842        9888 :             switch (eState)
    1843             :             {
    1844             :                 // these are to be continued
    1845             :                 case ssGetString:
    1846             :                 case ssSkipString:
    1847             :                 case ssGetReference:
    1848             :                 case ssSkipReference:
    1849           0 :                     break;
    1850             :                 default:
    1851        9888 :                     if (eState == ssGetChar)
    1852        5354 :                         *pSym++ = c;
    1853             :                     else
    1854        4534 :                         pSrc--;
    1855        9888 :                     eState = ssStop;
    1856             :             }
    1857             :         }
    1858             : Label_MaskStateMachine:
    1859      186426 :         switch (eState)
    1860             :         {
    1861             :             case ssGetChar :
    1862             :             {
    1863             :                 // Order is important!
    1864       31810 :                 if( nMask & SC_COMPILER_C_ODF_LABEL_OP )
    1865             :                 {
    1866             :                     // '!!' automatic intersection
    1867           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_ODF_LABEL_OP)
    1868             :                     {
    1869             :                         /* TODO: For now the UI "space operator" is used, this
    1870             :                          * could be enhanced using a specialized OpCode to get
    1871             :                          * rid of the space ambiguity, which would need some
    1872             :                          * places to be adapted though. And we would still need
    1873             :                          * to support the ambiguous space operator for UI
    1874             :                          * purposes anyway. However, we then could check for
    1875             :                          * invalid usage of '!!', which currently isn't
    1876             :                          * possible. */
    1877           0 :                         if (!bAutoIntersection)
    1878             :                         {
    1879           0 :                             ++pSrc;
    1880           0 :                             nSpaces += 2;   // must match the character count
    1881           0 :                             bAutoIntersection = true;
    1882             :                         }
    1883             :                         else
    1884             :                         {
    1885           0 :                             pSrc--;
    1886           0 :                             eState = ssStop;
    1887             :                         }
    1888             :                     }
    1889             :                     else
    1890             :                     {
    1891           0 :                         nMask &= ~SC_COMPILER_C_ODF_LABEL_OP;
    1892           0 :                         goto Label_MaskStateMachine;
    1893             :                     }
    1894             :                 }
    1895       31810 :                 else if( nMask & SC_COMPILER_C_ODF_NAME_MARKER )
    1896             :                 {
    1897             :                     // '$$' defined name marker
    1898           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_ODF_NAME_MARKER)
    1899             :                     {
    1900             :                         // both eaten, not added to pSym
    1901           0 :                         ++pSrc;
    1902             :                     }
    1903             :                     else
    1904             :                     {
    1905           0 :                         nMask &= ~SC_COMPILER_C_ODF_NAME_MARKER;
    1906           0 :                         goto Label_MaskStateMachine;
    1907             :                     }
    1908             :                 }
    1909       31810 :                 else if( nMask & SC_COMPILER_C_CHAR )
    1910             :                 {
    1911        9566 :                     *pSym++ = c;
    1912        9566 :                     eState = ssStop;
    1913             :                 }
    1914       22244 :                 else if( nMask & SC_COMPILER_C_ODF_LBRACKET )
    1915             :                 {
    1916             :                     // eaten, not added to pSym
    1917         648 :                     eState = ssGetReference;
    1918         648 :                     mnPredetectedReference = 1;
    1919             :                 }
    1920       21596 :                 else if( nMask & SC_COMPILER_C_CHAR_BOOL )
    1921             :                 {
    1922          22 :                     *pSym++ = c;
    1923          22 :                     eState = ssGetBool;
    1924             :                 }
    1925       21574 :                 else if( nMask & SC_COMPILER_C_CHAR_VALUE )
    1926             :                 {
    1927        4762 :                     *pSym++ = c;
    1928        4762 :                     eState = ssGetValue;
    1929             :                 }
    1930       16812 :                 else if( nMask & SC_COMPILER_C_CHAR_STRING )
    1931             :                 {
    1932        1020 :                     *pSym++ = c;
    1933        1020 :                     eState = ssGetString;
    1934             :                 }
    1935       15792 :                 else if( nMask & SC_COMPILER_C_CHAR_ERRCONST )
    1936             :                 {
    1937          46 :                     *pSym++ = c;
    1938          46 :                     eState = ssGetErrorConstant;
    1939             :                 }
    1940       15746 :                 else if( nMask & SC_COMPILER_C_CHAR_DONTCARE )
    1941             :                 {
    1942         784 :                     nSpaces++;
    1943             :                 }
    1944       14962 :                 else if( nMask & SC_COMPILER_C_CHAR_IDENT )
    1945             :                 {   // try to get a simple ASCII identifier before calling
    1946             :                     // i18n, to gain performance during import
    1947       14876 :                     *pSym++ = c;
    1948       14876 :                     eState = ssGetIdent;
    1949             :                 }
    1950             :                 else
    1951             :                 {
    1952          86 :                     bi18n = true;
    1953          86 :                     eState = ssStop;
    1954             :                 }
    1955             :             }
    1956       31810 :             break;
    1957             :             case ssGetIdent:
    1958             :             {
    1959      125044 :                 if ( nMask & SC_COMPILER_C_IDENT )
    1960             :                 {   // This catches also $Sheet1.A$1, for example.
    1961      114912 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    1962             :                     {
    1963           0 :                         SetError(errStringOverflow);
    1964           0 :                         eState = ssStop;
    1965             :                     }
    1966             :                     else
    1967      114912 :                         *pSym++ = c;
    1968             :                 }
    1969       10132 :                 else if (c == ':' && mnRangeOpPosInSymbol < 0)
    1970             :                 {
    1971             :                     // One range operator may form Sheet1.A:A, which we need to
    1972             :                     // pass as one entity to IsReference().
    1973        4246 :                     mnRangeOpPosInSymbol = pSym - &cSymbol[0];
    1974        8492 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    1975             :                     {
    1976           0 :                         SetError(errStringOverflow);
    1977           0 :                         eState = ssStop;
    1978             :                     }
    1979             :                     else
    1980        4246 :                         *pSym++ = c;
    1981             :                 }
    1982        5886 :                 else if ( 128 <= c || '\'' == c )
    1983             :                 {   // High values need reparsing with i18n,
    1984             :                     // single quoted $'sheet' names too (otherwise we'd had to
    1985             :                     // implement everything twice).
    1986         274 :                     bi18n = true;
    1987         274 :                     eState = ssStop;
    1988             :                 }
    1989             :                 else
    1990             :                 {
    1991        5612 :                     pSrc--;
    1992        5612 :                     eState = ssStop;
    1993             :                 }
    1994             :             }
    1995      125044 :             break;
    1996             :             case ssGetBool :
    1997             :             {
    1998          22 :                 if( nMask & SC_COMPILER_C_BOOL )
    1999             :                 {
    2000          20 :                     *pSym++ = c;
    2001          20 :                     eState = ssStop;
    2002             :                 }
    2003             :                 else
    2004             :                 {
    2005           2 :                     pSrc--;
    2006           2 :                     eState = ssStop;
    2007             :                 }
    2008             :             }
    2009          22 :             break;
    2010             :             case ssGetValue :
    2011             :             {
    2012        6416 :                 if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2013             :                 {
    2014           0 :                     SetError(errStringOverflow);
    2015           0 :                     eState = ssStop;
    2016             :                 }
    2017        6416 :                 else if (c == cDecSep)
    2018             :                 {
    2019         474 :                     if (++nDecSeps > 1)
    2020             :                     {
    2021             :                         // reparse with i18n, may be numeric sheet name as well
    2022           0 :                         bi18n = true;
    2023           0 :                         eState = ssStop;
    2024             :                     }
    2025             :                     else
    2026         474 :                         *pSym++ = c;
    2027             :                 }
    2028        5942 :                 else if( nMask & SC_COMPILER_C_VALUE )
    2029        3514 :                     *pSym++ = c;
    2030        2428 :                 else if( nMask & SC_COMPILER_C_VALUE_SEP )
    2031             :                 {
    2032        2364 :                     pSrc--;
    2033        2364 :                     eState = ssStop;
    2034             :                 }
    2035          64 :                 else if (c == 'E' || c == 'e')
    2036             :                 {
    2037           0 :                     if (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_VALUE_EXP)
    2038           0 :                         *pSym++ = c;
    2039             :                     else
    2040             :                     {
    2041             :                         // reparse with i18n
    2042           0 :                         bi18n = true;
    2043           0 :                         eState = ssStop;
    2044             :                     }
    2045             :                 }
    2046          64 :                 else if( nMask & SC_COMPILER_C_VALUE_SIGN )
    2047             :                 {
    2048          62 :                     if (((cLast == 'E') || (cLast == 'e')) &&
    2049           0 :                             (GetCharTableFlags( pSrc[0], 0 ) & SC_COMPILER_C_VALUE_VALUE))
    2050             :                     {
    2051           0 :                         *pSym++ = c;
    2052             :                     }
    2053             :                     else
    2054             :                     {
    2055          62 :                         pSrc--;
    2056          62 :                         eState = ssStop;
    2057             :                     }
    2058             :                 }
    2059             :                 else
    2060             :                 {
    2061             :                     // reparse with i18n
    2062           2 :                     bi18n = true;
    2063           2 :                     eState = ssStop;
    2064             :                 }
    2065             :             }
    2066        6416 :             break;
    2067             :             case ssGetString :
    2068             :             {
    2069        7558 :                 if( nMask & SC_COMPILER_C_STRING_SEP )
    2070             :                 {
    2071        1020 :                     if ( !bQuote )
    2072             :                     {
    2073        1020 :                         if ( *pSrc == '"' )
    2074           0 :                             bQuote = true;      // "" => literal "
    2075             :                         else
    2076        1020 :                             eState = ssStop;
    2077             :                     }
    2078             :                     else
    2079           0 :                         bQuote = false;
    2080             :                 }
    2081        7558 :                 if ( !bQuote )
    2082             :                 {
    2083        7558 :                     if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2084             :                     {
    2085           0 :                         SetError(errStringOverflow);
    2086           0 :                         eState = ssSkipString;
    2087             :                     }
    2088             :                     else
    2089        7558 :                         *pSym++ = c;
    2090             :                 }
    2091             :             }
    2092        7558 :             break;
    2093             :             case ssSkipString:
    2094           0 :                 if( nMask & SC_COMPILER_C_STRING_SEP )
    2095           0 :                     eState = ssStop;
    2096           0 :                 break;
    2097             :             case ssGetErrorConstant:
    2098             :                 {
    2099             :                     // ODFF Error ::= '#' [A-Z0-9]+ ([!?] | ('/' ([A-Z] | ([0-9] [!?]))))
    2100             :                     // BUT, in UI these may have been translated! So don't
    2101             :                     // check for ASCII alnum. Note that this construct can't be
    2102             :                     // parsed with i18n.
    2103             :                     /* TODO: be strict when reading ODFF, check for ASCII alnum
    2104             :                      * and proper continuation after '/'. However, even with
    2105             :                      * the lax parsing only the error constants we have defined
    2106             :                      * as opcode symbols will be recognized and others result
    2107             :                      * in ocBad, so the result is actually conformant. */
    2108         184 :                     bool bAdd = true;
    2109         184 :                     if ('!' == c || '?' == c)
    2110          46 :                         eState = ssStop;
    2111         138 :                     else if ('/' == c)
    2112             :                     {
    2113           0 :                         if (!bErrorConstantHadSlash)
    2114           0 :                             bErrorConstantHadSlash = true;
    2115             :                         else
    2116             :                         {
    2117           0 :                             bAdd = false;
    2118           0 :                             eState = ssStop;
    2119             :                         }
    2120             :                     }
    2121         138 :                     else if ((nMask & SC_COMPILER_C_WORD_SEP) ||
    2122         138 :                             (c < 128 && !rtl::isAsciiAlphanumeric( c)))
    2123             :                     {
    2124           0 :                         bAdd = false;
    2125           0 :                         eState = ssStop;
    2126             :                     }
    2127         184 :                     if (!bAdd)
    2128           0 :                         --pSrc;
    2129             :                     else
    2130             :                     {
    2131         184 :                         if (pSym == &cSymbol[ MAXSTRLEN-1 ])
    2132             :                         {
    2133           0 :                             SetError( errStringOverflow);
    2134           0 :                             eState = ssStop;
    2135             :                         }
    2136             :                         else
    2137         184 :                             *pSym++ = c;
    2138             :                     }
    2139             :                 }
    2140         184 :                 break;
    2141             :             case ssGetReference:
    2142        5504 :                 if( pSym == &cSymbol[ MAXSTRLEN-1 ] )
    2143             :                 {
    2144           0 :                     SetError( errStringOverflow);
    2145           0 :                     eState = ssSkipReference;
    2146             :                 }
    2147             :                 // fall through and follow logic
    2148             :             case ssSkipReference:
    2149             :                 // ODF reference: ['External'#$'Sheet'.A1:.B2] with dots being
    2150             :                 // mandatory also if no sheet name. 'External'# is optional,
    2151             :                 // sheet name is optional, quotes around sheet name are
    2152             :                 // optional if no quote contained. [#REF!] is valid.
    2153             :                 // 2nd usage: ['Sheet'.$$'DefinedName']
    2154             :                 // 3rd usage: ['External'#$$'DefinedName']
    2155             :                 // 4th usage: ['External'#$'Sheet'.$$'DefinedName']
    2156             :                 // Also for all these names quotes are optional if no quote
    2157             :                 // contained.
    2158             :                 {
    2159             : 
    2160             :                     // nRefInName: 0 := not in sheet name yet. 'External'
    2161             :                     // is parsed as if it was a sheet name and nRefInName
    2162             :                     // is reset when # is encountered immediately after closing
    2163             :                     // quote. Same with 'DefinedName', nRefInName is cleared
    2164             :                     // when : is encountered.
    2165             : 
    2166             :                     // Encountered leading $ before sheet name.
    2167             :                     static const int kDollar    = (1 << 1);
    2168             :                     // Encountered ' opening quote, which may be after $ or
    2169             :                     // not.
    2170             :                     static const int kOpen      = (1 << 2);
    2171             :                     // Somewhere in name.
    2172             :                     static const int kName      = (1 << 3);
    2173             :                     // Encountered ' in name, will be cleared if double or
    2174             :                     // transformed to kClose if not, in which case kOpen is
    2175             :                     // cleared.
    2176             :                     static const int kQuote     = (1 << 4);
    2177             :                     // Past ' closing quote.
    2178             :                     static const int kClose     = (1 << 5);
    2179             :                     // Encountered # file/sheet separator.
    2180             :                     static const int kFileSep   = (1 << 6);
    2181             :                     // Past . sheet name separator.
    2182             :                     static const int kPast      = (1 << 7);
    2183             :                     // Marked name $$ follows sheet name separator, detected
    2184             :                     // while we're still on the separator. Will be cleared when
    2185             :                     // entering the name.
    2186             :                     static const int kMarkAhead = (1 << 8);
    2187             :                     // In marked defined name.
    2188             :                     static const int kDefName   = (1 << 9);
    2189             :                     // Encountered # of #REF!
    2190             :                     static const int kRefErr    = (1 << 10);
    2191             : 
    2192        5504 :                     bool bAddToSymbol = true;
    2193        5504 :                     if ((nMask & SC_COMPILER_C_ODF_RBRACKET) && !(nRefInName & kOpen))
    2194             :                     {
    2195             :                         OSL_ENSURE( nRefInName & (kPast | kDefName | kRefErr),
    2196             :                                 "ScCompiler::NextSymbol: reference: "
    2197             :                                 "closing bracket ']' without prior sheet name separator '.' violates ODF spec");
    2198             :                         // eaten, not added to pSym
    2199         648 :                         bAddToSymbol = false;
    2200         648 :                         eState = ssStop;
    2201             :                     }
    2202        4856 :                     else if (cSheetSep == c && nRefInName == 0)
    2203             :                     {
    2204             :                         // eat it, no sheet name [.A1]
    2205         764 :                         bAddToSymbol = false;
    2206         764 :                         nRefInName |= kPast;
    2207        1528 :                         if ('$' == pSrc[0] && '$' == pSrc[1])
    2208           0 :                             nRefInName |= kMarkAhead;
    2209             :                     }
    2210        4092 :                     else if (!(nRefInName & kPast) || (nRefInName & (kMarkAhead | kDefName)))
    2211             :                     {
    2212             :                         // Not in col/row yet.
    2213             : 
    2214        3612 :                         if (SC_COMPILER_FILE_TAB_SEP == c && (nRefInName & kFileSep))
    2215          26 :                             nRefInName = 0;
    2216        1780 :                         else if ('$' == c && '$' == pSrc[0] && !(nRefInName & kOpen))
    2217             :                         {
    2218           0 :                             nRefInName &= ~kMarkAhead;
    2219           0 :                             if (!(nRefInName & kDefName))
    2220             :                             {
    2221             :                                 // eaten, not added to pSym (2 chars)
    2222           0 :                                 bAddToSymbol = false;
    2223           0 :                                 ++pSrc;
    2224           0 :                                 nRefInName &= kPast;
    2225           0 :                                 nRefInName |= kDefName;
    2226             :                             }
    2227             :                             else
    2228             :                             {
    2229             :                                 // ScAddress::Parse() will recognize this as
    2230             :                                 // invalid later.
    2231           0 :                                 if (eState != ssSkipReference)
    2232             :                                 {
    2233           0 :                                     *pSym++ = c;
    2234           0 :                                     *pSym++ = *pSrc++;
    2235             :                                 }
    2236           0 :                                 bAddToSymbol = false;
    2237             :                             }
    2238             :                         }
    2239        1780 :                         else if (cSheetPrefix == c && nRefInName == 0)
    2240          40 :                             nRefInName |= kDollar;
    2241        1740 :                         else if ('\'' == c)
    2242             :                         {
    2243             :                             // TODO: The conventions' parseExternalName()
    2244             :                             // should handle quoted names, but as long as they
    2245             :                             // don't remove non-embedded quotes here.
    2246          60 :                             if (!(nRefInName & kName))
    2247             :                             {
    2248          28 :                                 nRefInName |= (kOpen | kName);
    2249          28 :                                 bAddToSymbol = !(nRefInName & kDefName);
    2250             :                             }
    2251          32 :                             else if (!(nRefInName & kOpen))
    2252             :                             {
    2253             :                                 OSL_FAIL("ScCompiler::NextSymbol: reference: "
    2254             :                                         "a ''' without the name being enclosed in '...' violates ODF spec");
    2255             :                             }
    2256          32 :                             else if (nRefInName & kQuote)
    2257             :                             {
    2258             :                                 // escaped embedded quote
    2259           2 :                                 nRefInName &= ~kQuote;
    2260             :                             }
    2261             :                             else
    2262             :                             {
    2263          30 :                                 switch (pSrc[0])
    2264             :                                 {
    2265             :                                     case '\'':
    2266             :                                         // escapes embedded quote
    2267           2 :                                         nRefInName |= kQuote;
    2268           2 :                                         break;
    2269             :                                     case SC_COMPILER_FILE_TAB_SEP:
    2270             :                                         // sheet name should follow
    2271          26 :                                         nRefInName |= kFileSep;
    2272             :                                         // fallthru
    2273             :                                     default:
    2274             :                                         // quote not followed by quote => close
    2275          28 :                                         nRefInName |= kClose;
    2276          28 :                                         nRefInName &= ~kOpen;
    2277             :                                 }
    2278          30 :                                 bAddToSymbol = !(nRefInName & kDefName);
    2279             :                             }
    2280             :                         }
    2281        1680 :                         else if ('#' == c && nRefInName == 0)
    2282           0 :                             nRefInName |= kRefErr;
    2283        1680 :                         else if (cSheetSep == c && !(nRefInName & kOpen))
    2284             :                         {
    2285             :                             // unquoted sheet name separator
    2286          86 :                             nRefInName |= kPast;
    2287         172 :                             if ('$' == pSrc[0] && '$' == pSrc[1])
    2288           0 :                                 nRefInName |= kMarkAhead;
    2289             :                         }
    2290        1594 :                         else if (':' == c && !(nRefInName & kOpen))
    2291             :                         {
    2292             :                             OSL_FAIL("ScCompiler::NextSymbol: reference: "
    2293             :                                     "range operator ':' without prior sheet name separator '.' violates ODF spec");
    2294           0 :                             nRefInName = 0;
    2295           0 :                             ++mnPredetectedReference;
    2296             :                         }
    2297        1594 :                         else if (!(nRefInName & kName))
    2298             :                         {
    2299             :                             // start unquoted name
    2300         106 :                             nRefInName |= kName;
    2301             :                         }
    2302             :                     }
    2303        2286 :                     else if (':' == c)
    2304             :                     {
    2305             :                         // range operator
    2306         224 :                         nRefInName = 0;
    2307         224 :                         ++mnPredetectedReference;
    2308             :                     }
    2309        5504 :                     if (bAddToSymbol && eState != ssSkipReference)
    2310        4092 :                         *pSym++ = c;    // everything is part of reference
    2311             :                 }
    2312        5504 :                 break;
    2313             :             case ssStop:
    2314             :                 ;   // nothing, prevent warning
    2315        9888 :                 break;
    2316             :         }
    2317      186426 :         cLast = c;
    2318      186426 :         c = *pSrc;
    2319             :     }
    2320       47412 :     if ( bi18n )
    2321             :     {
    2322         362 :         nSrcPos = nSrcPos + nSpaces;
    2323         362 :         OUStringBuffer aSymbol;
    2324         362 :         mnRangeOpPosInSymbol = -1;
    2325         362 :         sal_uInt16 nErr = 0;
    2326         906 :         do
    2327             :         {
    2328         906 :             bi18n = false;
    2329             :             // special case  (e.g. $'sheetname' in OOO A1)
    2330         906 :             if ( pStart[nSrcPos] == cSheetPrefix && pStart[nSrcPos+1] == '\'' )
    2331         262 :                 aSymbol.append(pStart[nSrcPos++]);
    2332             : 
    2333         906 :             ParseResult aRes = pConv->parseAnyToken( aFormula, nSrcPos, pCharClass );
    2334             : 
    2335         906 :             if ( !aRes.TokenType )
    2336           0 :                 SetError( nErr = errIllegalChar );      // parsed chars as string
    2337         906 :             if ( aRes.EndPos <= nSrcPos )
    2338             :             {   // ?!?
    2339           0 :                 SetError( nErr = errIllegalChar );
    2340           0 :                 nSrcPos = aFormula.getLength();
    2341           0 :                 aSymbol.truncate(0);
    2342             :             }
    2343             :             else
    2344             :             {
    2345         906 :                 aSymbol.append( pStart + nSrcPos, aRes.EndPos - nSrcPos);
    2346         906 :                 nSrcPos = aRes.EndPos;
    2347         906 :                 c = pStart[nSrcPos];
    2348         906 :                 if ( aRes.TokenType & KParseType::SINGLE_QUOTE_NAME )
    2349             :                 {   // special cases (e.g. 'sheetname'. or 'filename'# in OOO A1)
    2350         344 :                     bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP);
    2351             :                 }
    2352             :                 // One range operator restarts parsing for second reference.
    2353         906 :                 if (c == ':' && mnRangeOpPosInSymbol < 0)
    2354             :                 {
    2355         200 :                     mnRangeOpPosInSymbol = aSymbol.getLength();
    2356         200 :                     bi18n = true;
    2357             :                 }
    2358         906 :                 if ( bi18n )
    2359         544 :                     aSymbol.append(pStart[nSrcPos++]);
    2360         906 :             }
    2361         544 :         } while ( bi18n && !nErr );
    2362         362 :         sal_Int32 nLen = aSymbol.getLength();
    2363         362 :         if ( nLen >= MAXSTRLEN )
    2364             :         {
    2365           0 :             SetError( errStringOverflow );
    2366           0 :             nLen = MAXSTRLEN-1;
    2367             :         }
    2368         362 :         lcl_UnicodeStrNCpy( cSymbol, aSymbol.getStr(), nLen );
    2369         362 :         pSym = &cSymbol[nLen];
    2370             :     }
    2371             :     else
    2372             :     {
    2373       47050 :         nSrcPos = pSrc - pStart;
    2374       47050 :         *pSym = 0;
    2375             :     }
    2376       47412 :     if (mnRangeOpPosInSymbol >= 0 && mnRangeOpPosInSymbol == (pSym-1) - &cSymbol[0])
    2377             :     {
    2378             :         // This is a trailing range operator, which is nonsense. Will be caught
    2379             :         // in next round.
    2380           0 :         mnRangeOpPosInSymbol = -1;
    2381           0 :         *--pSym = 0;
    2382           0 :         --nSrcPos;
    2383             :     }
    2384       47412 :     if ( bAutoCorrect )
    2385           0 :         aCorrectedSymbol = cSymbol;
    2386       47412 :     if (bAutoIntersection && nSpaces > 1)
    2387           0 :         --nSpaces;  // replace '!!' with only one space
    2388       47412 :     return nSpaces;
    2389             : }
    2390             : 
    2391             : // Convert symbol to token
    2392             : 
    2393       25470 : bool ScCompiler::IsOpCode( const OUString& rName, bool bInArray )
    2394             : {
    2395       25470 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName));
    2396       25470 :     bool bFound = (iLook != mxSymbols->getHashMap()->end());
    2397       25470 :     if (bFound)
    2398             :     {
    2399       18776 :         OpCode eOp = iLook->second;
    2400       18776 :         if (bInArray)
    2401             :         {
    2402         136 :             if (rName.equals(mxSymbols->getSymbol(ocArrayColSep)))
    2403          36 :                 eOp = ocArrayColSep;
    2404         100 :             else if (rName.equals(mxSymbols->getSymbol(ocArrayRowSep)))
    2405          62 :                 eOp = ocArrayRowSep;
    2406             :         }
    2407       18776 :         maRawToken.SetOpCode(eOp);
    2408             :     }
    2409        6694 :     else if (mxSymbols->isODFF())
    2410             :     {
    2411             :         // ODFF names that are not written in the current mapping but to be
    2412             :         // recognized. New names will be written in a future relase, then
    2413             :         // exchange (!) with the names in
    2414             :         // formula/source/core/resource/core_resource.src to be able to still
    2415             :         // read the old names as well.
    2416             :         struct FunctionName
    2417             :         {
    2418             :             const sal_Char* pName;
    2419             :             OpCode          eOp;
    2420             :         };
    2421             :         static const FunctionName aOdffAliases[] = {
    2422             :             // Renamed old names, still accept them:
    2423             :             { "B",              ocB },              // B -> BINOM.DIST.RANGE
    2424             :             { "TDIST",          ocTDist },          // TDIST -> LEGACY.TDIST
    2425             :             { "EASTERSUNDAY",   ocEasterSunday },   // EASTERSUNDAY -> ORG.OPENOFFICE.EASTERSUNDAY
    2426             :             { "ZGZ",            ocZGZ },            // ZGZ -> RRI
    2427             :             { "COLOR",          ocColor },          // COLOR -> ORG.LIBREOFFICE.COLOR
    2428             :             { "GOALSEEK",       ocBackSolver }      // GOALSEEK -> ORG.OPENOFFICE.GOALSEEK
    2429             :             // Renamed new names, prepare to read future names:
    2430             :             //{ "ORG.OPENOFFICE.XXX", ocXXX }         // XXX -> ORG.OPENOFFICE.XXX
    2431             :         };
    2432             :         static const size_t nOdffAliases = sizeof(aOdffAliases) / sizeof(aOdffAliases[0]);
    2433        1666 :         for (size_t i=0; i<nOdffAliases; ++i)
    2434             :         {
    2435        1428 :             if (rName.equalsIgnoreAsciiCaseAscii( aOdffAliases[i].pName))
    2436             :             {
    2437           0 :                 maRawToken.SetOpCode( aOdffAliases[i].eOp);
    2438           0 :                 bFound = true;
    2439           0 :                 break;  // for
    2440             :             }
    2441             :         }
    2442             :     }
    2443       25470 :     if (!bFound)
    2444             :     {
    2445        6694 :         OUString aIntName;
    2446        6694 :         if (mxSymbols->hasExternals())
    2447             :         {
    2448             :             // If symbols are set by filters get mapping to exact name.
    2449             :             ExternalHashMap::const_iterator iExt(
    2450        1222 :                     mxSymbols->getExternalHashMap()->find( rName));
    2451        1222 :             if (iExt != mxSymbols->getExternalHashMap()->end())
    2452             :             {
    2453         170 :                 if (ScGlobal::GetAddInCollection()->GetFuncData( (*iExt).second))
    2454         170 :                     aIntName = (*iExt).second;
    2455             :             }
    2456        1222 :             if (aIntName.isEmpty())
    2457             :             {
    2458             :                 // If that isn't found we might continue with rName lookup as a
    2459             :                 // last resort by just falling through to FindFunction(), but
    2460             :                 // it shouldn't happen if the map was setup correctly. Don't
    2461             :                 // waste time and bail out.
    2462        1052 :                 return false;
    2463             :             }
    2464             :         }
    2465        5642 :         if (aIntName.isEmpty())
    2466             :         {
    2467             :             // Old (deprecated) addins first for legacy.
    2468        5472 :             if (ScGlobal::GetFuncCollection()->findByName(cSymbol))
    2469             :             {
    2470           0 :                 maRawToken.SetExternal( cSymbol );
    2471             :             }
    2472             :             else
    2473             :                 // bLocalFirst=false for (English) upper full original name
    2474             :                 // (service.function)
    2475       10944 :                 aIntName = ScGlobal::GetAddInCollection()->FindFunction(
    2476       10944 :                         rName, !mxSymbols->isEnglish());
    2477             :         }
    2478        5642 :         if (!aIntName.isEmpty())
    2479             :         {
    2480         170 :             maRawToken.SetExternal( aIntName.getStr() );     // international name
    2481         170 :             bFound = true;
    2482        5642 :         }
    2483             :     }
    2484             :     OpCode eOp;
    2485       24418 :     if (bFound && ((eOp = maRawToken.GetOpCode()) == ocSub || eOp == ocNegSub))
    2486             :     {
    2487             :         bool bShouldBeNegSub =
    2488         576 :             (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub ||
    2489         192 :              (SC_OPCODE_START_BIN_OP <= eLastOp && eLastOp < SC_OPCODE_STOP_BIN_OP) ||
    2490         190 :              eLastOp == ocArrayOpen ||
    2491         468 :              eLastOp == ocArrayColSep || eLastOp == ocArrayRowSep);
    2492         280 :         if (bShouldBeNegSub && eOp == ocSub)
    2493         186 :             maRawToken.NewOpCode( ocNegSub );
    2494             :             //! if ocNegSub had ForceArray we'd have to set it here
    2495          94 :         else if (!bShouldBeNegSub && eOp == ocNegSub)
    2496           0 :             maRawToken.NewOpCode( ocSub );
    2497             :     }
    2498       24418 :     return bFound;
    2499             : }
    2500             : 
    2501           0 : bool ScCompiler::IsOpCode2( const OUString& rName )
    2502             : {
    2503           0 :     bool bFound = false;
    2504             :     sal_uInt16 i;
    2505             : 
    2506           0 :     for( i = ocInternalBegin; i <= ocInternalEnd && !bFound; i++ )
    2507           0 :         bFound = rName.equalsAscii( pInternal[ i-ocInternalBegin ] );
    2508             : 
    2509           0 :     if (bFound)
    2510             :     {
    2511           0 :         maRawToken.SetOpCode( (OpCode) --i );
    2512             :     }
    2513           0 :     return bFound;
    2514             : }
    2515             : 
    2516        4940 : bool ScCompiler::IsValue( const OUString& rSym )
    2517             : {
    2518             :     double fVal;
    2519        4940 :     sal_uInt32 nIndex = mxSymbols->isEnglish() ? mpFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US) : 0;
    2520             : 
    2521        4940 :     if (!mpFormatter->IsNumberFormat(rSym, nIndex, fVal))
    2522         180 :         return false;
    2523             : 
    2524        4760 :     sal_uInt16 nType = mpFormatter->GetType(nIndex);
    2525             : 
    2526             :     // Don't accept 3:3 as time, it is a reference to entire row 3 instead.
    2527             :     // Dates should never be entered directly and automatically converted
    2528             :     // to serial, because the serial would be wrong if null-date changed.
    2529             :     // Usually it wouldn't be accepted anyway because the date separator
    2530             :     // clashed with other separators or operators.
    2531        4760 :     if (nType & (NUMBERFORMAT_TIME | NUMBERFORMAT_DATE))
    2532           0 :         return false;
    2533             : 
    2534        4760 :     if (nType == NUMBERFORMAT_LOGICAL)
    2535             :     {
    2536           0 :         const sal_Unicode* p = aFormula.getStr() + nSrcPos;
    2537           0 :         while( *p == ' ' )
    2538           0 :             p++;
    2539           0 :         if (*p == '(')
    2540           0 :             return false;   // Boolean function instead.
    2541             :     }
    2542             : 
    2543        4760 :     if( nType == NUMBERFORMAT_TEXT )
    2544             :         // HACK: number too big!
    2545           0 :         SetError( errIllegalArgument );
    2546        4760 :     maRawToken.SetDouble( fVal );
    2547        4760 :     return true;
    2548             : }
    2549             : 
    2550       35732 : bool ScCompiler::IsString()
    2551             : {
    2552       35732 :     const sal_Unicode* p = cSymbol;
    2553      246334 :     while ( *p )
    2554      174870 :         p++;
    2555       35732 :     sal_Int32 nLen = sal::static_int_cast<sal_Int32>( p - cSymbol - 1 );
    2556       35732 :     bool bQuote = ((cSymbol[0] == '"') && (cSymbol[nLen] == '"'));
    2557       35732 :     if ((bQuote ? nLen-2 : nLen) > MAXSTRLEN-1)
    2558             :     {
    2559           0 :         SetError(errStringOverflow);
    2560           0 :         return false;
    2561             :     }
    2562       35732 :     if ( bQuote )
    2563             :     {
    2564        1020 :         cSymbol[nLen] = '\0';
    2565        1020 :         const sal_Unicode* pStr = cSymbol+1;
    2566        1020 :         svl::SharedString aSS = pDoc->GetSharedStringPool().intern(OUString(pStr));
    2567        1020 :         maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    2568        1020 :         return true;
    2569             :     }
    2570       34712 :     return false;
    2571             : }
    2572             : 
    2573         648 : bool ScCompiler::IsPredetectedReference(const OUString& rName)
    2574             : {
    2575             :     // Speedup documents with lots of broken references, e.g. sheet deleted.
    2576         648 :     sal_Int32 nPos = rName.indexOf("#REF!");
    2577         648 :     if (nPos != -1)
    2578             :     {
    2579             :         /* TODO: this may be enhanced by reusing scan information from
    2580             :          * NextSymbol(), the positions of quotes and special characters found
    2581             :          * there for $'sheet'.A1:... could be stored in a vector. We don't
    2582             :          * fully rescan here whether found positions are within single quotes
    2583             :          * for performance reasons. This code does not check for possible
    2584             :          * occurrences of insane "valid" sheet names like
    2585             :          * 'haha.#REF!1fooledyou' and will generate an error on such. */
    2586           0 :         if (nPos == 0)
    2587             :         {
    2588             :             // Per ODFF the correct string for a reference error is just #REF!,
    2589             :             // so pass it on.
    2590           0 :             if (rName.getLength() == 5)
    2591           0 :                 return IsErrorConstant( rName);
    2592           0 :             return false;           // #REF!.AB42 or #REF!42 or #REF!#REF!
    2593             :         }
    2594           0 :         sal_Unicode c = rName[nPos-1];      // before #REF!
    2595           0 :         if ('$' == c)
    2596             :         {
    2597           0 :             if (nPos == 1)
    2598           0 :                 return false;       // $#REF!.AB42 or $#REF!42 or $#REF!#REF!
    2599           0 :             c = rName[nPos-2];              // before $#REF!
    2600             :         }
    2601           0 :         sal_Unicode c2 = nPos+5 < rName.getLength() ? rName[nPos+5] : 0;     // after #REF!
    2602           0 :         switch (c)
    2603             :         {
    2604             :             case '.':
    2605           0 :                 if ('$' == c2 || '#' == c2 || ('0' <= c2 && c2 <= '9'))
    2606           0 :                     return false;   // sheet.#REF!42 or sheet.#REF!#REF!
    2607           0 :                 break;
    2608             :             case ':':
    2609           0 :                 if (mnPredetectedReference > 1 &&
    2610           0 :                         ('.' == c2 || '$' == c2 || '#' == c2 ||
    2611           0 :                          ('0' <= c2 && c2 <= '9')))
    2612           0 :                     return false;   // :#REF!.AB42 or :#REF!42 or :#REF!#REF!
    2613           0 :                 break;
    2614             :             default:
    2615           0 :                 if (comphelper::string::isalphaAscii(c) &&
    2616           0 :                         ((mnPredetectedReference > 1 && ':' == c2) || 0 == c2))
    2617           0 :                     return false;   // AB#REF!: or AB#REF!
    2618             :         }
    2619             :     }
    2620         648 :     switch (mnPredetectedReference)
    2621             :     {
    2622             :         case 1:
    2623         424 :             return IsSingleReference( rName);
    2624             :         case 2:
    2625         224 :             return IsDoubleReference( rName);
    2626             :     }
    2627           0 :     return false;
    2628             : }
    2629             : 
    2630        4670 : bool ScCompiler::IsDoubleReference( const OUString& rName )
    2631             : {
    2632        4670 :     ScRange aRange( aPos, aPos );
    2633        4670 :     const ScAddress::Details aDetails( pConv->meConv, aPos );
    2634        4670 :     ScAddress::ExternalInfo aExtInfo;
    2635        4670 :     sal_uInt16 nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    2636        4670 :     if( nFlags & SCA_VALID )
    2637             :     {
    2638             :         ScComplexRefData aRef;
    2639        4670 :         aRef.InitRange( aRange );
    2640        4670 :         aRef.Ref1.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
    2641        4670 :         aRef.Ref1.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
    2642        4670 :         aRef.Ref1.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
    2643        4670 :         if ( !(nFlags & SCA_VALID_TAB) )
    2644           0 :             aRef.Ref1.SetTabDeleted( true );        // #REF!
    2645        4670 :         aRef.Ref1.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
    2646        4670 :         aRef.Ref2.SetColRel( (nFlags & SCA_COL2_ABSOLUTE) == 0 );
    2647        4670 :         aRef.Ref2.SetRowRel( (nFlags & SCA_ROW2_ABSOLUTE) == 0 );
    2648        4670 :         aRef.Ref2.SetTabRel( (nFlags & SCA_TAB2_ABSOLUTE) == 0 );
    2649        4670 :         if ( !(nFlags & SCA_VALID_TAB2) )
    2650           6 :             aRef.Ref2.SetTabDeleted( true );        // #REF!
    2651        4670 :         aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
    2652        4670 :         aRef.SetRange(aRange, aPos);
    2653        4670 :         if (aExtInfo.mbExternal)
    2654             :         {
    2655          24 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2656          24 :             const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
    2657             :             maRawToken.SetExternalDoubleRef(
    2658          24 :                 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
    2659          24 :             maExternalFiles.push_back(aExtInfo.mnFileId);
    2660             :         }
    2661             :         else
    2662             :         {
    2663        4646 :             maRawToken.SetDoubleReference(aRef);
    2664             :         }
    2665             :     }
    2666             : 
    2667        4670 :     return ( nFlags & SCA_VALID ) != 0;
    2668             : }
    2669             : 
    2670       11384 : bool ScCompiler::IsSingleReference( const OUString& rName )
    2671             : {
    2672       11384 :     ScAddress aAddr( aPos );
    2673       11384 :     const ScAddress::Details aDetails( pConv->meConv, aPos );
    2674       11384 :     ScAddress::ExternalInfo aExtInfo;
    2675       11384 :     sal_uInt16 nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo, &maExternalLinks );
    2676             :     // Something must be valid in order to recognize Sheet1.blah or blah.a1
    2677             :     // as a (wrong) reference.
    2678       11384 :     if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) )
    2679             :     {
    2680             :         ScSingleRefData aRef;
    2681        6758 :         aRef.InitAddress( aAddr );
    2682        6758 :         aRef.SetColRel( (nFlags & SCA_COL_ABSOLUTE) == 0 );
    2683        6758 :         aRef.SetRowRel( (nFlags & SCA_ROW_ABSOLUTE) == 0 );
    2684        6758 :         aRef.SetTabRel( (nFlags & SCA_TAB_ABSOLUTE) == 0 );
    2685        6758 :         aRef.SetFlag3D( ( nFlags & SCA_TAB_3D ) != 0 );
    2686             :         // the reference is really invalid
    2687        6758 :         if( !( nFlags & SCA_VALID ) )
    2688             :         {
    2689           0 :             if( !( nFlags & SCA_VALID_COL ) )
    2690           0 :                 aRef.SetColDeleted(true);
    2691           0 :             if( !( nFlags & SCA_VALID_ROW ) )
    2692           0 :                 aRef.SetRowDeleted(true);
    2693           0 :             if( !( nFlags & SCA_VALID_TAB ) )
    2694           0 :                 aRef.SetTabDeleted(true);
    2695           0 :             nFlags |= SCA_VALID;
    2696             :         }
    2697        6758 :         aRef.SetAddress(aAddr, aPos);
    2698             : 
    2699        6758 :         if (aExtInfo.mbExternal)
    2700             :         {
    2701          76 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2702          76 :             const OUString* pRealTab = pRefMgr->getRealTableName(aExtInfo.mnFileId, aExtInfo.maTabName);
    2703             :             maRawToken.SetExternalSingleRef(
    2704          76 :                 aExtInfo.mnFileId, pRealTab ? *pRealTab : aExtInfo.maTabName, aRef);
    2705          76 :             maExternalFiles.push_back(aExtInfo.mnFileId);
    2706             :         }
    2707             :         else
    2708        6682 :             maRawToken.SetSingleReference(aRef);
    2709             :     }
    2710             : 
    2711       11384 :     return ( nFlags & SCA_VALID ) != 0;
    2712             : }
    2713             : 
    2714       15720 : bool ScCompiler::IsReference( const OUString& rName )
    2715             : {
    2716             :     // Has to be called before IsValue
    2717       15720 :     sal_Unicode ch1 = rName[0];
    2718       15720 :     sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' :
    2719       15720 :         ScGlobal::pLocaleData->getNumDecimalSep()[0] );
    2720       15720 :     if ( ch1 == cDecSep )
    2721           0 :         return false;
    2722             :     // Who was that imbecile introducing '.' as the sheet name separator!?!
    2723       15720 :     if ( rtl::isAsciiDigit( ch1 ) )
    2724             :     {
    2725             :         // Numerical sheet name is valid.
    2726             :         // But English 1.E2 or 1.E+2 is value 100, 1.E-2 is 0.01
    2727             :         // Don't create a #REF! of values. But also do not bail out on
    2728             :         // something like 3:3, meaning entire row 3.
    2729             :         do
    2730             :         {
    2731        4760 :             const sal_Int32 nPos = ScGlobal::FindUnquoted( rName, '.');
    2732        4760 :             if ( nPos == -1 )
    2733             :             {
    2734        4286 :                 if (ScGlobal::FindUnquoted( rName, ':') != -1)
    2735           0 :                     break;      // may be 3:3, continue as usual
    2736        4286 :                 return false;
    2737             :             }
    2738         474 :             sal_Unicode const * const pTabSep = rName.getStr() + nPos;
    2739         474 :             sal_Unicode ch2 = pTabSep[1];   // maybe a column identifier
    2740         474 :             if ( !(ch2 == '$' || rtl::isAsciiAlpha( ch2 )) )
    2741         474 :                 return false;
    2742           0 :             if ( cDecSep == '.' && (ch2 == 'E' || ch2 == 'e')   // E + - digit
    2743           0 :                     && (GetCharTableFlags( pTabSep[2], pTabSep[1] ) & SC_COMPILER_C_VALUE_EXP) )
    2744             :             {   // #91053#
    2745             :                 // If it is an 1.E2 expression check if "1" is an existent sheet
    2746             :                 // name. If so, a desired value 1.E2 would have to be entered as
    2747             :                 // 1E2 or 1.0E2 or 1.E+2, sorry. Another possibility would be to
    2748             :                 // require numerical sheet names always being entered quoted, which
    2749             :                 // is not desirable (too many 1999, 2000, 2001 sheets in use).
    2750             :                 // Furthermore, XML files created with versions prior to SRC640e
    2751             :                 // wouldn't contain the quotes added by MakeTabStr()/CheckTabQuotes()
    2752             :                 // and would produce wrong formulas if the conditions here are met.
    2753             :                 // If you can live with these restrictions you may remove the
    2754             :                 // check and return an unconditional FALSE.
    2755           0 :                 OUString aTabName( rName.copy( 0, nPos ) );
    2756             :                 SCTAB nTab;
    2757           0 :                 if ( !pDoc->GetTable( aTabName, nTab ) )
    2758           0 :                     return false;
    2759             :                 // If sheet "1" exists and the expression is 1.E+2 continue as
    2760             :                 // usual, the ScRange/ScAddress parser will take care of it.
    2761             :             }
    2762             :         } while(false);
    2763             :     }
    2764             : 
    2765       10960 :     if (IsSingleReference( rName))
    2766        6334 :         return true;
    2767             : 
    2768             :     // Though the range operator is handled explicitly, when encountering
    2769             :     // something like Sheet1.A:A we will have to treat it as one entity if it
    2770             :     // doesn't pass as single cell reference.
    2771        4626 :     if (mnRangeOpPosInSymbol > 0)   // ":foo" would be nonsense
    2772             :     {
    2773        4446 :         if (IsDoubleReference( rName))
    2774        4446 :             return true;
    2775             :         // Now try with a symbol up to the range operator, rewind source
    2776             :         // position.
    2777           0 :         sal_Int32 nLen = mnRangeOpPosInSymbol;
    2778           0 :         while (cSymbol[++nLen])
    2779             :             ;
    2780           0 :         cSymbol[mnRangeOpPosInSymbol] = 0;
    2781           0 :         nSrcPos -= (nLen - mnRangeOpPosInSymbol);
    2782           0 :         mnRangeOpPosInSymbol = -1;
    2783           0 :         mbRewind = true;
    2784           0 :         return true;    // end all checks
    2785             :     }
    2786             :     else
    2787             :     {
    2788             :         // Special treatment for the 'E:\[doc]Sheet1:Sheet3'!D5 Excel sickness,
    2789             :         // mnRangeOpPosInSymbol did not catch the range operator as it is
    2790             :         // within a quoted name.
    2791         180 :         switch (pConv->meConv)
    2792             :         {
    2793             :             case FormulaGrammar::CONV_XL_A1:
    2794             :             case FormulaGrammar::CONV_XL_R1C1:
    2795             :             case FormulaGrammar::CONV_XL_OOX:
    2796          26 :                 if (rName[0] == '\'' && IsDoubleReference( rName))
    2797           0 :                     return true;
    2798          26 :                 break;
    2799             :             default:
    2800             :                 ;   // nothing
    2801             :         }
    2802             :     }
    2803         180 :     return false;
    2804             : }
    2805             : 
    2806           2 : bool ScCompiler::IsMacro( const OUString& rName )
    2807             : {
    2808             : #if !HAVE_FEATURE_SCRIPTING
    2809             :     (void) rName;
    2810             : 
    2811             :     return false;
    2812             : #else
    2813             : 
    2814             :     // Calling SfxObjectShell::GetBasic() may result in all sort of things
    2815             :     // including obtaining the model and deep down in
    2816             :     // SfxBaseModel::getDocumentStorage() acquiring the SolarMutex, which when
    2817             :     // formulas are compiled from a threaded import may result in a deadlock.
    2818             :     // Check first if we actually could acquire it and if not bail out.
    2819             :     /* FIXME: yes, but how ... */
    2820           2 :     vcl::SolarMutexTryAndBuyGuard g;
    2821           2 :     if (!g.isAcquired())
    2822             :     {
    2823             :         SAL_WARN( "sc.core", "ScCompiler::IsMacro - SolarMutex would deadlock, not obtaining Basic");
    2824           0 :         return false;   // bad luck
    2825             :     }
    2826             : 
    2827           4 :     OUString aName( rName);
    2828           2 :     StarBASIC* pObj = 0;
    2829           2 :     SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
    2830             : 
    2831           2 :     SfxApplication* pSfxApp = SfxGetpApp();
    2832             : 
    2833             :     try
    2834             :     {
    2835           2 :         if( pDocSh )//XXX
    2836           2 :             pObj = pDocSh->GetBasic();
    2837             :         else
    2838           0 :             pObj = pSfxApp->GetBasic();
    2839             :     }
    2840           0 :     catch (...)
    2841             :     {
    2842           0 :         return false;
    2843             :     }
    2844             : 
    2845             :     // ODFF recommends to store user-defined functions prefixed with "USER.",
    2846             :     // use only unprefixed name if encountered. BASIC doesn't allow '.' in a
    2847             :     // function name so a function "USER.FOO" could not exist, and macro check
    2848             :     // is assigned the lowest priority in function name check.
    2849           2 :     if (FormulaGrammar::isODFF( GetGrammar()) && aName.startsWithIgnoreAsciiCase("USER."))
    2850           0 :         aName = aName.copy(5);
    2851             : 
    2852           2 :     SbxMethod* pMeth = static_cast<SbxMethod*>(pObj->Find( aName, SbxCLASS_METHOD ));
    2853           2 :     if( !pMeth )
    2854             :     {
    2855           0 :         return false;
    2856             :     }
    2857             :     // It really should be a BASIC function!
    2858           4 :     if( pMeth->GetType() == SbxVOID
    2859           2 :      || ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
    2860           4 :      || !pMeth->ISA(SbMethod) )
    2861             :     {
    2862           0 :         return false;
    2863             :     }
    2864           2 :     maRawToken.SetExternal( aName.getStr() );
    2865           2 :     maRawToken.eOp = ocMacro;
    2866           4 :     return true;
    2867             : #endif
    2868             : }
    2869             : 
    2870         180 : bool ScCompiler::IsNamedRange( const OUString& rUpperName )
    2871             : {
    2872             :     // IsNamedRange is called only from NextNewToken, with an upper-case string
    2873             : 
    2874             :     // try local names first
    2875         180 :     bool bGlobal = false;
    2876         180 :     ScRangeName* pRangeName = pDoc->GetRangeName(aPos.Tab());
    2877         180 :     const ScRangeData* pData = NULL;
    2878         180 :     if (pRangeName)
    2879         178 :         pData = pRangeName->findByUpperName(rUpperName);
    2880         180 :     if (!pData)
    2881             :     {
    2882         150 :         pRangeName = pDoc->GetRangeName();
    2883         150 :         if (pRangeName)
    2884         150 :             pData = pRangeName->findByUpperName(rUpperName);
    2885         150 :         if (pData)
    2886         100 :             bGlobal = true;
    2887             :     }
    2888             : 
    2889         180 :     if (pData)
    2890             :     {
    2891         130 :         maRawToken.SetName(bGlobal, pData->GetIndex());
    2892         130 :         return true;
    2893             :     }
    2894             :     else
    2895          50 :         return false;
    2896             : }
    2897             : 
    2898          50 : bool ScCompiler::IsExternalNamedRange( const OUString& rSymbol )
    2899             : {
    2900             :     /* FIXME: This code currently (2008-12-02T15:41+0100 in CWS mooxlsc)
    2901             :      * correctly parses external named references in OOo, as required per RFE
    2902             :      * #i3740#, just that we can't store them in ODF yet. We will need an OASIS
    2903             :      * spec first. Until then don't pretend to support external names that
    2904             :      * wouldn't survive a save and reload cycle, return false instead. */
    2905             : 
    2906          50 :     if (!pConv)
    2907           0 :         return false;
    2908             : 
    2909         100 :     OUString aFile, aName;
    2910          50 :     if (!pConv->parseExternalName( rSymbol, aFile, aName, pDoc, &maExternalLinks))
    2911          50 :         return false;
    2912             : 
    2913           0 :     if (aFile.getLength() > MAXSTRLEN || aName.getLength() > MAXSTRLEN)
    2914           0 :         return false;
    2915             : 
    2916           0 :     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    2917           0 :     OUString aTmp = aFile;
    2918           0 :     pRefMgr->convertToAbsName(aTmp);
    2919           0 :     aFile = aTmp;
    2920           0 :     sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile);
    2921           0 :     if (!pRefMgr->isValidRangeName(nFileId, aName))
    2922             :         // range name doesn't exist in the source document.
    2923           0 :         return false;
    2924             : 
    2925           0 :     const OUString* pRealName = pRefMgr->getRealRangeName(nFileId, aName);
    2926           0 :     maRawToken.SetExternalName(nFileId, pRealName ? *pRealName : OUString(aTmp));
    2927           0 :     maExternalFiles.push_back(nFileId);
    2928          50 :     return true;
    2929             : }
    2930             : 
    2931          50 : bool ScCompiler::IsDBRange( const OUString& rName )
    2932             : {
    2933          50 :     if (rName.equalsAscii("[]"))
    2934             :     {
    2935           0 :         if (maRawToken.GetOpCode() == ocDBArea)
    2936             :         {
    2937             :             // In OOXML, a database range is named Table1[], Table2[] etc.
    2938             :             // Skip the [] part if the previous token is a valid db range.
    2939           0 :             maRawToken.eOp = ocSkip;
    2940           0 :             return true;
    2941             :         }
    2942             :     }
    2943          50 :     ScDBCollection::NamedDBs& rDBs = pDoc->GetDBCollection()->getNamedDBs();
    2944          50 :     const ScDBData* p = rDBs.findByUpperName(rName);
    2945          50 :     if (!p)
    2946          34 :         return false;
    2947             : 
    2948          16 :     maRawToken.SetName(true, p->GetIndex()); // DB range is always global.
    2949          16 :     maRawToken.eOp = ocDBArea;
    2950          16 :     return true;
    2951             : }
    2952             : 
    2953          32 : bool ScCompiler::IsColRowName( const OUString& rName )
    2954             : {
    2955          32 :     bool bInList = false;
    2956          32 :     bool bFound = false;
    2957             :     ScSingleRefData aRef;
    2958          32 :     OUString aName( rName );
    2959          32 :     DeQuote( aName );
    2960          32 :     SCTAB nThisTab = aPos.Tab();
    2961          96 :     for ( short jThisTab = 1; jThisTab >= 0 && !bInList; jThisTab-- )
    2962             :     {   // first check ranges on this sheet, in case of duplicated names
    2963         192 :         for ( short jRow=0; jRow<2 && !bInList; jRow++ )
    2964             :         {
    2965             :             ScRangePairList* pRL;
    2966         128 :             if ( !jRow )
    2967          64 :                 pRL = pDoc->GetColNameRanges();
    2968             :             else
    2969          64 :                 pRL = pDoc->GetRowNameRanges();
    2970         128 :             for ( size_t iPair = 0, nPairs = pRL->size(); iPair < nPairs && !bInList; ++iPair )
    2971             :             {
    2972           0 :                 ScRangePair* pR = (*pRL)[iPair];
    2973           0 :                 const ScRange& rNameRange = pR->GetRange(0);
    2974           0 :                 if ( jThisTab && !(rNameRange.aStart.Tab() <= nThisTab &&
    2975           0 :                         nThisTab <= rNameRange.aEnd.Tab()) )
    2976           0 :                     continue;   // for
    2977           0 :                 ScCellIterator aIter( pDoc, rNameRange );
    2978           0 :                 for (bool bHas = aIter.first(); bHas && !bInList; bHas = aIter.next())
    2979             :                 {
    2980             :                     // Don't crash if cell (via CompileNameFormula) encounters
    2981             :                     // a formula cell without code and
    2982             :                     // HasStringData/Interpret/Compile is executed and all that
    2983             :                     // recursive..
    2984             :                     // Furthermore, *this* cell won't be touched, since no RPN exists yet.
    2985           0 :                     CellType eType = aIter.getType();
    2986           0 :                     bool bOk = false;
    2987           0 :                     if (eType == CELLTYPE_FORMULA)
    2988             :                     {
    2989           0 :                         ScFormulaCell* pFC = aIter.getFormulaCell();
    2990           0 :                         bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    2991             :                     }
    2992             :                     else
    2993           0 :                         bOk = true;
    2994             : 
    2995           0 :                     if (bOk && aIter.hasString())
    2996             :                     {
    2997           0 :                         OUString aStr = aIter.getString();
    2998           0 :                         if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
    2999             :                         {
    3000           0 :                             aRef.InitFlags();
    3001           0 :                             if ( !jRow )
    3002           0 :                                 aRef.SetColRel( true );     // ColName
    3003             :                             else
    3004           0 :                                 aRef.SetRowRel( true );     // RowName
    3005           0 :                             aRef.SetAddress(aIter.GetPos(), aPos);
    3006           0 :                             bInList = bFound = true;
    3007           0 :                         }
    3008             :                     }
    3009             :                 }
    3010           0 :             }
    3011             :         }
    3012             :     }
    3013          32 :     if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
    3014             :     {   // search in current sheet
    3015          26 :         long nDistance = 0, nMax = 0;
    3016          26 :         long nMyCol = (long) aPos.Col();
    3017          26 :         long nMyRow = (long) aPos.Row();
    3018          26 :         bool bTwo = false;
    3019          26 :         ScAddress aOne( 0, 0, aPos.Tab() );
    3020          26 :         ScAddress aTwo( MAXCOL, MAXROW, aPos.Tab() );
    3021             : 
    3022          26 :         ScAutoNameCache* pNameCache = pDoc->GetAutoNameCache();
    3023          26 :         if ( pNameCache )
    3024             :         {
    3025             :             //  use GetNameOccurrences to collect all positions of aName on the sheet
    3026             :             //  (only once), similar to the outer part of the loop in the "else" branch.
    3027             : 
    3028           8 :             const ScAutoNameAddresses& rAddresses = pNameCache->GetNameOccurrences( aName, aPos.Tab() );
    3029             : 
    3030             :             //  Loop through the found positions, similar to the inner part of the loop in the "else" branch.
    3031             :             //  The order of addresses in the vector is the same as from ScCellIterator.
    3032             : 
    3033           8 :             ScAutoNameAddresses::const_iterator aEnd(rAddresses.end());
    3034           8 :             for ( ScAutoNameAddresses::const_iterator aAdrIter(rAddresses.begin()); aAdrIter != aEnd; ++aAdrIter )
    3035             :             {
    3036           0 :                 ScAddress aAddress( *aAdrIter );        // cell address with an equal string
    3037             : 
    3038           0 :                 if ( bFound )
    3039             :                 {   // stop if everything else is further away
    3040           0 :                     if ( nMax < (long)aAddress.Col() )
    3041           0 :                         break;      // aIter
    3042             :                 }
    3043           0 :                 if ( aAddress != aPos )
    3044             :                 {
    3045             :                     // same treatment as in isEqual case below
    3046             : 
    3047           0 :                     SCCOL nCol = aAddress.Col();
    3048           0 :                     SCROW nRow = aAddress.Row();
    3049           0 :                     long nC = nMyCol - nCol;
    3050           0 :                     long nR = nMyRow - nRow;
    3051           0 :                     if ( bFound )
    3052             :                     {
    3053           0 :                         long nD = nC * nC + nR * nR;
    3054           0 :                         if ( nD < nDistance )
    3055             :                         {
    3056           0 :                             if ( nC < 0 || nR < 0 )
    3057             :                             {   // right or below
    3058           0 :                                 bTwo = true;
    3059           0 :                                 aTwo.Set( nCol, nRow, aAddress.Tab() );
    3060           0 :                                 nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3061           0 :                                 nDistance = nD;
    3062             :                             }
    3063           0 :                             else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
    3064             :                             {
    3065             :                                 // upper left, only if not further up than the
    3066             :                                 // current entry and nMyRow is below (CellIter
    3067             :                                 // runs column-wise)
    3068           0 :                                 bTwo = false;
    3069           0 :                                 aOne.Set( nCol, nRow, aAddress.Tab() );
    3070           0 :                                 nMax = std::max( nMyCol + nC, nMyRow + nR );
    3071           0 :                                 nDistance = nD;
    3072             :                             }
    3073             :                         }
    3074             :                     }
    3075             :                     else
    3076             :                     {
    3077           0 :                         aOne.Set( nCol, nRow, aAddress.Tab() );
    3078           0 :                         nDistance = nC * nC + nR * nR;
    3079           0 :                         nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3080             : 
    3081             :                     }
    3082           0 :                     bFound = true;
    3083             :                 }
    3084             :             }
    3085             :         }
    3086             :         else
    3087             :         {
    3088          18 :             ScCellIterator aIter( pDoc, ScRange( aOne, aTwo ) );
    3089         272 :             for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
    3090             :             {
    3091         254 :                 if ( bFound )
    3092             :                 {   // stop if everything else is further away
    3093           0 :                     if ( nMax < (long)aIter.GetPos().Col() )
    3094           0 :                         break;      // aIter
    3095             :                 }
    3096         254 :                 CellType eType = aIter.getType();
    3097         254 :                 bool bOk = false;
    3098         254 :                 if (eType == CELLTYPE_FORMULA)
    3099             :                 {
    3100         250 :                     ScFormulaCell* pFC = aIter.getFormulaCell();
    3101         250 :                     bOk = (pFC->GetCode()->GetCodeLen() > 0) && (pFC->aPos != aPos);
    3102             :                 }
    3103             :                 else
    3104           4 :                     bOk = true;
    3105             : 
    3106         254 :                 if (bOk && aIter.hasString())
    3107             :                 {
    3108           0 :                     OUString aStr = aIter.getString();
    3109           0 :                     if ( ScGlobal::GetpTransliteration()->isEqual( aStr, aName ) )
    3110             :                     {
    3111           0 :                         SCCOL nCol = aIter.GetPos().Col();
    3112           0 :                         SCROW nRow = aIter.GetPos().Row();
    3113           0 :                         long nC = nMyCol - nCol;
    3114           0 :                         long nR = nMyRow - nRow;
    3115           0 :                         if ( bFound )
    3116             :                         {
    3117           0 :                             long nD = nC * nC + nR * nR;
    3118           0 :                             if ( nD < nDistance )
    3119             :                             {
    3120           0 :                                 if ( nC < 0 || nR < 0 )
    3121             :                                 {   // right or below
    3122           0 :                                     bTwo = true;
    3123           0 :                                     aTwo.Set( nCol, nRow, aIter.GetPos().Tab() );
    3124           0 :                                     nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3125           0 :                                     nDistance = nD;
    3126             :                                 }
    3127           0 :                                 else if ( !(nRow < aOne.Row() && nMyRow >= (long)aOne.Row()) )
    3128             :                                 {
    3129             :                                     // upper left, only if not further up than the
    3130             :                                     // current entry and nMyRow is below (CellIter
    3131             :                                     // runs column-wise)
    3132           0 :                                     bTwo = false;
    3133           0 :                                     aOne.Set( nCol, nRow, aIter.GetPos().Tab() );
    3134           0 :                                     nMax = std::max( nMyCol + nC, nMyRow + nR );
    3135           0 :                                     nDistance = nD;
    3136             :                                 }
    3137             :                             }
    3138             :                         }
    3139             :                         else
    3140             :                         {
    3141           0 :                             aOne.Set( nCol, nRow, aIter.GetPos().Tab() );
    3142           0 :                             nDistance = nC * nC + nR * nR;
    3143           0 :                             nMax = std::max( nMyCol + std::abs( nC ), nMyRow + std::abs( nR ) );
    3144             :                         }
    3145           0 :                         bFound = true;
    3146           0 :                     }
    3147             :                 }
    3148          18 :             }
    3149             :         }
    3150             : 
    3151          26 :         if ( bFound )
    3152             :         {
    3153           0 :             ScAddress aAdr;
    3154           0 :             if ( bTwo )
    3155             :             {
    3156           0 :                 if ( nMyCol >= (long)aOne.Col() && nMyRow >= (long)aOne.Row() )
    3157           0 :                     aAdr = aOne;        // upper left takes precedence
    3158             :                 else
    3159             :                 {
    3160           0 :                     if ( nMyCol < (long)aOne.Col() )
    3161             :                     {   // two to the right
    3162           0 :                         if ( nMyRow >= (long)aTwo.Row() )
    3163           0 :                             aAdr = aTwo;        // directly right
    3164             :                         else
    3165           0 :                             aAdr = aOne;
    3166             :                     }
    3167             :                     else
    3168             :                     {   // two below or below and right, take the nearest
    3169           0 :                         long nC1 = nMyCol - aOne.Col();
    3170           0 :                         long nR1 = nMyRow - aOne.Row();
    3171           0 :                         long nC2 = nMyCol - aTwo.Col();
    3172           0 :                         long nR2 = nMyRow - aTwo.Row();
    3173           0 :                         if ( nC1 * nC1 + nR1 * nR1 <= nC2 * nC2 + nR2 * nR2 )
    3174           0 :                             aAdr = aOne;
    3175             :                         else
    3176           0 :                             aAdr = aTwo;
    3177             :                     }
    3178             :                 }
    3179             :             }
    3180             :             else
    3181           0 :                 aAdr = aOne;
    3182           0 :             aRef.InitAddress( aAdr );
    3183           0 :             if ( (aAdr.Row() != MAXROW && pDoc->HasStringData(
    3184           0 :                     aAdr.Col(), aAdr.Row() + 1, aAdr.Tab()))
    3185           0 :               || (aAdr.Row() != 0 && pDoc->HasStringData(
    3186           0 :                     aAdr.Col(), aAdr.Row() - 1, aAdr.Tab())))
    3187           0 :                 aRef.SetRowRel( true );     // RowName
    3188             :             else
    3189           0 :                 aRef.SetColRel( true );     // ColName
    3190           0 :             aRef.SetAddress(aAdr, aPos);
    3191             :         }
    3192             :     }
    3193          32 :     if ( bFound )
    3194             :     {
    3195           0 :         maRawToken.SetSingleReference( aRef );
    3196           0 :         maRawToken.eOp = ocColRowName;
    3197           0 :         return true;
    3198             :     }
    3199             :     else
    3200          32 :         return false;
    3201             : }
    3202             : 
    3203          56 : bool ScCompiler::IsBoolean( const OUString& rName )
    3204             : {
    3205          56 :     OpCodeHashMap::const_iterator iLook( mxSymbols->getHashMap()->find( rName ) );
    3206          56 :     if( iLook != mxSymbols->getHashMap()->end() &&
    3207           0 :         ((*iLook).second == ocTrue ||
    3208           0 :          (*iLook).second == ocFalse) )
    3209             :     {
    3210           0 :         maRawToken.SetOpCode( (*iLook).second );
    3211           0 :         return true;
    3212             :     }
    3213             :     else
    3214          56 :         return false;
    3215             : }
    3216             : 
    3217          46 : bool ScCompiler::IsErrorConstant( const OUString& rName ) const
    3218             : {
    3219          46 :     sal_uInt16 nError = GetErrorConstant( rName);
    3220          46 :     if (nError)
    3221             :     {
    3222          46 :         maRawToken.SetErrorConstant( nError);
    3223          46 :         return true;
    3224             :     }
    3225             :     else
    3226           0 :         return false;
    3227             : }
    3228             : 
    3229           0 : void ScCompiler::SetAutoCorrection( bool bVal )
    3230             : {
    3231             :     assert(mbJumpCommandReorder);
    3232           0 :     bAutoCorrect = bVal;
    3233           0 :     mbStopOnError = !bVal;
    3234           0 : }
    3235             : 
    3236           0 : void ScCompiler::AutoCorrectParsedSymbol()
    3237             : {
    3238           0 :     sal_Int32 nPos = aCorrectedSymbol.getLength();
    3239           0 :     if ( nPos )
    3240             :     {
    3241           0 :         nPos--;
    3242           0 :         const sal_Unicode cQuote = '\"';
    3243           0 :         const sal_Unicode cx = 'x';
    3244           0 :         const sal_Unicode cX = 'X';
    3245           0 :         sal_Unicode c1 = aCorrectedSymbol[0];
    3246           0 :         sal_Unicode c2 = aCorrectedSymbol[nPos];
    3247           0 :         sal_Unicode c2p = nPos > 0 ? aCorrectedSymbol[nPos-1] : 0;
    3248           0 :         if ( c1 == cQuote && c2 != cQuote  )
    3249             :         {   // "...
    3250             :             // What's not a word doesn't belong to it.
    3251             :             // Don't be pedantic: c < 128 should be sufficient here.
    3252           0 :             while ( nPos && ((aCorrectedSymbol[nPos] < 128) &&
    3253           0 :                     ((GetCharTableFlags(aCorrectedSymbol[nPos], aCorrectedSymbol[nPos-1]) &
    3254             :                     (SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_DONTCARE)) == 0)) )
    3255           0 :                 nPos--;
    3256           0 :             if ( nPos == MAXSTRLEN - 2 )
    3257           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAt( nPos, 1, OUString(cQuote) );   // '"' the 255th character
    3258             :             else
    3259           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAt( nPos + 1, 0, OUString(cQuote) );
    3260           0 :             bCorrected = true;
    3261             :         }
    3262           0 :         else if ( c1 != cQuote && c2 == cQuote )
    3263             :         {   // ..."
    3264           0 :             aCorrectedSymbol = OUString(cQuote) + aCorrectedSymbol;
    3265           0 :             bCorrected = true;
    3266             :         }
    3267           0 :         else if ( nPos == 0 && (c1 == cx || c1 == cX) )
    3268             :         {   // x => *
    3269           0 :             aCorrectedSymbol = mxSymbols->getSymbol(ocMul);
    3270           0 :             bCorrected = true;
    3271             :         }
    3272           0 :         else if ( (GetCharTableFlags( c1, 0 ) & SC_COMPILER_C_CHAR_VALUE)
    3273           0 :                && (GetCharTableFlags( c2, c2p ) & SC_COMPILER_C_CHAR_VALUE) )
    3274             :         {
    3275           0 :             if ( comphelper::string::getTokenCount(aCorrectedSymbol, cx) > 1 )
    3276             :             {   // x => *
    3277           0 :                 sal_Unicode c = mxSymbols->getSymbolChar(ocMul);
    3278           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAll(OUString(cx), OUString(c));
    3279           0 :                 bCorrected = true;
    3280             :             }
    3281           0 :             if ( comphelper::string::getTokenCount(aCorrectedSymbol, cX) > 1 )
    3282             :             {   // X => *
    3283           0 :                 sal_Unicode c = mxSymbols->getSymbolChar(ocMul);
    3284           0 :                 aCorrectedSymbol = aCorrectedSymbol.replaceAll(OUString(cX), OUString(c));
    3285           0 :                 bCorrected = true;
    3286             :             }
    3287             :         }
    3288             :         else
    3289             :         {
    3290           0 :             OUString aSymbol( aCorrectedSymbol );
    3291           0 :             OUString aDoc;
    3292             :             sal_Int32 nPosition;
    3293           0 :             if ( aSymbol[0] == '\''
    3294           0 :               && ((nPosition = aSymbol.indexOf( "'#" )) != -1) )
    3295             :             {   // Split off 'Doc'#, may be d:\... or whatever
    3296           0 :                 aDoc = aSymbol.copy(0, nPosition + 2);
    3297           0 :                 aSymbol = aSymbol.copy(nPosition + 2);
    3298             :             }
    3299           0 :             sal_Int32 nRefs = comphelper::string::getTokenCount(aSymbol, ':');
    3300             :             bool bColons;
    3301           0 :             if ( nRefs > 2 )
    3302             :             {   // duplicated or too many ':'? B:2::C10 => B2:C10
    3303           0 :                 bColons = true;
    3304           0 :                 sal_Int32 nIndex = 0;
    3305           0 :                 OUString aTmp1( aSymbol.getToken( 0, ':', nIndex ) );
    3306           0 :                 sal_Int32 nLen1 = aTmp1.getLength();
    3307           0 :                 OUString aSym, aTmp2;
    3308             :                 bool bLastAlp, bNextNum;
    3309           0 :                 bLastAlp = bNextNum = true;
    3310           0 :                 sal_Int32 nStrip = 0;
    3311           0 :                 sal_Int32 nCount = nRefs;
    3312           0 :                 for ( sal_Int32 j=1; j<nCount; j++ )
    3313             :                 {
    3314           0 :                     aTmp2 = aSymbol.getToken( 0, ':', nIndex );
    3315           0 :                     sal_Int32 nLen2 = aTmp2.getLength();
    3316           0 :                     if ( nLen1 || nLen2 )
    3317             :                     {
    3318           0 :                         if ( nLen1 )
    3319             :                         {
    3320           0 :                             aSym += aTmp1;
    3321           0 :                             bLastAlp = CharClass::isAsciiAlpha( aTmp1 );
    3322             :                         }
    3323           0 :                         if ( nLen2 )
    3324             :                         {
    3325           0 :                             bNextNum = CharClass::isAsciiNumeric( aTmp2 );
    3326           0 :                             if ( bLastAlp == bNextNum && nStrip < 1 )
    3327             :                             {
    3328             :                                 // Must be alternating number/string, only
    3329             :                                 // strip within a reference.
    3330           0 :                                 nRefs--;
    3331           0 :                                 nStrip++;
    3332             :                             }
    3333             :                             else
    3334             :                             {
    3335           0 :                                 if ( !aSym.isEmpty() && !aSym.endsWith(":"))
    3336           0 :                                     aSym += ":";
    3337           0 :                                 nStrip = 0;
    3338             :                             }
    3339           0 :                             bLastAlp = !bNextNum;
    3340             :                         }
    3341             :                         else
    3342             :                         {   // ::
    3343           0 :                             nRefs--;
    3344           0 :                             if ( nLen1 )
    3345             :                             {   // B10::C10 ? append ':' on next round
    3346           0 :                                 if ( !bLastAlp && !CharClass::isAsciiNumeric( aTmp1 ) )
    3347           0 :                                     nStrip++;
    3348             :                             }
    3349             :                         }
    3350           0 :                         aTmp1 = aTmp2;
    3351           0 :                         nLen1 = nLen2;
    3352             :                     }
    3353             :                     else
    3354           0 :                         nRefs--;
    3355             :                 }
    3356           0 :                 aSymbol = aSym;
    3357           0 :                 aSymbol += aTmp1;
    3358             :             }
    3359             :             else
    3360           0 :                 bColons = false;
    3361           0 :             if ( nRefs && nRefs <= 2 )
    3362             :             {   // reference twisted? 4A => A4 etc.
    3363           0 :                 OUString aTab[2], aRef[2];
    3364           0 :                 const ScAddress::Details aDetails( pConv->meConv, aPos );
    3365           0 :                 if ( nRefs == 2 )
    3366             :                 {
    3367           0 :                     aRef[0] = aSymbol.getToken( 0, ':' );
    3368           0 :                     aRef[1] = aSymbol.getToken( 1, ':' );
    3369             :                 }
    3370             :                 else
    3371           0 :                     aRef[0] = aSymbol;
    3372             : 
    3373           0 :                 bool bChanged = false;
    3374           0 :                 bool bOk = true;
    3375           0 :                 sal_uInt16 nMask = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW;
    3376           0 :                 for ( int j=0; j<nRefs; j++ )
    3377             :                 {
    3378           0 :                     sal_Int32 nTmp = 0;
    3379           0 :                     sal_Int32 nDotPos = -1;
    3380           0 :                     while ( (nTmp = aRef[j].indexOf( '.', nTmp )) != -1 )
    3381           0 :                         nDotPos = nTmp++;      // the last one counts
    3382           0 :                     if ( nDotPos != -1 )
    3383             :                     {
    3384           0 :                         aTab[j] = aRef[j].copy( 0, nDotPos + 1 );  // with '.'
    3385           0 :                         aRef[j] = aRef[j].copy( nDotPos + 1 );
    3386             :                     }
    3387           0 :                     OUString aOld( aRef[j] );
    3388           0 :                     OUString aStr2;
    3389           0 :                     const sal_Unicode* p = aRef[j].getStr();
    3390           0 :                     while ( *p && CharClass::isAsciiNumeric( OUString(*p) ) )
    3391           0 :                         aStr2 += OUString(*p++);
    3392           0 :                     aRef[j] = OUString( p );
    3393           0 :                     aRef[j] += aStr2;
    3394           0 :                     if ( bColons || aRef[j] != aOld )
    3395             :                     {
    3396           0 :                         bChanged = true;
    3397           0 :                         ScAddress aAdr;
    3398           0 :                         bOk &= ((aAdr.Parse( aRef[j], pDoc, aDetails ) & nMask) == nMask);
    3399             :                     }
    3400           0 :                 }
    3401           0 :                 if ( bChanged && bOk )
    3402             :                 {
    3403           0 :                     aCorrectedSymbol = aDoc;
    3404           0 :                     aCorrectedSymbol += aTab[0];
    3405           0 :                     aCorrectedSymbol += aRef[0];
    3406           0 :                     if ( nRefs == 2 )
    3407             :                     {
    3408           0 :                         aCorrectedSymbol += ":";
    3409           0 :                         aCorrectedSymbol += aTab[1];
    3410           0 :                         aCorrectedSymbol += aRef[1];
    3411             :                     }
    3412           0 :                     bCorrected = true;
    3413           0 :                 }
    3414           0 :             }
    3415             :         }
    3416             :     }
    3417           0 : }
    3418             : 
    3419        7944 : static inline bool lcl_UpperAsciiOrI18n( OUString& rUpper, const OUString& rOrg, FormulaGrammar::Grammar eGrammar )
    3420             : {
    3421        7944 :     if (FormulaGrammar::isODFF( eGrammar ))
    3422             :     {
    3423             :         // ODFF has a defined set of English function names, avoid i18n
    3424             :         // overhead.
    3425        4276 :         rUpper = rOrg.toAsciiUpperCase();
    3426        4276 :         return true;
    3427             :     }
    3428             :     else
    3429             :     {
    3430        3668 :         rUpper = ScGlobal::pCharClass->uppercase(rOrg);
    3431        3668 :         return false;
    3432             :     }
    3433             : }
    3434             : 
    3435       47412 : bool ScCompiler::NextNewToken( bool bInArray )
    3436             : {
    3437       47412 :     bool bAllowBooleans = bInArray;
    3438       47412 :     sal_Int32 nSpaces = NextSymbol(bInArray);
    3439             : 
    3440       47412 :     if (!cSymbol[0])
    3441       11032 :         return false;
    3442             : 
    3443       36380 :     if( nSpaces )
    3444             :     {
    3445         784 :         ScRawToken aToken;
    3446         784 :         aToken.SetOpCode( ocSpaces );
    3447         784 :         aToken.sbyte.cByte = (sal_uInt8) ( nSpaces > 255 ? 255 : nSpaces );
    3448         784 :         if( !static_cast<ScTokenArray*>(pArr)->AddRawToken( aToken ) )
    3449             :         {
    3450           0 :             SetError(errCodeOverflow);
    3451           0 :             return false;
    3452         784 :         }
    3453             :     }
    3454             : 
    3455             :     // Short cut for references when reading ODF to speedup things.
    3456       36380 :     if (mnPredetectedReference)
    3457             :     {
    3458         648 :         OUString aStr( cSymbol);
    3459         648 :         if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr))
    3460             :         {
    3461             :             /* TODO: it would be nice to generate a #REF! error here, which
    3462             :              * would need an ocBad token with additional error value.
    3463             :              * FormulaErrorToken wouldn't do because we want to preserve the
    3464             :              * original string containing partial valid address
    3465             :              * information if not ODFF (in that case it was already handled).
    3466             :              * */
    3467           0 :             svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aStr);
    3468           0 :             maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3469           0 :             maRawToken.NewOpCode( ocBad );
    3470             :         }
    3471         648 :         return true;
    3472             :     }
    3473             : 
    3474       35732 :     if ( (cSymbol[0] == '#' || cSymbol[0] == '$') && cSymbol[1] == 0 &&
    3475           0 :             !bAutoCorrect )
    3476             :     {   // special case to speed up broken [$]#REF documents
    3477             :         /* FIXME: ISERROR(#REF!) would be valid and true and the formula to
    3478             :          * be processed as usual. That would need some special treatment,
    3479             :          * also in NextSymbol() because of possible combinations of
    3480             :          * #REF!.#REF!#REF! parts. In case of reading ODF that is all
    3481             :          * handled by IsPredetectedReference(), this case here remains for
    3482             :          * manual/API input. */
    3483           0 :         OUString aBad( aFormula.copy( nSrcPos-1 ) );
    3484           0 :         eLastOp = pArr->AddBad( aBad )->GetOpCode();
    3485           0 :         return false;
    3486             :     }
    3487             : 
    3488       35732 :     if( IsString() )
    3489        1020 :         return true;
    3490             : 
    3491             :     bool bMayBeFuncName;
    3492             :     bool bAsciiNonAlnum;    // operators, separators, ...
    3493       34712 :     if ( cSymbol[0] < 128 )
    3494             :     {
    3495       34708 :         bMayBeFuncName = rtl::isAsciiAlpha( cSymbol[0] );
    3496       34708 :         if (!bMayBeFuncName && (cSymbol[0] == '_' && cSymbol[1] == '_') )
    3497             :         {
    3498           0 :             SvtMiscOptions aOpt;
    3499           0 :             bMayBeFuncName = aOpt.IsExperimentalMode();
    3500             :         }
    3501             : 
    3502       34708 :         bAsciiNonAlnum = !bMayBeFuncName && !rtl::isAsciiDigit( cSymbol[0] );
    3503             :     }
    3504             :     else
    3505             :     {
    3506           4 :         OUString aTmpStr( cSymbol[0] );
    3507           4 :         bMayBeFuncName = ScGlobal::pCharClass->isLetter( aTmpStr, 0 );
    3508           4 :         bAsciiNonAlnum = false;
    3509             :     }
    3510       34712 :     if ( bMayBeFuncName )
    3511             :     {
    3512             :         // a function name must be followed by a parenthesis
    3513        7396 :         const sal_Unicode* p = aFormula.getStr() + nSrcPos;
    3514       14820 :         while( *p == ' ' )
    3515          28 :             p++;
    3516        7396 :         bMayBeFuncName = ( *p == '(' );
    3517             :     }
    3518             : 
    3519             :     // Italian ARCTAN.2 resulted in #REF! => IsOpcode() before
    3520             :     // IsReference().
    3521             : 
    3522       34712 :     OUString aUpper;
    3523             : 
    3524          32 :     do
    3525             :     {
    3526       34712 :         mbRewind = false;
    3527       34712 :         const OUString aOrg( cSymbol );
    3528             : 
    3529       34712 :         if (bAsciiNonAlnum)
    3530             :         {
    3531       22556 :             if (cSymbol[0] == '#')
    3532             :             {
    3533             :                 // This can be only an error constant, if any.
    3534          46 :                 lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3535          46 :                 if (IsErrorConstant( aUpper))
    3536          46 :                     return true;
    3537           0 :                 break;  // do; create ocBad token or set error.
    3538             :             }
    3539       22510 :             if (IsOpCode( aOrg, bInArray ))
    3540       15988 :                 return true;
    3541             :         }
    3542             : 
    3543       18678 :         aUpper = "";
    3544       18678 :         bool bAsciiUpper = false;
    3545       18678 :         if (bMayBeFuncName)
    3546             :         {
    3547        2960 :             bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3548        2960 :             if (IsOpCode( aUpper, bInArray ))
    3549        2958 :                 return true;
    3550             :         }
    3551             : 
    3552             :         // Column 'DM' ("Deutsche Mark", German currency) couldn't be
    3553             :         // referred => IsReference() before IsValue().
    3554             :         // Preserve case of file names in external references.
    3555       15720 :         if (IsReference( aOrg ))
    3556             :         {
    3557       10780 :             if (mbRewind)   // Range operator, but no direct reference.
    3558           0 :                 continue;   // do; up to range operator.
    3559             :             // If a syntactically correct reference was recognized but invalid
    3560             :             // e.g. because of non-existing sheet name => entire reference
    3561             :             // ocBad to preserve input instead of #REF!.A1
    3562       10780 :             if (!maRawToken.IsValidReference())
    3563             :             {
    3564           0 :                 aUpper = aOrg;          // ensure for ocBad
    3565           0 :                 break;                  // do; create ocBad token or set error.
    3566             :             }
    3567       10780 :             return true;
    3568             :         }
    3569             : 
    3570        4940 :         if (aUpper.isEmpty())
    3571        4938 :             bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar);
    3572             : 
    3573             :         // IsBoolean() before IsValue() to catch inline bools without the kludge
    3574             :         //    for inline arrays.
    3575        4940 :         if (bAllowBooleans && IsBoolean( aUpper ))
    3576           0 :             return true;
    3577             : 
    3578        4940 :         if (IsValue( aUpper ))
    3579        4760 :             return true;
    3580             : 
    3581             :         // User defined names and such do need i18n upper also in ODF.
    3582         180 :         if (bAsciiUpper)
    3583          80 :             aUpper = ScGlobal::pCharClass->uppercase( aOrg );
    3584             : 
    3585         180 :         if (IsNamedRange( aUpper ))
    3586         130 :             return true;
    3587             :         // Preserve case of file names in external references.
    3588          50 :         if (IsExternalNamedRange( aOrg ))
    3589           0 :             return true;
    3590          50 :         if (IsDBRange( aUpper ))
    3591          16 :             return true;
    3592             :         // If followed by '(' (with or without space inbetween) it can not be a
    3593             :         // column/row label. Prevent arbitrary content detection.
    3594          34 :         if (!bMayBeFuncName && IsColRowName( aUpper ))
    3595           0 :             return true;
    3596          34 :         if (bMayBeFuncName && IsMacro( aUpper ))
    3597           2 :             return true;
    3598          32 :         if (bMayBeFuncName && IsOpCode2( aUpper ))
    3599           0 :             return true;
    3600             : 
    3601             :     } while (mbRewind);
    3602             : 
    3603          32 :     if ( meExtendedErrorDetection != EXTENDED_ERROR_DETECTION_NONE )
    3604             :     {
    3605             :         // set an error
    3606           2 :         SetError( errNoName );
    3607           2 :         if (meExtendedErrorDetection == EXTENDED_ERROR_DETECTION_NAME_BREAK)
    3608           0 :             return false;   // end compilation
    3609             :     }
    3610             : 
    3611             :     // Provide single token information and continue. Do not set an error, that
    3612             :     // would prematurely end compilation. Simple unknown names are handled by
    3613             :     // the interpreter.
    3614          32 :     aUpper = ScGlobal::pCharClass->lowercase( aUpper );
    3615          64 :     svl::SharedString aSS = pDoc->GetSharedStringPool().intern(aUpper);
    3616          32 :     maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase());
    3617          32 :     maRawToken.NewOpCode( ocBad );
    3618          32 :     if ( bAutoCorrect )
    3619           0 :         AutoCorrectParsedSymbol();
    3620       34744 :     return true;
    3621             : }
    3622             : 
    3623        1710 : void ScCompiler::CreateStringFromXMLTokenArray( OUString& rFormula, OUString& rFormulaNmsp )
    3624             : {
    3625        1710 :     bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL;
    3626        1710 :     sal_uInt16 nExpectedCount = bExternal ? 2 : 1;
    3627             :     OSL_ENSURE( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" );
    3628        1710 :     if( pArr->GetLen() == nExpectedCount )
    3629             :     {
    3630        1710 :         FormulaToken** ppTokens = pArr->GetArray();
    3631             :         // string tokens expected, GetString() will assert if token type is wrong
    3632        1710 :         rFormula = ppTokens[0]->GetString().getString();
    3633        1710 :         if( bExternal )
    3634           0 :             rFormulaNmsp = ppTokens[1]->GetString().getString();
    3635             :     }
    3636        1710 : }
    3637             : 
    3638             : namespace {
    3639             : 
    3640         100 : class ExternalFileInserter : std::unary_function<sal_uInt16, void>
    3641             : {
    3642             :     ScAddress maPos;
    3643             :     ScExternalRefManager& mrRefMgr;
    3644             : public:
    3645         100 :     ExternalFileInserter(const ScAddress& rPos, ScExternalRefManager& rRefMgr) :
    3646         100 :         maPos(rPos), mrRefMgr(rRefMgr) {}
    3647             : 
    3648         100 :     void operator() (sal_uInt16 nFileId) const
    3649             :     {
    3650         100 :         mrRefMgr.insertRefCell(nFileId, maPos);
    3651         100 :     }
    3652             : };
    3653             : 
    3654             : }
    3655             : 
    3656       11032 : ScTokenArray* ScCompiler::CompileString( const OUString& rFormula )
    3657             : {
    3658             :     OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" );
    3659       11032 :     if( meGrammar == FormulaGrammar::GRAM_EXTERNAL )
    3660           0 :         SetGrammar( FormulaGrammar::GRAM_PODF );
    3661             : 
    3662       11032 :     ScTokenArray aArr;
    3663       11032 :     pArr = &aArr;
    3664       11032 :     aFormula = comphelper::string::strip(rFormula, ' ');
    3665             : 
    3666       11032 :     nSrcPos = 0;
    3667       11032 :     bCorrected = false;
    3668       11032 :     if ( bAutoCorrect )
    3669             :     {
    3670           0 :         aCorrectedFormula = "";
    3671           0 :         aCorrectedSymbol = "";
    3672             :     }
    3673       11032 :     sal_uInt8 nForced = 0;   // ==formula forces recalc even if cell is not visible
    3674       11032 :     if( nSrcPos < aFormula.getLength() && aFormula[nSrcPos] == '=' )
    3675             :     {
    3676        3628 :         nSrcPos++;
    3677        3628 :         nForced++;
    3678        3628 :         if ( bAutoCorrect )
    3679           0 :             aCorrectedFormula += "=";
    3680             :     }
    3681       11032 :     if( nSrcPos < aFormula.getLength() && aFormula[nSrcPos] == '=' )
    3682             :     {
    3683           0 :         nSrcPos++;
    3684           0 :         nForced++;
    3685           0 :         if ( bAutoCorrect )
    3686           0 :             aCorrectedFormula += "=";
    3687             :     }
    3688             :     struct FunctionStack
    3689             :     {
    3690             :         OpCode  eOp;
    3691             :         short   nSep;
    3692             :     };
    3693             :     // FunctionStack only used if PODF or OOXML!
    3694       11032 :     bool bPODF = FormulaGrammar::isPODF( meGrammar);
    3695       11032 :     bool bOOXML = FormulaGrammar::isOOXML( meGrammar);
    3696       11032 :     bool bUseFunctionStack = (bPODF || bOOXML);
    3697       11032 :     const size_t nAlloc = 512;
    3698             :     FunctionStack aFuncs[ nAlloc ];
    3699        1764 :     FunctionStack* pFunctionStack = (bUseFunctionStack && static_cast<size_t>(rFormula.getLength()) > nAlloc ?
    3700       11032 :          new FunctionStack[rFormula.getLength()] : &aFuncs[0]);
    3701       11032 :     pFunctionStack[0].eOp = ocNone;
    3702       11032 :     pFunctionStack[0].nSep = 0;
    3703       11032 :     size_t nFunction = 0;
    3704       11032 :     short nBrackets = 0;
    3705       11032 :     bool bInArray = false;
    3706       11032 :     eLastOp = ocOpen;
    3707       58444 :     while( NextNewToken( bInArray ) )
    3708             :     {
    3709       36380 :         const OpCode eOp = maRawToken.GetOpCode();
    3710       36380 :         if (eOp == ocSkip)
    3711           0 :             continue;
    3712             : 
    3713       36380 :         switch (eOp)
    3714             :         {
    3715             :             case ocOpen:
    3716             :             {
    3717        4048 :                 ++nBrackets;
    3718        4048 :                 if (bUseFunctionStack)
    3719             :                 {
    3720        1512 :                     ++nFunction;
    3721        1512 :                     pFunctionStack[ nFunction ].eOp = eLastOp;
    3722        1512 :                     pFunctionStack[ nFunction ].nSep = 0;
    3723             :                 }
    3724             :             }
    3725        4048 :             break;
    3726             :             case ocClose:
    3727             :             {
    3728        4028 :                 if( !nBrackets )
    3729             :                 {
    3730           0 :                     SetError( errPairExpected );
    3731           0 :                     if ( bAutoCorrect )
    3732             :                     {
    3733           0 :                         bCorrected = true;
    3734           0 :                         aCorrectedSymbol = "";
    3735             :                     }
    3736             :                 }
    3737             :                 else
    3738        4028 :                     nBrackets--;
    3739        4028 :                 if (bUseFunctionStack && nFunction)
    3740        1496 :                     --nFunction;
    3741             :             }
    3742        4028 :             break;
    3743             :             case ocSep:
    3744             :             {
    3745        5338 :                 if (bUseFunctionStack)
    3746        2728 :                     ++pFunctionStack[ nFunction ].nSep;
    3747             :             }
    3748        5338 :             break;
    3749             :             case ocArrayOpen:
    3750             :             {
    3751          36 :                 if( bInArray )
    3752           0 :                     SetError( errNestedArray );
    3753             :                 else
    3754          36 :                     bInArray = true;
    3755             :                 // Don't count following column separator as parameter separator.
    3756          36 :                 if (bUseFunctionStack)
    3757             :                 {
    3758           0 :                     ++nFunction;
    3759           0 :                     pFunctionStack[ nFunction ].eOp = eOp;
    3760           0 :                     pFunctionStack[ nFunction ].nSep = 0;
    3761             :                 }
    3762             :             }
    3763          36 :             break;
    3764             :             case ocArrayClose:
    3765             :             {
    3766          36 :                 if( bInArray )
    3767             :                 {
    3768          36 :                     bInArray = false;
    3769             :                 }
    3770             :                 else
    3771             :                 {
    3772           0 :                     SetError( errPairExpected );
    3773           0 :                     if ( bAutoCorrect )
    3774             :                     {
    3775           0 :                         bCorrected = true;
    3776           0 :                         aCorrectedSymbol = "";
    3777             :                     }
    3778             :                 }
    3779          36 :                 if (bUseFunctionStack && nFunction)
    3780           0 :                     --nFunction;
    3781             :             }
    3782             :             default:
    3783       22930 :             break;
    3784             :         }
    3785       67422 :         if( (eLastOp == ocSep ||
    3786       62022 :              eLastOp == ocArrayRowSep ||
    3787       61924 :              eLastOp == ocArrayColSep ||
    3788       36416 :              eLastOp == ocArrayOpen) &&
    3789        5456 :             (eOp == ocSep ||
    3790        5448 :              eOp == ocClose ||
    3791        5448 :              eOp == ocArrayRowSep ||
    3792        5448 :              eOp == ocArrayColSep ||
    3793             :              eOp == ocArrayClose) )
    3794             :         {
    3795             :             // FIXME: should we check for known functions with optional empty
    3796             :             // args so the correction dialog can do better?
    3797          24 :             if ( !static_cast<ScTokenArray*>(pArr)->Add( new FormulaMissingToken ) )
    3798             :             {
    3799           0 :                 SetError(errCodeOverflow); break;
    3800             :             }
    3801             :         }
    3802       36380 :         if (bOOXML)
    3803             :         {
    3804             :             // Append a parameter for CEILING, FLOOR and WEEKNUM, all 1.0
    3805             :             // Function is already closed, parameter count is nSep+1
    3806       11400 :             size_t nFunc = nFunction + 1;
    3807       12816 :             if (eOp == ocClose && (
    3808        1416 :                     (pFunctionStack[ nFunc ].eOp == ocCeil &&   // 3rd Excel mode
    3809        1416 :                      pFunctionStack[ nFunc ].nSep == 1) ||
    3810        1416 :                     (pFunctionStack[ nFunc ].eOp == ocFloor &&  // 3rd Excel mode
    3811        1416 :                      pFunctionStack[ nFunc ].nSep == 1) ||
    3812        1416 :                     (pFunctionStack[ nFunc ].eOp == ocWeek &&   // 2nd week start
    3813           0 :                      pFunctionStack[ nFunc ].nSep == 0)))
    3814             :             {
    3815           0 :                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) ||
    3816           0 :                         !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
    3817             :                 {
    3818           0 :                     SetError(errCodeOverflow); break;
    3819             :                 }
    3820             :             }
    3821             :         }
    3822       24980 :         else if (bPODF)
    3823             :         {
    3824             :             /* TODO: for now this is the only PODF adapter. If there were more,
    3825             :              * factor this out. */
    3826             :             // Insert ADDRESS() new empty parameter 4 if there is a 4th, now to be 5th.
    3827        1030 :             if (eOp == ocSep &&
    3828          42 :                     pFunctionStack[ nFunction ].eOp == ocAddress &&
    3829           0 :                     pFunctionStack[ nFunction ].nSep == 3)
    3830             :             {
    3831           0 :                 if (    !static_cast<ScTokenArray*>(pArr)->Add( new FormulaToken( svSep, ocSep)) ||
    3832           0 :                         !static_cast<ScTokenArray*>(pArr)->Add( new FormulaDoubleToken( 1.0)))
    3833             :                 {
    3834           0 :                     SetError(errCodeOverflow); break;
    3835             :                 }
    3836           0 :                 ++pFunctionStack[ nFunction ].nSep;
    3837             :             }
    3838             :         }
    3839       36380 :         FormulaToken* pNewToken = static_cast<ScTokenArray*>(pArr)->Add( maRawToken.CreateToken());
    3840       36380 :         if (!pNewToken)
    3841             :         {
    3842           0 :             SetError(errCodeOverflow); break;
    3843             :         }
    3844       36380 :         else if (eLastOp == ocRange && pNewToken->GetOpCode() == ocPush &&
    3845           0 :                 pNewToken->GetType() == svSingleRef)
    3846           0 :             static_cast<ScTokenArray*>(pArr)->MergeRangeReference( aPos);
    3847       36380 :         eLastOp = maRawToken.GetOpCode();
    3848       36380 :         if ( bAutoCorrect )
    3849           0 :             aCorrectedFormula += aCorrectedSymbol;
    3850             :     }
    3851       11032 :     if ( mbCloseBrackets )
    3852             :     {
    3853       11032 :         if( bInArray )
    3854             :         {
    3855           0 :             FormulaByteToken aToken( ocArrayClose );
    3856           0 :             if( !pArr->AddToken( aToken ) )
    3857             :             {
    3858           0 :                 SetError(errCodeOverflow);
    3859             :             }
    3860           0 :             else if ( bAutoCorrect )
    3861           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocArrayClose);
    3862             :         }
    3863             : 
    3864       11032 :         FormulaByteToken aToken( ocClose );
    3865       22084 :         while( nBrackets-- )
    3866             :         {
    3867          20 :             if( !pArr->AddToken( aToken ) )
    3868             :             {
    3869           0 :                 SetError(errCodeOverflow); break;
    3870             :             }
    3871          20 :             if ( bAutoCorrect )
    3872           0 :                 aCorrectedFormula += mxSymbols->getSymbol(ocClose);
    3873       11032 :         }
    3874             :     }
    3875       11032 :     if ( nForced >= 2 )
    3876           0 :         pArr->SetRecalcModeForced();
    3877             : 
    3878       11032 :     if (pFunctionStack != &aFuncs[0])
    3879           0 :         delete [] pFunctionStack;
    3880             : 
    3881             :     // remember pArr, in case a subsequent CompileTokenArray() is executed.
    3882       11032 :     ScTokenArray* pNew = new ScTokenArray( aArr );
    3883       11032 :     pNew->GenHash();
    3884       11032 :     pArr = pNew;
    3885             : 
    3886       11032 :     if (!maExternalFiles.empty())
    3887             :     {
    3888             :         // Remove duplicates, and register all external files found in this cell.
    3889         100 :         std::sort(maExternalFiles.begin(), maExternalFiles.end());
    3890         100 :         std::vector<sal_uInt16>::iterator itEnd = std::unique(maExternalFiles.begin(), maExternalFiles.end());
    3891         100 :         std::for_each(maExternalFiles.begin(), itEnd, ExternalFileInserter(aPos, *pDoc->GetExternalRefManager()));
    3892         100 :         maExternalFiles.erase(itEnd, maExternalFiles.end());
    3893             :     }
    3894             : 
    3895       11032 :     return pNew;
    3896             : }
    3897             : 
    3898        1910 : ScTokenArray* ScCompiler::CompileString( const OUString& rFormula, const OUString& rFormulaNmsp )
    3899             : {
    3900             :     OSL_ENSURE( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || rFormulaNmsp.isEmpty(),
    3901             :         "ScCompiler::CompileString - unexpected formula namespace for internal grammar" );
    3902        1910 :     if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try
    3903             :     {
    3904           0 :         ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool();
    3905           0 :         uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW );
    3906           0 :         table::CellAddress aReferencePos;
    3907           0 :         ScUnoConversion::FillApiAddress( aReferencePos, aPos );
    3908           0 :         uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos );
    3909           0 :         ScTokenArray aTokenArray;
    3910           0 :         if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) )
    3911             :         {
    3912             :             // remember pArr, in case a subsequent CompileTokenArray() is executed.
    3913           0 :             ScTokenArray* pNew = new ScTokenArray( aTokenArray );
    3914           0 :             pArr = pNew;
    3915           0 :             return pNew;
    3916           0 :         }
    3917             :     }
    3918           0 :     catch( uno::Exception& )
    3919             :     {
    3920             :     }
    3921             :     // no success - fallback to some internal grammar and hope the best
    3922        1910 :     return CompileString( rFormula );
    3923             : }
    3924             : 
    3925         778 : ScRangeData* ScCompiler::GetRangeData( const FormulaToken& rToken ) const
    3926             : {
    3927         778 :     ScRangeData* pRangeData = NULL;
    3928         778 :     bool bGlobal = rToken.IsGlobal();
    3929         778 :     if (bGlobal)
    3930             :         // global named range.
    3931         718 :         pRangeData = pDoc->GetRangeName()->findByIndex( rToken.GetIndex());
    3932             :     else
    3933             :     {
    3934             :         // sheet local named range.
    3935          60 :         const ScRangeName* pRN = pDoc->GetRangeName( aPos.Tab());
    3936          60 :         if (pRN)
    3937          60 :             pRangeData = pRN->findByIndex( rToken.GetIndex());
    3938             :     }
    3939         778 :     return pRangeData;
    3940             : }
    3941             : 
    3942         722 : bool ScCompiler::HandleRange()
    3943             : {
    3944         722 :     const ScRangeData* pRangeData = GetRangeData( *mpToken);
    3945         722 :     if (pRangeData)
    3946             :     {
    3947         722 :         sal_uInt16 nErr = pRangeData->GetErrCode();
    3948         722 :         if( nErr )
    3949           0 :             SetError( errNoName );
    3950         722 :         else if (mbJumpCommandReorder)
    3951             :         {
    3952             :             ScTokenArray* pNew;
    3953             :             // put named formula into parentheses.
    3954             :             // But only if there aren't any yet, parenthetical
    3955             :             // ocSep doesn't work, e.g. SUM((...;...))
    3956             :             // or if not directly between ocSep/parenthesis,
    3957             :             // e.g. SUM(...;(...;...)) no, SUM(...;(...)*3) yes,
    3958             :             // in short: if it isn't a self-contained expression.
    3959         722 :             FormulaToken* p1 = pArr->PeekPrevNoSpaces();
    3960         722 :             FormulaToken* p2 = pArr->PeekNextNoSpaces();
    3961         722 :             OpCode eOp1 = (p1 ? p1->GetOpCode() : static_cast<OpCode>( ocSep ) );
    3962         722 :             OpCode eOp2 = (p2 ? p2->GetOpCode() : static_cast<OpCode>( ocSep ) );
    3963         722 :             bool bBorder1 = (eOp1 == ocSep || eOp1 == ocOpen);
    3964         722 :             bool bBorder2 = (eOp2 == ocSep || eOp2 == ocClose);
    3965         722 :             bool bAddPair = !(bBorder1 && bBorder2);
    3966         722 :             if ( bAddPair )
    3967             :             {
    3968          32 :                 pNew = new ScTokenArray();
    3969          32 :                 pNew->AddOpCode( ocClose );
    3970          32 :                 PushTokenArray( pNew, true );
    3971          32 :                 pNew->Reset();
    3972             :             }
    3973         722 :             pNew = pRangeData->GetCode()->Clone();
    3974         722 :             PushTokenArray( pNew, true );
    3975         722 :             if( pRangeData->HasReferences() )
    3976             :             {
    3977         710 :                 SetRelNameReference();
    3978         710 :                 MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
    3979             :             }
    3980         722 :             pNew->Reset();
    3981         722 :             if ( bAddPair )
    3982             :             {
    3983          32 :                 pNew = new ScTokenArray();
    3984          32 :                 pNew->AddOpCode( ocOpen );
    3985          32 :                 PushTokenArray( pNew, true );
    3986          32 :                 pNew->Reset();
    3987             :             }
    3988         722 :             return GetToken();
    3989             :         }
    3990             :     }
    3991             :     else
    3992           0 :         SetError(errNoName);
    3993           0 :     return true;
    3994             : }
    3995             : 
    3996         268 : bool ScCompiler::HandleExternalReference(const FormulaToken& _aToken)
    3997             : {
    3998             :     // Handle external range names.
    3999         268 :     switch (_aToken.GetType())
    4000             :     {
    4001             :         case svExternalSingleRef:
    4002             :         case svExternalDoubleRef:
    4003         268 :             pArr->IncrementRefs();
    4004         268 :         break;
    4005             :         case svExternalName:
    4006             :         {
    4007           0 :             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    4008           0 :             const OUString* pFile = pRefMgr->getExternalFileName(_aToken.GetIndex());
    4009           0 :             if (!pFile)
    4010             :             {
    4011           0 :                 SetError(errNoName);
    4012           0 :                 return true;
    4013             :             }
    4014             : 
    4015           0 :             OUString aName = _aToken.GetString().getString();
    4016             :             ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getRangeNameTokens(
    4017           0 :                 _aToken.GetIndex(), aName, &aPos);
    4018             : 
    4019           0 :             if (!xNew)
    4020             :             {
    4021           0 :                 SetError(errNoName);
    4022           0 :                 return true;
    4023             :             }
    4024             : 
    4025           0 :             ScTokenArray* pNew = xNew->Clone();
    4026           0 :             PushTokenArray( pNew, true);
    4027           0 :             if (pNew->GetNextReference() != NULL)
    4028             :             {
    4029           0 :                 SetRelNameReference();
    4030           0 :                 MoveRelWrap(MAXCOL, MAXROW);
    4031             :             }
    4032           0 :             pNew->Reset();
    4033           0 :             return GetToken();
    4034             :         }
    4035             :         default:
    4036             :             OSL_FAIL("Wrong type for external reference!");
    4037           0 :             return false;
    4038             :     }
    4039         268 :     return true;
    4040             : }
    4041             : 
    4042             : // reference of named range with relative references
    4043             : 
    4044         710 : void ScCompiler::SetRelNameReference()
    4045             : {
    4046         710 :     pArr->Reset();
    4047        1420 :     for( formula::FormulaToken* t = pArr->GetNextReference(); t;
    4048         710 :                   t = pArr->GetNextReference() )
    4049             :     {
    4050         710 :         ScSingleRefData& rRef1 = *t->GetSingleRef();
    4051         710 :         if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
    4052          38 :             rRef1.SetRelName( true );
    4053         710 :         if ( t->GetType() == svDoubleRef )
    4054             :         {
    4055          62 :             ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
    4056          62 :             if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
    4057          26 :                 rRef2.SetRelName( true );
    4058             :         }
    4059             :     }
    4060         710 : }
    4061             : 
    4062             : // Wrap-adjust relative references of a RangeName to current position,
    4063             : // don't call for other token arrays!
    4064         752 : void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow )
    4065             : {
    4066         752 :     pArr->Reset();
    4067        1504 :     for( formula::FormulaToken* t = pArr->GetNextReference(); t;
    4068         752 :                   t = pArr->GetNextReference() )
    4069             :     {
    4070         752 :         if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
    4071         666 :             ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( *t->GetSingleRef() ).Ref() );
    4072             :         else
    4073          86 :             ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, *t->GetDoubleRef() );
    4074             :     }
    4075         752 : }
    4076             : 
    4077             : // Wrap-adjust relative references of a RangeName to current position,
    4078             : // don't call for other token arrays!
    4079         252 : void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos,
    4080             :                               SCCOL nMaxCol, SCROW nMaxRow )
    4081             : {
    4082         252 :     rArr.Reset();
    4083         920 :     for( formula::FormulaToken* t = rArr.GetNextReference(); t;
    4084         668 :                   t = rArr.GetNextReference() )
    4085             :     {
    4086         668 :         if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef )
    4087         500 :             ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( *t->GetSingleRef() ).Ref() );
    4088             :         else
    4089         168 :             ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, *t->GetDoubleRef() );
    4090             :     }
    4091         252 : }
    4092             : 
    4093        3226 : bool ScCompiler::IsCharFlagAllConventions(
    4094             :     OUString const & rStr, sal_Int32 nPos, sal_uLong nFlags, bool bTestLetterNumeric )
    4095             : {
    4096        3226 :     sal_Unicode c = rStr[ nPos ];
    4097        3226 :     sal_Unicode cLast = nPos > 0 ? rStr[ nPos-1 ] : 0;
    4098        3226 :     if (c < 128)
    4099             :     {
    4100       25808 :         for ( int nConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
    4101             :                 ++nConv < formula::FormulaGrammar::CONV_LAST; )
    4102             :         {
    4103       32320 :             if (pConventions[nConv] &&
    4104       12964 :                     ((pConventions[nConv]->getCharTableFlags(c, cLast) & nFlags) != nFlags))
    4105           0 :                 return false;
    4106             :             // convention not known => assume valid
    4107             :         }
    4108        3226 :         return true;
    4109             :     }
    4110           0 :     else if (bTestLetterNumeric)
    4111           0 :         return ScGlobal::pCharClass->isLetterNumeric( rStr, nPos );
    4112             :     else
    4113           0 :         return false;
    4114             : }
    4115             : 
    4116          62 : void ScCompiler::CreateStringFromExternal(OUStringBuffer& rBuffer, FormulaToken* pTokenP) const
    4117             : {
    4118          62 :     FormulaToken* t = pTokenP;
    4119          62 :     sal_uInt16 nFileId = t->GetIndex();
    4120          62 :     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
    4121          62 :     const OUString* pFileName = pRefMgr->getExternalFileName(nFileId);
    4122          62 :     if (!pFileName)
    4123           0 :         return;
    4124             : 
    4125          62 :     switch (t->GetType())
    4126             :     {
    4127             :         case svExternalName:
    4128           0 :             rBuffer.append(pConv->makeExternalNameStr( nFileId, *pFileName, t->GetString().getString()));
    4129           0 :         break;
    4130             :         case svExternalSingleRef:
    4131             :             pConv->makeExternalRefStr(
    4132         100 :                    rBuffer, GetPos(), nFileId, *pFileName, t->GetString().getString(),
    4133         150 :                    *t->GetSingleRef());
    4134          50 :         break;
    4135             :         case svExternalDoubleRef:
    4136             :         {
    4137          12 :             vector<OUString> aTabNames;
    4138          12 :             pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
    4139          12 :             if (aTabNames.empty())
    4140           0 :                 return;
    4141             : 
    4142             :             pConv->makeExternalRefStr(
    4143          24 :                 rBuffer, GetPos(), nFileId, *pFileName, aTabNames, t->GetString().getString(),
    4144          36 :                 *t->GetDoubleRef());
    4145             :         }
    4146          12 :         break;
    4147             :         default:
    4148             :             // warning, not error, otherwise we may end up with a never
    4149             :             // ending message box loop if this was the cursor cell to be redrawn.
    4150             :             OSL_FAIL("ScCompiler::CreateStringFromToken: unknown type of ocExternalRef");
    4151             :     }
    4152             : }
    4153             : 
    4154           4 : void ScCompiler::CreateStringFromMatrix(
    4155             :     OUStringBuffer& rBuffer, FormulaToken* pTokenP) const
    4156             : {
    4157           4 :     const ScMatrix* pMatrix = pTokenP->GetMatrix();
    4158             :     SCSIZE nC, nMaxC, nR, nMaxR;
    4159             : 
    4160           4 :     pMatrix->GetDimensions( nMaxC, nMaxR);
    4161             : 
    4162           4 :     rBuffer.append( mxSymbols->getSymbol(ocArrayOpen) );
    4163           8 :     for( nR = 0 ; nR < nMaxR ; nR++)
    4164             :     {
    4165           4 :         if( nR > 0)
    4166             :         {
    4167           0 :             rBuffer.append( mxSymbols->getSymbol(ocArrayRowSep) );
    4168             :         }
    4169             : 
    4170          16 :         for( nC = 0 ; nC < nMaxC ; nC++)
    4171             :         {
    4172          12 :             if( nC > 0)
    4173             :             {
    4174           8 :                 rBuffer.append( mxSymbols->getSymbol(ocArrayColSep) );
    4175             :             }
    4176             : 
    4177          12 :             if( pMatrix->IsValue( nC, nR ) )
    4178             :             {
    4179          12 :                 if (pMatrix->IsBoolean(nC, nR))
    4180           0 :                     AppendBoolean(rBuffer, pMatrix->GetDouble(nC, nR) != 0.0);
    4181             :                 else
    4182             :                 {
    4183          12 :                     sal_uInt16 nErr = pMatrix->GetError(nC, nR);
    4184          12 :                     if (nErr)
    4185           0 :                         rBuffer.append(ScGlobal::GetErrorString(nErr));
    4186             :                     else
    4187          12 :                         AppendDouble(rBuffer, pMatrix->GetDouble(nC, nR));
    4188             :                 }
    4189             :             }
    4190           0 :             else if( pMatrix->IsEmpty( nC, nR ) )
    4191             :                 ;
    4192           0 :             else if( pMatrix->IsString( nC, nR ) )
    4193           0 :                 AppendString( rBuffer, pMatrix->GetString(nC, nR).getString() );
    4194             :         }
    4195             :     }
    4196           4 :     rBuffer.append( mxSymbols->getSymbol(ocArrayClose) );
    4197           4 : }
    4198             : 
    4199       29044 : void ScCompiler::CreateStringFromSingleRef(OUStringBuffer& rBuffer,FormulaToken* _pTokenP) const
    4200             : {
    4201       29044 :     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
    4202       29044 :     const OpCode eOp = _pTokenP->GetOpCode();
    4203       29044 :     const ScSingleRefData& rRef = *_pTokenP->GetSingleRef();
    4204             :     ScComplexRefData aRef;
    4205       29044 :     aRef.Ref1 = aRef.Ref2 = rRef;
    4206       29044 :     if ( eOp == ocColRowName )
    4207             :     {
    4208           0 :         ScAddress aAbs = rRef.toAbs(aPos);
    4209           0 :         if (pDoc->HasStringData(aAbs.Col(), aAbs.Row(), aAbs.Tab()))
    4210             :         {
    4211           0 :             OUString aStr = pDoc->GetString(aAbs);
    4212           0 :             EnQuote( aStr );
    4213           0 :             rBuffer.append(aStr);
    4214             :         }
    4215             :         else
    4216             :         {
    4217           0 :             rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
    4218             :             pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef,
    4219           0 :                               GetSetupTabNames(), aRef, true);
    4220             :         }
    4221             :     }
    4222             :     else
    4223             :         pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef,
    4224       29044 :                           GetSetupTabNames(), aRef, true);
    4225       29044 : }
    4226             : 
    4227       26172 : void ScCompiler::CreateStringFromDoubleRef(OUStringBuffer& rBuffer,FormulaToken* _pTokenP) const
    4228             : {
    4229       26172 :     OUString aErrRef = GetCurrentOpCodeMap()->getSymbol(ocErrRef);
    4230       26172 :     pConv->makeRefStr(rBuffer, meGrammar, aPos, aErrRef, GetSetupTabNames(),
    4231       52344 :                       *_pTokenP->GetDoubleRef(), false);
    4232       26172 : }
    4233             : 
    4234          62 : void ScCompiler::CreateStringFromIndex(OUStringBuffer& rBuffer,FormulaToken* _pTokenP) const
    4235             : {
    4236          62 :     const OpCode eOp = _pTokenP->GetOpCode();
    4237          62 :     OUStringBuffer aBuffer;
    4238          62 :     switch ( eOp )
    4239             :     {
    4240             :         case ocName:
    4241             :         {
    4242          56 :             const ScRangeData* pData = GetRangeData( *_pTokenP);
    4243          56 :             if (pData)
    4244          56 :                 aBuffer.append(pData->GetName());
    4245             :         }
    4246          56 :         break;
    4247             :         case ocDBArea:
    4248             :         {
    4249           6 :             const ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(_pTokenP->GetIndex());
    4250           6 :             if (pDBData)
    4251           6 :                 aBuffer.append(pDBData->GetName());
    4252             :         }
    4253           6 :         break;
    4254             :         default:
    4255             :             ;   // nothing
    4256             :     }
    4257          62 :     if ( !aBuffer.isEmpty() )
    4258          62 :         rBuffer.append(aBuffer.makeStringAndClear());
    4259             :     else
    4260           0 :         rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
    4261          62 : }
    4262             : 
    4263           2 : void ScCompiler::LocalizeString( OUString& rName ) const
    4264             : {
    4265           2 :     ScGlobal::GetAddInCollection()->LocalizeString( rName );
    4266           2 : }
    4267             : 
    4268             : // Put quotes around string if non-alphanumeric characters are contained,
    4269             : // quote characters contained within are escaped by '\\'.
    4270           0 : bool ScCompiler::EnQuote( OUString& rStr )
    4271             : {
    4272           0 :     sal_Int32 nType = ScGlobal::pCharClass->getStringType( rStr, 0, rStr.getLength() );
    4273           0 :     if ( !CharClass::isNumericType( nType )
    4274           0 :             && CharClass::isAlphaNumericType( nType ) )
    4275           0 :         return false;
    4276             : 
    4277           0 :     sal_Int32 nPos = 0;
    4278           0 :     while ( (nPos = rStr.indexOf( '\'', nPos)) != -1 )
    4279             :     {
    4280           0 :         rStr = rStr.replaceAt( nPos, 0, "\\" );
    4281           0 :         nPos += 2;
    4282             :     }
    4283           0 :     rStr = "'" + rStr + "'";
    4284           0 :     return true;
    4285             : }
    4286             : 
    4287           0 : sal_Unicode ScCompiler::GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const
    4288             : {
    4289           0 :     return pConv->getSpecialSymbol(eType);
    4290             : }
    4291             : 
    4292           0 : void ScCompiler::fillAddInToken(::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >& _rVec,bool _bIsEnglish) const
    4293             : {
    4294             :     // All known AddIn functions.
    4295           0 :     sheet::FormulaOpCodeMapEntry aEntry;
    4296           0 :     aEntry.Token.OpCode = ocExternal;
    4297             : 
    4298           0 :     ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
    4299           0 :     const long nCount = pColl->GetFuncCount();
    4300           0 :     for (long i=0; i < nCount; ++i)
    4301             :     {
    4302           0 :         const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i);
    4303           0 :         if (pFuncData)
    4304             :         {
    4305           0 :             if ( _bIsEnglish )
    4306             :             {
    4307           0 :                 OUString aName;
    4308           0 :                 if (pFuncData->GetExcelName( LANGUAGE_ENGLISH_US, aName))
    4309           0 :                     aEntry.Name = aName;
    4310             :                 else
    4311           0 :                     aEntry.Name = pFuncData->GetUpperName();
    4312             :             }
    4313             :             else
    4314           0 :                 aEntry.Name = pFuncData->GetUpperLocal();
    4315           0 :             aEntry.Token.Data <<= OUString( pFuncData->GetOriginalName());
    4316           0 :             _rVec.push_back( aEntry);
    4317             :         }
    4318           0 :     }
    4319             :     // FIXME: what about those old non-UNO AddIns?
    4320           0 : }
    4321             : 
    4322           0 : bool ScCompiler::HandleSingleRef()
    4323             : {
    4324           0 :     ScSingleRefData& rRef = *mpToken.get()->GetSingleRef();
    4325           0 :     ScAddress aAbs = rRef.toAbs(aPos);
    4326           0 :     if (!ValidAddress(aAbs))
    4327             :     {
    4328           0 :         SetError( errNoRef );
    4329           0 :         return true;
    4330             :     }
    4331           0 :     SCCOL nCol = aAbs.Col();
    4332           0 :     SCROW nRow = aAbs.Row();
    4333           0 :     SCTAB nTab = aAbs.Tab();
    4334           0 :     ScAddress aLook = aAbs;
    4335           0 :     bool bColName = rRef.IsColRel();
    4336           0 :     SCCOL nMyCol = aPos.Col();
    4337           0 :     SCROW nMyRow = aPos.Row();
    4338           0 :     bool bInList = false;
    4339           0 :     bool bValidName = false;
    4340             :     ScRangePairList* pRL = (bColName ?
    4341           0 :         pDoc->GetColNameRanges() : pDoc->GetRowNameRanges());
    4342           0 :     ScRange aRange;
    4343           0 :     for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4344             :     {
    4345           0 :         ScRangePair* pR = (*pRL)[i];
    4346           0 :         if ( pR->GetRange(0).In( aLook ) )
    4347             :         {
    4348           0 :             bInList = bValidName = true;
    4349           0 :             aRange = pR->GetRange(1);
    4350           0 :             if ( bColName )
    4351             :             {
    4352           0 :                 aRange.aStart.SetCol( nCol );
    4353           0 :                 aRange.aEnd.SetCol( nCol );
    4354             :             }
    4355             :             else
    4356             :             {
    4357           0 :                 aRange.aStart.SetRow( nRow );
    4358           0 :                 aRange.aEnd.SetRow( nRow );
    4359             :             }
    4360           0 :             break;  // for
    4361             :         }
    4362             :     }
    4363           0 :     if ( !bInList && pDoc->GetDocOptions().IsLookUpColRowNames() )
    4364             :     {   // automagically or created by copying and NamePos isn't in list
    4365           0 :         ScRefCellValue aCell;
    4366           0 :         aCell.assign(*pDoc, aLook);
    4367           0 :         bool bString = aCell.hasString();
    4368           0 :         if (!bString && aCell.isEmpty())
    4369           0 :             bString = true;     // empty cell is ok
    4370           0 :         if ( bString )
    4371             :         {   //! coresponds with ScInterpreter::ScColRowNameAuto()
    4372           0 :             bValidName = true;
    4373           0 :             if ( bColName )
    4374             :             {   // ColName
    4375           0 :                 SCROW nStartRow = nRow + 1;
    4376           0 :                 if ( nStartRow > MAXROW )
    4377           0 :                     nStartRow = MAXROW;
    4378           0 :                 SCROW nMaxRow = MAXROW;
    4379           0 :                 if ( nMyCol == nCol )
    4380             :                 {   // formula cell in same column
    4381           0 :                     if ( nMyRow == nStartRow )
    4382             :                     {   // take remainder under name cell
    4383           0 :                         nStartRow++;
    4384           0 :                         if ( nStartRow > MAXROW )
    4385           0 :                             nStartRow = MAXROW;
    4386             :                     }
    4387           0 :                     else if ( nMyRow > nStartRow )
    4388             :                     {   // from name cell down to formula cell
    4389           0 :                         nMaxRow = nMyRow - 1;
    4390             :                     }
    4391             :                 }
    4392           0 :                 for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4393             :                 {   // next defined ColNameRange below limits row
    4394           0 :                     ScRangePair* pR = (*pRL)[i];
    4395           0 :                     const ScRange& rRange = pR->GetRange(1);
    4396           0 :                     if ( rRange.aStart.Col() <= nCol && nCol <= rRange.aEnd.Col() )
    4397             :                     {   // identical column range
    4398           0 :                         SCROW nTmp = rRange.aStart.Row();
    4399           0 :                         if ( nStartRow < nTmp && nTmp <= nMaxRow )
    4400           0 :                             nMaxRow = nTmp - 1;
    4401             :                     }
    4402             :                 }
    4403           0 :                 aRange.aStart.Set( nCol, nStartRow, nTab );
    4404           0 :                 aRange.aEnd.Set( nCol, nMaxRow, nTab );
    4405             :             }
    4406             :             else
    4407             :             {   // RowName
    4408           0 :                 SCCOL nStartCol = nCol + 1;
    4409           0 :                 if ( nStartCol > MAXCOL )
    4410           0 :                     nStartCol = MAXCOL;
    4411           0 :                 SCCOL nMaxCol = MAXCOL;
    4412           0 :                 if ( nMyRow == nRow )
    4413             :                 {   // formula cell in same row
    4414           0 :                     if ( nMyCol == nStartCol )
    4415             :                     {   // take remainder right from name cell
    4416           0 :                         nStartCol++;
    4417           0 :                         if ( nStartCol > MAXCOL )
    4418           0 :                             nStartCol = MAXCOL;
    4419             :                     }
    4420           0 :                     else if ( nMyCol > nStartCol )
    4421             :                     {   // from name cell right to formula cell
    4422           0 :                         nMaxCol = nMyCol - 1;
    4423             :                     }
    4424             :                 }
    4425           0 :                 for ( size_t i = 0, nPairs = pRL->size(); i < nPairs; ++i )
    4426             :                 {   // next defined RowNameRange to the right limits column
    4427           0 :                     ScRangePair* pR = (*pRL)[i];
    4428           0 :                     const ScRange& rRange = pR->GetRange(1);
    4429           0 :                     if ( rRange.aStart.Row() <= nRow && nRow <= rRange.aEnd.Row() )
    4430             :                     {   // identical row range
    4431           0 :                         SCCOL nTmp = rRange.aStart.Col();
    4432           0 :                         if ( nStartCol < nTmp && nTmp <= nMaxCol )
    4433           0 :                             nMaxCol = nTmp - 1;
    4434             :                     }
    4435             :                 }
    4436           0 :                 aRange.aStart.Set( nStartCol, nRow, nTab );
    4437           0 :                 aRange.aEnd.Set( nMaxCol, nRow, nTab );
    4438             :             }
    4439           0 :         }
    4440             :     }
    4441           0 :     if ( bValidName )
    4442             :     {
    4443             :         // And now the magic to distinguish between a range and a single
    4444             :         // cell thereof, which is picked position-dependent of the formula
    4445             :         // cell. If a direct neighbor is a binary operator (ocAdd, ...) a
    4446             :         // SingleRef matching the column/row of the formula cell is
    4447             :         // generated. A ocColRowName or ocIntersect as a neighbor results
    4448             :         // in a range. Special case: if label is valid for a single cell, a
    4449             :         // position independent SingleRef is generated.
    4450           0 :         bool bSingle = (aRange.aStart == aRange.aEnd);
    4451             :         bool bFound;
    4452           0 :         if ( bSingle )
    4453           0 :             bFound = true;
    4454             :         else
    4455             :         {
    4456           0 :             FormulaToken* p1 = pArr->PeekPrevNoSpaces();
    4457           0 :             FormulaToken* p2 = pArr->PeekNextNoSpaces();
    4458             :             // begin/end of a formula => single
    4459           0 :             OpCode eOp1 = p1 ? p1->GetOpCode() : static_cast<OpCode>( ocAdd );
    4460           0 :             OpCode eOp2 = p2 ? p2->GetOpCode() : static_cast<OpCode>( ocAdd );
    4461           0 :             if ( eOp1 != ocColRowName && eOp1 != ocIntersect
    4462           0 :                 && eOp2 != ocColRowName && eOp2 != ocIntersect )
    4463             :             {
    4464           0 :                 if (    (SC_OPCODE_START_BIN_OP <= eOp1 && eOp1 < SC_OPCODE_STOP_BIN_OP) ||
    4465           0 :                         (SC_OPCODE_START_BIN_OP <= eOp2 && eOp2 < SC_OPCODE_STOP_BIN_OP))
    4466           0 :                     bSingle = true;
    4467             :             }
    4468           0 :             if ( bSingle )
    4469             :             {   // column and/or row must match range
    4470           0 :                 if ( bColName )
    4471             :                 {
    4472           0 :                     bFound = (aRange.aStart.Row() <= nMyRow
    4473           0 :                         && nMyRow <= aRange.aEnd.Row());
    4474           0 :                     if ( bFound )
    4475           0 :                         aRange.aStart.SetRow( nMyRow );
    4476             :                 }
    4477             :                 else
    4478             :                 {
    4479           0 :                     bFound = (aRange.aStart.Col() <= nMyCol
    4480           0 :                         && nMyCol <= aRange.aEnd.Col());
    4481           0 :                     if ( bFound )
    4482           0 :                         aRange.aStart.SetCol( nMyCol );
    4483             :                 }
    4484             :             }
    4485             :             else
    4486           0 :                 bFound = true;
    4487             :         }
    4488           0 :         if ( !bFound )
    4489           0 :             SetError(errNoRef);
    4490           0 :         else if (mbJumpCommandReorder)
    4491             :         {
    4492           0 :             ScTokenArray* pNew = new ScTokenArray();
    4493           0 :             if ( bSingle )
    4494             :             {
    4495             :                 ScSingleRefData aRefData;
    4496           0 :                 aRefData.InitAddress( aRange.aStart );
    4497           0 :                 if ( bColName )
    4498           0 :                     aRefData.SetColRel( true );
    4499             :                 else
    4500           0 :                     aRefData.SetRowRel( true );
    4501           0 :                 aRefData.SetAddress(aRange.aStart, aPos);
    4502           0 :                 pNew->AddSingleReference( aRefData );
    4503             :             }
    4504             :             else
    4505             :             {
    4506             :                 ScComplexRefData aRefData;
    4507           0 :                 aRefData.InitRange( aRange );
    4508           0 :                 if ( bColName )
    4509             :                 {
    4510           0 :                     aRefData.Ref1.SetColRel( true );
    4511           0 :                     aRefData.Ref2.SetColRel( true );
    4512             :                 }
    4513             :                 else
    4514             :                 {
    4515           0 :                     aRefData.Ref1.SetRowRel( true );
    4516           0 :                     aRefData.Ref2.SetRowRel( true );
    4517             :                 }
    4518           0 :                 aRefData.SetRange(aRange, aPos);
    4519           0 :                 if ( bInList )
    4520           0 :                     pNew->AddDoubleReference( aRefData );
    4521             :                 else
    4522             :                 {   // automagically
    4523           0 :                     pNew->Add( new ScDoubleRefToken( aRefData, ocColRowNameAuto ) );
    4524             :                 }
    4525             :             }
    4526           0 :             PushTokenArray( pNew, true );
    4527           0 :             pNew->Reset();
    4528           0 :             return GetToken();
    4529             :         }
    4530             :     }
    4531             :     else
    4532           0 :         SetError(errNoName);
    4533           0 :     return true;
    4534             : }
    4535             : 
    4536          16 : bool ScCompiler::HandleDbData()
    4537             : {
    4538          16 :     ScDBData* pDBData = pDoc->GetDBCollection()->getNamedDBs().findByIndex(mpToken->GetIndex());
    4539          16 :     if ( !pDBData )
    4540           0 :         SetError(errNoName);
    4541          16 :     else if (mbJumpCommandReorder)
    4542             :     {
    4543             :         ScComplexRefData aRefData;
    4544          16 :         aRefData.InitFlags();
    4545          16 :         ScRange aRange;
    4546          16 :         pDBData->GetArea(aRange);
    4547          16 :         aRange.aEnd.SetTab(aRange.aStart.Tab());
    4548          16 :         aRefData.SetRange(aRange, aPos);
    4549          16 :         ScTokenArray* pNew = new ScTokenArray();
    4550          16 :         pNew->AddDoubleReference( aRefData );
    4551          16 :         PushTokenArray( pNew, true );
    4552          16 :         pNew->Reset();
    4553          16 :         return GetToken();
    4554             :     }
    4555           0 :     return true;
    4556             : }
    4557             : 
    4558           0 : FormulaTokenRef ScCompiler::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, bool bReuseDoubleRef )
    4559             : {
    4560           0 :     return extendRangeReference( rTok1, rTok2, aPos,bReuseDoubleRef );
    4561         228 : }
    4562             : 
    4563             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10