/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svl.hxx"

#include <string.h>
#include <cstdarg>

#define _SVSTDARR_USHORTS
#define _SVSTDARR_ULONGS

#include <svl/svstdarr.hxx>
#include <svl/itemset.hxx>
#include <svl/itempool.hxx>
#include <svl/itemiter.hxx>
#include <svl/whiter.hxx>
#include <svl/nranges.hxx>
#include "whassert.hxx"

#include <tools/stream.hxx>
#include <tools/solar.h>

// STATIC DATA -----------------------------------------------------------

static const sal_uInt16 nInitCount = 10; // einzelne USHORTs => 5 Paare ohne '0'
#ifdef DBG_UTIL
static sal_uLong nRangesCopyCount = 0;	 // wie oft wurden Ranges kopiert
#endif

DBG_NAME(SfxItemSet)

//========================================================================

#define NUMTYPE 		sal_uInt16
#define SvNums			SvUShorts
#define SfxNumRanges    SfxUShortRanges
#include "nranges.cxx"
#undef NUMTYPE
#undef SvNums
#undef SfxNumRanges

#define NUMTYPE 		sal_uLong
#define SvNums			SvULongs
#define SfxNumRanges    SfxULongRanges
#include "nranges.cxx"
#undef NUMTYPE
#undef SvNums
#undef SfxNumRanges

//========================================================================

#ifdef DBG_UTIL


const sal_Char *DbgCheckItemSet( const void* pVoid )
{
	const SfxItemSet *pSet = (const SfxItemSet*) pVoid;
	SfxWhichIter aIter( *pSet );
	sal_uInt16 nCount = 0, n = 0;
	for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh; nWh = aIter.NextWhich(), ++n )
	{
		const SfxPoolItem *pItem = pSet->_aItems[n];
		if ( pItem )
		{
			++nCount;
			DBG_ASSERT( IsInvalidItem(pItem) ||
						pItem->Which() == 0 || pItem->Which() == nWh,
						"SfxItemSet: invalid which-id" );
			DBG_ASSERT( IsInvalidItem(pItem) || !pItem->Which() ||
					!SfxItemPool::IsWhich(pItem->Which()) ||
					pSet->GetPool()->IsItemFlag(nWh, SFX_ITEM_NOT_POOLABLE) ||
					SFX_ITEMS_NULL != pSet->GetPool()->GetSurrogate(pItem),
					"SfxItemSet: item in set which is not in pool" );
		}

	}
	DBG_ASSERT( pSet->_nCount == nCount, "wrong SfxItemSet::nCount detected" );

	return 0;
}

#endif
// -----------------------------------------------------------------------

SfxItemSet::SfxItemSet
(
	SfxItemPool&	rPool,  		/* der Pool, in dem die SfxPoolItems,
									   welche in dieses SfxItemSet gelangen,
									   aufgenommen werden sollen */
	sal_Bool
#ifdef DBG_UTIL
#ifdef SFX_ITEMSET_NO_DEFAULT_CTOR

                    bTotalRanges	/* komplette Pool-Ranges uebernehmen,
                                       muss auf sal_True gesetzt werden */
#endif
#endif
)
/*	[Beschreibung]

    Konstruktor fuer ein SfxItemSet mit genau den Which-Bereichen, welche
	dem angegebenen <SfxItemPool> bekannt sind.


	[Anmerkung]

	F"ur Sfx-Programmierer ein derart konstruiertes SfxItemSet kann
	keinerlei Items mit Slot-Ids als Which-Werte aufnehmen!
*/

:	_pPool( &rPool ),
	_pParent( 0 ),
	_nCount( 0 ),
	_aHashKey( 0 ) //i120575
{
	DBG_CTOR(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
	DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
//	DBG_ASSERT( bTotalRanges || abs( &bTotalRanges - this ) < 1000,
//				"please use suitable ranges" );
#ifdef DBG_UTIL
#ifdef SFX_ITEMSET_NO_DEFAULT_CTOR
	if ( !bTotalRanges )
		*(int*)0 = 0; // GPF
#endif
#endif

	_pWhichRanges = (sal_uInt16*) _pPool->GetFrozenIdRanges();
	DBG_ASSERT( _pWhichRanges, "don't create ItemSets with full range before FreezeIdRanges()" );
	if ( !_pWhichRanges )
		_pPool->FillItemIdRanges_Impl( _pWhichRanges );

	const sal_uInt16 nSize = TotalCount();
	_aItems = new const SfxPoolItem* [ nSize ];
	memset( (void*) _aItems, 0, nSize * sizeof( SfxPoolItem* ) );
}

// -----------------------------------------------------------------------

SfxItemSet::SfxItemSet( SfxItemPool& rPool, sal_uInt16 nWhich1, sal_uInt16 nWhich2 ):
	_pPool( &rPool ),
	_pParent( 0 ),
	_nCount( 0 ),
	_aHashKey( 0 ) //i120575
{
	DBG_CTOR(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( nWhich1 <= nWhich2, "Ungueltiger Bereich" );
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
	DBG( _pChildCountCtor; *_pChildCount(this) = 0 );

	InitRanges_Impl(nWhich1, nWhich2);
}

// -----------------------------------------------------------------------

void SfxItemSet::InitRanges_Impl(sal_uInt16 nWh1, sal_uInt16 nWh2)
{
	DBG_CHKTHIS(SfxItemSet, 0);
	_pWhichRanges = new sal_uInt16[ 3 ];
	*(_pWhichRanges+0) = nWh1;
	*(_pWhichRanges+1) = nWh2;
	*(_pWhichRanges+2) = 0;
	const sal_uInt16 nRg = nWh2 - nWh1 + 1;
	_aItems = new const SfxPoolItem* [ nRg ];
	memset( (void*) _aItems, 0, nRg * sizeof( SfxPoolItem* ) );
}

// -----------------------------------------------------------------------

void SfxItemSet::InitRanges_Impl(va_list pArgs, sal_uInt16 nWh1, sal_uInt16 nWh2, sal_uInt16 nNull)
{
	DBG_CHKTHIS(SfxItemSet, 0);

	sal_uInt16 nSize = InitializeRanges_Impl( _pWhichRanges, pArgs, nWh1, nWh2, nNull );
	_aItems = new const SfxPoolItem* [ nSize ];
	memset( (void*) _aItems, 0, sizeof( SfxPoolItem* ) * nSize );
}

// -----------------------------------------------------------------------

SfxItemSet::SfxItemSet( SfxItemPool& rPool,
						USHORT_ARG nWh1, USHORT_ARG nWh2, USHORT_ARG nNull, ... ):
	_pPool( &rPool ),
	_pParent( 0 ),
	_pWhichRanges( 0 ),
	_nCount( 0 ),
	_aHashKey( 0 ) //i120575
{
	DBG_CTOR(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( nWh1 <= nWh2, "Ungueltiger Bereich" );
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
	DBG( _pChildCountCtor; *_pChildCount(this) = 0 );

	if(!nNull)
		InitRanges_Impl(
            sal::static_int_cast< sal_uInt16 >(nWh1),
            sal::static_int_cast< sal_uInt16 >(nWh2));
	else {
		va_list pArgs;
		va_start( pArgs, nNull );
		InitRanges_Impl(
            pArgs, sal::static_int_cast< sal_uInt16 >(nWh1),
            sal::static_int_cast< sal_uInt16 >(nWh2),
            sal::static_int_cast< sal_uInt16 >(nNull));
	}
}

// -----------------------------------------------------------------------

void SfxItemSet::InitRanges_Impl(const sal_uInt16 *pWhichPairTable)
{
	DBG_CHKTHIS(SfxItemSet, 0);
	DBG_TRACE1("SfxItemSet: Ranges-CopyCount==%ul", ++nRangesCopyCount);

	sal_uInt16 nCnt = 0;
	const sal_uInt16* pPtr = pWhichPairTable;
	while( *pPtr )
	{
		nCnt += ( *(pPtr+1) - *pPtr ) + 1;
		pPtr += 2;
	}

	_aItems = new const SfxPoolItem* [ nCnt ];
	memset( (void*) _aItems, 0, sizeof( SfxPoolItem* ) * nCnt );

	std::ptrdiff_t cnt = pPtr - pWhichPairTable +1;
	_pWhichRanges = new sal_uInt16[ cnt ];
	memcpy( _pWhichRanges, pWhichPairTable, sizeof( sal_uInt16 ) * cnt );
}


// -----------------------------------------------------------------------

SfxItemSet::SfxItemSet( SfxItemPool& rPool, const sal_uInt16* pWhichPairTable ):
	_pPool( &rPool ),
	_pParent( 0 ),
	_pWhichRanges(0),
	_nCount( 0 ),
	_aHashKey( 0 ) //i120575
{
	DBG_CTOR(SfxItemSet, 0);
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
	DBG( _pChildCountCtor; *_pChildCount(this) = 0 );

	// pWhichPairTable == 0 ist f"ur das SfxAllEnumItemSet
	if ( pWhichPairTable )
		InitRanges_Impl(pWhichPairTable);
}

// -----------------------------------------------------------------------

SfxItemSet::SfxItemSet( const SfxItemSet& rASet ):
	_pPool( rASet._pPool ),
	_pParent( rASet._pParent ),
	_nCount( rASet._nCount ),
	_aHashKey( 0 ) //i120575
{
	DBG_CTOR(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );
	DBG( _pChildCountCtor; *_pChildCount(this) = 0 );
	DBG( ++*_pChildCount(_pParent) );

	// errechne die Anzahl von Attributen
	sal_uInt16 nCnt = 0;
	sal_uInt16* pPtr = rASet._pWhichRanges;
	while( *pPtr )
	{
		nCnt += ( *(pPtr+1) - *pPtr ) + 1;
		pPtr += 2;
	}

	_aItems = new const SfxPoolItem* [ nCnt ];

	// Attribute kopieren
	SfxItemArray ppDst = _aItems, ppSrc = rASet._aItems;
	for( sal_uInt16 n = nCnt; n; --n, ++ppDst, ++ppSrc )
		if ( 0 == *ppSrc || 				// aktueller Default?
			 IsInvalidItem(*ppSrc) ||		// Dont Care?
			 IsStaticDefaultItem(*ppSrc) )	// nicht zu poolende Defaults
			// einfach Pointer kopieren
			*ppDst = *ppSrc;
		else if ( _pPool->IsItemFlag( **ppSrc, SFX_ITEM_POOLABLE ) )
		{
			// einfach Pointer kopieren und Ref-Count erh"ohen
			*ppDst = *ppSrc;
			( (SfxPoolItem*) (*ppDst) )->AddRef();
		}
		else if ( !(*ppSrc)->Which() )
			*ppDst = (*ppSrc)->Clone();
		else
			// !IsPoolable() => via Pool zuweisen
			*ppDst = &_pPool->Put( **ppSrc );

	// dann noch die Which Ranges kopieren
	DBG_TRACE1("SfxItemSet: Ranges-CopyCount==%ul", ++nRangesCopyCount);
	std::ptrdiff_t cnt = pPtr - rASet._pWhichRanges+1;
	_pWhichRanges = new sal_uInt16[ cnt ];
	memcpy( _pWhichRanges, rASet._pWhichRanges, sizeof( sal_uInt16 ) * cnt);
}

// -----------------------------------------------------------------------

SfxItemSet::~SfxItemSet()
{
	DBG_DTOR(SfxItemSet, DbgCheckItemSet);
#ifdef DBG_UTIL
	DBG( DBG_ASSERT( 0 == *_pChildCount(this), "SfxItemSet: deleting parent-itemset" ) )
#endif

	sal_uInt16 nCount = TotalCount();
	if( Count() )
	{
		SfxItemArray ppFnd = _aItems;
		for( sal_uInt16 nCnt = nCount; nCnt; --nCnt, ++ppFnd )
			if( *ppFnd && !IsInvalidItem(*ppFnd) )
			{
				if( !(*ppFnd)->Which() )
					delete (SfxPoolItem*) *ppFnd;
				else {
					// noch mehrer Referenzen vorhanden, also nur den
					// ReferenzCounter manipulieren
					if ( 1 < (*ppFnd)->GetRefCount() && !IsDefaultItem(*ppFnd) )
						(*ppFnd)->ReleaseRef();
					else
						if ( !IsDefaultItem(*ppFnd) )
							// aus dem Pool loeschen
							_pPool->Remove( **ppFnd );
				}
			}
	}

	// FIXME: could be delete[] (SfxPoolItem **)_aItems;
	delete[] _aItems;
	if ( _pWhichRanges != _pPool->GetFrozenIdRanges() )
		delete[] _pWhichRanges;
	_pWhichRanges = 0; // for invariant-testing

	DBG( --*_pChildCount(_pParent) );
	DBG( delete _pChildCount(this); _pChildCountDtor );
}

// -----------------------------------------------------------------------

sal_uInt16 SfxItemSet::ClearItem( sal_uInt16 nWhich )

// einzelnes Item oder alle Items (nWhich==0) l"oschen

{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	if( !Count() )
		return 0;

	sal_uInt16 nDel = 0;
	SfxItemArray ppFnd = _aItems;

	if( nWhich )
	{
		const sal_uInt16* pPtr = _pWhichRanges;
		while( *pPtr )
		{
			// in diesem Bereich?
			if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
			{
				// "uberhaupt gesetzt?
				ppFnd += nWhich - *pPtr;
				if( *ppFnd )
				{
					// wegen der Assertions ins Sub-Calls mu\s das hier sein
					--_nCount;
					const SfxPoolItem *pItemToClear = *ppFnd;
					*ppFnd = 0;

					if ( !IsInvalidItem(pItemToClear) )
					{
						if ( nWhich <= SFX_WHICH_MAX )
						{
							const SfxPoolItem& rNew = _pParent
									? _pParent->Get( nWhich, sal_True )
									: _pPool->GetDefaultItem( nWhich );

							Changed( *pItemToClear, rNew );
						}
						if ( pItemToClear->Which() )
							_pPool->Remove( *pItemToClear );
					}
					++nDel;
				}

				// gefunden => raus
				break;
			}
			ppFnd += *(pPtr+1) - *pPtr + 1;
			pPtr += 2;
		}
	}
	else
	{
		nDel = _nCount;

		sal_uInt16* pPtr = _pWhichRanges;
		while( *pPtr )
		{
			for( nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
				if( *ppFnd )
				{
					// wegen der Assertions ins Sub-Calls mu\s das hier sein
					--_nCount;
					const SfxPoolItem *pItemToClear = *ppFnd;
					*ppFnd = 0;

					if ( !IsInvalidItem(pItemToClear) )
					{
						if ( nWhich <= SFX_WHICH_MAX )
						{
							const SfxPoolItem& rNew = _pParent
									? _pParent->Get( nWhich, sal_True )
									: _pPool->GetDefaultItem( nWhich );

							Changed( *pItemToClear, rNew );
						}

						// #i32448#
						// Take care of disabled items, too.
						if(!pItemToClear->nWhich)
						{
							// item is disabled, delete it
							delete pItemToClear;
						}
						else
						{
							// remove item from pool
							_pPool->Remove( *pItemToClear );
						}
					}
				}
			pPtr += 2;
		}
	}
	InvalidateHashKey();	//i120575
	return nDel;
}

// -----------------------------------------------------------------------

void SfxItemSet::ClearInvalidItems( sal_Bool bHardDefault )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	sal_uInt16* pPtr = _pWhichRanges;
	SfxItemArray ppFnd = _aItems;
	if ( bHardDefault )
		while( *pPtr )
		{
			for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
				if ( IsInvalidItem(*ppFnd) )
					 *ppFnd = &_pPool->Put( _pPool->GetDefaultItem(nWhich) );
			pPtr += 2;
		}
	else
		while( *pPtr )
		{
			for( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
				if( IsInvalidItem(*ppFnd) )
				{
					*ppFnd = 0;
					--_nCount;
				}
			pPtr += 2;
		}
	InvalidateHashKey();	//i120575
}

//------------------------------------------------------------------------


void SfxItemSet::InvalidateAllItems()
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( !_nCount, "Es sind noch Items gesetzt" );

	memset( (void*)_aItems, -1, ( _nCount = TotalCount() ) * sizeof( SfxPoolItem*) );
	InvalidateHashKey();	//i120575
}

// -----------------------------------------------------------------------

SfxItemState SfxItemSet::GetItemState( sal_uInt16 nWhich,
										sal_Bool bSrchInParent,
										const SfxPoolItem **ppItem ) const
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	// suche den Bereich in dem das Which steht:
	const SfxItemSet* pAktSet = this;
	SfxItemState eRet = SFX_ITEM_UNKNOWN;
	do
	{
		SfxItemArray ppFnd = pAktSet->_aItems;
		const sal_uInt16* pPtr = pAktSet->_pWhichRanges;
		if (pPtr)
		{
			while ( *pPtr )
			{
				if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
				{
					// in diesem Bereich
					ppFnd += nWhich - *pPtr;
					if ( !*ppFnd )
					{
						eRet = SFX_ITEM_DEFAULT;
						if( !bSrchInParent )
							return eRet;  // nicht vorhanden
						break; // JP: in den Parents weitersuchen !!!
					}

					if ( (SfxPoolItem*) -1 == *ppFnd )
						// Unterschiedlich vorhanden
						return SFX_ITEM_DONTCARE;

					if ( (*ppFnd)->Type() == TYPE(SfxVoidItem) )
						return SFX_ITEM_DISABLED;

					if (ppItem)
					{
                        #ifdef DBG_UTIL
						const SfxPoolItem *pItem = *ppFnd;
						DBG_ASSERT( !pItem->ISA(SfxSetItem) ||
								0 != &((const SfxSetItem*)pItem)->GetItemSet(),
								"SetItem without ItemSet" );
                        #endif
						*ppItem = *ppFnd;
					}
					return SFX_ITEM_SET;
				}
				ppFnd += *(pPtr+1) - *pPtr + 1;
				pPtr += 2;
			}
		}
	} while( bSrchInParent && 0 != ( pAktSet = pAktSet->_pParent ));
	return eRet;
}

// -----------------------------------------------------------------------

const SfxPoolItem* SfxItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
			0 != &((const SfxSetItem&)rItem).GetItemSet(),
			"SetItem without ItemSet" );
	if ( !nWhich )
		return 0; //! nur wegen Outliner-Bug
	SfxItemArray ppFnd = _aItems;
	const sal_uInt16* pPtr = _pWhichRanges;
	while( *pPtr )
	{
		if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
		{
			// in diesem Bereich
			ppFnd += nWhich - *pPtr;
			if( *ppFnd )		// schon einer vorhanden
			{
				// selbes Item bereits vorhanden?
				if ( *ppFnd == &rItem )
					return 0;

				// wird dontcare oder disabled mit was echtem ueberschrieben?
				if ( rItem.Which() && ( IsInvalidItem(*ppFnd) || !(*ppFnd)->Which() ) )
				{
					*ppFnd = &_pPool->Put( rItem, nWhich );
					InvalidateHashKey();	//i120575
					return *ppFnd;
				}

				// wird disabled?
				if( !rItem.Which() )
				{
					*ppFnd = rItem.Clone(_pPool);
					InvalidateHashKey();	//i120575
					return 0;
				}
				else
				{
					// selber Wert bereits vorhanden?
					if ( rItem == **ppFnd )
						return 0;

					// den neuen eintragen, den alten austragen
					const SfxPoolItem& rNew = _pPool->Put( rItem, nWhich );
					const SfxPoolItem* pOld = *ppFnd;
					*ppFnd = &rNew;
					if(nWhich <= SFX_WHICH_MAX)
						Changed( *pOld, rNew );
					_pPool->Remove( *pOld );
				}
			}
			else
			{
				++_nCount;
				if( !rItem.Which() )
					*ppFnd = rItem.Clone(_pPool);
				else {
					const SfxPoolItem& rNew = _pPool->Put( rItem, nWhich );
					*ppFnd = &rNew;
					if (nWhich <= SFX_WHICH_MAX )
					{
						const SfxPoolItem& rOld = _pParent
							? _pParent->Get( nWhich, sal_True )
							: _pPool->GetDefaultItem( nWhich );
						Changed( rOld, rNew );
					}
				}
			}
			SFX_ASSERT( !_pPool->IsItemFlag(nWhich, SFX_ITEM_POOLABLE) ||
						rItem.ISA(SfxSetItem) || **ppFnd == rItem,
						nWhich, "putted Item unequal" );
			
			InvalidateHashKey();	//i120575
			return *ppFnd;
		}
		ppFnd += *(pPtr+1) - *pPtr + 1;
		pPtr += 2;
	}
	InvalidateHashKey();	//i120575
	return 0;
}

// -----------------------------------------------------------------------

int SfxItemSet::Put( const SfxItemSet& rSet, sal_Bool bInvalidAsDefault )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	sal_Bool bRet = sal_False;
	if( rSet.Count() )
	{
		SfxItemArray ppFnd = rSet._aItems;
		const sal_uInt16* pPtr = rSet._pWhichRanges;
		while ( *pPtr )
		{
			for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
				if( *ppFnd )
				{
					if ( IsInvalidItem( *ppFnd ) )
					{
						if ( bInvalidAsDefault )
							bRet |= 0 != ClearItem( nWhich );
							// gab GPF bei non.WIDs:
							// bRet |= 0 != Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
						else
							InvalidateItem( nWhich );
					}
					else
						bRet |= 0 != Put( **ppFnd, nWhich );
				}
			pPtr += 2;
		}
	}
	return bRet;
}

// -----------------------------------------------------------------------

void SfxItemSet::PutExtended
(
	const SfxItemSet&	rSet,			// Quelle der zu puttenden Items
	SfxItemState		eDontCareAs,	// was mit DontCare-Items passiert
	SfxItemState		eDefaultAs		// was mit Default-Items passiert
)

/*	[Beschreibung]

	Diese Methode "ubernimmt die Items aus 'rSet' in '*this'. Die
	Which-Bereiche in '*this', die in 'rSet' nicht vorkommen bleiben unver-
	"andert. Der Which-Bereich von '*this' bleibt auch unver"andert.

	In 'rSet' gesetzte Items werden auch in '*this*' gesetzt. Default-
	(0 Pointer) und Invalid- (-1 Pointer) Items werden je nach Parameter
	('eDontCareAs' und 'eDefaultAs' behandelt:

	SFX_ITEM_SET:		hart auf Default des Pools gesetzt
	SFX_ITEM_DEFAULT:	gel"oscht (0 Pointer)
	SFX_ITEM_DONTCARE:	invalidiert (-1 Pointer)

	Alle anderen Werte f"ur 'eDontCareAs' und 'eDefaultAs' sind ung"ultig.
*/

{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);

	// don't "optimize" with "if( rSet.Count()" because of dont-care + defaults
	SfxItemArray ppFnd = rSet._aItems;
	const sal_uInt16* pPtr = rSet._pWhichRanges;
	while ( *pPtr )
	{
		for ( sal_uInt16 nWhich = *pPtr; nWhich <= *(pPtr+1); ++nWhich, ++ppFnd )
			if( *ppFnd )
			{
				if ( IsInvalidItem( *ppFnd ) )
				{
					// Item ist DontCare:
					switch ( eDontCareAs )
					{
						case SFX_ITEM_SET:
							Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
							break;

						case SFX_ITEM_DEFAULT:
							ClearItem( nWhich );
							break;

						case SFX_ITEM_DONTCARE:
							InvalidateItem( nWhich );
							break;

						default:
							DBG_ERROR( "invalid Argument for eDontCareAs" );
					}
				}
				else
					// Item ist gesetzt:
					Put( **ppFnd, nWhich );
			}
			else
			{
				// Item ist Default:
				switch ( eDefaultAs )
				{
					case SFX_ITEM_SET:
						Put( rSet.GetPool()->GetDefaultItem(nWhich), nWhich );
						break;

					case SFX_ITEM_DEFAULT:
						ClearItem( nWhich );
						break;

					case SFX_ITEM_DONTCARE:
						InvalidateItem( nWhich );
						break;

					default:
						DBG_ERROR( "invalid Argument for eDefaultAs" );
				}
			}
		pPtr += 2;
	}
}

// -----------------------------------------------------------------------

void SfxItemSet::MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo )
/**	<H3>Description</H3>

	Expands the ranges of settable items by 'nFrom' to 'nTo'. Keeps state of
	items which are new ranges too.
*/

{
	// special case: exactly one sal_uInt16 which is already included?
	if ( nFrom == nTo && SFX_ITEM_AVAILABLE <= GetItemState(nFrom, sal_False) )
		return;

	// merge new range
	SfxUShortRanges aRanges( _pWhichRanges );
	aRanges += SfxUShortRanges( nFrom, nTo );
	SetRanges( aRanges );
}

// -----------------------------------------------------------------------

void SfxItemSet::SetRanges( const sal_uInt16 *pNewRanges )

/**	<H3>Description</H3>

	Modifies the ranges of settable items. Keeps state of items which
	are new ranges too.
*/

{
	// identische Ranges?
	if ( _pWhichRanges == pNewRanges )
		return;
	const sal_uInt16* pOld = _pWhichRanges;
	const sal_uInt16* pNew = pNewRanges;
	while ( *pOld == *pNew )
	{
		if ( !*pOld && !*pNew )
			return;
		++pOld, ++pNew;
	}

	// create new item-array (by iterating through all new ranges)
	sal_uLong		 nSize = Capacity_Impl(pNewRanges);
	SfxItemArray aNewItems = new const SfxPoolItem* [ nSize ];
	sal_uInt16		 n = 0, nNewCount = 0;
	if ( _nCount == 0 )
		memset( aNewItems, 0, nSize * sizeof( SfxPoolItem* ) );
	else
	{
		for ( const sal_uInt16 *pRange = pNewRanges; *pRange; pRange += 2 )
		{
			// iterate through all ids in the range
			for ( sal_uInt16 nWID = *pRange; nWID <= pRange[1]; ++nWID, ++n )
			{
				// direct move of pointer (not via pool)
				SfxItemState eState = GetItemState( nWID, sal_False, aNewItems+n );
				if ( SFX_ITEM_SET == eState )
				{
					// increment new item count and possibly increment ref count
					++nNewCount;
					aNewItems[n]->AddRef();
				}
				else if ( SFX_ITEM_DISABLED == eState )
				{
					// put "disabled" item
					++nNewCount;
					aNewItems[n] = new SfxVoidItem(0);
				}
				else if ( SFX_ITEM_DONTCARE == eState )
				{
					++nNewCount;
					aNewItems[n] = (SfxPoolItem*)-1;
				}
				else
				{
					// default
					aNewItems[n] = 0;
				}
			}
		}
		// free old items
		sal_uInt16 nOldTotalCount = TotalCount();
		for ( sal_uInt16 nItem = 0; nItem < nOldTotalCount; ++nItem )
		{
			const SfxPoolItem *pItem = _aItems[nItem];
			if ( pItem && !IsInvalidItem(pItem) && pItem->Which() )
				_pPool->Remove(*pItem);
		}
	}

	// replace old items-array and ranges
	delete[] _aItems;
	_aItems = aNewItems;
	_nCount = nNewCount;

	if( pNewRanges == GetPool()->GetFrozenIdRanges() )
	{
		delete[] _pWhichRanges;
		_pWhichRanges = ( sal_uInt16* ) pNewRanges;
	}
	else
	{
		sal_uInt16 nCount = Count_Impl(pNewRanges) + 1;
		if ( _pWhichRanges != _pPool->GetFrozenIdRanges() )
			delete[] _pWhichRanges;
		_pWhichRanges = new sal_uInt16[ nCount ];
		memcpy( _pWhichRanges, pNewRanges, sizeof( sal_uInt16 ) * nCount );
	}
	InvalidateHashKey();	//i120575
}

// -----------------------------------------------------------------------

int SfxItemSet::Set
(
	const SfxItemSet&	rSet,	/*	das SfxItemSet, dessen SfxPoolItems
									"ubernommen werden sollen */

	sal_Bool				bDeep	/*	sal_True (default)
									auch die SfxPoolItems aus den ggf. an
									rSet vorhandenen Parents werden direkt
									in das SfxItemSet "ubernommen

									sal_False
									die SfxPoolItems aus den Parents von
									rSet werden nicht ber"ucksichtigt */
)

/*	[Beschreibung]

	Das SfxItemSet nimmt genau die SfxPoolItems an, die auch in
	rSet gesetzt sind und im eigenen <Which-Bereich> liegen. Alle
	anderen werden entfernt. Der SfxItemPool wird dabei beibehalten,
	so da"s die "ubernommenen SfxPoolItems dabei ggf. vom SfxItemPool
	von rSet in den SfxItemPool von *this "ubernommen werden.

	SfxPoolItems, f"ur die in rSet IsInvalidItem() == sal_True gilt,
	werden als Invalid-Item "ubernommen.


	[R"uckgabewert]

	int 							sal_True
									es wurden SfxPoolItems "ubernommen

									sal_False
									es wurden keine SfxPoolItems "ubernommen,
									da z.B. die Which-Bereiche der SfxItemSets
									keine Schnittmenge haben oder in der
									Schnittmenge keine SfxPoolItems in rSet
									gesetzt sind

*/

{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	int bRet = sal_False;
	if ( _nCount )
		ClearItem();
	if ( bDeep )
	{
		SfxWhichIter aIter(*this);
		sal_uInt16 nWhich = aIter.FirstWhich();
		while ( nWhich )
		{
			const SfxPoolItem* pItem;
			if( SFX_ITEM_SET == rSet.GetItemState( nWhich, sal_True, &pItem ) )
				bRet |= 0 != Put( *pItem, pItem->Which() );
			nWhich = aIter.NextWhich();
		}
	}
	else
		bRet = Put(rSet, sal_False);

	return bRet;
}

//------------------------------------------------------------------------

const SfxPoolItem* SfxItemSet::GetItem
(
	sal_uInt16 				nId,   			// Slot-Id oder Which-Id des Items
	sal_Bool 				bSrchInParent,  // sal_True: auch in Parent-ItemSets suchen
	TypeId 				aItemType       // != 0 =>  RTTI Pruefung mit Assertion
)	const

/*	[Beschreibung]

	Mit dieser Methode wird der Zugriff auf einzelne Items im
	SfxItemSet wesentlich vereinfacht. Insbesondere wird die Typpr"ufung
	(per Assertion) durchgef"uhrt, wodurch die Applikations-Sourcen
	wesentlich "ubersichtlicher werden. In der PRODUCT-Version wird
	eine 0 zur"uckgegeben, wenn das gefundene Item nicht von der
	angegebenen Klasse ist. Ist kein Item mit der Id 'nWhich' in dem ItemSet,
	so wird 0 zurueckgegeben.
*/

{
	// ggf. in Which-Id umrechnen
	sal_uInt16 nWhich = GetPool()->GetWhich(nId);

	// ist das Item gesetzt oder bei bDeep==sal_True verf"ugbar?
	const SfxPoolItem *pItem = 0;
	SfxItemState eState = GetItemState( nWhich, bSrchInParent, &pItem );
	if ( bSrchInParent && SFX_ITEM_AVAILABLE == eState &&
		 nWhich <= SFX_WHICH_MAX )
		pItem = &_pPool->GetDefaultItem(nWhich);
	if ( pItem )
	{
		// stimmt der Typ "uberein?
		if ( !aItemType || pItem->IsA(aItemType) )
			return pItem;

		// sonst Fehler melden
		DBG_ERROR( "invalid argument type" );
	}

	// kein Item gefunden oder falschen Typ gefunden
	return 0;
}


//------------------------------------------------------------------------


const SfxPoolItem& SfxItemSet::Get( sal_uInt16 nWhich, sal_Bool bSrchInParent) const
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	// suche den Bereich in dem das Which steht:
	const SfxItemSet* pAktSet = this;
	do
	{
		if( pAktSet->Count() )
		{
			SfxItemArray ppFnd = pAktSet->_aItems;
			const sal_uInt16* pPtr = pAktSet->_pWhichRanges;
			while( *pPtr )
			{
				if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
				{
					// in diesem Bereich
					ppFnd += nWhich - *pPtr;
					if( *ppFnd )
					{
						if( (SfxPoolItem*)-1 == *ppFnd ) {
							//?MI: folgender code ist Doppelt (unten)
							SFX_ASSERT(_pPool, nWhich, "kein Pool, aber Status uneindeutig");
							//!((SfxAllItemSet *)this)->aDefault.SetWhich(nWhich);
							//!return aDefault;
							return _pPool->GetDefaultItem( nWhich );
						}
#ifdef DBG_UTIL
						const SfxPoolItem *pItem = *ppFnd;
						DBG_ASSERT( !pItem->ISA(SfxSetItem) ||
								0 != &((const SfxSetItem*)pItem)->GetItemSet(),
								"SetItem without ItemSet" );
						if ( pItem->ISA(SfxVoidItem) || !pItem->Which() )
							DBG_WARNING( "SFX_WARNING: Getting disabled Item" );
#endif
						return **ppFnd;
					}
					break; 			// dann beim Parent suchen
				}
				ppFnd += *(pPtr+1) - *pPtr + 1;
				pPtr += 2;
			}
		}
// bis zum Ende vom Such-Bereich: was nun ? zum Parent, oder Default ??
//		if( !*pPtr )			// bis zum Ende vom Such-Bereich ?
//		break;
	} while( bSrchInParent && 0 != ( pAktSet = pAktSet->_pParent ));

	// dann das Default vom Pool holen und returnen
	SFX_ASSERT(_pPool, nWhich, "kein Pool, aber Status uneindeutig");
	const SfxPoolItem *pItem = &_pPool->GetDefaultItem( nWhich );
	DBG_ASSERT( !pItem->ISA(SfxSetItem) ||
			0 != &((const SfxSetItem*)pItem)->GetItemSet(),
			"SetItem without ItemSet" );
	return *pItem;
}

	// Notification-Callback
// -----------------------------------------------------------------------

void SfxItemSet::Changed( const SfxPoolItem&, const SfxPoolItem& )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
}

// -----------------------------------------------------------------------

sal_uInt16 SfxItemSet::TotalCount() const
{
	DBG_CHKTHIS(SfxItemSet, 0); // wird im Ctor benutzt bevor vollst. init.
	sal_uInt16 nRet = 0;
	sal_uInt16* pPtr = _pWhichRanges;
	while( *pPtr )
	{
		nRet += ( *(pPtr+1) - *pPtr ) + 1;
		pPtr += 2;
	}
	return nRet;
}
// -----------------------------------------------------------------------

// behalte nur die Items, die auch in rSet enthalten sein (Wert egal)

void SfxItemSet::Intersect( const SfxItemSet& rSet )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT(_pPool, "nicht implementiert ohne Pool");
	if( !Count() )		 // gar keine gesetzt ?
		return;

	// loesche alle Items, die im rSet nicht mehr vorhanden sind
	if( !rSet.Count() )
	{
		ClearItem();		// alles loeschen
		return;
	}

	// teste mal, ob sich die Which-Bereiche unterscheiden.
	sal_Bool bEqual = sal_True;
	sal_uInt16* pWh1 = _pWhichRanges;
	sal_uInt16* pWh2 = rSet._pWhichRanges;
	sal_uInt16 nSize = 0;

	for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
	{
		if( *pWh1 != *pWh2 )
		{
			bEqual = sal_False;
			break;
		}
		if( n & 1 )
			nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
	}
	bEqual = *pWh1 == *pWh2;		// auch die 0 abpruefen

	// sind die Bereiche identisch, ist es einfacher zu handhaben !
	if( bEqual )
	{
		SfxItemArray ppFnd1 = _aItems;
		SfxItemArray ppFnd2 = rSet._aItems;

		for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
			if( *ppFnd1 && !*ppFnd2 )
			{
				// aus dem Pool loeschen
				if( !IsInvalidItem( *ppFnd1 ) )
				{
					sal_uInt16 nWhich = (*ppFnd1)->Which();
					if(nWhich <= SFX_WHICH_MAX)
					{
						const SfxPoolItem& rNew = _pParent
							? _pParent->Get( nWhich, sal_True )
							: _pPool->GetDefaultItem( nWhich );

						Changed( **ppFnd1, rNew );
					}
					_pPool->Remove( **ppFnd1 );
				}
				*ppFnd1 = 0;
				--_nCount;
			}
	}
	else
	{
		SfxItemIter aIter( *this );
		const SfxPoolItem* pItem = aIter.GetCurItem();
		while( sal_True )
		{
			sal_uInt16 nWhich = IsInvalidItem( pItem )
								? GetWhichByPos( aIter.GetCurPos() )
								: pItem->Which();
			if( 0 == rSet.GetItemState( nWhich, sal_False ) )
				ClearItem( nWhich );		// loeschen
			if( aIter.IsAtEnd() )
				break;
			pItem = aIter.NextItem();
		}
	}
	InvalidateHashKey();	//i120575	
}

// -----------------------------------------------------------------------

void SfxItemSet::Differentiate( const SfxItemSet& rSet )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	if( !Count() || !rSet.Count() )  // gar keine gesetzt ?
		return;

	// teste mal, ob sich die Which-Bereiche unterscheiden.
	sal_Bool bEqual = sal_True;
	sal_uInt16* pWh1 = _pWhichRanges;
	sal_uInt16* pWh2 = rSet._pWhichRanges;
	sal_uInt16 nSize = 0;

	for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
	{
		if( *pWh1 != *pWh2 )
		{
			bEqual = sal_False;
			break;
		}
		if( n & 1 )
			nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
	}
	bEqual = *pWh1 == *pWh2;		// auch die 0 abpruefen

	// sind die Bereiche identisch, ist es einfacher zu handhaben !
	if( bEqual )
	{
		SfxItemArray ppFnd1 = _aItems;
		SfxItemArray ppFnd2 = rSet._aItems;

		for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
			if( *ppFnd1 && *ppFnd2 )
			{
				// aus dem Pool loeschen
				if( !IsInvalidItem( *ppFnd1 ) )
				{
					sal_uInt16 nWhich = (*ppFnd1)->Which();
					if(nWhich <= SFX_WHICH_MAX)
					{
						const SfxPoolItem& rNew = _pParent
							? _pParent->Get( nWhich, sal_True )
							: _pPool->GetDefaultItem( nWhich );

						Changed( **ppFnd1, rNew );
					}
					_pPool->Remove( **ppFnd1 );
				}
				*ppFnd1 = 0;
				--_nCount;
			}
	}
	else
	{
		SfxItemIter aIter( *this );
		const SfxPoolItem* pItem = aIter.GetCurItem();
		while( sal_True )
		{
			sal_uInt16 nWhich = IsInvalidItem( pItem )
								? GetWhichByPos( aIter.GetCurPos() )
								: pItem->Which();
			if( SFX_ITEM_SET == rSet.GetItemState( nWhich, sal_False ) )
				ClearItem( nWhich );		// loeschen
			if( aIter.IsAtEnd() )
				break;
			pItem = aIter.NextItem();
		}

	}
	InvalidateHashKey();	//i120575	
}

// -----------------------------------------------------------------------
/* Entscheidungstabelle fuer MergeValue[s]

Grundsaetze:
	1. Ist der Which-Wert im 1.Set "unknown", dann folgt niemals eine Aktion.
	2. Ist der Which-Wert im 2.Set "unknown", dann gilt er als "default".
	3. Es gelten fuer Vergleiche die Werte der "default"-Items.

1.-Item     2.-Item     Values  bIgnoreDefs     Remove      Assign      Add

set         set         ==      sal_False           -           -           -
default     set         ==      sal_False           -           -           -
dontcare    set         ==      sal_False           -           -           -
unknown     set         ==      sal_False           -           -           -
set         default     ==      sal_False           -           -           -
default     default     ==      sal_False           -           -           -
dontcare    default     ==      sal_False           -           -           -
unknown     default     ==      sal_False           -           -           -
set         dontcare    ==      sal_False           1.-Item     -1          -
default 	dontcare	==		sal_False			-			-1			-
dontcare    dontcare    ==      sal_False           -           -           -
unknown     dontcare    ==      sal_False           -           -           -
set         unknown     ==      sal_False           1.-Item     -1          -
default     unknown     ==      sal_False           -           -           -
dontcare    unknown     ==      sal_False           -           -           -
unknown     unknown     ==      sal_False           -           -           -

set         set         !=      sal_False           1.-Item     -1          -
default     set         !=      sal_False           -           -1          -
dontcare    set         !=      sal_False           -           -           -
unknown     set         !=      sal_False           -           -           -
set         default     !=      sal_False           1.-Item     -1          -
default     default     !=      sal_False           -           -           -
dontcare    default     !=      sal_False           -           -           -
unknown     default     !=      sal_False           -           -           -
set         dontcare    !=      sal_False           1.-Item     -1          -
default     dontcare    !=      sal_False           -           -1          -
dontcare    dontcare    !=      sal_False           -           -           -
unknown     dontcare    !=      sal_False           -           -           -
set         unknown     !=      sal_False           1.-Item     -1          -
default     unknown     !=      sal_False           -           -           -
dontcare    unknown     !=      sal_False           -           -           -
unknown     unknown     !=      sal_False           -           -           -

set         set         ==      sal_True            -           -           -
default 	set 		==		sal_True			-			2.-Item 	2.-Item
dontcare    set         ==      sal_True            -           -           -
unknown     set         ==      sal_True            -           -           -
set         default     ==      sal_True            -           -           -
default     default     ==      sal_True            -           -           -
dontcare    default     ==      sal_True            -           -           -
unknown     default     ==      sal_True            -           -           -
set         dontcare    ==      sal_True            -           -           -
default 	dontcare	==		sal_True			-			-1			-
dontcare    dontcare    ==      sal_True            -           -           -
unknown     dontcare    ==      sal_True            -           -           -
set         unknown     ==      sal_True            -           -           -
default     unknown     ==      sal_True            -           -           -
dontcare    unknown     ==      sal_True            -           -           -
unknown     unknown     ==      sal_True            -           -           -

set         set         !=      sal_True            1.-Item     -1          -
default     set         !=      sal_True            -           2.-Item     2.-Item
dontcare	set 		!=		sal_True			-			-			-
unknown     set         !=      sal_True            -           -           -
set         default     !=      sal_True            -           -           -
default     default     !=      sal_True            -           -           -
dontcare    default     !=      sal_True            -           -           -
unknown     default     !=      sal_True            -           -           -
set         dontcare    !=      sal_True            1.-Item     -1          -
default     dontcare    !=      sal_True            -           -1          -
dontcare    dontcare    !=      sal_True            -           -           -
unknown     dontcare    !=      sal_True            -           -           -
set         unknown     !=      sal_True            -           -           -
default     unknown     !=      sal_True            -           -           -
dontcare    unknown     !=      sal_True            -           -           -
unknown     unknown     !=      sal_True            -           -           -
*/


static void MergeItem_Impl( SfxItemPool *_pPool, sal_uInt16 &rCount,
							const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2,
							sal_Bool bIgnoreDefaults )
{
	DBG_ASSERT( ppFnd1 != 0, "Merging to 0-Item" );

	// 1. Item ist default?
	if ( !*ppFnd1 )
	{
		if ( IsInvalidItem(pFnd2) )
			// Entscheidungstabelle: default, dontcare, egal, egal
			*ppFnd1 = (SfxPoolItem*) -1;

		else if ( pFnd2 && !bIgnoreDefaults &&
				  _pPool->GetDefaultItem(pFnd2->Which()) != *pFnd2 )
			// Entscheidungstabelle: default, set, !=, sal_False
			*ppFnd1 = (SfxPoolItem*) -1;

		else if ( pFnd2 && bIgnoreDefaults )
			// Entscheidungstabelle: default, set, egal, sal_True
			*ppFnd1 = &_pPool->Put( *pFnd2 );

		if ( *ppFnd1 )
			++rCount;
	}

	// 1. Item ist gesetzt?
	else if ( !IsInvalidItem(*ppFnd1) )
	{
		if ( !pFnd2 )
		{
			// 2. Item ist default
			if ( !bIgnoreDefaults &&
				 **ppFnd1 != _pPool->GetDefaultItem((*ppFnd1)->Which()) )
			{
				// Entscheidungstabelle: set, default, !=, sal_False
				_pPool->Remove( **ppFnd1 );
				*ppFnd1 = (SfxPoolItem*) -1;
			}
		}
		else if ( IsInvalidItem(pFnd2) )
		{
			// 2. Item ist dontcare
			if ( !bIgnoreDefaults ||
				 **ppFnd1 != _pPool->GetDefaultItem( (*ppFnd1)->Which()) )
			{
				// Entscheidungstabelle: set, dontcare, egal, sal_False
				// oder:				 set, dontcare, !=, sal_True
				_pPool->Remove( **ppFnd1 );
				*ppFnd1 = (SfxPoolItem*) -1;
			}
		}
		else
		{
			// 2. Item ist gesetzt
			if ( **ppFnd1 != *pFnd2 )
			{
				// Entscheidungstabelle: set, set, !=, egal
				_pPool->Remove( **ppFnd1 );
				*ppFnd1 = (SfxPoolItem*) -1;
			}
		}
	}
}

// -----------------------------------------------------------------------

void SfxItemSet::MergeValues( const SfxItemSet& rSet, sal_Bool bIgnoreDefaults )
{
	// Achtung!!! Bei Aenderungen/Bugfixes immer obenstehende Tabelle pflegen!
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( GetPool() == rSet.GetPool(), "MergeValues mit verschiedenen Pools" );

	// teste mal, ob sich die Which-Bereiche unterscheiden.
	sal_Bool bEqual = sal_True;
	sal_uInt16* pWh1 = _pWhichRanges;
	sal_uInt16* pWh2 = rSet._pWhichRanges;
	sal_uInt16 nSize = 0;

	for( sal_uInt16 n = 0; *pWh1 && *pWh2; ++pWh1, ++pWh2, ++n )
	{
		if( *pWh1 != *pWh2 )
		{
			bEqual = sal_False;
			break;
		}
		if( n & 1 )
			nSize += ( *(pWh1) - *(pWh1-1) ) + 1;
	}
	bEqual = *pWh1 == *pWh2; // auch die 0 abpruefen

	// sind die Bereiche identisch, ist es effizieter zu handhaben !
	if( bEqual )
	{
		SfxItemArray ppFnd1 = _aItems;
		SfxItemArray ppFnd2 = rSet._aItems;

		for( ; nSize; --nSize, ++ppFnd1, ++ppFnd2 )
			MergeItem_Impl( _pPool, _nCount, ppFnd1, *ppFnd2, bIgnoreDefaults );
	}
	else
	{
		SfxWhichIter aIter( rSet );
		sal_uInt16 nWhich;
		while( 0 != ( nWhich = aIter.NextWhich() ) )
		{
			const SfxPoolItem* pItem = 0;
			rSet.GetItemState( nWhich, sal_True, &pItem );
			if( !pItem )
			{
				// nicht gesetzt, also default
				if ( !bIgnoreDefaults )
					MergeValue( rSet.GetPool()->GetDefaultItem( nWhich ), bIgnoreDefaults );
			}
			else if( IsInvalidItem( pItem ) )
				// dont care
				InvalidateItem( nWhich );
			else
				MergeValue( *pItem, bIgnoreDefaults );
		}
	}
	InvalidateHashKey();	//i120575	
}

// -----------------------------------------------------------------------

void SfxItemSet::MergeValue( const SfxPoolItem& rAttr, sal_Bool bIgnoreDefaults )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	SfxItemArray ppFnd = _aItems;
	const sal_uInt16* pPtr = _pWhichRanges;
	const sal_uInt16 nWhich = rAttr.Which();
	while( *pPtr )
	{
		// in diesem Bereich?
		if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
		{
			ppFnd += nWhich - *pPtr;
			MergeItem_Impl( _pPool, _nCount, ppFnd, &rAttr, bIgnoreDefaults );
			break;
		}
		ppFnd += *(pPtr+1) - *pPtr + 1;
		pPtr += 2;
	}
	InvalidateHashKey();	//i120575	
}

// -----------------------------------------------------------------------

void SfxItemSet::InvalidateItem( sal_uInt16 nWhich )
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	SfxItemArray ppFnd = _aItems;
	const sal_uInt16* pPtr = _pWhichRanges;
	while( *pPtr )
	{
		if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
		{
			// in diesem Bereich
			ppFnd += nWhich - *pPtr;

			if( *ppFnd )   	// bei mir gesetzt
			{
				if( (SfxPoolItem*)-1 != *ppFnd )		// noch nicht dontcare !
				{
					_pPool->Remove( **ppFnd );
					*ppFnd = (SfxPoolItem*)-1;
				}
			}
			else
			{
				*ppFnd = (SfxPoolItem*)-1;
				++_nCount;
			}
			break;
		}
		ppFnd += *(pPtr+1) - *pPtr + 1;
		pPtr += 2;
	}
	InvalidateHashKey();	//i120575	
}

// -----------------------------------------------------------------------

sal_uInt16 SfxItemSet::GetWhichByPos( sal_uInt16 nPos ) const
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	sal_uInt16 n = 0;
	sal_uInt16* pPtr  = _pWhichRanges;
	while( *pPtr )
	{
		n = ( *(pPtr+1) - *pPtr ) + 1;
		if( nPos < n )
			return *(pPtr)+nPos;
		nPos = nPos - n;
		pPtr += 2;
	}
	DBG_ASSERT( sal_False, "Hier sind wir falsch" );
	return 0;
}

// -----------------------------------------------------------------------

SvStream &SfxItemSet::Store
(
	SvStream&	rStream,		// Zielstream f"ur normale Items
	FASTBOOL	bDirect 		// sal_True: Items direkt speicher, sal_False: Surrogate
)	const

/*	[Beschreibung]

	Speichert die <SfxItemSet>-Instanz in den angegebenen Stream. Dabei
	werden die Surrorage der gesetzten <SfxPoolItem>s bzw. ('bDirect==sal_True')
	die gesetzten Items selbst wie folgt im Stream abgelegt:

			sal_uInt16				(Count) Anzahl der gesetzten Items
	Count*	_pPool->StoreItem()  siehe <SfxItemPool::StoreItem()const>


	[Querverweise]

	<SfxItemSet::Load(SvStream&,sal_Bool,const SfxItemPool*)>
*/

{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( _pPool, "Kein Pool" );
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "kein Master-Pool" );

	// Position des Counts merken, um ggf. zu korrigieren
	sal_uLong nCountPos = rStream.Tell();
	rStream << _nCount;

	// wenn nichts zu speichern ist, auch keinen ItemIter aufsetzen!
	if ( _nCount )
	{
		// mitz"ahlen wieviel Items tats"achlich gespeichert werden
		sal_uInt16 nWrittenCount = 0;  // Anzahl in 'rStream' gestreamter Items

		// "uber alle gesetzten Items iterieren
		SfxItemIter aIter(*this);
		for ( const SfxPoolItem *pItem = aIter.FirstItem();
			  pItem;
			  pItem = aIter.NextItem() )
		{
			// Item (ggf. als Surrogat) via Pool speichern lassen
			DBG_ASSERT( !IsInvalidItem(pItem), "can't store invalid items" );
			if ( !IsInvalidItem(pItem) &&
				 _pPool->StoreItem( rStream, *pItem, bDirect ) )
				// Item wurde in 'rStream' gestreamt
				++nWrittenCount;
		};

		// weniger geschrieben als enthalten (z.B. altes Format)
		if ( nWrittenCount != _nCount )
		{
			// tats"achlichen Count im Stream ablegen
			sal_uLong nPos = rStream.Tell();
			rStream.Seek( nCountPos );
			rStream << nWrittenCount;
			rStream.Seek( nPos );
		}
	}

	return rStream;
}

// -----------------------------------------------------------------------

SvStream &SfxItemSet::Load
(
	SvStream&			rStream,	//	Stream, aus dem geladen werden soll

	FASTBOOL			bDirect,	/*	sal_True
										Items werden direkt aus dem Stream
										gelesen, nicht "uber Surrogate

										sal_False (default)
										Items werden "uber Surrogate gelesen */

	const SfxItemPool*	pRefPool 	/*	Pool, der die Surrogate aufl"osen kann
										(z.B. zum Einf"ugen von Dokumenten) */
)

/*	[Beschreibung]

	Diese Methode l"adt ein <SfxItemSet> aus einem Stream. Falls der
	<SfxItemPool> ohne Ref-Counts geladen wurde, werden die geladenen
	Item-Referenzen in den Items hochgez"ahlt, ansonsten wird vorausgesetzt,
	da\s sie schon beim Laden des SfxItemPools ber"ucksichtigt waren.

	[Querverweise]

	<SfxItemSet::Store(Stream&,sal_Bool)const>
*/

{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_ASSERT( _pPool, "Kein Pool");
	DBG_ASSERTWARNING( _pPool == _pPool->GetMasterPool(), "Kein Master-Pool");

	// kein Ref-Pool => Surrogate mit Pool des ItemSets aufl"osen
	if ( !pRefPool )
		pRefPool = _pPool;

	// Anzahl der zu ladenden Items laden und dann ebensoviele Items
	sal_uInt16 nCount = 0;
	rStream >> nCount;
	for ( sal_uInt16 i = 0; i < nCount; ++i )
	{
		// Surrogat/Item laden und (Surrogat) aufl"osen lassen
		const SfxPoolItem *pItem =
				_pPool->LoadItem( rStream, bDirect, pRefPool );

		// konnte ein Item geladen oder via Surrogat aufgel"ost werden?
		if ( pItem )
		{
			// Position f"ur Item-Pointer im Set suchen
			sal_uInt16 nWhich = pItem->Which();
			SfxItemArray ppFnd = _aItems;
			const sal_uInt16* pPtr = _pWhichRanges;
			while ( *pPtr )
			{
				// in diesem Bereich?
				if ( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
				{
					// Item-Pointer im Set merken
					ppFnd += nWhich - *pPtr;
					SFX_ASSERT( !*ppFnd, nWhich, "Item doppelt eingetragen");
					*ppFnd = pItem;
					++_nCount;
					break;
				}

				// im Range-Array und Item-Array zum n"achsten Which-Range
				ppFnd += *(pPtr+1) - *pPtr + 1;
				pPtr += 2;
			}
		}
	}

	
	InvalidateHashKey();	//i120575
	return rStream;
}

// -----------------------------------------------------------------------

int	SfxItemSet::operator==(const SfxItemSet &rCmp) const
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	DBG_CHKOBJ(&rCmp, SfxItemSet, DbgCheckItemSet);

	// besonders schnell zu ermittelnde Werte muessen gleich sein
	if ( _pParent != rCmp._pParent ||
		 _pPool != rCmp._pPool ||
		 Count() != rCmp.Count() )
		return sal_False;

	// Ranges durchzaehlen lassen dauert laenger, muss aber auch gleich sein
	sal_uInt16 nCount1 = TotalCount();
	sal_uInt16 nCount2 = rCmp.TotalCount();
	if ( nCount1 != nCount2 )
		return sal_False;

	// sind die Ranges selbst ungleich?
	for ( sal_uInt16 nRange = 0; _pWhichRanges[nRange]; nRange += 2 )
		if ( _pWhichRanges[nRange] != rCmp._pWhichRanges[nRange] ||
			 _pWhichRanges[nRange+1] != rCmp._pWhichRanges[nRange+1] )
		{
			// dann m"ussen wir die langsame Methode verwenden
			SfxWhichIter aIter( *this );
			for ( sal_uInt16 nWh = aIter.FirstWhich();
				  nWh;
				  nWh = aIter.NextWhich() )
			{
				// wenn die Pointer von poolable Items ungleich sind,
				// muessen die Items gleich sein
				const SfxPoolItem *pItem1 = 0, *pItem2 = 0;
				if ( GetItemState( nWh, sal_False, &pItem1 ) !=
						rCmp.GetItemState( nWh, sal_False, &pItem2 ) ||
					 ( pItem1 != pItem2 &&
						( !pItem1 || IsInvalidItem(pItem1) ||
						  ( _pPool->IsItemFlag(*pItem1, SFX_ITEM_POOLABLE) &&
							*pItem1 != *pItem2 ) ) ) )
					return sal_False;
			}

			return sal_True;
		}

	// Pointer alle gleich?
	if ( 0 == memcmp( _aItems, rCmp._aItems, nCount1 * sizeof(_aItems[0]) ) )
		return sal_True;

	// dann werden wir wohl alle einzeln vergleichen muessen
	const SfxPoolItem **ppItem1 = (const SfxPoolItem**) _aItems;
	const SfxPoolItem **ppItem2 = (const SfxPoolItem**) rCmp._aItems;
	for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
	{
		// wenn die Pointer von poolable Items ungleich sind,
		// muessen die Items gleich sein
		if ( *ppItem1 != *ppItem2 &&
			 ( ( !*ppItem1 || !*ppItem2 ) ||
			   ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
			   ( _pPool->IsItemFlag(**ppItem1, SFX_ITEM_POOLABLE) ) ||
				 **ppItem1 != **ppItem2 ) )
			return sal_False;

		++ppItem1;
		++ppItem2;
	}

	return sal_True;
}

// -----------------------------------------------------------------------

SfxItemSet *SfxItemSet::Clone(sal_Bool bItems, SfxItemPool *pToPool ) const
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	if ( pToPool && pToPool != _pPool )
	{
		SfxItemSet *pNewSet = new SfxItemSet( *pToPool, _pWhichRanges );
		if ( bItems )
		{
			SfxWhichIter aIter(*pNewSet);
			sal_uInt16 nWhich = aIter.FirstWhich();
			while ( nWhich )
			{
				const SfxPoolItem* pItem;
				if ( SFX_ITEM_SET == GetItemState( nWhich, sal_False, &pItem ) )
					pNewSet->Put( *pItem, pItem->Which() );
				nWhich = aIter.NextWhich();
			}
		}
		return pNewSet;
	}
	else
		return bItems
				? new SfxItemSet(*this)
				: new SfxItemSet(*_pPool, _pWhichRanges);
}

// -----------------------------------------------------------------------

int	SfxItemSet::PutDirect(const SfxPoolItem &rItem)
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	SfxItemArray ppFnd = _aItems;
	const sal_uInt16* pPtr = _pWhichRanges;
	const sal_uInt16 nWhich = rItem.Which();
#ifdef DBG_UTIL
	IsPoolDefaultItem(&rItem) || _pPool->GetSurrogate(&rItem);
		// nur Assertion in den callees provozieren
#endif
	while( *pPtr )
	{
		if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
		{
			// in diesem Bereich
			ppFnd += nWhich - *pPtr;
			const SfxPoolItem* pOld = *ppFnd;
			if( pOld )		// schon einer vorhanden
			{
				if( rItem == **ppFnd )
					return sal_False;		// schon vorhanden !
				_pPool->Remove( *pOld );
			}
			else
				++_nCount;

			// den neuen eintragen
			if( IsPoolDefaultItem(&rItem) )
				*ppFnd = &_pPool->Put( rItem );
			else
			{
				*ppFnd = &rItem;
				if( !IsStaticDefaultItem( &rItem ) )
					rItem.AddRef();
			}

			InvalidateHashKey();	//i120575
			return sal_True;
		}
		ppFnd += *(pPtr+1) - *pPtr + 1;
		pPtr += 2;
	}
	return sal_False;
}

// -----------------------------------------------------------------------

SfxAllItemSet::SfxAllItemSet( SfxItemPool &rPool )
:	SfxItemSet(rPool, (const sal_uInt16*) 0),
	aDefault(0),
	nFree(nInitCount)
{
	// initial keine Items
	_aItems = 0;

	// nInitCount Paare an USHORTs fuer Ranges allozieren
	_pWhichRanges = new sal_uInt16[ nInitCount + 1 ];
	memset( _pWhichRanges, 0, ( nInitCount + 1 ) * sizeof(sal_uInt16) );
}


// -----------------------------------------------------------------------


SfxAllItemSet::SfxAllItemSet(const SfxItemSet &rCopy)
:   SfxItemSet(rCopy),
	aDefault(0),
	nFree(0)
{
}

// -----------------------------------------------------------------------



SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
:   SfxItemSet(rCopy),
	aDefault(0),
	nFree(0)
/*	[Anmerkung]

	Der mu\s sein, da sonst vom Compiler einer generiert wird, er nimmt
	nicht den Ctor mit der 'const SfxItemSet&'!
*/
{
}

// -----------------------------------------------------------------------

static sal_uInt16 *AddRanges_Impl(
    sal_uInt16 *pUS, std::ptrdiff_t nOldSize, sal_uInt16 nIncr)

/* 	Diese interne Funktion erzeugt ein neues Which-Range-Array, welches von
    dem 'nOldSize'-USHORTs langen 'pUS' kopiert wird und hinten an Platz
    f"ur 'nIncr' neue USHORTs hat. Das terminierende sal_uInt16 mit der '0'
    wird weder in 'nOldSize' noch in 'nIncr' mitgez"ahlt, sondern implizit
	hinzugerechnet.

	Das neue Which-Range-Array wird als Returnwert zur"uckgegeben, das alte
    'pUS' freigegeben.
*/

{
	// neues Which-Range-Array anlegen
	sal_uInt16 *pNew = new sal_uInt16[ nOldSize + nIncr + 1 ];

	// die alten Ranges "ubernehmen
	memcpy( pNew, pUS, nOldSize * sizeof(sal_uInt16) );

	// die neuen auf 0 initialisieren
	memset( pNew + nOldSize, 0, ( nIncr + 1 ) * sizeof(sal_uInt16) );

	// das alte Array freigeben
	delete[] pUS;

	return pNew;
}

// -----------------------------------------------------------------------

static SfxItemArray AddItem_Impl(SfxItemArray pItems, sal_uInt16 nOldSize, sal_uInt16 nPos)

/*  Diese interne Funktion erzeugt ein neues ItemArray, welches von 'pItems'
    kopiert wird, an der Position 'nPos' jedoch Platz f"ur einen neuen
	ItemPointer hat.

    Das neue ItemArray wird als Returnwert zur"uckgegeben, das alte 'pItems'
	wird freigegeben.
*/

{
	// neues ItemArray anlegen
	SfxItemArray pNew = new const SfxPoolItem*[nOldSize+1];

	// war schon vorher eins da?
	if ( pItems )
	{
		// alte Items vor nPos kopieren
		if ( nPos )
			memcpy( (void*) pNew, pItems, nPos * sizeof(SfxPoolItem **) );

		// alte Items hinter nPos kopieren
		if ( nPos < nOldSize )
			memcpy( (void*) (pNew + nPos + 1), pItems + nPos,
					(nOldSize-nPos) * sizeof(SfxPoolItem **) );
	}

	// neues Item initialisieren
	*(pNew + nPos) = 0;

	// altes ItemArray freigeben
	delete[] pItems;

	return pNew;
}

// -----------------------------------------------------------------------

const SfxPoolItem* SfxAllItemSet::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )

// Putten mit automatischer Erweiterung der Whichs-Ids um die ID
// des Items.

{
    sal_uInt16 nPos = 0; // Position f"ur 'rItem' in '_aItems'
	const sal_uInt16 nItemCount = TotalCount();

	// erstmal sehen, ob es schon einen passenden Bereich gibt
	sal_uInt16 *pPtr = _pWhichRanges;
	while ( *pPtr )
	{
		// Which-Id liegt in diesem Bereich?
		if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
		{
			// Einfuegen
			nPos += nWhich - *pPtr;
			break;
		}

		// Position des Items in _aItems mitf"uhren
		nPos += *(pPtr+1) - *pPtr + 1;

		// zum n"achsten Bereich
		pPtr += 2;
	}

	// Which-Id noch nicht vorhanden?
	if ( !*pPtr )
	{
		// suchen, ob man sie irgendwo dranpacken kann
		pPtr = _pWhichRanges;
		nPos = 0;
		while ( *pPtr )
		{
			// Which-Id liegt exakt vor diesem Bereich?
			if ( (nWhich+1) == *pPtr )
			{
				// Bereich waechst nach unten
				(*pPtr)--;

				// vor erstem Item dieses Bereichs Platz schaffen
				_aItems = AddItem_Impl(_aItems, nItemCount, nPos);
				break;
			}

			// Which-Id liegt exakt hinter diesem Bereich?
			else if ( (nWhich-1) == *(pPtr+1) )
			{
				// Bereich waechst nach oben
				(*(pPtr+1))++;

				// hinter letztem Item dieses Bereichs Platz schaffen
				nPos += nWhich - *pPtr;
				_aItems = AddItem_Impl(_aItems, nItemCount, nPos);
				break;
			}

			// Position des Items in _aItems mitf"uhren
			nPos += *(pPtr+1) - *pPtr + 1;

			// zum n"achsten Bereich
			pPtr += 2;
		}
	}

	// keinen erweiterbaren Bereich gefunden?
	if ( !*pPtr )
	{
		// kein Platz mehr in _pWhichRanges => erweitern
		std::ptrdiff_t nSize = pPtr - _pWhichRanges;
		if( !nFree )
		{
			_pWhichRanges = AddRanges_Impl(_pWhichRanges, nSize, nInitCount);
			nFree += nInitCount;
		}

		// neuen Which-Range anh"angen
		pPtr = _pWhichRanges + nSize;
		*pPtr++ = nWhich;
		*pPtr = nWhich;
		nFree -= 2;

		// Itemarray vergroessern
		nPos = nItemCount;
		_aItems = AddItem_Impl(_aItems, nItemCount, nPos);
	}

	// neues Item in Pool aufnehmen
	const SfxPoolItem& rNew = _pPool->Put( rItem, nWhich );

	// altes Item merken
    sal_Bool bIncrementCount = sal_False;
	const SfxPoolItem* pOld = *( _aItems + nPos );
    if ( reinterpret_cast< SfxPoolItem* >( -1 ) == pOld )   // state "dontcare"
        pOld = NULL;
    if ( !pOld )
    {
        bIncrementCount = sal_True;
        pOld = _pParent ?
                &_pParent->Get( nWhich, sal_True )
                : nWhich <= SFX_WHICH_MAX ? &_pPool->GetDefaultItem( nWhich ) : 0;
    }

	// neue Item in ItemSet aufnehmen
	*(_aItems + nPos) = &rNew;

	// Changed Notification versenden
	if ( pOld )
	{
		Changed( *pOld, rNew );
		if ( !IsDefaultItem(pOld) )
			_pPool->Remove( *pOld );
	}

    if ( bIncrementCount )
        ++_nCount;
	
	InvalidateHashKey();	//i120575

	return &rNew;
}

// -----------------------------------------------------------------------


/*	Diese Methode wird forwarded, damit sie nicht durch die anderen
	Put-Methoden dieser SubClass gehided wird.
*/

int SfxAllItemSet::Put( const SfxItemSet& rSet, sal_Bool bInvalidAsDefault )
{
	//? pruefen, ob Which-Ranges erweitert werden
	return SfxItemSet::Put( rSet, bInvalidAsDefault );
}

// -----------------------------------------------------------------------
// Item disablen, wenn durch ein VoidItem mit dem Which-Wert 0 ausgedrueckt

void SfxItemSet::DisableItem(sal_uInt16 nWhich)
{
	DBG_CHKTHIS(SfxItemSet, 0);
	Put( SfxVoidItem(0), nWhich );
}

// -----------------------------------------------------------------------

#if 0
sal_Bool SfxAllItemSet::Remove(sal_uInt16 nWhich)
{
	DBG_CHKTHIS(SfxAllItemSet, 0);
	sal_uInt16 *pPtr = _pWhichRanges;
	sal_uInt16 nPos = 0;
	while( *pPtr )
	{
		if( *pPtr <= nWhich && nWhich <= *(pPtr+1) )
		{
			sal_uInt16 *pTmp = pPtr;
			sal_uInt16 nLeft = 0;
			sal_uInt16 nRest = 0;
			while(*++pTmp){
				if( nLeft & 1 )
					nRest = *pTmp - *(pTmp-1) + 1;
				++nLeft;
			}

			// in diesem Bereich
			nPos += nWhich - *pPtr;
			nRest -= nWhich - *pPtr;
			// 3,3
			if(*pPtr == nWhich && *(pPtr+1) == nWhich) {
				memmove(pPtr, pPtr + 2, nLeft * sizeof(sal_uInt16));
				nFree += 2;
			}
				// Anfang
			else if(*pPtr == nWhich)
				(*pPtr)++;
				// Ende
			else if(*(pPtr+1) == nWhich)
				(*(pPtr+1))--;
			else {
				if(nPos + nRest + 2 > nFree) {
					sal_uInt16 nOf = pPtr - _pWhichRanges;
					_pWhichRanges = IncrSize(_pWhichRanges, nPos + nRest, nInitCount);
					nFree += nInitCount;
					pPtr = _pWhichRanges + nOf;
				}
				memmove(pPtr +2, pPtr, (nLeft+2) * sizeof(sal_uInt16));
				*++pPtr  = nWhich-1;
				*++pPtr = nWhich+1;
				nFree -= 2;
			}
			SfxPoolItem* pItem = *( _aItems + nPos );
			if( pItem )
			{
				if(_pPool)
					_pPool->Remove(*pItem );
				else
					delete pItem;
				--_nCount;
			}
			memmove(_aItems + nPos +1, _aItems + nPos,
					sizeof(SfxPoolItem *) * (nRest - 1));
			break; 			// dann beim Parent suchen
		}
		nPos += *(pPtr+1) - *pPtr + 1;
		pPtr += 2;
	}
	return *pPtr? sal_True: sal_False;
}
#endif

// -----------------------------------------------------------------------

SfxItemSet *SfxAllItemSet::Clone(sal_Bool bItems, SfxItemPool *pToPool ) const
{
	DBG_CHKTHIS(SfxItemSet, DbgCheckItemSet);
	if ( pToPool && pToPool != _pPool )
	{
		SfxAllItemSet *pNewSet = new SfxAllItemSet( *pToPool );
		if ( bItems )
			pNewSet->Set( *this );
		return pNewSet;
	}
	else
		return bItems ? new SfxAllItemSet(*this) : new SfxAllItemSet(*_pPool);
}

//for i120575
//align with the rtl_hash, return signed int result and input len limited to 2G.
//can be replaced with other hash function in future for better performance, e.g. fnv hash.
inline sal_Int32 myhash(void * buf, sal_Int32 buf_len)
{
	return rtl_str_hashCode_WithLength( reinterpret_cast<const sal_Char *>(buf), buf_len);
}

inline void SfxItemSet::UpdateHashKey()
{
	_aHashKey= myhash(_aItems,TotalCount()* sizeof(_aItems[0]));

	//always treat '0' as invalidate hash key, not using additional bool data field for saving space.
	if (!IsValidateHashKey() )
	{
		_aHashKey = 1;
	}
}

sal_Bool SfxItemSet::QuickCompare( SfxItemSet & rCmp)
{
	if ( _pParent != rCmp._pParent ||
		 _pPool != rCmp._pPool ||
		 Count() != rCmp.Count() )
		return sal_False;

	if ((0==Count())&&(0==rCmp.Count())) 
		return sal_True;

	if (!IsValidateHashKey()) 
	{
		UpdateHashKey();
	}
	if (!rCmp.IsValidateHashKey()) 
	{
		rCmp.UpdateHashKey();
	}

	//improved performance here, in most cases, the hashkey is not equal.
	if (GetHashKey() != rCmp.GetHashKey()) 
		return sal_False;

	if ( 0 == memcmp( _aItems, rCmp._aItems,  TotalCount() * sizeof(_aItems[0]) ) )
		return sal_True;
	else
		return sal_False;
}
//end: i120575