SCSIZE nMatCols = 1, nMatRows = 1, nNode = 0; // In array/matrix context node elements' results are to be // subsequently stored. Check this before obtaining any argument from // the stack so the stack type can be used. if (pJumpMatrix || IsInArrayContext())
{ if (pJumpMatrix)
{ // Single result, GetString() will retrieve the corresponding // argument and JumpMatrix() will store it at the proper // position. Note that nMatCols and nMatRows are still 1.
SCSIZE nCurCol = 0, nCurRow = 0;
pJumpMatrix->GetPos( nCurCol, nCurRow);
nNode = nCurRow;
} elseif (bMatrixFormula)
{ // If there is no formula cell then continue with a single // result. if (pMyFormulaCell)
{
SCCOL nCols;
SCROW nRows;
pMyFormulaCell->GetMatColsRows( nCols, nRows);
nMatCols = nCols;
nMatRows = nRows;
}
} elseif (GetStackType() == formula::svMatrix)
{ const ScMatrix* pPathMatrix = pStack[sp-1]->GetMatrix(); if (!pPathMatrix)
{
PushIllegalParameter(); return;
}
pPathMatrix->GetDimensions( nMatCols, nMatRows);
/* TODO: it is unclear what should happen if there are *differentpathargumentsinmatrixelements.Wemayhaveto *evaluateeach,andforrepeatedidenticalpathsuse *subsequentnodes.Asis,thepathat0,0isusedasobtained
* by GetString(). */
}
} if (!nMatCols || !nMatRows)
{
PushNoValue(); return;
}
switch(pXPathObj->type)
{ case XPATH_UNDEFINED:
PushNoValue(); break; case XPATH_NODESET:
{
xmlNodeSetPtr pNodeSet = pXPathObj->nodesetval; if(!pNodeSet)
{
PushError( FormulaError::NoValue ); return;
}
const size_t nSize = pNodeSet->nodeNr; if (nNode >= nSize)
{ // For pJumpMatrix
PushError( FormulaError::NotAvailable); return;
}
/* TODO: for nMatCols>1 IF stack type is svMatrix, i.e. *pPathMatrix!=nullptr,wemaywantaresultmatrixwith *nMatColscolumnsaswell,butclarifyfirsthowtotreat
* differing path elements. */
if (!mpLinkManager)
{ if (!mrDoc.IsFunctionAccess() || mrDoc.HasLinkFormulaNeedingCheck())
{
PushError( FormulaError::NoValue);
} else
{
OUString aResult; if (lcl_FunctionAccessLoadWebServiceLink( aResult, &mrDoc, aURI))
PushString( aResult); else
PushError( FormulaError::NoValue);
} return;
}
// Need to reinterpret after loading (build links)
pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
// while the link is not evaluated, idle must be disabled (to avoid circular references) bool bOldEnabled = mrDoc.IsIdleEnabled();
mrDoc.EnableIdle(false);
// Get/ Create link object
ScWebServiceLink* pLink = lcl_GetWebServiceLink(mpLinkManager, aURI);
if (!pLink)
{
pLink = new ScWebServiceLink(&mrDoc, aURI);
mpLinkManager->InsertFileLink(*pLink, sfx2::SvBaseLinkObjectType::ClientFile, aURI); if ( mpLinkManager->GetLinks().size() == 1 ) // the first one?
{
SfxBindings* pBindings = mrDoc.GetViewBindings(); if (pBindings)
pBindings->Invalidate( SID_LINKS ); // Link-Manager enabled
}
//if the document was just loaded, but the ScDdeLink entry was missing, then //don't update this link until the links are updated in response to the users //decision if (!mrDoc.HasLinkFormulaNeedingCheck())
{
pLink->Update();
}
if (pMyFormulaCell)
{ // StartListening after the Update to avoid circular references
pMyFormulaCell->StartListening(*pLink);
}
} else
{ if (pMyFormulaCell)
pMyFormulaCell->StartListening(*pLink);
}
// If a new Error from Reschedule appears when the link is executed then reset the errorflag if (pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE && !bWasError)
pMyFormulaCell->SetErrCode(FormulaError::NONE);
// check the value if (pLink->HasResult())
PushString(pLink->GetResult()); elseif (mrDoc.HasLinkFormulaNeedingCheck())
{ // If this formula cell is recalculated just after load and the // expression is exactly WEBSERVICE("literal_URI") (i.e. no other // calculation involved, not even a cell reference) and a cached // result is set as hybrid string then use that as result value to // prevent a #VALUE! result due to the "Automatic update of // external links has been disabled." // This will work only once, as the new formula cell result won't // be a hybrid anymore. /* TODO: the FormulaError::LinkFormulaNeedingCheck could be used as *asignalfortheformulacelltokeepthehybridstringas *resultoftheoverallformula*iff*nohigherprioritized *ScRecalcModethanONLOAD_LENIENTispresentintheentire *document(i.e.theformularesultcouldnotbeinfluencedbyan *ONLOAD_MUSTorALWAYSrecalc,necessaryaswedon'ttrack *interimresultsofsubexpressionsthatcouldbecompared),which *alsomeanstotracksettingScRecalcModesomehow...notethisis
* just a vague idea so far and might or might not work. */ if (pMyFormulaCell && pMyFormulaCell->HasHybridStringResult())
{ if (pMyFormulaCell->GetCode()->GetCodeLen() == 2)
{
formula::FormulaToken const * const * pRPN = pMyFormulaCell->GetCode()->GetCode(); if (pRPN[0]->GetType() == formula::svString && pRPN[1]->GetOpCode() == ocWebservice)
PushString( pMyFormulaCell->GetResultString()); else
PushError(FormulaError::LinkFormulaNeedingCheck);
} else
PushError(FormulaError::LinkFormulaNeedingCheck);
} else
PushError(FormulaError::LinkFormulaNeedingCheck);
} else
PushError(FormulaError::NoValue);
OString aUtf8Str( aStr.toUtf8()); const sal_Int32 nLen = aUtf8Str.getLength();
OStringBuffer aUrlBuf( nLen ); for ( int i = 0; i < nLen; i++ )
{ char c = aUtf8Str[ i ]; if ( rtl::isAsciiAlphanumeric( static_cast<unsignedchar>( c ) ) || c == '-' || c == '_' )
aUrlBuf.append( c ); else
{
aUrlBuf.append( '%' );
OString convertedChar = OString::number( static_cast<unsignedchar>( c ), 16 ).toAsciiUpperCase(); // RFC 3986 indicates: // "A percent-encoded octet is encoded as a character triplet, // consisting of the percent character "%" followed by the two hexadecimal digits // representing that octet's numeric value" if (convertedChar.getLength() == 1)
aUrlBuf.append("0");
aUrlBuf.append(convertedChar);
}
}
PushString( OUString::fromUtf8( aUrlBuf ) );
}
void ScInterpreter::ScDebugVar()
{ // This is to be used by developers only! Never document this for end // users. This is a convenient way to extract arbitrary internal state to // a cell for easier debugging.
if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
{
PushError(FormulaError::NoName); return;
}
if (!MustHaveParamCount(GetByte(), 1)) return;
rtl_uString* p = GetString().getDataIgnoreCase(); if (!p)
{
PushIllegalParameter(); return;
}
OUString aStrUpper(p);
if (aStrUpper == "PIVOTCOUNT")
{ // Set the number of pivot tables in the document.