bump product version to 5.0.4.1
[LibreOffice.git] / basic / source / sbx / sbxarray.cxx
blob0d77d4d9a6b87d9718edbc1e14c7cc13dd4bbc55
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
29 using namespace std;
31 struct SbxVarEntry
33 SbxVariableRef mpVar;
34 boost::optional<OUString> maAlias;
37 TYPEINIT1(SbxArray,SbxBase)
38 TYPEINIT1(SbxDimArray,SbxArray)
40 // SbxArray
42 SbxArray::SbxArray( SbxDataType t ) : SbxBase()
44 mpVarEntries = new VarEntriesType;
45 eType = t;
46 if( t != SbxVARIANT )
47 SetFlag( SBX_FIXED );
50 SbxArray::SbxArray( const SbxArray& rArray ) :
51 SvRefBase( rArray ), SbxBase()
53 mpVarEntries = new VarEntriesType;
54 if( rArray.eType != SbxVARIANT )
55 SetFlag( SBX_FIXED );
56 *this = rArray;
59 SbxArray& SbxArray::operator=( const SbxArray& rArray )
61 if( &rArray != this )
63 eType = rArray.eType;
64 Clear();
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;
70 if( !pSrc_ )
71 continue;
72 SbxVarEntry* pDstRef = new SbxVarEntry;
73 pDstRef->mpVar = pSrcRef->mpVar;
75 if (pSrcRef->maAlias)
76 pDstRef->maAlias.reset(*pSrcRef->maAlias);
78 if( eType != SbxVARIANT )
80 // Convert no objects
81 if( eType != SbxOBJECT || pSrc_->GetClass() != SbxCLASS_OBJECT )
83 pSrc_->Convert(eType);
86 mpVarEntries->push_back( pDstRef );
89 return *this;
92 SbxArray::~SbxArray()
94 Clear();
95 delete mpVarEntries;
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];
114 delete pEntry;
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" );
135 // Very Hot Fix
136 if( nIdx > SBX_MAXINDEX32 )
138 SetError( SbxERR_BOUNDS );
139 nIdx = 0;
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" );
152 // Very Hot Fix
153 if( nIdx > SBX_MAXINDEX )
155 SetError( SbxERR_BOUNDS );
156 nIdx = 0;
158 while( mpVarEntries->size() <= nIdx )
160 mpVarEntries->push_back(new SbxVarEntry);
162 return (*mpVarEntries)[nIdx]->mpVar;
165 SbxVariable* SbxArray::Get32( sal_uInt32 nIdx )
167 if( !CanRead() )
169 SetError( SbxERR_PROP_WRITEONLY );
170 return NULL;
172 SbxVariableRef& rRef = GetRef32( nIdx );
174 if ( !rRef.Is() )
175 rRef = new SbxVariable( eType );
177 return rRef;
180 SbxVariable* SbxArray::Get( sal_uInt16 nIdx )
182 if( !CanRead() )
184 SetError( SbxERR_PROP_WRITEONLY );
185 return NULL;
187 SbxVariableRef& rRef = GetRef( nIdx );
189 if ( !rRef.Is() )
190 rRef = new SbxVariable( eType );
192 return rRef;
195 void SbxArray::Put32( SbxVariable* pVar, sal_uInt32 nIdx )
197 if( !CanWrite() )
198 SetError( SbxERR_PROP_READONLY );
199 else
201 if( pVar )
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 )
209 rRef = pVar;
210 SetFlag( SBX_MODIFIED );
215 void SbxArray::Put( SbxVariable* pVar, sal_uInt16 nIdx )
217 if( !CanWrite() )
218 SetError( SbxERR_PROP_READONLY );
219 else
221 if( pVar )
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 )
229 rRef = pVar;
230 SetFlag( SBX_MODIFIED );
235 OUString SbxArray::GetAlias( sal_uInt16 nIdx )
237 if( !CanRead() )
239 SetError( SbxERR_PROP_WRITEONLY );
240 return OUString();
242 SbxVarEntry& rRef = reinterpret_cast<SbxVarEntry&>(GetRef( nIdx ));
244 if (!rRef.maAlias)
245 return OUString();
247 return *rRef.maAlias;
250 void SbxArray::PutAlias( const OUString& rAlias, sal_uInt16 nIdx )
252 if( !CanWrite() )
254 SetError( SbxERR_PROP_READONLY );
256 else
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 )
268 return;
270 SbxVarEntry* p = new SbxVarEntry;
271 p->mpVar = pVar;
272 size_t nSize = mpVarEntries->size();
273 if( nIdx > nSize )
275 nIdx = nSize;
277 if( eType != SbxVARIANT && pVar )
279 p->mpVar->Convert(eType);
281 if( nIdx == nSize )
283 mpVarEntries->push_back( p );
285 else
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 )
297 return;
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 );
308 delete pRef;
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 );
319 delete pRef;
320 SetFlag( SBX_MODIFIED );
324 void SbxArray::Remove( SbxVariable* pVar )
326 if( 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 )
344 if (!p)
345 return;
347 for (sal_uInt16 i = 0; i < p->Count(); ++i)
349 SbxVarEntry* pEntry1 = (*p->mpVarEntries)[i];
350 if (!pEntry1->mpVar)
351 continue;
353 OUString aName = pEntry1->mpVar->GetName();
354 sal_uInt16 nHash = pEntry1->mpVar->GetHashCode();
356 // Is the element by the same name already inside?
357 // Then overwrite!
358 for (size_t j = 0; j < mpVarEntries->size(); ++j)
360 SbxVarEntry* pEntry2 = (*mpVarEntries)[j];
361 if (!pEntry2->mpVar)
362 continue;
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();
370 break;
374 if (pEntry1->mpVar)
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];
395 if (!pEntry->mpVar)
396 continue;
398 if (pEntry->mpVar->IsVisible() && pEntry->mpVar->GetUserData() == nData)
400 p = &pEntry->mpVar;
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);
418 break;
419 case SbxCLASS_ARRAY:
420 // Casting SbxVariable to SbxArray? Really?
421 p = reinterpret_cast<SbxArray&>(*pEntry->mpVar).FindUserData(nData);
422 break;
423 default:
427 if (p)
429 p->SetFlag(SBX_EXTFOUND);
430 break;
434 return p;
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();
444 if( !nCount )
445 return NULL;
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())
452 continue;
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)))
460 p = &pEntry->mpVar;
461 p->ResetFlag(SBX_EXTFOUND);
462 break;
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);
478 break;
479 case SbxCLASS_ARRAY:
480 // Casting SbxVariable to SbxArray? Really?
481 p = reinterpret_cast<SbxArray&>(*pEntry->mpVar).Find(rName, t);
482 break;
483 default:
487 if (p)
489 p->SetFlag(SBX_EXTFOUND);
490 break;
494 return p;
497 bool SbxArray::LoadData( SvStream& rStrm, sal_uInt16 nVer )
499 sal_uInt16 nElem;
500 Clear();
501 bool bRes = true;
502 SbxFlagBits f = nFlags;
503 nFlags |= SBX_WRITE;
504 rStrm.ReadUInt16( nElem );
505 nElem &= 0x7FFF;
506 for( sal_uInt32 n = 0; n < nElem; n++ )
508 sal_uInt16 nIdx;
509 rStrm.ReadUInt16( nIdx );
510 SbxVariable* pVar = static_cast<SbxVariable*>(Load( rStrm ));
511 if( pVar )
513 SbxVariableRef& rRef = GetRef( nIdx );
514 rRef = pVar;
516 else
518 bRes = false;
519 break;
522 if( bRes )
523 bRes = LoadPrivateData( rStrm, nVer );
524 nFlags = f;
525 return bRes;
528 bool SbxArray::StoreData( SvStream& rStrm ) const
530 sal_uInt32 nElem = 0;
531 sal_uInt32 n;
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)
537 nElem++;
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))
547 return false;
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 );
557 rRef = pVar;
561 // SbxArray
563 SbxDimArray::SbxDimArray( SbxDataType t ) : SbxArray( t ), mbHasFixedSize( false )
567 SbxDimArray::SbxDimArray( const SbxDimArray& rArray )
568 : SvRefBase( rArray ), SbxArray( rArray.eType )
570 *this = rArray;
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;
581 return *this;
584 SbxDimArray::~SbxDimArray()
586 Clear();
589 void SbxDimArray::Clear()
591 m_vDimensions.clear();
594 // Add a dimension
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;
602 ub = lb;
604 SbxDim d;
605 d.nLbound = lb;
606 d.nUbound = ub;
607 d.nSize = ub - lb + 1;
608 m_vDimensions.push_back(d);
609 if( eRes )
610 SetError( eRes );
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 );
642 rub = rlb = 0;
643 return false;
645 SbxDim d = m_vDimensions[n - 1];
646 rub = d.nUbound;
647 rlb = d.nLbound;
648 return true;
651 bool SbxDimArray::GetDim( short n, short& rlb, short& rub ) const
653 sal_Int32 rlb32, rub32;
654 bool bRet = GetDim32( n, rlb32, rub32 );
655 rub = (short)rub32;
656 rlb = (short)rlb32;
657 if( bRet )
659 if( rlb32 < -SBX_MAXINDEX || rub32 > SBX_MAXINDEX )
661 SetError( SbxERR_BOUNDS );
662 return false;
665 return bRet;
668 // Element-Ptr with the help of an index list
670 sal_uInt32 SbxDimArray::Offset32( const sal_Int32* pIdx )
672 sal_uInt32 nPos = 0;
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 );
686 nPos = 0;
688 return nPos;
691 sal_uInt16 SbxDimArray::Offset( const short* pIdx )
693 long nPos = 0;
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;
701 break;
703 nPos = nPos * it->nSize + nIdx - it->nLbound;
705 if( m_vDimensions.empty() || nPos > SBX_MAXINDEX )
707 SetError( SbxERR_BOUNDS );
708 nPos = 0;
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 );
742 return 0;
744 #endif
745 sal_uInt32 nPos = 0;
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;
754 break;
756 nPos = nPos * it->nSize + nIdx - it->nLbound;
758 if( nPos > (sal_uInt32) SBX_MAXINDEX32 )
760 SetError( SbxERR_BOUNDS );
761 nPos = 0;
763 return nPos;
766 SbxVariable* SbxDimArray::Get( SbxArray* pPar )
768 return SbxArray::Get32( Offset32( pPar ) );
771 bool SbxDimArray::LoadData( SvStream& rStrm, sal_uInt16 nVer )
773 short nDimension;
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 );
779 AddDim( lb, 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++ )
789 short lb, ub;
790 GetDim( i, lb, ub );
791 rStrm.WriteInt16( lb ).WriteInt16( ub );
793 return SbxArray::StoreData( rStrm );
796 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */