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 <tools/stream.hxx>
21 #include <basic/sbx.hxx>
22 #include "runtime.hxx"
26 struct SbxDim
{ // an array-dimension:
27 SbxDim
* pNext
; // Link
28 sal_Int32 nLbound
, nUbound
; // Limitations
29 sal_Int32 nSize
; // Number of elements
32 class SbxVarEntry
: public SbxVariableRef
{
35 SbxVarEntry() : SbxVariableRef(), pAlias( NULL
) {}
36 ~SbxVarEntry() { delete pAlias
; }
39 typedef SbxVarEntry
* SbxVarEntryPtr
;
40 typedef vector
< SbxVarEntryPtr
> SbxVarEntryPtrVector
;
41 class SbxVarRefs
: public SbxVarEntryPtrVector
48 TYPEINIT1(SbxArray
,SbxBase
)
49 TYPEINIT1(SbxDimArray
,SbxArray
)
53 SbxArray::SbxArray( SbxDataType t
) : SbxBase()
55 pData
= new SbxVarRefs
;
61 SbxArray::SbxArray( const SbxArray
& rArray
) :
62 SvRefBase( rArray
), SbxBase()
64 pData
= new SbxVarRefs
;
65 if( rArray
.eType
!= SbxVARIANT
)
70 SbxArray
& SbxArray::operator=( const SbxArray
& rArray
)
76 SbxVarRefs
* pSrc
= rArray
.pData
;
77 for( sal_uInt32 i
= 0; i
< pSrc
->size(); i
++ )
79 SbxVarEntryPtr pSrcRef
= (*pSrc
)[i
];
80 const SbxVariable
* pSrc_
= *pSrcRef
;
83 SbxVarEntryPtr pDstRef
= new SbxVarEntry
;
84 *((SbxVariableRef
*) pDstRef
) = *((SbxVariableRef
*) pSrcRef
);
87 pDstRef
->pAlias
= new OUString( *pSrcRef
->pAlias
);
89 if( eType
!= SbxVARIANT
)
92 if( eType
!= SbxOBJECT
|| pSrc_
->GetClass() != SbxCLASS_OBJECT
)
94 ((SbxVariable
*) pSrc_
)->Convert( eType
);
97 pData
->push_back( pDstRef
);
103 SbxArray::~SbxArray()
109 SbxDataType
SbxArray::GetType() const
111 return (SbxDataType
) ( eType
| SbxARRAY
);
114 SbxClassType
SbxArray::GetClass() const
116 return SbxCLASS_ARRAY
;
119 void SbxArray::Clear()
121 sal_uInt32 nSize
= pData
->size();
122 for( sal_uInt32 i
= 0 ; i
< nSize
; i
++ )
124 SbxVarEntry
* pEntry
= (*pData
)[i
];
130 sal_uInt32
SbxArray::Count32() const
132 return pData
->size();
135 sal_uInt16
SbxArray::Count() const
137 sal_uInt32 nCount
= pData
->size();
138 DBG_ASSERT( nCount
<= SBX_MAXINDEX
, "SBX: Array-Index > SBX_MAXINDEX" );
139 return (sal_uInt16
)nCount
;
142 SbxVariableRef
& SbxArray::GetRef32( sal_uInt32 nIdx
)
144 // If necessary extend the array
145 DBG_ASSERT( nIdx
<= SBX_MAXINDEX32
, "SBX: Array-Index > SBX_MAXINDEX32" );
147 if( nIdx
> SBX_MAXINDEX32
)
149 SetError( SbxERR_BOUNDS
);
152 while( pData
->size() <= nIdx
)
154 const SbxVarEntryPtr p
= new SbxVarEntry
;
155 pData
->push_back( p
);
157 return *((*pData
)[nIdx
]);
160 SbxVariableRef
& SbxArray::GetRef( sal_uInt16 nIdx
)
162 // If necessary extend the array
163 DBG_ASSERT( nIdx
<= SBX_MAXINDEX
, "SBX: Array-Index > SBX_MAXINDEX" );
165 if( nIdx
> SBX_MAXINDEX
)
167 SetError( SbxERR_BOUNDS
);
170 while( pData
->size() <= nIdx
)
172 const SbxVarEntryPtr p
= new SbxVarEntry
;
173 pData
->push_back( p
);
175 return *((*pData
)[nIdx
]);
178 SbxVariable
* SbxArray::Get32( sal_uInt32 nIdx
)
182 SetError( SbxERR_PROP_WRITEONLY
);
185 SbxVariableRef
& rRef
= GetRef32( nIdx
);
188 rRef
= new SbxVariable( eType
);
191 DBG_CHKOBJ( rRef
, SbxBase
, 0 );
197 SbxVariable
* SbxArray::Get( sal_uInt16 nIdx
)
201 SetError( SbxERR_PROP_WRITEONLY
);
204 SbxVariableRef
& rRef
= GetRef( nIdx
);
207 rRef
= new SbxVariable( eType
);
210 DBG_CHKOBJ( rRef
, SbxBase
, 0 );
216 void SbxArray::Put32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
219 SetError( SbxERR_PROP_READONLY
);
223 if( eType
!= SbxVARIANT
)
224 // Convert no objects
225 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxCLASS_OBJECT
)
226 pVar
->Convert( eType
);
227 SbxVariableRef
& rRef
= GetRef32( nIdx
);
228 if( (SbxVariable
*) rRef
!= pVar
)
231 SetFlag( SBX_MODIFIED
);
236 void SbxArray::Put( SbxVariable
* pVar
, sal_uInt16 nIdx
)
239 SetError( SbxERR_PROP_READONLY
);
243 if( eType
!= SbxVARIANT
)
244 // Convert no objects
245 if( eType
!= SbxOBJECT
|| pVar
->GetClass() != SbxCLASS_OBJECT
)
246 pVar
->Convert( eType
);
247 SbxVariableRef
& rRef
= GetRef( nIdx
);
248 if( (SbxVariable
*) rRef
!= pVar
)
251 SetFlag( SBX_MODIFIED
);
256 const OUString
& SbxArray::GetAlias( sal_uInt16 nIdx
)
258 static const OUString
sEmpty("");
262 SetError( SbxERR_PROP_WRITEONLY
);
265 SbxVarEntry
& rRef
= (SbxVarEntry
&) GetRef( nIdx
);
274 DBG_CHKOBJ( rRef
, SbxBase
, 0 );
281 void SbxArray::PutAlias( const OUString
& rAlias
, sal_uInt16 nIdx
)
285 SetError( SbxERR_PROP_READONLY
);
289 SbxVarEntry
& rRef
= (SbxVarEntry
&) GetRef( nIdx
);
292 rRef
.pAlias
= new OUString( rAlias
);
296 *rRef
.pAlias
= rAlias
;
301 void SbxArray::Insert32( SbxVariable
* pVar
, sal_uInt32 nIdx
)
303 DBG_ASSERT( pData
->size() <= SBX_MAXINDEX32
, "SBX: Array gets too big" );
304 if( pData
->size() > SBX_MAXINDEX32
)
308 SbxVarEntryPtr p
= new SbxVarEntry
;
309 *((SbxVariableRef
*) p
) = pVar
;
310 SbxVarEntryPtrVector::size_type nSize
= pData
->size();
315 if( eType
!= SbxVARIANT
&& pVar
)
317 (*p
)->Convert( eType
);
321 pData
->push_back( p
);
325 pData
->insert( pData
->begin() + nIdx
, p
);
327 SetFlag( SBX_MODIFIED
);
330 void SbxArray::Insert( SbxVariable
* pVar
, sal_uInt16 nIdx
)
332 DBG_ASSERT( pData
->size() <= 0x3FF0, "SBX: Array gets too big" );
333 if( pData
->size() > 0x3FF0 )
337 Insert32( pVar
, nIdx
);
340 void SbxArray::Remove32( sal_uInt32 nIdx
)
342 if( nIdx
< pData
->size() )
344 SbxVariableRef
* pRef
= (*pData
)[nIdx
];
345 pData
->erase( pData
->begin() + nIdx
);
347 SetFlag( SBX_MODIFIED
);
351 void SbxArray::Remove( sal_uInt16 nIdx
)
353 if( nIdx
< pData
->size() )
355 SbxVariableRef
* pRef
= (*pData
)[nIdx
];
356 pData
->erase( pData
->begin() + nIdx
);
358 SetFlag( SBX_MODIFIED
);
362 void SbxArray::Remove( SbxVariable
* pVar
)
366 for( sal_uInt32 i
= 0; i
< pData
->size(); i
++ )
368 SbxVariableRef
* pRef
= (*pData
)[i
];
371 Remove32( i
); break;
377 // Taking over of the data from the passed array, at which
378 // the variable of the same name will be overwritten.
380 void SbxArray::Merge( SbxArray
* p
)
384 sal_uInt32 nSize
= p
->Count();
385 for( sal_uInt32 i
= 0; i
< nSize
; i
++ )
387 SbxVarEntryPtr pRef1
= (*(p
->pData
))[i
];
388 // Is the element by name already inside?
390 SbxVariable
* pVar
= *pRef1
;
393 OUString aName
= pVar
->GetName();
394 sal_uInt16 nHash
= pVar
->GetHashCode();
395 for( sal_uInt32 j
= 0; j
< pData
->size(); j
++ )
397 SbxVariableRef
* pRef2
= (*pData
)[j
];
398 if( (*pRef2
)->GetHashCode() == nHash
399 && (*pRef2
)->GetName().equalsIgnoreAsciiCase( aName
) )
401 *pRef2
= pVar
; pRef1
= NULL
;
407 SbxVarEntryPtr pRef
= new SbxVarEntry
;
408 const SbxVarEntryPtr pTemp
= pRef
;
409 pData
->push_back( pTemp
);
410 *((SbxVariableRef
*) pRef
) = *((SbxVariableRef
*) pRef1
);
413 pRef
->pAlias
= new OUString( *pRef1
->pAlias
);
421 // Search of an element via the user data. If the element is
422 // object, it will also be scanned.
424 SbxVariable
* SbxArray::FindUserData( sal_uInt32 nData
)
426 SbxVariable
* p
= NULL
;
427 for( sal_uInt32 i
= 0; i
< pData
->size(); i
++ )
429 SbxVariableRef
* pRef
= (*pData
)[i
];
430 SbxVariable
* pVar
= *pRef
;
433 if( pVar
->IsVisible() && pVar
->GetUserData() == nData
)
436 p
->ResetFlag( SBX_EXTFOUND
);
437 break; // JSM 1995-10-06
439 // Did we have an array/object with extended search?
440 else if( pVar
->IsSet( SBX_EXTSEARCH
) )
442 switch( pVar
->GetClass() )
444 case SbxCLASS_OBJECT
:
446 // Objects are not allowed to scan their parent.
447 sal_uInt16 nOld
= pVar
->GetFlags();
448 pVar
->ResetFlag( SBX_GBLSEARCH
);
449 p
= ((SbxObject
*) pVar
)->FindUserData( nData
);
450 pVar
->SetFlags( nOld
);
454 p
= ((SbxArray
*) pVar
)->FindUserData( nData
);
460 p
->SetFlag( SBX_EXTFOUND
);
469 // Search of an element by his name and type. If an element is an object,
470 // it will also be scanned..
472 SbxVariable
* SbxArray::Find( const OUString
& rName
, SbxClassType t
)
474 SbxVariable
* p
= NULL
;
475 sal_uInt32 nCount
= pData
->size();
478 sal_Bool bExtSearch
= IsSet( SBX_EXTSEARCH
);
479 sal_uInt16 nHash
= SbxVariable::MakeHashCode( rName
);
480 for( sal_uInt32 i
= 0; i
< nCount
; i
++ )
482 SbxVariableRef
* pRef
= (*pData
)[i
];
483 SbxVariable
* pVar
= *pRef
;
484 if( pVar
&& pVar
->IsVisible() )
486 // The very secure search works as well, if there is no hashcode!
487 sal_uInt16 nVarHash
= pVar
->GetHashCode();
488 if( ( !nVarHash
|| nVarHash
== nHash
)
489 && ( t
== SbxCLASS_DONTCARE
|| pVar
->GetClass() == t
)
490 && ( pVar
->GetName().equalsIgnoreAsciiCase( rName
) ) )
493 p
->ResetFlag( SBX_EXTFOUND
);
496 // Did we have an array/object with extended search?
497 else if( bExtSearch
&& pVar
->IsSet( SBX_EXTSEARCH
) )
499 switch( pVar
->GetClass() )
501 case SbxCLASS_OBJECT
:
503 // Objects are not allowed to scan their parent.
504 sal_uInt16 nOld
= pVar
->GetFlags();
505 pVar
->ResetFlag( SBX_GBLSEARCH
);
506 p
= ((SbxObject
*) pVar
)->Find( rName
, t
);
507 pVar
->SetFlags( nOld
);
511 p
= ((SbxArray
*) pVar
)->Find( rName
, t
);
517 p
->SetFlag( SBX_EXTFOUND
);
526 sal_Bool
SbxArray::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
530 sal_Bool bRes
= sal_True
;
531 sal_uInt16 f
= nFlags
;
535 for( sal_uInt32 n
= 0; n
< nElem
; n
++ )
539 SbxVariable
* pVar
= (SbxVariable
*) Load( rStrm
);
542 SbxVariableRef
& rRef
= GetRef( nIdx
);
547 bRes
= sal_False
; break;
551 bRes
= LoadPrivateData( rStrm
, nVer
);
556 sal_Bool
SbxArray::StoreData( SvStream
& rStrm
) const
558 sal_uInt32 nElem
= 0;
560 // Which elements are even defined?
561 for( n
= 0; n
< pData
->size(); n
++ )
563 SbxVariableRef
* pRef
= (*pData
)[n
];
564 SbxVariable
* p
= *pRef
;
565 if( p
&& !( p
->GetFlags() & SBX_DONTSTORE
) )
568 rStrm
<< (sal_uInt16
) nElem
;
569 for( n
= 0; n
< pData
->size(); n
++ )
571 SbxVariableRef
* pRef
= (*pData
)[n
];
572 SbxVariable
* p
= *pRef
;
573 if( p
&& !( p
->GetFlags() & SBX_DONTSTORE
) )
575 rStrm
<< (sal_uInt16
) n
;
576 if( !p
->Store( rStrm
) )
580 return StorePrivateData( rStrm
);
583 // #100883 Method to set method directly to parameter array
584 void SbxArray::PutDirect( SbxVariable
* pVar
, sal_uInt32 nIdx
)
586 SbxVariableRef
& rRef
= GetRef32( nIdx
);
593 SbxDimArray::SbxDimArray( SbxDataType t
) : SbxArray( t
), mbHasFixedSize( false )
595 pFirst
= pLast
= NULL
;
599 SbxDimArray::SbxDimArray( const SbxDimArray
& rArray
)
600 : SvRefBase( rArray
), SbxArray( rArray
.eType
)
602 pFirst
= pLast
= NULL
;
607 SbxDimArray
& SbxDimArray::operator=( const SbxDimArray
& rArray
)
609 if( &rArray
!= this )
611 SbxArray::operator=( (const SbxArray
&) rArray
);
612 SbxDim
* p
= rArray
.pFirst
;
615 AddDim32( p
->nLbound
, p
->nUbound
);
618 this->mbHasFixedSize
= rArray
.mbHasFixedSize
;
623 SbxDimArray::~SbxDimArray()
628 void SbxDimArray::Clear()
633 SbxDim
* q
= p
->pNext
;
637 pFirst
= pLast
= NULL
;
643 void SbxDimArray::AddDimImpl32( sal_Int32 lb
, sal_Int32 ub
, sal_Bool bAllowSize0
)
645 SbxError eRes
= SbxERR_OK
;
646 if( ub
< lb
&& !bAllowSize0
)
648 eRes
= SbxERR_BOUNDS
;
651 SbxDim
* p
= new SbxDim
;
654 p
->nSize
= ub
- lb
+ 1;
659 pLast
->pNext
= p
, pLast
= p
;
665 short SbxDimArray::GetDims() const
670 void SbxDimArray::AddDim( short lb
, short ub
)
672 AddDimImpl32( lb
, ub
, sal_False
);
675 void SbxDimArray::unoAddDim( short lb
, short ub
)
677 AddDimImpl32( lb
, ub
, sal_True
);
680 void SbxDimArray::AddDim32( sal_Int32 lb
, sal_Int32 ub
)
682 AddDimImpl32( lb
, ub
, sal_False
);
685 void SbxDimArray::unoAddDim32( sal_Int32 lb
, sal_Int32 ub
)
687 AddDimImpl32( lb
, ub
, sal_True
);
691 // Readout dimension data
693 sal_Bool
SbxDimArray::GetDim32( sal_Int32 n
, sal_Int32
& rlb
, sal_Int32
& rub
) const
695 if( n
< 1 || n
> nDim
)
697 SetError( SbxERR_BOUNDS
); rub
= rlb
= 0; return sal_False
;
707 sal_Bool
SbxDimArray::GetDim( short n
, short& rlb
, short& rub
) const
709 sal_Int32 rlb32
, rub32
;
710 sal_Bool bRet
= GetDim32( n
, rlb32
, rub32
);
713 if( rlb32
< -SBX_MAXINDEX
|| rub32
> SBX_MAXINDEX
)
715 SetError( SbxERR_BOUNDS
);
724 // Element-Ptr with the help of an index list
726 sal_uInt32
SbxDimArray::Offset32( const sal_Int32
* pIdx
)
729 for( SbxDim
* p
= pFirst
; p
; p
= p
->pNext
)
731 sal_Int32 nIdx
= *pIdx
++;
732 if( nIdx
< p
->nLbound
|| nIdx
> p
->nUbound
)
734 nPos
= (sal_uInt32
)SBX_MAXINDEX32
+ 1; break;
736 nPos
= nPos
* p
->nSize
+ nIdx
- p
->nLbound
;
738 if( nDim
== 0 || nPos
> SBX_MAXINDEX32
)
740 SetError( SbxERR_BOUNDS
); nPos
= 0;
745 sal_uInt16
SbxDimArray::Offset( const short* pIdx
)
748 for( SbxDim
* p
= pFirst
; p
; p
= p
->pNext
)
750 short nIdx
= *pIdx
++;
751 if( nIdx
< p
->nLbound
|| nIdx
> p
->nUbound
)
753 nPos
= SBX_MAXINDEX
+ 1; break;
755 nPos
= nPos
* p
->nSize
+ nIdx
- p
->nLbound
;
757 if( nDim
== 0 || nPos
> SBX_MAXINDEX
)
759 SetError( SbxERR_BOUNDS
); nPos
= 0;
761 return (sal_uInt16
) nPos
;
764 SbxVariable
* SbxDimArray::Get( const short* pIdx
)
766 return SbxArray::Get( Offset( pIdx
) );
769 void SbxDimArray::Put( SbxVariable
* p
, const short* pIdx
)
771 SbxArray::Put( p
, Offset( pIdx
) );
774 SbxVariable
* SbxDimArray::Get32( const sal_Int32
* pIdx
)
776 return SbxArray::Get32( Offset32( pIdx
) );
779 void SbxDimArray::Put32( SbxVariable
* p
, const sal_Int32
* pIdx
)
781 SbxArray::Put32( p
, Offset32( pIdx
) );
785 // Element-Number with the help of Parameter-Array
787 sal_uInt32
SbxDimArray::Offset32( SbxArray
* pPar
)
789 #ifndef DISABLE_SCRIPTING
790 if( nDim
== 0 || !pPar
|| ( ( nDim
!= ( pPar
->Count() - 1 ) ) && SbiRuntime::isVBAEnabled() ) )
792 SetError( SbxERR_BOUNDS
); return 0;
796 sal_uInt16 nOff
= 1; // Non element 0!
797 for( SbxDim
* p
= pFirst
; p
&& !IsError(); p
= p
->pNext
)
799 sal_Int32 nIdx
= pPar
->Get( nOff
++ )->GetLong();
800 if( nIdx
< p
->nLbound
|| nIdx
> p
->nUbound
)
802 nPos
= (sal_uInt32
) SBX_MAXINDEX32
+1; break;
804 nPos
= nPos
* p
->nSize
+ nIdx
- p
->nLbound
;
806 if( nPos
> (sal_uInt32
) SBX_MAXINDEX32
)
808 SetError( SbxERR_BOUNDS
); nPos
= 0;
813 SbxVariable
* SbxDimArray::Get( SbxArray
* pPar
)
815 return SbxArray::Get32( Offset32( pPar
) );
818 sal_Bool
SbxDimArray::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
822 for( short i
= 0; i
< nDimension
&& rStrm
.GetError() == SVSTREAM_OK
; i
++ )
828 return SbxArray::LoadData( rStrm
, nVer
);
831 sal_Bool
SbxDimArray::StoreData( SvStream
& rStrm
) const
833 rStrm
<< (sal_Int16
) nDim
;
834 for( short i
= 0; i
< nDim
; i
++ )
838 rStrm
<< (sal_Int16
) lb
<< (sal_Int16
) ub
;
840 return SbxArray::StoreData( rStrm
);
843 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */