/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
void ScCompiler::fillFromAddInCollectionExcelName( const NonConstOpCodeMapPtr& xMap ) const
{ const LanguageTag aDestLang(LANGUAGE_ENGLISH_US);
ScUnoAddInCollection* pColl = ScGlobal::GetAddInCollection();
tools::Long nCount = pColl->GetFuncCount(); for (tools::Long i=0; i < nCount; ++i)
{
OUString aExcelName; const ScUnoAddInFuncData* pFuncData = pColl->GetFuncData(i); if (pFuncData && pFuncData->GetExcelName( aDestLang, aExcelName, true))
{ // Note that function names not defined in OOXML but implemented by // Excel should have the "_xlfn." prefix. We have no way to check // though what an Add-In actually implements.
xMap->putExternalSoftly( GetCharClassEnglish()->uppercase(aExcelName), pFuncData->GetOriginalName());
}
}
}
bool ScCompiler::IsEnglishSymbol( const OUString& rName )
{ // function names are always case-insensitive
OUString aUpper = GetCharClassEnglish()->uppercase(rName);
// 1. built-in function name
formula::FormulaCompiler aCompiler;
OpCode eOp = aCompiler.GetEnglishOpCode( aUpper ); if ( eOp != ocNone )
{ returntrue;
} // 2. old add in functions if (ScGlobal::GetLegacyFuncCollection()->findByName(aUpper))
{ returntrue;
}
// 3. new (uno) add in functions
OUString aIntName = ScGlobal::GetAddInCollection()->FindFunction(aUpper, false); return !aIntName.isEmpty(); // no valid function name
}
const CharClass* ScCompiler::GetCharClassEnglish()
{
std::scoped_lock aGuard(gCharClassMutex); if (!pCharClassEnglish)
{
pCharClassEnglish = new CharClass( ::comphelper::getProcessComponentContext(),
LanguageTag( LANGUAGE_ENGLISH_US));
} return pCharClassEnglish;
}
const CharClass* ScCompiler::GetCharClassLocalized()
{ // Switching UI language requires restart; if not, we would have to // keep track of that.
std::scoped_lock aGuard(gCharClassMutex); if (!pCharClassLocalized)
{
pCharClassLocalized = new CharClass( ::comphelper::getProcessComponentContext(),
Application::GetSettings().GetUILanguageTag());
} return pCharClassLocalized;
}
void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar )
{
assert( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED && "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED"); if (eGrammar == GetGrammar()) return; // nothing to be done
// Save old grammar for call to SetGrammarAndRefConvention().
FormulaGrammar::Grammar eOldGrammar = GetGrammar(); // This also sets the grammar associated with the map!
SetFormulaLanguage( xMap);
// Override if necessary. if (eMyGrammar != GetGrammar())
SetGrammarAndRefConvention( eMyGrammar, eOldGrammar);
}
}
// Unclear how this was intended to be refreshed when the // grammar or sheet count is changed ? Ideally this would be // a method on Document that would globally cache these.
std::vector<OUString> &ScCompiler::GetSetupTabNames() const
{
std::vector<OUString> &rTabNames = const_cast<ScCompiler *>(this)->maTabNames;
if (rTabNames.empty())
{
rTabNames = rDoc.GetAllTableNames(); for (auto& rTabName : rTabNames)
ScCompiler::CheckTabQuotes(rTabName, formula::FormulaGrammar::extractRefConvention(meGrammar));
}
// The difference is needed for an uppercase() call that usually does not // result in different strings but for a few languages like Turkish; // though even de-DE and de-CH may differ in ß/SS handling.. // At least don't care if both are English. // The current locale is more likely to not be "en" so check first. const LanguageTag& rLT1 = ScGlobal::getCharClass().getLanguageTag(); const LanguageTag& rLT2 = pCharClass->getLanguageTag();
mbCharClassesDiffer = (rLT1 != rLT2 && (rLT1.getLanguage() != "en" || rLT2.getLanguage() != "en"));
staticbool lcl_isValidQuotedText( std::u16string_view rFormula, size_t nSrcPos, ParseResult& rRes )
{ // Tokens that start at ' can have anything in them until a final ' // but '' marks an escaped ' // We've earlier guaranteed that a string containing '' will be // surrounded by ' if (nSrcPos < rFormula.size() && rFormula[nSrcPos] == '\'')
{
size_t nPos = nSrcPos+1; while (nPos < rFormula.size())
{ if (rFormula[nPos] == '\'')
{ if ( (nPos+1 == rFormula.size()) || (rFormula[nPos+1] != '\'') )
{
rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
rRes.EndPos = nPos+1; returntrue;
}
++nPos;
}
++nPos;
}
}
returnfalse;
}
staticbool lcl_parseExternalName( const OUString& rSymbol,
OUString& rFile,
OUString& rName, const sal_Unicode cSep, const ScDocument& rDoc, const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
{ /* TODO: future versions will have to support sheet-local names too, thus
* return a possible sheet name as well. */ const sal_Unicode* const pStart = rSymbol.getStr(); const sal_Unicode* p = pStart;
sal_Int32 nLen = rSymbol.getLength();
OUString aTmpFile;
OUStringBuffer aTmpName;
sal_Int32 i = 0; bool bInName = false; if (cSep == '!')
{ // For XL use existing parser that resolves bracketed and quoted and // indexed external document names.
ScRange aRange;
OUString aStartTabName, aEndTabName;
ScRefFlags nFlags = ScRefFlags::ZERO;
p = aRange.Parse_XL_Header( p, rDoc, aTmpFile, aStartTabName,
aEndTabName, nFlags, true, pExternalLinks ); if (!p || p == pStart) returnfalse;
i = sal_Int32(p - pStart);
} for ( ; i < nLen; ++i, ++p)
{
sal_Unicode c = *p; if (i == 0)
{ if (c == '.' || c == cSep) returnfalse;
if (c == '\'')
{ // Move to the next char and loop until the second single // quote.
sal_Unicode cPrev = c;
++i; ++p; for (sal_Int32 j = i; j < nLen; ++j, ++p)
{
c = *p; if (c == '\'')
{ if (j == i)
{ // empty quote e.g. (=''!Name) returnfalse;
}
if (cPrev == '\'')
{ // two consecutive quotes equal a single quote in // the file name.
aTmpFile += OUStringChar(c);
cPrev = 'a';
} else
cPrev = c;
continue;
}
if (cPrev == '\'' && j != i)
{ // this is not a quote but the previous one is. This // ends the parsing of the quoted segment. At this // point, the current char must equal the separator // char.
i = j;
bInName = true;
aTmpName.append(c); // Keep the separator as part of the name. break;
}
aTmpFile += OUStringChar(c);
cPrev = c;
}
if (!bInName)
{ // premature ending of the quoted segment. returnfalse;
}
if (c != cSep)
{ // only the separator is allowed after the closing quote. returnfalse;
}
continue;
}
}
if (bInName)
{ if (c == cSep)
{ // A second separator ? Not a valid external name. returnfalse;
}
aTmpName.append(c);
} else
{ if (c == cSep)
{
bInName = true;
aTmpName.append(c); // Keep the separator as part of the name.
} else
{ do
{ if (rtl::isAsciiAlphanumeric(c)) // allowed. break;
if (c > 128) // non-ASCII character is allowed. break;
bool bValid = false; switch (c)
{ case'_': case'-': case'.': // these special characters are allowed.
bValid = true; break;
} if (bValid) break;
returnfalse;
} while (false);
aTmpFile += OUStringChar(c);
}
}
}
if (!bInName)
{ // No name found - most likely the symbol has no '!'s. returnfalse;
}
sal_Int32 nNameLen = aTmpName.getLength(); if (nNameLen < 2)
{ // Name must be at least 2-char long (separator plus name). returnfalse;
}
if (aTmpName[0] != cSep)
{ // 1st char of the name must equal the separator. returnfalse;
}
if (aTmpName[nNameLen-1] == '!')
{ // Check against #REF!. if (OUString::unacquired(aTmpName).equalsIgnoreAsciiCase("#REF!")) returnfalse;
}
rFile = aTmpFile;
rName = aTmpName.makeStringAndClear().copy(1); // Skip the first char as it is always the separator. returntrue;
}
if (eSingletonDisplay != SINGLETON_ROW)
{ if (!rRef.IsColRel())
rBuffer.append('$'); if (!rLimits.ValidCol(rAbsRef.Col()) || rRef.IsColDeleted())
rBuffer.append(rErrRef); else
MakeColStr(rLimits, rBuffer, rAbsRef.Col());
}
if (eSingletonDisplay != SINGLETON_COL)
{ if (!rRef.IsRowRel())
rBuffer.append('$'); if (!rLimits.ValidRow(rAbsRef.Row()) || rRef.IsRowDeleted())
rBuffer.append(rErrRef); else
MakeRowStr(rLimits, rBuffer, rAbsRef.Row());
}
}
static SingletonDisplay getSingletonDisplay( const ScSheetLimits& rLimits, const ScAddress& rAbs1, const ScAddress& rAbs2, const ScComplexRefData& rRef, bool bFromRangeName )
{ // If any part is error, display as such. if (!rLimits.ValidCol(rAbs1.Col()) || rRef.Ref1.IsColDeleted() || !rLimits.ValidRow(rAbs1.Row()) || rRef.Ref1.IsRowDeleted() ||
!rLimits.ValidCol(rAbs2.Col()) || rRef.Ref2.IsColDeleted() || !rLimits.ValidRow(rAbs2.Row()) || rRef.Ref2.IsRowDeleted()) return SINGLETON_NONE;
// A:A or $A:$A or A:$A or $A:A if (rRef.IsEntireCol(rLimits)) return SINGLETON_COL;
// Same if not in named expression and both rows of entire columns are // relative references. if (!bFromRangeName && rAbs1.Row() == 0 && rAbs2.Row() == rLimits.mnMaxRow &&
rRef.Ref1.IsRowRel() && rRef.Ref2.IsRowRel()) return SINGLETON_COL;
// 1:1 or $1:$1 or 1:$1 or $1:1 if (rRef.IsEntireRow(rLimits)) return SINGLETON_ROW;
// Same if not in named expression and both columns of entire rows are // relative references. if (!bFromRangeName && rAbs1.Col() == 0 && rAbs2.Col() == rLimits.mnMaxCol &&
rRef.Ref1.IsColRel() && rRef.Ref2.IsColRel()) return SINGLETON_ROW;
if (bODF)
rBuffer.append( '['); // Ensure that there's always a closing bracket, no premature returns. bool bEncodeUrl = bODF;
do
{ if (!makeExternalSingleRefStr(rLimits, rBuffer, rFileName, rTabName, rRef.Ref1, rPos, true, bEncodeUrl)) break;
rBuffer.append(':');
OUString aLastTabName; bool bDisplayTabName = (aAbsRange.aStart.Tab() != aAbsRange.aEnd.Tab()); if (bDisplayTabName)
{ // Get the name of the last table. if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, aAbsRange))
{
OSL_FAIL( "ConventionOOO_A1::makeExternalRefStrImpl: sheet name not found"); // aLastTabName contains #REF!, proceed.
}
} elseif (bODF)
rBuffer.append( '.'); // need at least the sheet separator in ODF
makeExternalSingleRefStr(rLimits,
rBuffer, rFileName, aLastTabName, rRef.Ref2, rPos, bDisplayTabName, bEncodeUrl);
} while (false);
staticvoid makeExternalDocStr( OUStringBuffer& rBuffer, std::u16string_view rFullName )
{ // Format that is easier to deal with inside OOo, because we use file // URL, and all characters are allowed. Check if it makes sense to do // it the way Gnumeric does it. Gnumeric doesn't use the URL form // and allows relative file path. // // ['file:///path/to/source/filename.xls']
virtualvoid parseExternalDocName( const OUString& rFormula, sal_Int32& rSrcPos ) const
{
sal_Int32 nLen = rFormula.getLength(); const sal_Unicode* p = rFormula.getStr();
sal_Unicode cPrev = 0; for (sal_Int32 i = rSrcPos; i < nLen; ++i)
{
sal_Unicode c = p[i]; if (i == rSrcPos)
{ // first character must be '['. if (c != '[') return;
} elseif (i == rSrcPos + 1)
{ // second character must be a single quote. if (c != '\'') return;
} elseif (c == '\'')
{ if (cPrev == '\'') // two successive single quote is treated as a single // valid character.
c = 'a';
} elseif (c == ']')
{ if (cPrev == '\'')
{ // valid source document path found. Increment the // current position to skip the source path.
rSrcPos = i + 1; if (rSrcPos >= nLen)
rSrcPos = nLen - 1; return;
} else return;
} else
{ // any other character if (i > rSrcPos + 2 && cPrev == '\'') // unless it's the 3rd character, a normal character // following immediately a single quote is invalid. return;
}
cPrev = c;
}
}
};
// Play fast and loose with invalid refs. There is not much point in producing // Foo!A1:#REF! versus #REF! at this point
ScAddress aAbs1 = aRef.Ref1.toAbs(rLimits, rPos), aAbs2;
virtualvoid makeExternalRefStr(
ScSheetLimits& rLimits,
OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 /*nFileId*/, const OUString& rFileName, const OUString& rTabName, const ScSingleRefData& rRef ) const override
{ // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1 // This is a little different from the format Excel uses, as Excel // puts [] only around the file name. But we need to enclose the // whole file path with [] because the file name can contain any // characters.
virtualvoid makeRefStr( ScSheetLimits& rLimits,
OUStringBuffer& rBuf,
formula::FormulaGrammar::Grammar eGram, const ScAddress& rPos, const OUString& rErrRef, const std::vector<OUString>& rTabNames, const ScComplexRefData& rRef, bool bSingleRef, bool bFromRangeName ) const override
{ // In OOXML relative references in named expressions are relative to // column 0 and row 0. Relative sheet references don't exist.
ScAddress aPos( rPos ); if (bFromRangeName)
{ // XXX NOTE: by decrementing the reference position we may end up // with resolved references with negative values. There's no proper // way to solve that or wrap them around without sheet dimensions // that are stored along. That, or blindly assume fixed dimensions // here and in import. /* TODO: maybe do that blind fixed dimensions wrap? */
aPos.SetCol(0);
aPos.SetRow(0);
}
if (rRef.Ref1.IsDeleted() || (!bSingleRef && rRef.Ref2.IsDeleted()))
{ // For OOXML write plain "#REF!" instead of detailed sheet/col/row // information.
rBuf.append(rErrRef); return;
}
/* TODO: add support for sheet local names, would be * [N]'Sheet Name'!DefinedName * Similar to makeExternalRefStr() but with DefinedName instead of
* CellStr. */
}
virtualvoid parseExternalDocName(const OUString& rFormula, sal_Int32& rSrcPos) const override
{
sal_Int32 nLen = rFormula.getLength(); const sal_Unicode* p = rFormula.getStr(); for (sal_Int32 i = rSrcPos; i < nLen; ++i)
{
sal_Unicode c = p[i]; if (i == rSrcPos)
{ // first character must be '['. if (c != '[') return;
} elseif (c == ']')
{
rSrcPos = i + 1; return;
}
}
}
virtualvoid makeExternalRefStr(
ScSheetLimits& rLimits,
OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/, const OUString& rTabName, const ScSingleRefData& rRef ) const override
{ // '[N]Sheet Name'!$A$1 or [N]SheetName!$A$1 // Where N is a 1-based positive integer number of a file name in OOXML // xl/externalLinks/externalLinkN.xml
virtualvoid makeExternalRefStr(
ScSheetLimits& rLimits,
OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, const OUString& /*rFileName*/, const std::vector<OUString>& rTabNames, const OUString& rTabName, const ScComplexRefData& rRef ) const override
{ // '[N]Sheet One':'Sheet Two'!A1:B2 or [N]SheetOne!A1:B2 // Actually Excel writes '[N]Sheet One:Sheet Two'!A1:B2 but reads the // simpler to produce and more logical form with independently quoted // sheet names as well. The [N] having to be within the quoted sheet // name is ugly enough...
// Play fast and loose with invalid refs. There is not much point in producing // Foo!A1:#REF! versus #REF! at this point if (!rLimits.ValidCol(aAbsRef.aStart.Col()) || !rLimits.ValidRow(aAbsRef.aStart.Row()))
{
rBuf.append(rErrRef); return;
}
r1c1_add_row(rBuf, rRef.Ref1, aAbsRef.aStart);
r1c1_add_col(rBuf, rRef.Ref1, aAbsRef.aStart); // We can't parse a single col/row reference in the context of a R1C1 // 3D reference back yet, otherwise (if Excel understands it) an // additional condition similar to ConventionXL_A1::makeRefStr() could // be // // && (aAbsRef.aStart.Row() != aAbsRef.aEnd.Row() || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel() || // aAbsRef.aStart.Col() != aAbsRef.aEnd.Col() || rRef.Ref1.IsColRel() != rRef.Ref2.IsColRel()) if (!bSingleRef)
{
rBuf.append( ':' );
r1c1_add_row(rBuf, rRef.Ref2, aAbsRef.aEnd);
r1c1_add_col(rBuf, rRef.Ref2, aAbsRef.aEnd);
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.20Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.