Milán Major

netscape-revival

1 branch
Code

lib/mac/VText/V_PowerPlant_Mods/LDescTube.cp

//	===========================================================================
//	LDescTube.cp				©1995 Metrowerks Inc. All rights reserved.
//	===========================================================================

//	For routine descriptions see LDataTube.cp.

#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif

#include	"LDescTube.h"
#include	<UMemoryMgr.h>
#include	<LTubeableItem.h>
#include	<LTubeStreams.h>
#include	<URange32.h>


#pragma	warn_unusedarg off

LDescTube::LDescTube()
{
	mReqdFlavorsOnly = false;
	mAddSendsData = true;

	mNextRef = 0x10000;
	mDesc = &mOwnedDesc.mDesc;
	
	mStream = NULL;
}

LDescTube::LDescTube(const AEDesc &inTubeDesc)
{
	mDesc = (AEDesc *) &inTubeDesc;
	mTubeMap = LAESubDesc(*mDesc);
	
	mReqdFlavorsOnly = false;
	mAddSendsData = true;
	
	mNextRef = 0x10000;
	
	mStream = NULL;
}

LDescTube::LDescTube(
	AEDesc				*ioTubeDesc,
	const LTubeableItem	*inTubeableItem,
	Boolean				inReqdFlavorsOnly
)
/*
	Don't call this constructor from a more derived tube -- you want
	FillFrom to be called when the tube is fully constructed
*/
{
	mDesc = ioTubeDesc;
	mAddSendsData = true;

	mNextRef = 0x10000;
	
	mStream = NULL;
	
	FillFrom(inTubeableItem, inReqdFlavorsOnly);
}

LDescTube::~LDescTube()
{
	delete mStream;
	mStream = NULL;
	
	while (mItemStack.Depth()) {
		if (	(mItemStack.Depth() == 1) ||
				(mItemStack.Top().stream != mItemStack.PeekBack(1).stream)
		) {
			delete mItemStack.Top().stream;
			mItemStack.Top().stream = NULL;
		}
		mItemStack.Pop();
	}
}

Boolean	LDescTube::GetOnlyReqdFlavors(void) const
{
	return mReqdFlavorsOnly;
}

void	LDescTube::FillFrom(const LTubeableItem *inItem, Boolean inReqdFlavorsOnly)
{
	mReqdFlavorsOnly = inReqdFlavorsOnly;
	
	if (inItem) {
		OpenItem(inItem);
		inItem->AddFlavorTypesTo(this);
		CloseItem();
		
		if (mItemStack.Depth() != 0)
			Throw_(paramErr);	//	nesting error
	}
}

//	----------------------------------------------------------------------
//	Read:

Boolean	LDescTube::FlavorExists(FlavorType inFlavor) const
{
	Boolean rval = false;
	
	if (inFlavor == typeWildCard) {
		switch (mTubeMap.CountItems()) {

			case 0:
				break;
			
			case 1:
				if (!mTubeMap.KeyExists(typeTubeMapItems))
					rval = true;
				break;
			
			default:
				rval = true;
				break;
		}
	} else {
		rval = mTubeMap.KeyExists(inFlavor);
	}
	
	return rval;	
}

Size	LDescTube::GetFlavorSize(FlavorType inFlavor) const
{
	Size	rval = 0;
	
	LAESubDesc	flavor = mTubeMap.KeyedItem(inFlavor);
	
	if (flavor.GetType() != typeNull)
		rval = flavor.GetDataLength();

	return rval;
}

void *	LDescTube::GetFlavorData(
	FlavorType	inFlavor,
	void		*outFlavorData
) const
//	For routine description see LDataTube.cp.
{
	if (inFlavor == typeTubeMapItems)
		Throw_(paramErr);
		
	Int32		amount = GetFlavorSize(inFlavor);
	void		*source = NULL;
	LAESubDesc	flavor = mTubeMap.KeyedItem(inFlavor);
	
	if (flavor.GetType() == typeNull)
		Throw_(noTypeErr);

	source = flavor.GetDataPtr();
	if (source) {
		source = (Int8 *) source;
		if (outFlavorData && amount)
			BlockMoveData(source, outFlavorData, amount);
	}

	if (outFlavorData)
		return NULL;
	else
		return source;
}

LStream &	LDescTube::GetFlavorStreamOpen(FlavorType inFlavor) const
{
	LDescTube	&my = (LDescTube&)*this;
	
	if (mStream)
		Throw_(paramErr);	//	presently you can have a total of only one flavor stream open at a time
	
	my.mStreamFlavor = inFlavor;
	my.mStream = new LAESubDescReadStream(mTubeMap.KeyedItem(mStreamFlavor));
	return *mStream;
}

void	LDescTube::GetFlavorStreamClose(void) const
{
	LDescTube	&my = (LDescTube&)*this;

	if (!mStream)
		Throw_(paramErr);	//	close without balanced open

	delete mStream;
	my.mStream = NULL;
}

Int32	LDescTube::CountItems(void) const
{
	Int32	rval = 0;
	
	if (mTubeMap.KeyExists(typeTubeMapItems))
		rval = mTubeMap.KeyedItem(typeTubeMapItems).CountItems();

	return	rval;
}

LDataTube	LDescTube::NthItem(Int32 inIndex, ItemReference *outReference) const
{
	AEKeyword	key = 0;
	LAESubDesc	item = mTubeMap.KeyedItem(typeTubeMapItems).NthItem(inIndex, &key);
	
	if (item.GetType() == typeNull)
		Throw_(paramErr);	//	non existent item
	
	if (outReference)
		*outReference = key;
		
	return LDataTube(this, key, item, mTubeDepth + 1);
}

LDataTube	LDescTube::KeyedItem(ItemReference inItemRef) const
{
	LAESubDesc	item = mTubeMap.KeyedItem(typeTubeMapItems).KeyedItem(inItemRef);
	
	if (item.GetType() == typeNull)
		Throw_(paramErr);	//	non existent item
		
	return LDataTube(this, inItemRef, item, mTubeDepth + 1);
}

//	----------------------------------------------------------------------
//	Generic functions:

void	LDescTube::WriteDesc(LAEStream *inStream) const
{
	if (mItemStack.Depth() != 0)
		Throw_(paramErr);	//	Tube isn't finished
	
	inStream->WriteSubDesc(mTubeMap);
}

Int32	LDescTube::FlavorCount(void) const
{
	Int32	rval = mTubeMap.CountItems();
	
	if (mTubeMap.KeyExists(typeTubeMapItems))
		rval--;
		
	return rval;
}

FlavorType	LDescTube::NthFlavor(Int32 inIndex) const
{
	DescType	rval;
	AEKeyword	keyFound;
	Int32		index = 0;
	
	Assert_((0 < inIndex) && (inIndex <= FlavorCount()));
	
	do {
		index++;
		mTubeMap.NthItem(index, &keyFound);
		if (keyFound == typeTubeMapItems)
			index++;
		inIndex--;
	} while (inIndex > 0);
	
	mTubeMap.NthItem(index, &rval);

	return rval;
}

//	----------------------------------------------------------------------
//	Write:

void	LDescTube::AddFlavor(FlavorType inFlavor)
{
	if (inFlavor == typeTubeMapItems)
		Throw_(paramErr);	//	typeTubeMapItems is reserved.
		
	if (inFlavor == typeNull)
		Throw_(paramErr);	//	typeNull is reserved.
		
	if (!mItemStack.Depth())
		Throw_(paramErr);	//	An item must be opened first!
	
	if (mItemStack.Top().subCt)
		Throw_(paramErr);	//	Can't add item flavors after starting to add sub items
	
	//	Write flavor key
	if (mItemStack.Top().stream)
		mItemStack.Top().stream->WriteKey(inFlavor);
	
	//	Write flavor data?
	if (mItemStack.Top().item && mAddSendsData) {
		mItemStack.Top().item->SendFlavorTo(inFlavor, this);
	} else {
		StAEDescriptor	nullDesc;
		if (mItemStack.Top().stream)
			mItemStack.Top().stream->WriteDesc(nullDesc);
	}
}

void	LDescTube::SetFlavorData(
	FlavorType	inFlavor,
	const void	*inFlavorData,
	Int32		inFlavorSize
)
//	For routine description see LDataTube.cp.
{
	mItemStack.Top().stream->OpenDesc(inFlavor);

	mItemStack.Top().stream->WriteData(inFlavorData, inFlavorSize);
	
	mItemStack.Top().stream->CloseDesc();
}

LStream &	LDescTube::SetFlavorStreamOpen(FlavorType inFlavor)
{
	if (mStream)
		Throw_(paramErr);	//	presently you can have a total of only one flavor stream open at a time
	
	mStreamFlavor = inFlavor;
	
	mItemStack.Top().stream->OpenDesc(mStreamFlavor);
	mStream = new LAEStreamWriteStream(mItemStack.Top().stream);
	
	return *mStream;
}

void	LDescTube::SetFlavorStreamClose(void)
{
	if (!mStream)
		Throw_(paramErr);	//	close without balanced open
	
	mItemStack.Top().stream->CloseDesc();
	delete mStream;
	mStream = NULL;
}

void	LDescTube::OpenItem(
	const LTubeableItem	*inItem,
	ItemReference		inItemRef
)
{
	//	Make stack record
	ItemRecT	r;
	
	r.item = NULL;
	r.ref = (inItemRef == defaultItemReference) ? mNextRef++ : inItemRef;
	r.subCt = 0;
	r.stream = 0;
		
	if (mItemStack.Depth()) {
		if (mItemStack.Top().stream) {
			//	New group of items?
			if (!mItemStack.Top().subCt) {
				mItemStack.Top().stream->WriteKey(typeTubeMapItems);
				mItemStack.Top().stream->OpenRecord();	//	of subitems
			}
			mItemStack.Top().stream->WriteKey(r.ref);	//	of item	
		}		

		mItemStack.Top().subCt++;
	}

	//	Push it
	mItemStack.Push(r);
	SetItem((LTubeableItem *)inItem);
	NewTop();
	
	if (mItemStack.Top().stream)
		mItemStack.Top().stream->OpenRecord();	//	of item flavors
}

void	LDescTube::CloseItem(void)
{
	if (!mItemStack.Depth())
		Throw_(paramErr);
	
	if (mItemStack.Top().stream) {
		if (mItemStack.Top().subCt)
			mItemStack.Top().stream->CloseRecord();	//	of subitems
		
		mItemStack.Top().stream->CloseRecord();		//	of item flavors
	}
	
	OldTop();
	
	//	Don't leak an LAEStream!
	Assert_(!mItemStack.Top().stream ||
			(mItemStack.Depth() >= 2) && (mItemStack.Top().stream == mItemStack.PeekBack(1).stream)
	);
	
	mItemStack.Pop();
}

void	LDescTube::SetItem(LTubeableItem *inItem)
{
	Assert_(mItemStack.Depth());
	
	mItemStack.Top().item = inItem;
}

void	LDescTube::NewTop(void)
{
	if (mStream)
		Throw_(paramErr);	//	Flavor stream nesting error
		
	if (mItemStack.Depth() == 1)
		mItemStack.Top().stream = new LAEStream;
}

void	LDescTube::OldTop(void)
{
	if (mStream)
		Throw_(paramErr);	//	Flavor stream nesting error
		
	if (mItemStack.Depth() == 1) {
//?		Assert_(mDesc->descriptorType == typeNull);
		mItemStack.Top().stream->Close(mDesc);
		delete mItemStack.Top().stream;
		mItemStack.Top().stream = NULL;
	}
}

//	----------------------------------------------------------------------
//	stack template instantiation...

#include	<LStack.t>

template class	LStack<ItemRecT>;