/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" // INCLUDE --------------------------------------------------------------- #include #include #include #include #include #include "token.hxx" #include "tokenarray.hxx" #include "compiler.hxx" #include #include "rechead.hxx" #include "parclass.hxx" #include "jumpmatrix.hxx" #include "rangeseq.hxx" #include "externalrefmgr.hxx" #include "document.hxx" using ::std::vector; #include #include #include using namespace formula; using namespace com::sun::star; namespace { void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI ) { rRef.InitFlags(); rRef.nCol = static_cast(rAPI.Column); rRef.nRow = static_cast(rAPI.Row); rRef.nTab = static_cast(rAPI.Sheet); rRef.nRelCol = static_cast(rAPI.RelativeColumn); rRef.nRelRow = static_cast(rAPI.RelativeRow); rRef.nRelTab = static_cast(rAPI.RelativeSheet); rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 ); rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 ); rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 ); rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 ); rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 ); rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 ); rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 ); rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 ); } void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI ) { rRef.InitFlags(); rRef.nCol = static_cast(rAPI.Column); rRef.nRow = static_cast(rAPI.Row); rRef.nTab = 0; rRef.nRelCol = static_cast(rAPI.RelativeColumn); rRef.nRelRow = static_cast(rAPI.RelativeRow); rRef.nRelTab = 0; rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 ); rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 ); rRef.SetTabRel( false ); // sheet index must be absolute for external refs rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 ); rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 ); rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 ); rRef.SetRelName( false ); } // } // namespace // // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch // SubCode via FormulaTokenIterator Push/Pop moeglich IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 ) // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2) // Since RawTokens are temporary for the compiler, don't align on 4k and waste memory. // ScRawToken size is FixMembers + MAXSTRLEN + ~4 ~= 1036 IMPL_FIXEDMEMPOOL_NEWDEL( ScRawToken, 8, 4 ) // Some ScDoubleRawToken, FixMembers + sizeof(double) ~= 16 const sal_uInt16 nMemPoolDoubleRawToken = 0x0400 / sizeof(ScDoubleRawToken); IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken, nMemPoolDoubleRawToken, nMemPoolDoubleRawToken ) // Need a whole bunch of ScSingleRefToken const sal_uInt16 nMemPoolSingleRefToken = (0x4000 - 64) / sizeof(ScSingleRefToken); IMPL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken, nMemPoolSingleRefToken, nMemPoolSingleRefToken ) // Need quite a lot of ScDoubleRefToken const sal_uInt16 nMemPoolDoubleRefToken = (0x2000 - 64) / sizeof(ScDoubleRefToken); IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken, nMemPoolDoubleRefToken, nMemPoolDoubleRefToken ) // --- helpers -------------------------------------------------------------- inline sal_Bool lcl_IsReference( OpCode eOp, StackVar eType ) { return (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef)) || (eOp == ocColRowNameAuto && eType == svDoubleRef) || (eOp == ocColRowName && eType == svSingleRef) || (eOp == ocMatRef && eType == svSingleRef) ; } // --- class ScRawToken ----------------------------------------------------- xub_StrLen ScRawToken::GetStrLen( const sal_Unicode* pStr ) { if ( !pStr ) return 0; register const sal_Unicode* p = pStr; while ( *p ) p++; return sal::static_int_cast( p - pStr ); } void ScRawToken::SetOpCode( OpCode e ) { eOp = e; switch (eOp) { case ocIf: eType = svJump; nJump[ 0 ] = 3; // If, Else, Behind break; case ocChose: eType = svJump; nJump[ 0 ] = MAXJUMPCOUNT+1; break; case ocMissing: eType = svMissing; break; case ocSep: case ocOpen: case ocClose: case ocArrayRowSep: case ocArrayColSep: case ocArrayOpen: case ocArrayClose: eType = svSep; break; default: eType = svByte; sbyte.cByte = 0; sbyte.bHasForceArray = ScParameterClassification::HasForceArray( eOp); } nRefCnt = 0; } void ScRawToken::SetString( const sal_Unicode* pStr ) { eOp = ocPush; eType = svString; if ( pStr ) { xub_StrLen nLen = GetStrLen( pStr ) + 1; if( nLen > MAXSTRLEN ) nLen = MAXSTRLEN; memcpy( cStr, pStr, GetStrLenBytes( nLen ) ); cStr[ nLen-1 ] = 0; } else cStr[0] = 0; nRefCnt = 0; } void ScRawToken::SetSingleReference( const ScSingleRefData& rRef ) { eOp = ocPush; eType = svSingleRef; aRef.Ref1 = aRef.Ref2 = rRef; nRefCnt = 0; } void ScRawToken::SetDoubleReference( const ScComplexRefData& rRef ) { eOp = ocPush; eType = svDoubleRef; aRef = rRef; nRefCnt = 0; } void ScRawToken::SetDouble(double rVal) { eOp = ocPush; eType = svDouble; nValue = rVal; nRefCnt = 0; } void ScRawToken::SetName( sal_uInt16 n ) { eOp = ocName; eType = svIndex; nIndex = n; nRefCnt = 0; } void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) { eOp = ocExternalRef; eType = svExternalSingleRef; nRefCnt = 0; extref.nFileId = nFileId; extref.aRef.Ref1 = extref.aRef.Ref2 = rRef; xub_StrLen n = rTabName.Len(); memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode)); extref.cTabName[n] = 0; } void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef ) { eOp = ocExternalRef; eType = svExternalDoubleRef; nRefCnt = 0; extref.nFileId = nFileId; extref.aRef = rRef; xub_StrLen n = rTabName.Len(); memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode)); extref.cTabName[n] = 0; } void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName ) { eOp = ocExternalRef; eType = svExternalName; nRefCnt = 0; extname.nFileId = nFileId; xub_StrLen n = rName.Len(); memcpy(extname.cName, rName.GetBuffer(), n*sizeof(sal_Unicode)); extname.cName[n] = 0; } //UNUSED2008-05 void ScRawToken::SetInt(int rVal) //UNUSED2008-05 { //UNUSED2008-05 eOp = ocPush; //UNUSED2008-05 eType = svDouble; //UNUSED2008-05 nValue = (double)rVal; //UNUSED2008-05 nRefCnt = 0; //UNUSED2008-05 //UNUSED2008-05 } //UNUSED2008-05 void ScRawToken::SetMatrix( ScMatrix* p ) //UNUSED2008-05 { //UNUSED2008-05 eOp = ocPush; //UNUSED2008-05 eType = svMatrix; //UNUSED2008-05 pMat = p; //UNUSED2008-05 nRefCnt = 0; //UNUSED2008-05 } //UNUSED2008-05 //UNUSED2008-05 ScComplexRefData& ScRawToken::GetReference() //UNUSED2008-05 { //UNUSED2008-05 DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "GetReference: no Ref" ); //UNUSED2008-05 return aRef; //UNUSED2008-05 } //UNUSED2008-05 //UNUSED2008-05 void ScRawToken::SetReference( ScComplexRefData& rRef ) //UNUSED2008-05 { //UNUSED2008-05 DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "SetReference: no Ref" ); //UNUSED2008-05 aRef = rRef; //UNUSED2008-05 if( GetType() == svSingleRef ) //UNUSED2008-05 aRef.Ref2 = aRef.Ref1; //UNUSED2008-05 } void ScRawToken::SetExternal( const sal_Unicode* pStr ) { eOp = ocExternal; eType = svExternal; xub_StrLen nLen = GetStrLen( pStr ) + 1; if( nLen >= MAXSTRLEN ) nLen = MAXSTRLEN-1; // Platz fuer Byte-Parameter lassen! memcpy( cStr+1, pStr, GetStrLenBytes( nLen ) ); cStr[ nLen+1 ] = 0; nRefCnt = 0; } sal_uInt16 lcl_ScRawTokenOffset() { // offset of sbyte in ScRawToken // offsetof(ScRawToken, sbyte) gives a warning with gcc, because ScRawToken is no POD ScRawToken aToken; return static_cast( reinterpret_cast(&aToken.sbyte) - reinterpret_cast(&aToken) ); } ScRawToken* ScRawToken::Clone() const { ScRawToken* p; if ( eType == svDouble ) { p = (ScRawToken*) new ScDoubleRawToken; p->eOp = eOp; p->eType = eType; p->nValue = nValue; } else { static sal_uInt16 nOffset = lcl_ScRawTokenOffset(); // offset of sbyte sal_uInt16 n = nOffset; if (eOp == ocExternalRef) { switch (eType) { case svExternalSingleRef: case svExternalDoubleRef: n += sizeof(extref); break; case svExternalName: n += sizeof(extname); break; default: { DBG_ERROR1( "unknown ScRawToken::Clone() external type %d", int(eType)); } } } else { switch( eType ) { case svSep: break; case svByte: n += sizeof(ScRawToken::sbyte); break; case svDouble: n += sizeof(double); break; case svString: n = sal::static_int_cast( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break; case svSingleRef: case svDoubleRef: n += sizeof(aRef); break; case svMatrix: n += sizeof(ScMatrix*); break; case svIndex: n += sizeof(sal_uInt16); break; case svJump: n += nJump[ 0 ] * 2 + 2; break; case svExternal: n = sal::static_int_cast( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break; default: { DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType)); } } } p = (ScRawToken*) new sal_uInt8[ n ]; memcpy( p, this, n * sizeof(sal_uInt8) ); } p->nRefCnt = 0; p->bRaw = sal_False; return p; } FormulaToken* ScRawToken::CreateToken() const { #ifdef DBG_UTIL #define IF_NOT_OPCODE_ERROR(o,c) if (eOp!=o) DBG_ERROR1( #c "::ctor: OpCode %d lost, converted to " #o "; maybe inherit from FormulaToken instead!", int(eOp)) #else #define IF_NOT_OPCODE_ERROR(o,c) #endif switch ( GetType() ) { case svByte : return new FormulaByteToken( eOp, sbyte.cByte, sbyte.bHasForceArray ); case svDouble : IF_NOT_OPCODE_ERROR( ocPush, FormulaDoubleToken); return new FormulaDoubleToken( nValue ); case svString : if (eOp == ocPush) return new FormulaStringToken( String( cStr ) ); else return new FormulaStringOpToken( eOp, String( cStr ) ); case svSingleRef : if (eOp == ocPush) return new ScSingleRefToken( aRef.Ref1 ); else return new ScSingleRefToken( aRef.Ref1, eOp ); case svDoubleRef : if (eOp == ocPush) return new ScDoubleRefToken( aRef ); else return new ScDoubleRefToken( aRef, eOp ); case svMatrix : IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken); return new ScMatrixToken( pMat ); case svIndex : return new FormulaIndexToken( eOp, nIndex ); case svExternalSingleRef: { String aTabName(extref.cTabName); return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1); } case svExternalDoubleRef: { String aTabName(extref.cTabName); return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef); } case svExternalName: { String aName(extname.cName); return new ScExternalNameToken( extname.nFileId, aName ); } case svJump : return new FormulaJumpToken( eOp, (short*) nJump ); case svExternal : return new FormulaExternalToken( eOp, sbyte.cByte, String( cStr+1 ) ); case svFAP : return new FormulaFAPToken( eOp, sbyte.cByte, NULL ); case svMissing : IF_NOT_OPCODE_ERROR( ocMissing, FormulaMissingToken); return new FormulaMissingToken; case svSep : return new FormulaToken( svSep,eOp ); case svUnknown : return new FormulaUnknownToken( eOp ); default: { DBG_ERROR1( "unknown ScRawToken::CreateToken() type %d", int(GetType())); return new FormulaUnknownToken( ocBad ); } } #undef IF_NOT_OPCODE_ERROR } void ScRawToken::Delete() { if ( bRaw ) delete this; // FixedMemPool ScRawToken else { // created per Clone switch ( eType ) { case svDouble : delete (ScDoubleRawToken*) this; // FixedMemPool ScDoubleRawToken break; default: delete [] (sal_uInt8*) this; } } } // --- class ScToken -------------------------------------------------------- ScSingleRefData lcl_ScToken_InitSingleRef() { ScSingleRefData aRef; aRef.InitAddress( ScAddress() ); return aRef; } ScComplexRefData lcl_ScToken_InitDoubleRef() { ScComplexRefData aRef; aRef.Ref1 = lcl_ScToken_InitSingleRef(); aRef.Ref2 = aRef.Ref1; return aRef; } ScToken::~ScToken() { } // TextEqual: if same formula entered (for optimization in sort) sal_Bool ScToken::TextEqual( const FormulaToken& _rToken ) const { if ( eType == svSingleRef || eType == svDoubleRef ) { // in relative Refs only compare relative parts if ( eType != _rToken.GetType() || GetOpCode() != _rToken.GetOpCode() ) return sal_False; const ScToken& rToken = static_cast(_rToken); ScComplexRefData aTemp1; if ( eType == svSingleRef ) { aTemp1.Ref1 = GetSingleRef(); aTemp1.Ref2 = aTemp1.Ref1; } else aTemp1 = GetDoubleRef(); ScComplexRefData aTemp2; if ( rToken.eType == svSingleRef ) { aTemp2.Ref1 = rToken.GetSingleRef(); aTemp2.Ref2 = aTemp2.Ref1; } else aTemp2 = rToken.GetDoubleRef(); ScAddress aPos; aTemp1.SmartRelAbs(aPos); aTemp2.SmartRelAbs(aPos); // memcmp doesn't work because of the alignment byte after bFlags. // After SmartRelAbs only absolute parts have to be compared. return aTemp1.Ref1.nCol == aTemp2.Ref1.nCol && aTemp1.Ref1.nRow == aTemp2.Ref1.nRow && aTemp1.Ref1.nTab == aTemp2.Ref1.nTab && aTemp1.Ref1.bFlags == aTemp2.Ref1.bFlags && aTemp1.Ref2.nCol == aTemp2.Ref2.nCol && aTemp1.Ref2.nRow == aTemp2.Ref2.nRow && aTemp1.Ref2.nTab == aTemp2.Ref2.nTab && aTemp1.Ref2.bFlags == aTemp2.Ref2.bFlags; } else return *this == _rToken; // else normal operator== } sal_Bool ScToken::Is3DRef() const { switch ( eType ) { case svDoubleRef : if ( GetSingleRef2().IsFlag3D() ) return sal_True; //! fallthru case svSingleRef : if ( GetSingleRef().IsFlag3D() ) return sal_True; break; case svExternalSingleRef: case svExternalDoubleRef: return sal_True; default: { // added to avoid warnings } } return sal_False; } // static FormulaTokenRef ScToken::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, const ScAddress & rPos, bool bReuseDoubleRef ) { StackVar sv1, sv2; // Doing a RangeOp with RefList is probably utter nonsense, but Xcl // supports it, so do we. if (((sv1 = rTok1.GetType()) != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList && sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef ) || ((sv2 = rTok2.GetType()) != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)) return NULL; ScToken *p1 = static_cast(&rTok1); ScToken *p2 = static_cast(&rTok2); ScTokenRef xRes; bool bExternal = (sv1 == svExternalSingleRef); if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef) { // Range references like Sheet1.A1:A2 are generalized and built by // first creating a DoubleRef from the first SingleRef, effectively // generating Sheet1.A1:A1, and then extending that with A2 as if // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the // references apply as well. /* Given the current structure of external references an external * reference can only be extended if the second reference does not * point to a different sheet. 'file'#Sheet1.A1:A2 is ok, * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a * svSingleRef whether the sheet would be different from the one given * in the external reference, we have to bail out if there is any sheet * specified. NOTE: Xcl does handle external 3D references as in * '[file]Sheet1:Sheet2'!A1:A2 * * FIXME: For OOo syntax be smart and remember an external singleref * encountered and if followed by ocRange and singleref, create an * external singleref for the second singleref. Both could then be * merged here. For Xcl syntax already parse an external range * reference entirely, cumbersome. */ const ScSingleRefData& rRef2 = p2->GetSingleRef(); if (bExternal && rRef2.IsFlag3D()) return NULL; ScComplexRefData aRef; aRef.Ref1 = aRef.Ref2 = p1->GetSingleRef(); aRef.Ref2.SetFlag3D( false); aRef.Extend( rRef2, rPos); if (bExternal) xRes = new ScExternalDoubleRefToken( p1->GetIndex(), p1->GetString(), aRef); else xRes = new ScDoubleRefToken( aRef); } else { bExternal |= (sv1 == svExternalDoubleRef); const ScRefList* pRefList = NULL; if (sv1 == svDoubleRef) { xRes = (bReuseDoubleRef && p1->GetRef() == 1 ? p1 : static_cast(p1->Clone())); sv1 = svUnknown; // mark as handled } else if (sv2 == svDoubleRef) { xRes = (bReuseDoubleRef && p2->GetRef() == 1 ? p2 : static_cast(p2->Clone())); sv2 = svUnknown; // mark as handled } else if (sv1 == svRefList) pRefList = p1->GetRefList(); else if (sv2 == svRefList) pRefList = p2->GetRefList(); if (pRefList) { if (!pRefList->size()) return NULL; if (bExternal) return NULL; // external reference list not possible xRes = new ScDoubleRefToken( (*pRefList)[0] ); } if (!xRes) return NULL; // shouldn't happen.. StackVar sv[2] = { sv1, sv2 }; ScToken* pt[2] = { p1, p2 }; ScComplexRefData& rRef = xRes->GetDoubleRef(); for (size_t i=0; i<2; ++i) { switch (sv[i]) { case svSingleRef: rRef.Extend( pt[i]->GetSingleRef(), rPos); break; case svDoubleRef: rRef.Extend( pt[i]->GetDoubleRef(), rPos); break; case svRefList: { const ScRefList* p = pt[i]->GetRefList(); if (!p->size()) return NULL; ScRefList::const_iterator it( p->begin()); ScRefList::const_iterator end( p->end()); for ( ; it != end; ++it) { rRef.Extend( *it, rPos); } } break; case svExternalSingleRef: if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D()) return NULL; // no other sheets with external refs else rRef.Extend( pt[i]->GetSingleRef(), rPos); break; case svExternalDoubleRef: if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D()) return NULL; // no other sheets with external refs else rRef.Extend( pt[i]->GetDoubleRef(), rPos); break; default: ; // nothing, prevent compiler warning } } } return FormulaTokenRef(xRes.get()); } const ScSingleRefData& ScToken::GetSingleRef() const { DBG_ERRORFILE( "ScToken::GetSingleRef: virtual dummy called" ); static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); return aDummySingleRef; } ScSingleRefData& ScToken::GetSingleRef() { DBG_ERRORFILE( "ScToken::GetSingleRef: virtual dummy called" ); static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); return aDummySingleRef; } const ScComplexRefData& ScToken::GetDoubleRef() const { DBG_ERRORFILE( "ScToken::GetDoubleRef: virtual dummy called" ); static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef(); return aDummyDoubleRef; } ScComplexRefData& ScToken::GetDoubleRef() { DBG_ERRORFILE( "ScToken::GetDoubleRef: virtual dummy called" ); static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef(); return aDummyDoubleRef; } const ScSingleRefData& ScToken::GetSingleRef2() const { DBG_ERRORFILE( "ScToken::GetSingleRef2: virtual dummy called" ); static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); return aDummySingleRef; } ScSingleRefData& ScToken::GetSingleRef2() { DBG_ERRORFILE( "ScToken::GetSingleRef2: virtual dummy called" ); static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); return aDummySingleRef; } void ScToken::CalcAbsIfRel( const ScAddress& /* rPos */ ) { DBG_ERRORFILE( "ScToken::CalcAbsIfRel: virtual dummy called" ); } void ScToken::CalcRelFromAbs( const ScAddress& /* rPos */ ) { DBG_ERRORFILE( "ScToken::CalcRelFromAbs: virtual dummy called" ); } const ScMatrix* ScToken::GetMatrix() const { DBG_ERRORFILE( "ScToken::GetMatrix: virtual dummy called" ); return NULL; } ScMatrix* ScToken::GetMatrix() { DBG_ERRORFILE( "ScToken::GetMatrix: virtual dummy called" ); return NULL; } ScJumpMatrix* ScToken::GetJumpMatrix() const { DBG_ERRORFILE( "ScToken::GetJumpMatrix: virtual dummy called" ); return NULL; } const ScRefList* ScToken::GetRefList() const { DBG_ERRORFILE( "ScToken::GetRefList: virtual dummy called" ); return NULL; } ScRefList* ScToken::GetRefList() { DBG_ERRORFILE( "ScToken::GetRefList: virtual dummy called" ); return NULL; } // ========================================================================== // real implementations of virtual functions // -------------------------------------------------------------------------- const ScSingleRefData& ScSingleRefToken::GetSingleRef() const { return aSingleRef; } ScSingleRefData& ScSingleRefToken::GetSingleRef() { return aSingleRef; } void ScSingleRefToken::CalcAbsIfRel( const ScAddress& rPos ) { aSingleRef.CalcAbsIfRel( rPos ); } void ScSingleRefToken::CalcRelFromAbs( const ScAddress& rPos ) { aSingleRef.CalcRelFromAbs( rPos ); } sal_Bool ScSingleRefToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && aSingleRef == static_cast(r).GetSingleRef(); } const ScSingleRefData& ScDoubleRefToken::GetSingleRef() const { return aDoubleRef.Ref1; } ScSingleRefData& ScDoubleRefToken::GetSingleRef() { return aDoubleRef.Ref1; } const ScComplexRefData& ScDoubleRefToken::GetDoubleRef() const { return aDoubleRef; } ScComplexRefData& ScDoubleRefToken::GetDoubleRef() { return aDoubleRef; } const ScSingleRefData& ScDoubleRefToken::GetSingleRef2() const { return aDoubleRef.Ref2; } ScSingleRefData& ScDoubleRefToken::GetSingleRef2() { return aDoubleRef.Ref2; } void ScDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos ) { aDoubleRef.CalcAbsIfRel( rPos ); } void ScDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos ) { aDoubleRef.CalcRelFromAbs( rPos ); } sal_Bool ScDoubleRefToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && aDoubleRef == static_cast(r).GetDoubleRef(); } const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; } ScRefList* ScRefListToken::GetRefList() { return &aRefList; } void ScRefListToken::CalcAbsIfRel( const ScAddress& rPos ) { for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it) (*it).CalcAbsIfRel( rPos); } void ScRefListToken::CalcRelFromAbs( const ScAddress& rPos ) { for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it) (*it).CalcRelFromAbs( rPos); } sal_Bool ScRefListToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && &aRefList == static_cast(r).GetRefList(); } const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix; } ScMatrix* ScMatrixToken::GetMatrix() { return pMatrix; } sal_Bool ScMatrixToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && pMatrix == static_cast(r).GetMatrix(); } // ============================================================================ ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) : ScToken( svExternalSingleRef, ocExternalRef), mnFileId(nFileId), maTabName(rTabName), maSingleRef(r) { } ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) : ScToken(r), mnFileId(r.mnFileId), maTabName(r.maTabName), maSingleRef(r.maSingleRef) { } ScExternalSingleRefToken::~ScExternalSingleRefToken() { } sal_uInt16 ScExternalSingleRefToken::GetIndex() const { return mnFileId; } const String& ScExternalSingleRefToken::GetString() const { return maTabName; } const ScSingleRefData& ScExternalSingleRefToken::GetSingleRef() const { return maSingleRef; } ScSingleRefData& ScExternalSingleRefToken::GetSingleRef() { return maSingleRef; } void ScExternalSingleRefToken::CalcAbsIfRel( const ScAddress& rPos ) { maSingleRef.CalcAbsIfRel( rPos ); } void ScExternalSingleRefToken::CalcRelFromAbs( const ScAddress& rPos ) { maSingleRef.CalcRelFromAbs( rPos ); } sal_Bool ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const { if (!FormulaToken::operator==(r)) return false; if (mnFileId != r.GetIndex()) return false; if (maTabName != r.GetString()) return false; return maSingleRef == static_cast(r).GetSingleRef(); } // ============================================================================ ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r ) : ScToken( svExternalDoubleRef, ocExternalRef), mnFileId(nFileId), maTabName(rTabName), maDoubleRef(r) { } ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) : ScToken(r), mnFileId(r.mnFileId), maTabName(r.maTabName), maDoubleRef(r.maDoubleRef) { } ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalSingleRefToken& r ) : ScToken( svExternalDoubleRef, ocExternalRef), mnFileId( r.GetIndex()), maTabName( r.GetString()) { maDoubleRef.Ref1 = maDoubleRef.Ref2 = r.GetSingleRef(); } ScExternalDoubleRefToken::~ScExternalDoubleRefToken() { } sal_uInt16 ScExternalDoubleRefToken::GetIndex() const { return mnFileId; } const String& ScExternalDoubleRefToken::GetString() const { return maTabName; } const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef() const { return maDoubleRef.Ref1; } ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef() { return maDoubleRef.Ref1; } const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const { return maDoubleRef.Ref2; } ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2() { return maDoubleRef.Ref2; } const ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef() const { return maDoubleRef; } ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef() { return maDoubleRef; } void ScExternalDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos ) { maDoubleRef.CalcAbsIfRel( rPos ); } void ScExternalDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos ) { maDoubleRef.CalcRelFromAbs( rPos ); } sal_Bool ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const { if (!ScToken::operator==(r)) return false; if (mnFileId != r.GetIndex()) return false; if (maTabName != r.GetString()) return false; return maDoubleRef == static_cast(r).GetDoubleRef(); } // ============================================================================ ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) : ScToken( svExternalName, ocExternalRef), mnFileId(nFileId), maName(rName) { } ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) : ScToken(r), mnFileId(r.mnFileId), maName(r.maName) { } ScExternalNameToken::~ScExternalNameToken() {} sal_uInt16 ScExternalNameToken::GetIndex() const { return mnFileId; } const String& ScExternalNameToken::GetString() const { return maName; } sal_Bool ScExternalNameToken::operator==( const FormulaToken& r ) const { if ( !FormulaToken::operator==(r) ) return false; if (mnFileId != r.GetIndex()) return false; xub_StrLen nLen = maName.Len(); const String& rName = r.GetString(); if (nLen != rName.Len()) return false; const sal_Unicode* p1 = maName.GetBuffer(); const sal_Unicode* p2 = rName.GetBuffer(); for (xub_StrLen j = 0; j < nLen; ++j) { if (p1[j] != p2[j]) return false; } return true; } // ============================================================================ ScJumpMatrix* ScJumpMatrixToken::GetJumpMatrix() const { return pJumpMatrix; } sal_Bool ScJumpMatrixToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && pJumpMatrix == static_cast(r).GetJumpMatrix(); } ScJumpMatrixToken::~ScJumpMatrixToken() { delete pJumpMatrix; } double ScEmptyCellToken::GetDouble() const { return 0.0; } const String & ScEmptyCellToken::GetString() const { static String aDummyString; return aDummyString; } sal_Bool ScEmptyCellToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() && bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString(); } double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); } const String & ScMatrixCellResultToken::GetString() const { return xUpperLeft->GetString(); } const ScMatrix* ScMatrixCellResultToken::GetMatrix() const { return xMatrix; } // Non-const GetMatrix() is private and unused but must be implemented to // satisfy vtable linkage. ScMatrix* ScMatrixCellResultToken::GetMatrix() { return const_cast(xMatrix.operator->()); } sal_Bool ScMatrixCellResultToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && xUpperLeft == static_cast(r).xUpperLeft && xMatrix == static_cast(r).xMatrix; } sal_Bool ScMatrixFormulaCellToken::operator==( const FormulaToken& r ) const { const ScMatrixFormulaCellToken* p = dynamic_cast(&r); return p && ScMatrixCellResultToken::operator==( r ) && nCols == p->nCols && nRows == p->nRows; } void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken& r ) { if (this == &r) return; const ScMatrixCellResultToken* p = dynamic_cast(&r); if (p) ScMatrixCellResultToken::Assign( *p); else { DBG_ASSERT( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead"); if (r.GetType() == svMatrix) { xUpperLeft = NULL; xMatrix = static_cast(r).GetMatrix(); } else { xUpperLeft = &r; xMatrix = NULL; } } } void ScMatrixFormulaCellToken::SetUpperLeftDouble( double f ) { switch (GetUpperLeftType()) { case svDouble: const_cast(xUpperLeft.get())->GetDoubleAsReference() = f; break; case svUnknown: if (!xUpperLeft) { xUpperLeft = new FormulaDoubleToken( f); break; } // fall thru default: { DBG_ERRORFILE("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type"); } } } double ScHybridCellToken::GetDouble() const { return fDouble; } const String & ScHybridCellToken::GetString() const { return aString; } sal_Bool ScHybridCellToken::operator==( const FormulaToken& r ) const { return FormulaToken::operator==( r ) && fDouble == r.GetDouble() && aString == r.GetString() && aFormula == static_cast(r).GetFormula(); } ////////////////////////////////////////////////////////////////////////// bool ScTokenArray::AddFormulaToken(const com::sun::star::sheet::FormulaToken& _aToken,formula::ExternalReferenceHelper* _pRef) { bool bError = FormulaTokenArray::AddFormulaToken(_aToken,_pRef); if ( bError ) { bError = false; const OpCode eOpCode = static_cast(_aToken.OpCode); //! assuming equal values for the moment const uno::TypeClass eClass = _aToken.Data.getValueTypeClass(); switch ( eClass ) { case uno::TypeClass_STRUCT: { uno::Type aType = _aToken.Data.getValueType(); if ( aType.equals( cppu::UnoType::get() ) ) { ScSingleRefData aSingleRef; sheet::SingleReference aApiRef; _aToken.Data >>= aApiRef; lcl_SingleRefToCalc( aSingleRef, aApiRef ); if ( eOpCode == ocPush ) AddSingleReference( aSingleRef ); else if ( eOpCode == ocColRowName ) AddColRowName( aSingleRef ); else bError = true; } else if ( aType.equals( cppu::UnoType::get() ) ) { ScComplexRefData aComplRef; sheet::ComplexReference aApiRef; _aToken.Data >>= aApiRef; lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 ); lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 ); if ( eOpCode == ocPush ) AddDoubleReference( aComplRef ); else bError = true; } else if ( aType.equals( cppu::UnoType::get() ) ) { sheet::ExternalReference aApiExtRef; if( (eOpCode == ocPush) && (_aToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) ) { sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index ); sheet::SingleReference aApiSRef; sheet::ComplexReference aApiCRef; ::rtl::OUString aName; if( aApiExtRef.Reference >>= aApiSRef ) { // try to resolve cache index to sheet name size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet ); String aTabName = _pRef->getCacheTableName( nFileId, nCacheId ); if( aTabName.Len() > 0 ) { ScSingleRefData aSingleRef; // convert column/row settings, set sheet index to absolute lcl_ExternalRefToCalc( aSingleRef, aApiSRef ); AddExternalSingleReference( nFileId, aTabName, aSingleRef ); } else bError = true; } else if( aApiExtRef.Reference >>= aApiCRef ) { // try to resolve cache index to sheet name. size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet ); String aTabName = _pRef->getCacheTableName( nFileId, nCacheId ); if( aTabName.Len() > 0 ) { ScComplexRefData aComplRef; // convert column/row settings, set sheet index to absolute lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 ); lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 ); // NOTE: This assumes that cached sheets are in consecutive order! aComplRef.Ref2.nTab = aComplRef.Ref1.nTab + static_cast(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet); AddExternalDoubleReference( nFileId, aTabName, aComplRef ); } else bError = true; } else if( aApiExtRef.Reference >>= aName ) { if( aName.getLength() > 0 ) AddExternalName( nFileId, aName ); else bError = true; } else bError = true; } else bError = true; } else bError = true; // unknown struct } break; case uno::TypeClass_SEQUENCE: { if ( eOpCode != ocPush ) bError = true; // not an inline array else if (!_aToken.Data.getValueType().equals( getCppuType( (uno::Sequence< uno::Sequence< uno::Any > > *)0))) bError = true; // unexpected sequence type else { ScMatrixRef xMat = ScSequenceToMatrix::CreateMixedMatrix( _aToken.Data); if (xMat) AddMatrix( xMat); else bError = true; } } break; default: bError = true; } } return bError; } sal_Bool ScTokenArray::ImplGetReference( ScRange& rRange, sal_Bool bValidOnly ) const { sal_Bool bIs = sal_False; if ( pCode && nLen == 1 ) { const FormulaToken* pToken = pCode[0]; if ( pToken ) { if ( pToken->GetType() == svSingleRef ) { const ScSingleRefData& rRef = ((const ScSingleRefToken*)pToken)->GetSingleRef(); rRange.aStart = rRange.aEnd = ScAddress( rRef.nCol, rRef.nRow, rRef.nTab ); bIs = !bValidOnly || !rRef.IsDeleted(); } else if ( pToken->GetType() == svDoubleRef ) { const ScComplexRefData& rCompl = ((const ScDoubleRefToken*)pToken)->GetDoubleRef(); const ScSingleRefData& rRef1 = rCompl.Ref1; const ScSingleRefData& rRef2 = rCompl.Ref2; rRange.aStart = ScAddress( rRef1.nCol, rRef1.nRow, rRef1.nTab ); rRange.aEnd = ScAddress( rRef2.nCol, rRef2.nRow, rRef2.nTab ); bIs = !bValidOnly || (!rRef1.IsDeleted() && !rRef2.IsDeleted()); } } } return bIs; } sal_Bool ScTokenArray::IsReference( ScRange& rRange ) const { return ImplGetReference( rRange, sal_False ); } sal_Bool ScTokenArray::IsValidReference( ScRange& rRange ) const { return ImplGetReference( rRange, sal_True ); } //////////////////////////////////////////////////////////////////////////// ScTokenArray::ScTokenArray() { } ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) : FormulaTokenArray(rArr) { } ScTokenArray::~ScTokenArray() { } ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr ) { Clear(); Assign( rArr ); return *this; } ScTokenArray* ScTokenArray::Clone() const { ScTokenArray* p = new ScTokenArray(); p->nLen = nLen; p->nRPN = nRPN; p->nRefs = nRefs; p->nMode = nMode; p->nError = nError; p->bHyperLink = bHyperLink; FormulaToken** pp; if( nLen ) { pp = p->pCode = new FormulaToken*[ nLen ]; memcpy( pp, pCode, nLen * sizeof( ScToken* ) ); for( sal_uInt16 i = 0; i < nLen; i++, pp++ ) { *pp = (*pp)->Clone(); (*pp)->IncRef(); } } if( nRPN ) { pp = p->pRPN = new FormulaToken*[ nRPN ]; memcpy( pp, pRPN, nRPN * sizeof( ScToken* ) ); for( sal_uInt16 i = 0; i < nRPN; i++, pp++ ) { FormulaToken* t = *pp; if( t->GetRef() > 1 ) { FormulaToken** p2 = pCode; sal_uInt16 nIdx = 0xFFFF; for( sal_uInt16 j = 0; j < nLen; j++, p2++ ) { if( *p2 == t ) { nIdx = j; break; } } if( nIdx == 0xFFFF ) *pp = t->Clone(); else *pp = p->pCode[ nIdx ]; } else *pp = t->Clone(); (*pp)->IncRef(); } } return p; } FormulaToken* ScTokenArray::AddRawToken( const ScRawToken& r ) { return Add( r.CreateToken() ); } // Utility function to ensure that there is strict alternation of values and // seperators. static bool checkArraySep( bool & bPrevWasSep, bool bNewVal ) { bool bResult = (bPrevWasSep == bNewVal); bPrevWasSep = bNewVal; return bResult; } FormulaToken* ScTokenArray::MergeArray( ) { int nCol = -1, nRow = 0; int i, nPrevRowSep = -1, nStart = 0; bool bPrevWasSep = false; // top of stack is ocArrayClose FormulaToken* t; bool bNumeric = false; // numeric value encountered in current element // (1) Iterate from the end to the start to find matrix dims // and do basic validation. for ( i = nLen ; i-- > nStart ; ) { t = pCode[i]; switch ( t->GetOpCode() ) { case ocPush : if( checkArraySep( bPrevWasSep, false ) ) { return NULL; } // no references or nested arrays if ( t->GetType() != svDouble && t->GetType() != svString ) { return NULL; } bNumeric = (t->GetType() == svDouble); break; case ocMissing : case ocTrue : case ocFalse : if( checkArraySep( bPrevWasSep, false ) ) { return NULL; } bNumeric = false; break; case ocArrayColSep : case ocSep : if( checkArraySep( bPrevWasSep, true ) ) { return NULL; } bNumeric = false; break; case ocArrayClose : // not possible with the , but check just in case // something changes in the future if( i != (nLen-1)) { return NULL; } if( checkArraySep( bPrevWasSep, true ) ) { return NULL; } nPrevRowSep = i; bNumeric = false; break; case ocArrayOpen : nStart = i; // stop iteration // fall through to ArrayRowSep case ocArrayRowSep : if( checkArraySep( bPrevWasSep, true ) ) { return NULL; } if( nPrevRowSep < 0 || // missing ocArrayClose ((nPrevRowSep - i) % 2) == 1) // no complex elements { return NULL; } if( nCol < 0 ) { nCol = (nPrevRowSep - i) / 2; } else if( (nPrevRowSep - i)/2 != nCol) // irregular array { return NULL; } nPrevRowSep = i; nRow++; bNumeric = false; break; case ocNegSub : case ocAdd : // negation or unary plus must precede numeric value if( !bNumeric ) { return NULL; } --nPrevRowSep; // shorten this row by 1 bNumeric = false; // one level only, no --42 break; case ocSpaces : // ignore spaces --nPrevRowSep; // shorten this row by 1 break; default : // no functions or operators return NULL; } } if( nCol <= 0 || nRow <= 0 ) return NULL; // fprintf (stderr, "Array (cols = %d, rows = %d)\n", nCol, nRow ); int nSign = 1; ScMatrix* pArray = new ScMatrix( nCol, nRow ); for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ ) { t = pCode[i]; switch ( t->GetOpCode() ) { case ocPush : if ( t->GetType() == svDouble ) { pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow ); nSign = 1; } else if ( t->GetType() == svString ) { pArray->PutString( t->GetString(), nCol, nRow ); } break; case ocMissing : pArray->PutEmpty( nCol, nRow ); break; case ocTrue : pArray->PutBoolean( true, nCol, nRow ); break; case ocFalse : pArray->PutBoolean( false, nCol, nRow ); break; case ocArrayColSep : case ocSep : nCol++; break; case ocArrayRowSep : nRow++; nCol = 0; break; case ocNegSub : nSign = -nSign; break; default : break; } pCode[i] = NULL; t->DecRef(); } nLen = sal_uInt16( nStart ); return AddMatrix( pArray ); } FormulaToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos ) { if (!pCode || !nLen) return NULL; sal_uInt16 nIdx = nLen; FormulaToken *p1, *p2, *p3; // ref, ocRange, ref // The actual types are checked in ExtendRangeReference(). if (((p3 = PeekPrev(nIdx)) != 0) && (((p2 = PeekPrev(nIdx)) != 0) && p2->GetOpCode() == ocRange) && ((p1 = PeekPrev(nIdx)) != 0)) { FormulaTokenRef p = ScToken::ExtendRangeReference( *p1, *p3, rPos, true); if (p) { p->IncRef(); p1->DecRef(); p2->DecRef(); p3->DecRef(); nLen -= 2; pCode[ nLen-1 ] = p; nRefs--; } } return pCode[ nLen-1 ]; } FormulaToken* ScTokenArray::AddOpCode( OpCode e ) { ScRawToken t; t.SetOpCode( e ); return AddRawToken( t ); } FormulaToken* ScTokenArray::AddSingleReference( const ScSingleRefData& rRef ) { return Add( new ScSingleRefToken( rRef ) ); } FormulaToken* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData& rRef ) { return Add( new ScSingleRefToken( rRef, ocMatRef ) ); } FormulaToken* ScTokenArray::AddDoubleReference( const ScComplexRefData& rRef ) { return Add( new ScDoubleRefToken( rRef ) ); } FormulaToken* ScTokenArray::AddMatrix( ScMatrix* p ) { return Add( new ScMatrixToken( p ) ); } FormulaToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const String& rName ) { return Add( new ScExternalNameToken(nFileId, rName) ); } FormulaToken* ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) { return Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) ); } FormulaToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef ) { return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) ); } FormulaToken* ScTokenArray::AddColRowName( const ScSingleRefData& rRef ) { return Add( new ScSingleRefToken( rRef, ocColRowName ) ); } sal_Bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend, const ScAddress& rPos, ScDirection eDir ) { SCCOL nCol = 0; SCROW nRow = 0; switch ( eDir ) { case DIR_BOTTOM : if ( rPos.Row() < MAXROW ) nRow = (nExtend = rPos.Row()) + 1; else return sal_False; break; case DIR_RIGHT : if ( rPos.Col() < MAXCOL ) nCol = static_cast(nExtend = rPos.Col()) + 1; else return sal_False; break; case DIR_TOP : if ( rPos.Row() > 0 ) nRow = (nExtend = rPos.Row()) - 1; else return sal_False; break; case DIR_LEFT : if ( rPos.Col() > 0 ) nCol = static_cast(nExtend = rPos.Col()) - 1; else return sal_False; break; default: DBG_ERRORFILE( "unknown Direction" ); return sal_False; } if ( pRPN && nRPN ) { FormulaToken* t = pRPN[nRPN-1]; if ( t->GetType() == svByte ) { sal_uInt8 nParamCount = t->GetByte(); if ( nParamCount && nRPN > nParamCount ) { sal_Bool bRet = sal_False; sal_uInt16 nParam = nRPN - nParamCount - 1; for ( ; nParam < nRPN-1; nParam++ ) { FormulaToken* p = pRPN[nParam]; switch ( p->GetType() ) { case svSingleRef : { ScSingleRefData& rRef = static_cast(p)->GetSingleRef(); rRef.CalcAbsIfRel( rPos ); switch ( eDir ) { case DIR_BOTTOM : if ( rRef.nRow == nRow && rRef.nRow > nExtend ) { nExtend = rRef.nRow; bRet = sal_True; } break; case DIR_RIGHT : if ( rRef.nCol == nCol && static_cast(rRef.nCol) > nExtend ) { nExtend = rRef.nCol; bRet = sal_True; } break; case DIR_TOP : if ( rRef.nRow == nRow && rRef.nRow < nExtend ) { nExtend = rRef.nRow; bRet = sal_True; } break; case DIR_LEFT : if ( rRef.nCol == nCol && static_cast(rRef.nCol) < nExtend ) { nExtend = rRef.nCol; bRet = sal_True; } break; } } break; case svDoubleRef : { ScComplexRefData& rRef = static_cast(p)->GetDoubleRef(); rRef.CalcAbsIfRel( rPos ); switch ( eDir ) { case DIR_BOTTOM : if ( rRef.Ref1.nRow == nRow && rRef.Ref2.nRow > nExtend ) { nExtend = rRef.Ref2.nRow; bRet = sal_True; } break; case DIR_RIGHT : if ( rRef.Ref1.nCol == nCol && static_cast(rRef.Ref2.nCol) > nExtend ) { nExtend = rRef.Ref2.nCol; bRet = sal_True; } break; case DIR_TOP : if ( rRef.Ref2.nRow == nRow && rRef.Ref1.nRow < nExtend ) { nExtend = rRef.Ref1.nRow; bRet = sal_True; } break; case DIR_LEFT : if ( rRef.Ref2.nCol == nCol && static_cast(rRef.Ref1.nCol) < nExtend ) { nExtend = rRef.Ref1.nCol; bRet = sal_True; } break; } } break; default: { // added to avoid warnings } } // switch } // for return bRet; } } } return sal_False; } void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos, const ScAddress& rNewPos ) { for ( sal_uInt16 j=0; jGetType() ) { case svDoubleRef : { ScSingleRefData& rRef2 = static_cast(pCode[j])->GetSingleRef2(); // Also adjust if the reference is of the form Sheet1.A2:A3 if ( rRef2.IsFlag3D() || static_cast(pCode[j])->GetSingleRef().IsFlag3D() ) { rRef2.CalcAbsIfRel( rOldPos ); rRef2.CalcRelFromAbs( rNewPos ); } } //! fallthru case svSingleRef : { ScSingleRefData& rRef1 = static_cast(pCode[j])->GetSingleRef(); if ( rRef1.IsFlag3D() ) { rRef1.CalcAbsIfRel( rOldPos ); rRef1.CalcRelFromAbs( rNewPos ); } } break; case svExternalDoubleRef: { ScSingleRefData& rRef2 = static_cast(pCode[j])->GetSingleRef2(); rRef2.CalcAbsIfRel( rOldPos ); rRef2.CalcRelFromAbs( rNewPos ); } //! fallthru case svExternalSingleRef: { ScSingleRefData& rRef1 = static_cast(pCode[j])->GetSingleRef(); rRef1.CalcAbsIfRel( rOldPos ); rRef1.CalcRelFromAbs( rNewPos ); } break; default: { // added to avoid warnings } } } }