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
;
40 SbxArray::SbxArray( SbxDataType t
) : SbxBase()
44 SetFlag( SbxFlagBits::Fixed
);
47 SbxArray
& SbxArray::operator=( const SbxArray
& rArray
)
53 for( const auto& rpSrcRef
: rArray
.mVarEntries
)
55 SbxVariableRef pSrc_
= rpSrcRef
.mpVar
;
59 if( eType
!= SbxVARIANT
)
62 if( eType
!= SbxOBJECT
|| pSrc_
->GetClass() != SbxClassType::Object
)
64 pSrc_
->Convert(eType
);
67 mVarEntries
.push_back( rpSrcRef
);
77 SbxDataType
SbxArray::GetType() const
79 return static_cast<SbxDataType
>( eType
| SbxARRAY
);
82 void SbxArray::Clear()
87 sal_uInt32
SbxArray::Count32() const
89 return mVarEntries
.size();
92 sal_uInt16
SbxArray::Count() const
94 sal_uInt32 nCount
= mVarEntries
.size();
95 DBG_ASSERT( nCount
<= SBX_MAXINDEX
, "SBX: Array-Index > SBX_MAXINDEX" );
96 return static_cast<sal_uInt16
>(nCount
);
99 SbxVariableRef
& SbxArray::GetRef32( sal_uInt32 nIdx
)
101 // If necessary extend the array
102 DBG_ASSERT( nIdx
<= SBX_MAXINDEX32
, "SBX: Array-Index > SBX_MAXINDEX32" );
104 if( nIdx
> SBX_MAXINDEX32
)
106 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
109 if ( mVarEntries
.size() <= nIdx
)
110 mVarEntries
.resize(nIdx
+1);
112 return mVarEntries
[nIdx
].mpVar
;
115 SbxVariableRef
& SbxArray::GetRef( sal_uInt16 nIdx
)
117 // If necessary extend the array
118 DBG_ASSERT( nIdx
<= SBX_MAXINDEX
, "SBX: Array-Index > SBX_MAXINDEX" );
120 if( nIdx
> SBX_MAXINDEX
)
122 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
125 if ( mVarEntries
.size() <= nIdx
)
126 mVarEntries
.resize(nIdx
+1);
128 return mVarEntries
[nIdx
].mpVar
;
131 SbxVariable
* SbxArray::Get32( sal_uInt32 nIdx
)
135 SetError( ERRCODE_BASIC_PROP_WRITEONLY
);
138 SbxVariableRef
& rRef
= GetRef32( nIdx
);
141 rRef
= new SbxVariable( eType
);
146 SbxVariable
* SbxArray::Get( sal_uInt16 nIdx
)
150 SetError( ERRCODE_BASIC_PROP_WRITEONLY
);
153 SbxVariableRef
& rRef
= GetRef( nIdx
);
156 rRef
= new SbxVariable( eType
);
161 void SbxArray::Put32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
164 SetError( ERRCODE_BASIC_PROP_READONLY
);
168 if( eType
!= SbxVARIANT
)
169 // Convert no objects
170 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxClassType::Object
)
171 pVar
->Convert( eType
);
172 SbxVariableRef
& rRef
= GetRef32( nIdx
);
173 if( rRef
.get() != pVar
)
176 SetFlag( SbxFlagBits::Modified
);
181 void SbxArray::Put( SbxVariable
* pVar
, sal_uInt16 nIdx
)
184 SetError( ERRCODE_BASIC_PROP_READONLY
);
188 if( eType
!= SbxVARIANT
)
189 // Convert no objects
190 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxClassType::Object
)
191 pVar
->Convert( eType
);
192 SbxVariableRef
& rRef
= GetRef( nIdx
);
193 // tdf#122250. It is possible that I hold the last reference to myself, so check, otherwise I might
194 // call SetFlag on myself after I have died.
195 bool removingMyself
= rRef
.get() && rRef
->GetParameters() == this && GetRefCount() == 1;
196 if(rRef
.get() != pVar
)
200 SetFlag( SbxFlagBits::Modified
);
205 OUString
SbxArray::GetAlias( sal_uInt16 nIdx
)
209 SetError( ERRCODE_BASIC_PROP_WRITEONLY
);
212 SbxVarEntry
& rRef
= reinterpret_cast<SbxVarEntry
&>(GetRef( nIdx
));
217 return *rRef
.maAlias
;
220 void SbxArray::PutAlias( const OUString
& rAlias
, sal_uInt16 nIdx
)
224 SetError( ERRCODE_BASIC_PROP_READONLY
);
228 SbxVarEntry
& rRef
= reinterpret_cast<SbxVarEntry
&>( GetRef( nIdx
) );
229 rRef
.maAlias
= rAlias
;
233 void SbxArray::Insert32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
235 DBG_ASSERT( mVarEntries
.size() <= SBX_MAXINDEX32
, "SBX: Array gets too big" );
236 if( mVarEntries
.size() > SBX_MAXINDEX32
)
242 size_t nSize
= mVarEntries
.size();
247 if( eType
!= SbxVARIANT
&& pVar
)
249 p
.mpVar
->Convert(eType
);
253 mVarEntries
.push_back( p
);
257 mVarEntries
.insert( mVarEntries
.begin() + nIdx
, p
);
259 SetFlag( SbxFlagBits::Modified
);
262 void SbxArray::Insert( SbxVariable
* pVar
, sal_uInt16 nIdx
)
264 DBG_ASSERT( mVarEntries
.size() <= 0x3FF0, "SBX: Array gets too big" );
265 if( mVarEntries
.size() > 0x3FF0 )
269 Insert32( pVar
, nIdx
);
272 void SbxArray::Remove( sal_uInt32 nIdx
)
274 if( nIdx
< mVarEntries
.size() )
276 mVarEntries
.erase( mVarEntries
.begin() + nIdx
);
277 SetFlag( SbxFlagBits::Modified
);
281 void SbxArray::Remove( SbxVariable
const * pVar
)
285 for( size_t i
= 0; i
< mVarEntries
.size(); i
++ )
287 if (mVarEntries
[i
].mpVar
.get() == pVar
)
295 // Taking over of the data from the passed array, at which
296 // the variable of the same name will be overwritten.
298 void SbxArray::Merge( SbxArray
* p
)
303 for (auto& rEntry1
: p
->mVarEntries
)
305 if (!rEntry1
.mpVar
.is())
308 OUString aName
= rEntry1
.mpVar
->GetName();
309 sal_uInt16 nHash
= rEntry1
.mpVar
->GetHashCode();
311 // Is the element by the same name already inside?
313 for (auto& rEntry2
: mVarEntries
)
315 if (!rEntry2
.mpVar
.is())
318 if (rEntry2
.mpVar
->GetHashCode() == nHash
&&
319 rEntry2
.mpVar
->GetName().equalsIgnoreAsciiCase(aName
))
321 // Take this element and clear the original.
322 rEntry2
.mpVar
= rEntry1
.mpVar
;
323 rEntry1
.mpVar
.clear();
328 if (rEntry1
.mpVar
.is())
330 // We don't have element with the same name. Add a new entry.
331 SbxVarEntry aNewEntry
;
332 aNewEntry
.mpVar
= rEntry1
.mpVar
;
334 aNewEntry
.maAlias
= *rEntry1
.maAlias
;
335 mVarEntries
.push_back(aNewEntry
);
340 // Search of an element by his name and type. If an element is an object,
341 // it will also be scanned...
343 SbxVariable
* SbxArray::Find( const OUString
& rName
, SbxClassType t
)
345 SbxVariable
* p
= nullptr;
346 if( mVarEntries
.empty() )
348 bool bExtSearch
= IsSet( SbxFlagBits::ExtSearch
);
349 sal_uInt16 nHash
= SbxVariable::MakeHashCode( rName
);
350 for (auto& rEntry
: mVarEntries
)
352 if (!rEntry
.mpVar
.is() || !rEntry
.mpVar
->IsVisible())
355 // The very secure search works as well, if there is no hashcode!
356 sal_uInt16 nVarHash
= rEntry
.mpVar
->GetHashCode();
357 if ( (!nVarHash
|| nVarHash
== nHash
)
358 && (t
== SbxClassType::DontCare
|| rEntry
.mpVar
->GetClass() == t
)
359 && (rEntry
.mpVar
->GetName().equalsIgnoreAsciiCase(rName
)))
361 p
= rEntry
.mpVar
.get();
362 p
->ResetFlag(SbxFlagBits::ExtFound
);
366 // Did we have an array/object with extended search?
367 if (bExtSearch
&& rEntry
.mpVar
->IsSet(SbxFlagBits::ExtSearch
))
369 switch (rEntry
.mpVar
->GetClass())
371 case SbxClassType::Object
:
373 // Objects are not allowed to scan their parent.
374 SbxFlagBits nOld
= rEntry
.mpVar
->GetFlags();
375 rEntry
.mpVar
->ResetFlag(SbxFlagBits::GlobalSearch
);
376 p
= static_cast<SbxObject
&>(*rEntry
.mpVar
).Find(rName
, t
);
377 rEntry
.mpVar
->SetFlags(nOld
);
380 case SbxClassType::Array
:
381 // Casting SbxVariable to SbxArray? Really?
382 p
= reinterpret_cast<SbxArray
&>(*rEntry
.mpVar
).Find(rName
, t
);
390 p
->SetFlag(SbxFlagBits::ExtFound
);
398 bool SbxArray::LoadData( SvStream
& rStrm
, sal_uInt16
/*nVer*/ )
403 SbxFlagBits f
= nFlags
;
404 nFlags
|= SbxFlagBits::Write
;
405 rStrm
.ReadUInt16( nElem
);
407 for( sal_uInt32 n
= 0; n
< nElem
; n
++ )
410 rStrm
.ReadUInt16( nIdx
);
411 SbxVariable
* pVar
= static_cast<SbxVariable
*>(Load( rStrm
));
414 SbxVariableRef
& rRef
= GetRef( nIdx
);
427 bool SbxArray::StoreData( SvStream
& rStrm
) const
429 sal_uInt32 nElem
= 0;
430 // Which elements are even defined?
431 for( auto& rEntry
: mVarEntries
)
433 if (rEntry
.mpVar
.is() && !(rEntry
.mpVar
->GetFlags() & SbxFlagBits::DontStore
))
436 rStrm
.WriteUInt16( nElem
);
437 for( size_t n
= 0; n
< mVarEntries
.size(); n
++ )
439 const SbxVarEntry
& rEntry
= mVarEntries
[n
];
440 if (rEntry
.mpVar
.is() && !(rEntry
.mpVar
->GetFlags() & SbxFlagBits::DontStore
))
442 rStrm
.WriteUInt16( n
);
443 if (!rEntry
.mpVar
->Store(rStrm
))
450 // #100883 Method to set method directly to parameter array
451 void SbxArray::PutDirect( SbxVariable
* pVar
, sal_uInt32 nIdx
)
453 SbxVariableRef
& rRef
= GetRef32( nIdx
);
460 SbxDimArray::SbxDimArray( SbxDataType t
) : SbxArray( t
), mbHasFixedSize( false )
464 SbxDimArray
& SbxDimArray::operator=( const SbxDimArray
& rArray
)
466 if( &rArray
!= this )
468 SbxArray::operator=( static_cast<const SbxArray
&>(rArray
) );
469 m_vDimensions
= rArray
.m_vDimensions
;
470 mbHasFixedSize
= rArray
.mbHasFixedSize
;
475 SbxDimArray::~SbxDimArray()
479 void SbxDimArray::Clear()
481 m_vDimensions
.clear();
487 void SbxDimArray::AddDimImpl32( sal_Int32 lb
, sal_Int32 ub
, bool bAllowSize0
)
489 ErrCode eRes
= ERRCODE_NONE
;
490 if( ub
< lb
&& !bAllowSize0
)
492 eRes
= ERRCODE_BASIC_OUT_OF_RANGE
;
498 d
.nSize
= ub
- lb
+ 1;
499 m_vDimensions
.push_back(d
);
505 void SbxDimArray::AddDim( short lb
, short ub
)
507 AddDimImpl32( lb
, ub
, false );
510 void SbxDimArray::unoAddDim( short lb
, short ub
)
512 AddDimImpl32( lb
, ub
, true );
515 void SbxDimArray::AddDim32( sal_Int32 lb
, sal_Int32 ub
)
517 AddDimImpl32( lb
, ub
, false );
520 void SbxDimArray::unoAddDim32( sal_Int32 lb
, sal_Int32 ub
)
522 AddDimImpl32( lb
, ub
, true );
526 // Readout dimension data
528 bool SbxDimArray::GetDim32( sal_Int32 n
, sal_Int32
& rlb
, sal_Int32
& rub
) const
530 if( n
< 1 || n
> static_cast<sal_Int32
>(m_vDimensions
.size()) )
532 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
536 SbxDim d
= m_vDimensions
[n
- 1];
542 bool SbxDimArray::GetDim( short n
, short& rlb
, short& rub
) const
544 sal_Int32 rlb32
, rub32
;
545 bool bRet
= GetDim32( n
, rlb32
, rub32
);
546 rub
= static_cast<short>(rub32
);
547 rlb
= static_cast<short>(rlb32
);
550 if( rlb32
< -SBX_MAXINDEX
|| rub32
> SBX_MAXINDEX
)
552 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
559 // Element-Ptr with the help of an index list
561 sal_uInt32
SbxDimArray::Offset32( const sal_Int32
* pIdx
)
564 for( const auto& rDimension
: m_vDimensions
)
566 sal_Int32 nIdx
= *pIdx
++;
567 if( nIdx
< rDimension
.nLbound
|| nIdx
> rDimension
.nUbound
)
569 nPos
= sal_uInt32(SBX_MAXINDEX32
) + 1; break;
571 nPos
= nPos
* rDimension
.nSize
+ nIdx
- rDimension
.nLbound
;
573 if( m_vDimensions
.empty() || nPos
> SBX_MAXINDEX32
)
575 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
581 sal_uInt16
SbxDimArray::Offset( const short* pIdx
)
584 for (auto const& vDimension
: m_vDimensions
)
586 short nIdx
= *pIdx
++;
587 if( nIdx
< vDimension
.nLbound
|| nIdx
> vDimension
.nUbound
)
589 nPos
= SBX_MAXINDEX
+ 1;
592 nPos
= nPos
* vDimension
.nSize
+ nIdx
- vDimension
.nLbound
;
594 if( m_vDimensions
.empty() || nPos
> SBX_MAXINDEX
)
596 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
599 return static_cast<sal_uInt16
>(nPos
);
602 SbxVariable
* SbxDimArray::Get( const short* pIdx
)
604 return SbxArray::Get( Offset( pIdx
) );
607 void SbxDimArray::Put( SbxVariable
* p
, const short* pIdx
)
609 SbxArray::Put( p
, Offset( pIdx
) );
612 SbxVariable
* SbxDimArray::Get32( const sal_Int32
* pIdx
)
614 return SbxArray::Get32( Offset32( pIdx
) );
617 void SbxDimArray::Put32( SbxVariable
* p
, const sal_Int32
* pIdx
)
619 SbxArray::Put32( p
, Offset32( pIdx
) );
622 // Element-Number with the help of Parameter-Array
623 sal_uInt32
SbxDimArray::Offset32( SbxArray
* pPar
)
625 #if HAVE_FEATURE_SCRIPTING
626 if (m_vDimensions
.empty() || !pPar
||
627 ((m_vDimensions
.size() != sal::static_int_cast
<size_t>(pPar
->Count() - 1))
628 && SbiRuntime::isVBAEnabled()))
630 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
635 sal_uInt16 nOff
= 1; // Non element 0!
636 for (auto const& vDimension
: m_vDimensions
)
638 sal_Int32 nIdx
= pPar
->Get( nOff
++ )->GetLong();
639 if( nIdx
< vDimension
.nLbound
|| nIdx
> vDimension
.nUbound
)
641 nPos
= sal_uInt32(SBX_MAXINDEX32
)+1;
644 nPos
= nPos
* vDimension
.nSize
+ nIdx
- vDimension
.nLbound
;
648 if( nPos
> sal_uInt32(SBX_MAXINDEX32
) )
650 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
656 SbxVariable
* SbxDimArray::Get( SbxArray
* pPar
)
658 return SbxArray::Get32( Offset32( pPar
) );
661 bool SbxDimArray::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
664 rStrm
.ReadInt16( nDimension
);
665 for( short i
= 0; i
< nDimension
&& rStrm
.GetError() == ERRCODE_NONE
; i
++ )
667 sal_Int16
lb(0), ub(0);
668 rStrm
.ReadInt16( lb
).ReadInt16( ub
);
671 return SbxArray::LoadData( rStrm
, nVer
);
674 bool SbxDimArray::StoreData( SvStream
& rStrm
) const
676 rStrm
.WriteInt16( m_vDimensions
.size() );
677 for( short i
= 0; i
< static_cast<short>(m_vDimensions
.size()); i
++ )
681 rStrm
.WriteInt16( lb
).WriteInt16( ub
);
683 return SbxArray::StoreData( rStrm
);
686 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */