netscape-revival
lib/mac/VText/V_PowerPlant_Mods/LFileTube.cp
// ===========================================================================
// LFileTube.cp ©1995 Metrowerks Inc. All rights reserved.
// ===========================================================================
// For routine descriptions see LDataTube.cp.
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include "LFileTube.h"
#include <UMemoryMgr.h>
#include <LTubeableItem.h>
#include <LFileStream.h>
#include <URange32.h>
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#pragma warn_unusedarg off
const Int16 refNum_Undefined = -1;
#define AssertValidResID_(num) Assert_((min_Int16 <= ((Int32)(num))) && (((Int32)(num)) <= max_Int16))
LFileTube::LFileTube(
LFile *inFile,
Int16 inPrivileges,
ResIDT inLevel1Ref)
{
FSSpec fsSpec;
FInfo fndrInfo;
OSErr err;
mSwapDepth = 2;
mLevel1Ref = inLevel1Ref;
mNextRef = mLevel1Ref;
mItemRef = mLevel1Ref;
mFile = inFile;
mPrivileges = inPrivileges;
// mFileType
mFile->GetSpecifier(fsSpec);
err = FSpGetFInfo(&fsSpec, &fndrInfo);
ThrowIfOSErr_(err);
mFileType = fndrInfo.fdType;
}
LFileTube::LFileTube(
LFile *inFile,
const LTubeableItem *inTubeableItem,
Int16 inPrivileges,
Boolean inReqdFlavorsOnly,
ResIDT inLevel1Ref
)
{
FSSpec fsSpec;
FInfo fndrInfo;
OSErr err;
mSwapDepth = 2;
mLevel1Ref = inLevel1Ref;
mNextRef = mLevel1Ref;
mFile = inFile;
mPrivileges = inPrivileges;
// mFileType
mFile->GetSpecifier(fsSpec);
err = FSpGetFInfo(&fsSpec, &fndrInfo);
ThrowIfOSErr_(err);
mFileType = fndrInfo.fdType;
FillFrom(inTubeableItem, inReqdFlavorsOnly);
}
LFileTube::~LFileTube()
{
if (mFile) {
mFile->CloseDataFork();
mFile->CloseResourceFork();
}
}
// ----------------------------------------------------------------------
// Read:
Boolean LFileTube::FlavorExists(FlavorType inFlavor) const
{
Boolean rval = false;
if ((mTubeDepth+1 == mSwapDepth) || (mTubeDepth == mSwapDepth)) {
do {
if (inFlavor == typeWildCard) {
rval = true;
break;
}
if ((mFileType == inFlavor) && (mItemRef == mLevel1Ref)) {
rval = true;
break;
}
if (HasResourceFork()) {
CheckResourceFork();
// An incredibly inefficient but safe way to do this...
AssertValidResID_(mItemRef);
StResource r(inFlavor, mItemRef, false, true);
if (r.mResourceH)
rval = true;
break;
}
} while (false);
} else {
rval = inherited::FlavorExists(inFlavor);
}
return rval;
}
Size LFileTube::GetFlavorSize(FlavorType inFlavor) const
{
long rval = 0;
if ((mTubeDepth+1 == mSwapDepth) || (mTubeDepth == mSwapDepth)) {
OSErr err;
if ((mFileType == inFlavor) && (mItemRef == mLevel1Ref)) {
CheckDataFork();
err = GetEOF(mFile->GetDataForkRefNum(), &rval);
ThrowIfOSErr_(err);
} else if (HasResourceFork()) {
CheckResourceFork();
AssertValidResID_(mItemRef);
StResource r(inFlavor, mItemRef, false, true);
if (r.mResourceH)
rval = GetHandleSize(r);
}
} else {
rval = inherited::GetFlavorSize(inFlavor);
}
return rval;
}
void * LFileTube::GetFlavorData(
FlavorType inFlavor,
void *outFlavorData
) const
// For routine description see LDataTube.cp.
{
void *rval = NULL;
if ((mTubeDepth+1 == mSwapDepth) || (mTubeDepth == mSwapDepth)) {
long count = GetFlavorSize(inFlavor);
OSErr err;
if (outFlavorData == NULL)
return NULL;
if ((mFileType == inFlavor) && (mItemRef == mLevel1Ref)) {
CheckDataFork();
err = FSRead(mFile->GetDataForkRefNum(), &count, outFlavorData);
ThrowIfOSErr_(err);
} else {
CheckResourceFork();
AssertValidResID_(mItemRef);
StResource r(inFlavor, mItemRef, true, true);
count = URange32::Min(count, GetHandleSize(r));
if (count > 0)
BlockMoveData(*r.mResourceH, outFlavorData, count);
}
} else {
rval = inherited::GetFlavorData(inFlavor, outFlavorData);
}
return rval;
}
LStream & LFileTube::GetFlavorStreamOpen(FlavorType inFlavor) const
{
if (mStream)
Throw_(paramErr); // presently you can have a total of only one flavor stream open at a time
if ( ((mTubeDepth+1 == mSwapDepth) || (mTubeDepth == mSwapDepth)) &&
(mFileType == inFlavor) &&
(mItemRef == mLevel1Ref)
) {
LFileTube &my = (LFileTube&)*this;
my.mStreamFlavor = inFlavor;
FSSpec fsSpec;
ThrowIfNULL_(mFile);
mFile->GetSpecifier(fsSpec);
LFileStream *stream = new LFileStream(fsSpec);
my.mStream = stream;
stream->OpenDataFork(mPrivileges);
stream->SetLength(0);
stream->SetMarker(0, streamFrom_Start);
return *mStream;
} else {
return inherited::GetFlavorStreamOpen(inFlavor);
}
}
void LFileTube::GetFlavorStreamClose(void) const
{
if (!mStream)
Throw_(paramErr); // close without balanced open
if ( ((mTubeDepth+1 == mSwapDepth) || (mTubeDepth == mSwapDepth)) &&
(mFileType == mStreamFlavor) &&
(mItemRef == mLevel1Ref)
) {
LFileTube &my = (LFileTube&)*this;
LFileStream *stream = dynamic_cast<LFileStream *>(my.mStream);
ThrowIfNULL_(stream);
stream->CloseDataFork();
delete mStream;
my.mStream = NULL;
} else {
inherited::GetFlavorStreamClose();
}
}
Int32 LFileTube::CountItems(void) const
{
Int32 rval = 0;
if (mTubeDepth+1 == mSwapDepth) {
Assert_(false); // Can't count here
rval = 1; // not correct!
// should be...
// rval = UResourceMap::CountIDs(currentResourceMap, typeWildCard);
// Assert_(UResourceMap::IDExists(currentResourceMap, typeWildCard, sLevel1ID);
// rval -= 1; // for sLevel1ID
} else if (mTubeDepth == mSwapDepth) {
StAEDescriptor items;
GetFlavorAsDesc(typeTubeMapItems, &items.mDesc);
LAESubDesc itemsSD(items);
return itemsSD.CountItems();
} else {
rval = inherited::CountItems();
}
return rval;
}
LDataTube LFileTube::KeyedItem(ItemReference inItemRef) const
{
if (mTubeDepth+1 == mSwapDepth) {
LAESubDesc sd; // null sd
return LDataTube(this, inItemRef, sd, mTubeDepth + 1);
} else if (mTubeDepth == mSwapDepth) {
CheckResourceFork();
// Get typeTubeMapItems data
AssertValidResID_(inItemRef);
StResource r(typeTubeMapItems, inItemRef, true, true);
// Swap mOwnedDesc
OSErr err;
AEDesc *desc = &(((LFileTube *)this)->mOwnedDesc.mDesc);
AEDisposeDesc(desc);
desc->descriptorType = typeAERecord;
desc->dataHandle = r.mResourceH;
err = HandToHand(&(desc->dataHandle));
ThrowIfOSErr_(err);
return LDataTube(this, inItemRef, LAESubDesc(*desc), mTubeDepth + 1);
} else {
return inherited::KeyedItem(inItemRef);
}
}
LDataTube LFileTube::NthItem(Int32 inIndex, ItemReference *outReference) const
{
if (mTubeDepth+1 == mSwapDepth) {
if (inIndex != 1)
Throw_(paramErr); // Can't do that
if (outReference)
*outReference = mLevel1Ref;
return KeyedItem(mLevel1Ref);
} else if (mTubeDepth == mSwapDepth) {
Throw_(paramErr); // Can't do this here
return LDataTube(); // Bogus
} else {
return inherited::NthItem(inIndex, outReference);
}
}
// ----------------------------------------------------------------------
// Write:
void LFileTube::AddFlavor(FlavorType inFlavor)
{
if ( (mItemStack.Depth()+1 == mSwapDepth) ||
(mItemStack.Depth() == mSwapDepth)
) {
if (mItemStack.Top().item && mAddSendsData) {
mItemStack.Top().item->SendFlavorTo(inFlavor, this);
}
} else {
inherited::AddFlavor(inFlavor);
}
}
void LFileTube::SetFlavorData(
FlavorType inFlavor,
const void *inFlavorData,
Int32 inFlavorSize
)
// For routine description see LDataTube.cp.
{
if ( (mItemStack.Depth()+1 == mSwapDepth) ||
(mItemStack.Depth() == mSwapDepth)
) {
OSErr err;
long count = inFlavorSize;
ThrowIfNULL_(inFlavorData);
if ((mFileType == inFlavor) && (mItemStack.Top().ref == mLevel1Ref)) {
CheckDataFork();
err = FSWrite(mFile->GetDataForkRefNum(), &count, inFlavorData);
ThrowIfOSErr_(err);
err = SetEOF(mFile->GetDataForkRefNum(), inFlavorSize);
ThrowIfOSErr_(err);
} else {
if (!HasResourceFork())
AddResourceFork();
CheckResourceFork();
AssertValidResID_(mItemStack.Top().ref);
StResource r(inFlavor, mItemStack.Top().ref, false, true);
if (r.mResourceH) {
SetHandleSize(r, inFlavorSize);
ThrowIfMemError_();
BlockMoveData(inFlavorData, *r, inFlavorSize);
ChangedResource(r);
ThrowIfResError_();
} else {
r.mResourceH = NewHandle(inFlavorSize);
ThrowIfNULL_(r);
BlockMoveData(inFlavorData, *r, inFlavorSize);
AddResource(r, inFlavor, mItemStack.Top().ref, "\p");
ThrowIfResError_();
}
WriteResource(r);
ThrowIfResError_();
}
} else {
inherited::SetFlavorData(
inFlavor,
inFlavorData,
inFlavorSize);
}
}
LStream & LFileTube::SetFlavorStreamOpen(FlavorType inFlavor)
{
if (mStream)
Throw_(paramErr); // presently you can have a total of only one flavor stream open at a time
if ( ((mItemStack.Depth()+1 == mSwapDepth) || (mItemStack.Depth() == mSwapDepth)) &&
(mFileType == inFlavor) &&
(mItemStack.Top().ref == mLevel1Ref)
) {
mStreamFlavor = inFlavor;
FSSpec fsSpec;
ThrowIfNULL_(mFile);
mFile->GetSpecifier(fsSpec);
LFileStream *stream = new LFileStream(fsSpec);
mStream = stream;
stream->OpenDataFork(mPrivileges);
stream->SetLength(0);
stream->SetMarker(0, streamFrom_Start);
} else {
inherited::SetFlavorStreamOpen(inFlavor);
}
return *mStream;
}
void LFileTube::SetFlavorStreamClose(void)
{
if (!mStream)
Throw_(paramErr); // close without balanced open
if ( ((mItemStack.Depth()+1 == mSwapDepth) || (mItemStack.Depth() == mSwapDepth)) &&
(mFileType == mStreamFlavor) &&
(mItemStack.Top().ref == mLevel1Ref)
) {
LFileStream *stream = dynamic_cast<LFileStream*>(mStream);
ThrowIfNULL_(stream);
stream->CloseDataFork();
delete mStream;
mStream = NULL;
} else {
inherited::SetFlavorStreamClose();
}
}
// ----------------------------------------------------------------------
// Implementation:
void LFileTube::CheckDataFork(void) const
{
ThrowIfNULL_(mFile);
if (mFile->GetDataForkRefNum() == refNum_Undefined) {
mFile->OpenDataFork(mPrivileges);
}
}
void LFileTube::CheckResourceFork(void) const
{
ThrowIfNULL_(mFile);
if (HasResourceFork())
MakeResourceForkCurrent();
}
Boolean LFileTube::HasResourceFork(void) const
{
Boolean rval = true;
Try_ {
#ifdef Debug_Throw
// It IS okay for this to fail, so turn off Throw debugging.
StValueChanger<EDebugAction> okayToFail(gDebugThrow, debugAction_Nothing);
#endif
if (mFile->GetResourceForkRefNum() == refNum_Undefined)
mFile->OpenResourceFork(mPrivileges);
} Catch_(err) {
if (err != eofErr)
ThrowIfOSErr_(err);
rval = false;
} EndCatch_;
return rval;
}
void LFileTube::AddResourceFork(void)
{
OSErr err;
FSSpec fSpec;
FInfo fInfo;
if (!HasResourceFork()) {
mFile->GetSpecifier(fSpec);
err = FSpGetFInfo(&fSpec, &fInfo);
ThrowIfOSErr_(err);
mFile->CreateNewFile(fInfo.fdCreator, fInfo.fdType);
}
}
void LFileTube::MakeResourceForkCurrent(void) const
{
if (CurResFile() != mFile->GetResourceForkRefNum()) {
UseResFile(mFile->GetResourceForkRefNum());
ThrowIfResError_();
}
}
// ----------------------------------------------------------------------
// Helper class:
/*
Wouldn't this be nice? It would allow a sensible CountItems for
level 2. IF, it didn't have to illegally walk the resource map.
If this is ever implemented, it should be placed in a shared
library -- so it can easily be replaced if a subseqent OS releases
breaks it.
typedef Handle ResourceMapH;
class UResourceMap {
public:
static Int32 CountIDs(const ResourceMapH inMap, ResType inType);
static Boolean IDExists(const ResourceMapH inMap, ResType inType, ResIDT inID);
static ResIDT NthID(const ResourceMapH inMap, ResType inType, Int32 inIndex);
static ResourceMapH CurrentMap(void);
};
*/