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>
21 #include <o3tl/safeint.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/stream.hxx>
24 #include <basic/sbx.hxx>
25 #include <runtime.hxx>
34 std::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 SbxVariableRef
& SbxArray::GetRef32( sal_uInt32 nIdx
)
94 // If necessary extend the array
95 DBG_ASSERT( nIdx
<= SBX_MAXINDEX32
, "SBX: Array-Index > SBX_MAXINDEX32" );
97 if( nIdx
> SBX_MAXINDEX32
)
99 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
102 if ( mVarEntries
.size() <= nIdx
)
103 mVarEntries
.resize(nIdx
+1);
105 return mVarEntries
[nIdx
].mpVar
;
108 SbxVariable
* SbxArray::Get32( sal_uInt32 nIdx
)
112 SetError( ERRCODE_BASIC_PROP_WRITEONLY
);
115 SbxVariableRef
& rRef
= GetRef32( nIdx
);
118 rRef
= new SbxVariable( eType
);
123 void SbxArray::Put32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
126 SetError( ERRCODE_BASIC_PROP_READONLY
);
130 if( eType
!= SbxVARIANT
)
131 // Convert no objects
132 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxClassType::Object
)
133 pVar
->Convert( eType
);
134 SbxVariableRef
& rRef
= GetRef32( nIdx
);
135 // tdf#122250. It is possible that I hold the last reference to myself, so check, otherwise I might
136 // call SetFlag on myself after I have died.
137 bool removingMyself
= rRef
&& rRef
->GetParameters() == this && GetRefCount() == 1;
138 if( rRef
.get() != pVar
)
142 SetFlag( SbxFlagBits::Modified
);
147 OUString
SbxArray::GetAlias32( sal_uInt32 nIdx
)
151 SetError( ERRCODE_BASIC_PROP_WRITEONLY
);
154 SbxVarEntry
& rRef
= reinterpret_cast<SbxVarEntry
&>(GetRef32( nIdx
));
159 return *rRef
.maAlias
;
162 void SbxArray::PutAlias32( const OUString
& rAlias
, sal_uInt32 nIdx
)
166 SetError( ERRCODE_BASIC_PROP_READONLY
);
170 SbxVarEntry
& rRef
= reinterpret_cast<SbxVarEntry
&>( GetRef32( nIdx
) );
171 rRef
.maAlias
= rAlias
;
175 void SbxArray::Insert32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
177 DBG_ASSERT( mVarEntries
.size() <= SBX_MAXINDEX32
, "SBX: Array gets too big" );
178 if( mVarEntries
.size() > SBX_MAXINDEX32
)
184 size_t nSize
= mVarEntries
.size();
189 if( eType
!= SbxVARIANT
&& pVar
)
191 p
.mpVar
->Convert(eType
);
195 mVarEntries
.push_back( p
);
199 mVarEntries
.insert( mVarEntries
.begin() + nIdx
, p
);
201 SetFlag( SbxFlagBits::Modified
);
204 void SbxArray::Remove( sal_uInt32 nIdx
)
206 if( nIdx
< mVarEntries
.size() )
208 mVarEntries
.erase( mVarEntries
.begin() + nIdx
);
209 SetFlag( SbxFlagBits::Modified
);
213 void SbxArray::Remove( SbxVariable
const * pVar
)
217 for( size_t i
= 0; i
< mVarEntries
.size(); i
++ )
219 if (mVarEntries
[i
].mpVar
.get() == pVar
)
227 // Taking over of the data from the passed array, at which
228 // the variable of the same name will be overwritten.
230 void SbxArray::Merge( SbxArray
* p
)
235 for (auto& rEntry1
: p
->mVarEntries
)
237 if (!rEntry1
.mpVar
.is())
240 OUString aName
= rEntry1
.mpVar
->GetName();
241 sal_uInt16 nHash
= rEntry1
.mpVar
->GetHashCode();
243 // Is the element by the same name already inside?
245 for (auto& rEntry2
: mVarEntries
)
247 if (!rEntry2
.mpVar
.is())
250 if (rEntry2
.mpVar
->GetHashCode() == nHash
&&
251 rEntry2
.mpVar
->GetName().equalsIgnoreAsciiCase(aName
))
253 // Take this element and clear the original.
254 rEntry2
.mpVar
= rEntry1
.mpVar
;
255 rEntry1
.mpVar
.clear();
260 if (rEntry1
.mpVar
.is())
262 // We don't have element with the same name. Add a new entry.
263 SbxVarEntry aNewEntry
;
264 aNewEntry
.mpVar
= rEntry1
.mpVar
;
266 aNewEntry
.maAlias
= *rEntry1
.maAlias
;
267 mVarEntries
.push_back(aNewEntry
);
272 // Search of an element by his name and type. If an element is an object,
273 // it will also be scanned...
275 SbxVariable
* SbxArray::Find( const OUString
& rName
, SbxClassType t
)
277 SbxVariable
* p
= nullptr;
278 if( mVarEntries
.empty() )
280 bool bExtSearch
= IsSet( SbxFlagBits::ExtSearch
);
281 sal_uInt16 nHash
= SbxVariable::MakeHashCode( rName
);
282 for (auto& rEntry
: mVarEntries
)
284 if (!rEntry
.mpVar
.is() || !rEntry
.mpVar
->IsVisible())
287 // The very secure search works as well, if there is no hashcode!
288 sal_uInt16 nVarHash
= rEntry
.mpVar
->GetHashCode();
289 if ( (!nVarHash
|| nVarHash
== nHash
)
290 && (t
== SbxClassType::DontCare
|| rEntry
.mpVar
->GetClass() == t
)
291 && (rEntry
.mpVar
->GetName().equalsIgnoreAsciiCase(rName
)))
293 p
= rEntry
.mpVar
.get();
294 p
->ResetFlag(SbxFlagBits::ExtFound
);
298 // Did we have an array/object with extended search?
299 if (bExtSearch
&& rEntry
.mpVar
->IsSet(SbxFlagBits::ExtSearch
))
301 switch (rEntry
.mpVar
->GetClass())
303 case SbxClassType::Object
:
305 // Objects are not allowed to scan their parent.
306 SbxFlagBits nOld
= rEntry
.mpVar
->GetFlags();
307 rEntry
.mpVar
->ResetFlag(SbxFlagBits::GlobalSearch
);
308 p
= static_cast<SbxObject
&>(*rEntry
.mpVar
).Find(rName
, t
);
309 rEntry
.mpVar
->SetFlags(nOld
);
312 case SbxClassType::Array
:
313 // Casting SbxVariable to SbxArray? Really?
314 p
= reinterpret_cast<SbxArray
&>(*rEntry
.mpVar
).Find(rName
, t
);
322 p
->SetFlag(SbxFlagBits::ExtFound
);
330 bool SbxArray::LoadData( SvStream
& rStrm
, sal_uInt16
/*nVer*/ )
335 SbxFlagBits f
= nFlags
;
336 nFlags
|= SbxFlagBits::Write
;
337 rStrm
.ReadUInt16( nElem
);
339 for( sal_uInt32 n
= 0; n
< nElem
; n
++ )
342 rStrm
.ReadUInt16( nIdx
);
343 SbxVariable
* pVar
= static_cast<SbxVariable
*>(Load( rStrm
));
346 SbxVariableRef
& rRef
= GetRef32( nIdx
);
359 bool SbxArray::StoreData( SvStream
& rStrm
) const
361 sal_uInt32 nElem
= 0;
362 // Which elements are even defined?
363 for( auto& rEntry
: mVarEntries
)
365 if (rEntry
.mpVar
.is() && !(rEntry
.mpVar
->GetFlags() & SbxFlagBits::DontStore
))
368 rStrm
.WriteUInt16( nElem
);
369 for( size_t n
= 0; n
< mVarEntries
.size(); n
++ )
371 const SbxVarEntry
& rEntry
= mVarEntries
[n
];
372 if (rEntry
.mpVar
.is() && !(rEntry
.mpVar
->GetFlags() & SbxFlagBits::DontStore
))
374 rStrm
.WriteUInt16( n
);
375 if (!rEntry
.mpVar
->Store(rStrm
))
382 // #100883 Method to set method directly to parameter array
383 void SbxArray::PutDirect( SbxVariable
* pVar
, sal_uInt32 nIdx
)
385 SbxVariableRef
& rRef
= GetRef32( nIdx
);
392 SbxDimArray::SbxDimArray( SbxDataType t
) : SbxArray( t
), mbHasFixedSize( false )
396 SbxDimArray
& SbxDimArray::operator=( const SbxDimArray
& rArray
)
398 if( &rArray
!= this )
400 SbxArray::operator=( static_cast<const SbxArray
&>(rArray
) );
401 m_vDimensions
= rArray
.m_vDimensions
;
402 mbHasFixedSize
= rArray
.mbHasFixedSize
;
407 SbxDimArray::~SbxDimArray()
411 void SbxDimArray::Clear()
413 m_vDimensions
.clear();
419 void SbxDimArray::AddDimImpl32( sal_Int32 lb
, sal_Int32 ub
, bool bAllowSize0
)
421 ErrCode eRes
= ERRCODE_NONE
;
422 if( ub
< lb
&& !bAllowSize0
)
424 eRes
= ERRCODE_BASIC_OUT_OF_RANGE
;
430 d
.nSize
= ub
- lb
+ 1;
431 m_vDimensions
.push_back(d
);
436 void SbxDimArray::AddDim32( sal_Int32 lb
, sal_Int32 ub
)
438 AddDimImpl32( lb
, ub
, false );
441 void SbxDimArray::unoAddDim32( sal_Int32 lb
, sal_Int32 ub
)
443 AddDimImpl32( lb
, ub
, true );
447 // Readout dimension data
449 bool SbxDimArray::GetDim32( sal_Int32 n
, sal_Int32
& rlb
, sal_Int32
& rub
) const
451 if( n
< 1 || n
> static_cast<sal_Int32
>(m_vDimensions
.size()) )
453 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
457 SbxDim d
= m_vDimensions
[n
- 1];
463 // Element-Ptr with the help of an index list
465 sal_uInt32
SbxDimArray::Offset32( const sal_Int32
* pIdx
)
468 for( const auto& rDimension
: m_vDimensions
)
470 sal_Int32 nIdx
= *pIdx
++;
471 if( nIdx
< rDimension
.nLbound
|| nIdx
> rDimension
.nUbound
)
473 nPos
= sal_uInt32(SBX_MAXINDEX32
) + 1; break;
475 nPos
= nPos
* rDimension
.nSize
+ nIdx
- rDimension
.nLbound
;
477 if( m_vDimensions
.empty() || nPos
> SBX_MAXINDEX32
)
479 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
485 SbxVariable
* SbxDimArray::Get32( const sal_Int32
* pIdx
)
487 return SbxArray::Get32( Offset32( pIdx
) );
490 void SbxDimArray::Put32( SbxVariable
* p
, const sal_Int32
* pIdx
)
492 SbxArray::Put32( p
, Offset32( pIdx
) );
495 // Element-Number with the help of Parameter-Array
496 sal_uInt32
SbxDimArray::Offset32( SbxArray
* pPar
)
498 #if HAVE_FEATURE_SCRIPTING
499 if (m_vDimensions
.empty() || !pPar
||
500 ((m_vDimensions
.size() != sal::static_int_cast
<size_t>(pPar
->Count32() - 1))
501 && SbiRuntime::isVBAEnabled()))
503 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
508 sal_uInt32 nOff
= 1; // Non element 0!
509 for (auto const& vDimension
: m_vDimensions
)
511 sal_Int32 nIdx
= pPar
->Get32( nOff
++ )->GetLong();
512 if( nIdx
< vDimension
.nLbound
|| nIdx
> vDimension
.nUbound
)
514 nPos
= sal_uInt32(SBX_MAXINDEX32
)+1;
517 nPos
= nPos
* vDimension
.nSize
+ nIdx
- vDimension
.nLbound
;
521 if( nPos
> o3tl::make_unsigned(SBX_MAXINDEX32
) )
523 SetError( ERRCODE_BASIC_OUT_OF_RANGE
);
529 SbxVariable
* SbxDimArray::Get( SbxArray
* pPar
)
531 return SbxArray::Get32( Offset32( pPar
) );
534 bool SbxDimArray::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
537 rStrm
.ReadInt16( nDimension
);
538 for( short i
= 0; i
< nDimension
&& rStrm
.GetError() == ERRCODE_NONE
; i
++ )
540 sal_Int16
lb(0), ub(0);
541 rStrm
.ReadInt16( lb
).ReadInt16( ub
);
544 return SbxArray::LoadData( rStrm
, nVer
);
547 bool SbxDimArray::StoreData( SvStream
& rStrm
) const
549 assert(m_vDimensions
.size() <= sal::static_int_cast
<size_t>(std::numeric_limits
<sal_Int16
>::max()));
550 rStrm
.WriteInt16( m_vDimensions
.size() );
551 for( sal_Int32 i
= 1; i
<= static_cast<sal_Int32
>(m_vDimensions
.size()); i
++ )
553 sal_Int32 lb32
, ub32
;
554 GetDim32(i
, lb32
, ub32
);
555 assert(lb32
>= -SBX_MAXINDEX
&& ub32
<= SBX_MAXINDEX
);
556 rStrm
.WriteInt16(lb32
).WriteInt16(ub32
);
558 return SbxArray::StoreData( rStrm
);
561 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */