1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <tools/debug.hxx>
23 #include <tools/stream.hxx>
24 #include <basic/sbx.hxx>
25 #include "runtime.hxx"
27 #include <boost/optional.hpp>
34 boost::optional
<OUString
> maAlias
;
37 TYPEINIT1(SbxArray
,SbxBase
)
38 TYPEINIT1(SbxDimArray
,SbxArray
)
42 SbxArray::SbxArray( SbxDataType t
) : SbxBase()
44 mpVarEntries
= new VarEntriesType
;
50 SbxArray::SbxArray( const SbxArray
& rArray
) :
51 SvRefBase( rArray
), SbxBase()
53 mpVarEntries
= new VarEntriesType
;
54 if( rArray
.eType
!= SbxVARIANT
)
59 SbxArray
& SbxArray::operator=( const SbxArray
& rArray
)
65 VarEntriesType
* pSrc
= rArray
.mpVarEntries
;
66 for( sal_uInt32 i
= 0; i
< pSrc
->size(); i
++ )
68 SbxVarEntry
* pSrcRef
= (*pSrc
)[i
];
69 SbxVariableRef pSrc_
= pSrcRef
->mpVar
;
72 SbxVarEntry
* pDstRef
= new SbxVarEntry
;
73 pDstRef
->mpVar
= pSrcRef
->mpVar
;
76 pDstRef
->maAlias
.reset(*pSrcRef
->maAlias
);
78 if( eType
!= SbxVARIANT
)
81 if( eType
!= SbxOBJECT
|| pSrc_
->GetClass() != SbxCLASS_OBJECT
)
83 pSrc_
->Convert(eType
);
86 mpVarEntries
->push_back( pDstRef
);
98 SbxDataType
SbxArray::GetType() const
100 return (SbxDataType
) ( eType
| SbxARRAY
);
103 SbxClassType
SbxArray::GetClass() const
105 return SbxCLASS_ARRAY
;
108 void SbxArray::Clear()
110 sal_uInt32 nSize
= mpVarEntries
->size();
111 for( sal_uInt32 i
= 0 ; i
< nSize
; i
++ )
113 SbxVarEntry
* pEntry
= (*mpVarEntries
)[i
];
116 mpVarEntries
->clear();
119 sal_uInt32
SbxArray::Count32() const
121 return mpVarEntries
->size();
124 sal_uInt16
SbxArray::Count() const
126 sal_uInt32 nCount
= mpVarEntries
->size();
127 DBG_ASSERT( nCount
<= SBX_MAXINDEX
, "SBX: Array-Index > SBX_MAXINDEX" );
128 return (sal_uInt16
)nCount
;
131 SbxVariableRef
& SbxArray::GetRef32( sal_uInt32 nIdx
)
133 // If necessary extend the array
134 DBG_ASSERT( nIdx
<= SBX_MAXINDEX32
, "SBX: Array-Index > SBX_MAXINDEX32" );
136 if( nIdx
> SBX_MAXINDEX32
)
138 SetError( SbxERR_BOUNDS
);
141 while( mpVarEntries
->size() <= nIdx
)
143 mpVarEntries
->push_back(new SbxVarEntry
);
145 return (*mpVarEntries
)[nIdx
]->mpVar
;
148 SbxVariableRef
& SbxArray::GetRef( sal_uInt16 nIdx
)
150 // If necessary extend the array
151 DBG_ASSERT( nIdx
<= SBX_MAXINDEX
, "SBX: Array-Index > SBX_MAXINDEX" );
153 if( nIdx
> SBX_MAXINDEX
)
155 SetError( SbxERR_BOUNDS
);
158 while( mpVarEntries
->size() <= nIdx
)
160 mpVarEntries
->push_back(new SbxVarEntry
);
162 return (*mpVarEntries
)[nIdx
]->mpVar
;
165 SbxVariable
* SbxArray::Get32( sal_uInt32 nIdx
)
169 SetError( SbxERR_PROP_WRITEONLY
);
172 SbxVariableRef
& rRef
= GetRef32( nIdx
);
175 rRef
= new SbxVariable( eType
);
180 SbxVariable
* SbxArray::Get( sal_uInt16 nIdx
)
184 SetError( SbxERR_PROP_WRITEONLY
);
187 SbxVariableRef
& rRef
= GetRef( nIdx
);
190 rRef
= new SbxVariable( eType
);
195 void SbxArray::Put32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
198 SetError( SbxERR_PROP_READONLY
);
202 if( eType
!= SbxVARIANT
)
203 // Convert no objects
204 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxCLASS_OBJECT
)
205 pVar
->Convert( eType
);
206 SbxVariableRef
& rRef
= GetRef32( nIdx
);
207 if( (SbxVariable
*) rRef
!= pVar
)
210 SetFlag( SBX_MODIFIED
);
215 void SbxArray::Put( SbxVariable
* pVar
, sal_uInt16 nIdx
)
218 SetError( SbxERR_PROP_READONLY
);
222 if( eType
!= SbxVARIANT
)
223 // Convert no objects
224 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxCLASS_OBJECT
)
225 pVar
->Convert( eType
);
226 SbxVariableRef
& rRef
= GetRef( nIdx
);
227 if( (SbxVariable
*) rRef
!= pVar
)
230 SetFlag( SBX_MODIFIED
);
235 OUString
SbxArray::GetAlias( sal_uInt16 nIdx
)
239 SetError( SbxERR_PROP_WRITEONLY
);
242 SbxVarEntry
& rRef
= reinterpret_cast<SbxVarEntry
&>(GetRef( nIdx
));
247 return *rRef
.maAlias
;
250 void SbxArray::PutAlias( const OUString
& rAlias
, sal_uInt16 nIdx
)
254 SetError( SbxERR_PROP_READONLY
);
258 SbxVarEntry
& rRef
= reinterpret_cast<SbxVarEntry
&>( GetRef( nIdx
) );
259 rRef
.maAlias
.reset(rAlias
);
263 void SbxArray::Insert32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
265 DBG_ASSERT( mpVarEntries
->size() <= SBX_MAXINDEX32
, "SBX: Array gets too big" );
266 if( mpVarEntries
->size() > SBX_MAXINDEX32
)
270 SbxVarEntry
* p
= new SbxVarEntry
;
272 size_t nSize
= mpVarEntries
->size();
277 if( eType
!= SbxVARIANT
&& pVar
)
279 p
->mpVar
->Convert(eType
);
283 mpVarEntries
->push_back( p
);
287 mpVarEntries
->insert( mpVarEntries
->begin() + nIdx
, p
);
289 SetFlag( SBX_MODIFIED
);
292 void SbxArray::Insert( SbxVariable
* pVar
, sal_uInt16 nIdx
)
294 DBG_ASSERT( mpVarEntries
->size() <= 0x3FF0, "SBX: Array gets too big" );
295 if( mpVarEntries
->size() > 0x3FF0 )
299 Insert32( pVar
, nIdx
);
302 void SbxArray::Remove32( sal_uInt32 nIdx
)
304 if( nIdx
< mpVarEntries
->size() )
306 SbxVarEntry
* pRef
= (*mpVarEntries
)[nIdx
];
307 mpVarEntries
->erase( mpVarEntries
->begin() + nIdx
);
309 SetFlag( SBX_MODIFIED
);
313 void SbxArray::Remove( sal_uInt16 nIdx
)
315 if( nIdx
< mpVarEntries
->size() )
317 SbxVarEntry
* pRef
= (*mpVarEntries
)[nIdx
];
318 mpVarEntries
->erase( mpVarEntries
->begin() + nIdx
);
320 SetFlag( SBX_MODIFIED
);
324 void SbxArray::Remove( SbxVariable
* pVar
)
328 for( sal_uInt32 i
= 0; i
< mpVarEntries
->size(); i
++ )
330 SbxVarEntry
* pRef
= (*mpVarEntries
)[i
];
331 if (&pRef
->mpVar
== pVar
)
333 Remove32( i
); break;
339 // Taking over of the data from the passed array, at which
340 // the variable of the same name will be overwritten.
342 void SbxArray::Merge( SbxArray
* p
)
347 for (sal_uInt16 i
= 0; i
< p
->Count(); ++i
)
349 SbxVarEntry
* pEntry1
= (*p
->mpVarEntries
)[i
];
353 OUString aName
= pEntry1
->mpVar
->GetName();
354 sal_uInt16 nHash
= pEntry1
->mpVar
->GetHashCode();
356 // Is the element by the same name already inside?
358 for (size_t j
= 0; j
< mpVarEntries
->size(); ++j
)
360 SbxVarEntry
* pEntry2
= (*mpVarEntries
)[j
];
364 if (pEntry2
->mpVar
->GetHashCode() == nHash
&&
365 pEntry2
->mpVar
->GetName().equalsIgnoreAsciiCase(aName
))
367 // Take this element and clear the original.
368 pEntry2
->mpVar
= pEntry1
->mpVar
;
369 pEntry1
->mpVar
.Clear();
376 // We don't have element with the same name. Add a new entry.
377 SbxVarEntry
* pNewEntry
= new SbxVarEntry
;
378 mpVarEntries
->push_back(pNewEntry
);
379 pNewEntry
->mpVar
= pEntry1
->mpVar
;
380 if (pEntry1
->maAlias
)
381 pNewEntry
->maAlias
.reset(*pEntry1
->maAlias
);
386 // Search of an element via the user data. If the element is
387 // object, it will also be scanned.
389 SbxVariable
* SbxArray::FindUserData( sal_uInt32 nData
)
391 SbxVariable
* p
= NULL
;
392 for (size_t i
= 0; i
< mpVarEntries
->size(); ++i
)
394 SbxVarEntry
* pEntry
= (*mpVarEntries
)[i
];
398 if (pEntry
->mpVar
->IsVisible() && pEntry
->mpVar
->GetUserData() == nData
)
401 p
->ResetFlag( SBX_EXTFOUND
);
402 break; // JSM 1995-10-06
405 // Did we have an array/object with extended search?
406 if (pEntry
->mpVar
->IsSet(SBX_EXTSEARCH
))
408 switch (pEntry
->mpVar
->GetClass())
410 case SbxCLASS_OBJECT
:
412 // Objects are not allowed to scan their parent.
413 SbxFlagBits nOld
= pEntry
->mpVar
->GetFlags();
414 pEntry
->mpVar
->ResetFlag(SBX_GBLSEARCH
);
415 p
= static_cast<SbxObject
&>(*pEntry
->mpVar
).FindUserData(nData
);
416 pEntry
->mpVar
->SetFlags(nOld
);
420 // Casting SbxVariable to SbxArray? Really?
421 p
= reinterpret_cast<SbxArray
&>(*pEntry
->mpVar
).FindUserData(nData
);
429 p
->SetFlag(SBX_EXTFOUND
);
437 // Search of an element by his name and type. If an element is an object,
438 // it will also be scanned..
440 SbxVariable
* SbxArray::Find( const OUString
& rName
, SbxClassType t
)
442 SbxVariable
* p
= NULL
;
443 sal_uInt32 nCount
= mpVarEntries
->size();
446 bool bExtSearch
= IsSet( SBX_EXTSEARCH
);
447 sal_uInt16 nHash
= SbxVariable::MakeHashCode( rName
);
448 for( sal_uInt32 i
= 0; i
< nCount
; i
++ )
450 SbxVarEntry
* pEntry
= (*mpVarEntries
)[i
];
451 if (!pEntry
->mpVar
|| !pEntry
->mpVar
->IsVisible())
454 // The very secure search works as well, if there is no hashcode!
455 sal_uInt16 nVarHash
= pEntry
->mpVar
->GetHashCode();
456 if ( (!nVarHash
|| nVarHash
== nHash
)
457 && (t
== SbxCLASS_DONTCARE
|| pEntry
->mpVar
->GetClass() == t
)
458 && (pEntry
->mpVar
->GetName().equalsIgnoreAsciiCase(rName
)))
461 p
->ResetFlag(SBX_EXTFOUND
);
465 // Did we have an array/object with extended search?
466 if (bExtSearch
&& pEntry
->mpVar
->IsSet(SBX_EXTSEARCH
))
468 switch (pEntry
->mpVar
->GetClass())
470 case SbxCLASS_OBJECT
:
472 // Objects are not allowed to scan their parent.
473 SbxFlagBits nOld
= pEntry
->mpVar
->GetFlags();
474 pEntry
->mpVar
->ResetFlag(SBX_GBLSEARCH
);
475 p
= static_cast<SbxObject
&>(*pEntry
->mpVar
).Find(rName
, t
);
476 pEntry
->mpVar
->SetFlags(nOld
);
480 // Casting SbxVariable to SbxArray? Really?
481 p
= reinterpret_cast<SbxArray
&>(*pEntry
->mpVar
).Find(rName
, t
);
489 p
->SetFlag(SBX_EXTFOUND
);
497 bool SbxArray::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
502 SbxFlagBits f
= nFlags
;
504 rStrm
.ReadUInt16( nElem
);
506 for( sal_uInt32 n
= 0; n
< nElem
; n
++ )
509 rStrm
.ReadUInt16( nIdx
);
510 SbxVariable
* pVar
= static_cast<SbxVariable
*>(Load( rStrm
));
513 SbxVariableRef
& rRef
= GetRef( nIdx
);
523 bRes
= LoadPrivateData( rStrm
, nVer
);
528 bool SbxArray::StoreData( SvStream
& rStrm
) const
530 sal_uInt32 nElem
= 0;
532 // Which elements are even defined?
533 for( n
= 0; n
< mpVarEntries
->size(); n
++ )
535 SbxVarEntry
* pEntry
= (*mpVarEntries
)[n
];
536 if (pEntry
->mpVar
&& (pEntry
->mpVar
->GetFlags() & SBX_DONTSTORE
) == SBX_NONE
)
539 rStrm
.WriteUInt16( nElem
);
540 for( n
= 0; n
< mpVarEntries
->size(); n
++ )
542 SbxVarEntry
* pEntry
= (*mpVarEntries
)[n
];
543 if (pEntry
->mpVar
&& (pEntry
->mpVar
->GetFlags() & SBX_DONTSTORE
) == SBX_NONE
)
545 rStrm
.WriteUInt16( n
);
546 if (!pEntry
->mpVar
->Store(rStrm
))
550 return StorePrivateData( rStrm
);
553 // #100883 Method to set method directly to parameter array
554 void SbxArray::PutDirect( SbxVariable
* pVar
, sal_uInt32 nIdx
)
556 SbxVariableRef
& rRef
= GetRef32( nIdx
);
563 SbxDimArray::SbxDimArray( SbxDataType t
) : SbxArray( t
), mbHasFixedSize( false )
567 SbxDimArray::SbxDimArray( const SbxDimArray
& rArray
)
568 : SvRefBase( rArray
), SbxArray( rArray
.eType
)
573 SbxDimArray
& SbxDimArray::operator=( const SbxDimArray
& rArray
)
575 if( &rArray
!= this )
577 SbxArray::operator=( (const SbxArray
&) rArray
);
578 m_vDimensions
= rArray
.m_vDimensions
;
579 this->mbHasFixedSize
= rArray
.mbHasFixedSize
;
584 SbxDimArray::~SbxDimArray()
589 void SbxDimArray::Clear()
591 m_vDimensions
.clear();
596 void SbxDimArray::AddDimImpl32( sal_Int32 lb
, sal_Int32 ub
, bool bAllowSize0
)
598 SbxError eRes
= SbxERR_OK
;
599 if( ub
< lb
&& !bAllowSize0
)
601 eRes
= SbxERR_BOUNDS
;
607 d
.nSize
= ub
- lb
+ 1;
608 m_vDimensions
.push_back(d
);
614 void SbxDimArray::AddDim( short lb
, short ub
)
616 AddDimImpl32( lb
, ub
, false );
619 void SbxDimArray::unoAddDim( short lb
, short ub
)
621 AddDimImpl32( lb
, ub
, true );
624 void SbxDimArray::AddDim32( sal_Int32 lb
, sal_Int32 ub
)
626 AddDimImpl32( lb
, ub
, false );
629 void SbxDimArray::unoAddDim32( sal_Int32 lb
, sal_Int32 ub
)
631 AddDimImpl32( lb
, ub
, true );
635 // Readout dimension data
637 bool SbxDimArray::GetDim32( sal_Int32 n
, sal_Int32
& rlb
, sal_Int32
& rub
) const
639 if( n
< 1 || n
> static_cast<sal_Int32
>(m_vDimensions
.size()) )
641 SetError( SbxERR_BOUNDS
);
645 SbxDim d
= m_vDimensions
[n
- 1];
651 bool SbxDimArray::GetDim( short n
, short& rlb
, short& rub
) const
653 sal_Int32 rlb32
, rub32
;
654 bool bRet
= GetDim32( n
, rlb32
, rub32
);
659 if( rlb32
< -SBX_MAXINDEX
|| rub32
> SBX_MAXINDEX
)
661 SetError( SbxERR_BOUNDS
);
668 // Element-Ptr with the help of an index list
670 sal_uInt32
SbxDimArray::Offset32( const sal_Int32
* pIdx
)
673 for( std::vector
<SbxDim
>::const_iterator it
= m_vDimensions
.begin();
674 it
!= m_vDimensions
.end(); ++it
)
676 sal_Int32 nIdx
= *pIdx
++;
677 if( nIdx
< it
->nLbound
|| nIdx
> it
->nUbound
)
679 nPos
= (sal_uInt32
)SBX_MAXINDEX32
+ 1; break;
681 nPos
= nPos
* it
->nSize
+ nIdx
- it
->nLbound
;
683 if( m_vDimensions
.empty() || nPos
> SBX_MAXINDEX32
)
685 SetError( SbxERR_BOUNDS
);
691 sal_uInt16
SbxDimArray::Offset( const short* pIdx
)
694 for( std::vector
<SbxDim
>::const_iterator it
= m_vDimensions
.begin();
695 it
!= m_vDimensions
.end(); ++it
)
697 short nIdx
= *pIdx
++;
698 if( nIdx
< it
->nLbound
|| nIdx
> it
->nUbound
)
700 nPos
= SBX_MAXINDEX
+ 1;
703 nPos
= nPos
* it
->nSize
+ nIdx
- it
->nLbound
;
705 if( m_vDimensions
.empty() || nPos
> SBX_MAXINDEX
)
707 SetError( SbxERR_BOUNDS
);
710 return (sal_uInt16
) nPos
;
713 SbxVariable
* SbxDimArray::Get( const short* pIdx
)
715 return SbxArray::Get( Offset( pIdx
) );
718 void SbxDimArray::Put( SbxVariable
* p
, const short* pIdx
)
720 SbxArray::Put( p
, Offset( pIdx
) );
723 SbxVariable
* SbxDimArray::Get32( const sal_Int32
* pIdx
)
725 return SbxArray::Get32( Offset32( pIdx
) );
728 void SbxDimArray::Put32( SbxVariable
* p
, const sal_Int32
* pIdx
)
730 SbxArray::Put32( p
, Offset32( pIdx
) );
733 // Element-Number with the help of Parameter-Array
734 sal_uInt32
SbxDimArray::Offset32( SbxArray
* pPar
)
736 #if HAVE_FEATURE_SCRIPTING
737 if (m_vDimensions
.empty() || !pPar
||
738 ((m_vDimensions
.size() != sal::static_int_cast
<size_t>(pPar
->Count() - 1))
739 && SbiRuntime::isVBAEnabled()))
741 SetError( SbxERR_BOUNDS
);
746 sal_uInt16 nOff
= 1; // Non element 0!
747 for( std::vector
<SbxDim
>::const_iterator it
= m_vDimensions
.begin();
748 it
!= m_vDimensions
.end() && !IsError(); ++it
)
750 sal_Int32 nIdx
= pPar
->Get( nOff
++ )->GetLong();
751 if( nIdx
< it
->nLbound
|| nIdx
> it
->nUbound
)
753 nPos
= (sal_uInt32
) SBX_MAXINDEX32
+1;
756 nPos
= nPos
* it
->nSize
+ nIdx
- it
->nLbound
;
758 if( nPos
> (sal_uInt32
) SBX_MAXINDEX32
)
760 SetError( SbxERR_BOUNDS
);
766 SbxVariable
* SbxDimArray::Get( SbxArray
* pPar
)
768 return SbxArray::Get32( Offset32( pPar
) );
771 bool SbxDimArray::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
774 rStrm
.ReadInt16( nDimension
);
775 for( short i
= 0; i
< nDimension
&& rStrm
.GetError() == SVSTREAM_OK
; i
++ )
777 sal_Int16
lb(0), ub(0);
778 rStrm
.ReadInt16( lb
).ReadInt16( ub
);
781 return SbxArray::LoadData( rStrm
, nVer
);
784 bool SbxDimArray::StoreData( SvStream
& rStrm
) const
786 rStrm
.WriteInt16( m_vDimensions
.size() );
787 for( short i
= 0; i
< static_cast<short>(m_vDimensions
.size()); i
++ )
791 rStrm
.WriteInt16( lb
).WriteInt16( ub
);
793 return SbxArray::StoreData( rStrm
);
796 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */