Sources/FileClass.cp

/*
    File:       FileClass.cp
 
    Contains:   TFile is a simple object that does file manipulations   
                TFile.cp contains the TFile class and subclass member functions.
 
    Written by: Kent Sandvik    
 
    Copyright:  Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/18/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
#ifndef _FILECLASS_
#include "FileClass.h"
#endif
 
 
// _________________________________________________________________________________________________________ //
//  TFile
#pragma segment File
TFile::TFile(char* name)
// Create a file object based on the name.
{
    this->Initialize();                         // initialize internal fields to known values
 
    // We are going to assume a lot of things for the default setting
    // and files, for instance that we are creating files in the current working directory (folder)
 
    WDPBRec folderBlock;
    folderBlock.ioNamePtr = nil;
    fError = ::PBHGetVolSync(&folderBlock);
    VASSERT(fError == noErr, ("Problems with PBHGetVol = %d", fError));
 
    fFileSpec.vRefNum = folderBlock.ioVRefNum;
    fFileSpec.parID = folderBlock.ioWDDirID;
    c2p(name);
    Pstrcpy(fFileSpec.name, (StringPtr)name);
}
 
 
#pragma segment File
TFile::TFile(FSSpec theSpec)
// Create a file object based on the FSSpec.
{
    this->Initialize();                         // initialize internal fields to known values
 
    fFileSpec.vRefNum = theSpec.vRefNum;        // store the FSSpec
    fFileSpec.parID = theSpec.parID;
    Pstrcpy(fFileSpec.name, theSpec.name);
}
 
 
#pragma segment File
TFile::TFile(short volume,
             long dirID,
             Str63 name)
// Create a file object based on the volume no, directory ID and the name.
{
    this->Initialize();                         // initialize internal fields to known values
 
    fFileSpec.vRefNum = volume;                 // store values into the FSSpec
    fFileSpec.parID = dirID;
    Pstrcpy(fFileSpec.name, name);
}
 
 
#pragma segment File
TFile::~TFile()
// Default destructor -- empty for the time being.
{
}
 
 
#pragma segment File
void TFile::Initialize()
// Initialize fields to known values.
{
    fFileType = kDefaultType;                   // gee, we assume everyone's reading/writing text files
    fCreator = kDefaultCreator;                 // and who's that?
    fOpened = false;                            // not open yetÉ
    fFlushing = false;                          // assume things are OK, so we don't flush unless something's critical
}
 
 
// MAIN INTERFACE
#pragma segment File
Boolean TFile::Create()
// Create a new file.
{
    if (!this->FileExists())
    {
        fError = ::HCreate(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name, fCreator, fFileType);
        VASSERT(fError == noErr, ("Problems with HCreate = %d\n", fError));
        goto CreateOK;
    }
    return false;
CreateOK:return true;
}
 
 
#pragma segment File
Boolean TFile::Rename(char* newName)
// Rename the file.
{
    if (this->FileExists())
    {
        c2p(newName);
        fError = ::HRename(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name, (StringPtr)newName);
        VASSERT(fError == noErr, ("Problems with HRename = %d", fError));
 
        Pstrcpy(fFileSpec.name, (StringPtr)newName);
        goto RenameOK;
    }
    return false;
RenameOK:return true;
}
 
 
#pragma segment File
void TFile::Delete()
// Delete the file.
{
    if (fOpened)
        this->Close();                          // first close the file
 
    fError = ::HDelete(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name);
    VASSERT(fError == noErr, ("nProblems with HDelete = %d", fError));
}
 
 
#pragma segment File
Boolean TFile::FileExists()
// Test if the file exists or not.
{
    FInfo info;
    fError = HGetFInfo(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name, &info);
    return (fError == noErr);
}
 
 
// ACCESSORS AND MUTATORS
#pragma segment File
void TFile::SetType(const OSType creator,
                    const OSType fileType)
// Set file type.
{
    fCreator = creator;
    fFileType = fileType;
}
 
 
#pragma segment File
void TFile::SetFileName(const Str63 fileName)
// Set file name.
{
    Pstrcpy(fFileSpec.name, (StringPtr)fileName);
}
 
 
#pragma segment File
FInfo TFile::GetFileInfo()
// Get FInfo from the specified file.
{
    FInfo info;
    fError = ::HGetFInfo(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name, &info);
    VASSERT(fError == noErr, ("Problems with HGetFInfo = %d", fError));
    return info;
}
 
 
// _________________________________________________________________________________________________________ //
//  TDataFile
 
// CONSTRUCTORS AND DESTRUCTORS
#pragma segment File
TDataFile::TDataFile(char* name) :
    TFile(name)
// Default constructor, create a file based on the name.
{
}
 
#pragma segment File
TDataFile::~TDataFile()
// Default destructor -- empty for the time being.
{
}
 
 
// MAIN INTERFACE
#pragma segment File
Boolean TDataFile::Open(SignedByte permission)
// Open a file for data fork only access.
{
    fError = ::HOpen(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name, permission, &fRefNum);
    VASSERT(fError == noErr, ("Problems with HOpen = %d", fError));
 
    if (fError == noErr)
        fOpened = true;
    return (fError == noErr);
}
 
 
#pragma segment File
Boolean TDataFile::Close()
// Close the file.
{
    fError = ::FSClose(fRefNum);
    VASSERT(fError == noErr, ("Problems with FSClose = %d", fError));
 
    if (fError == noErr)
        fOpened = false;
 
    if (fFlushing)                              // if flagged, flush the volume
    {
        fError = ::FlushVol(NULL, fFileSpec.vRefNum);
        VASSERT(fError == noErr, ("Problems with FlushVol = %d", fError));
    }
 
    return (fError == noErr);
}
 
 
#pragma segment File
Boolean TDataFile::WriteHandle(Handle h)
// Write a handle to file (the whole handle).
{
    long len = ::GetHandleSize(h);              // get lenght of handle
 
    fError = ::SetFPos(fRefNum, fsFromStart, kNoOffset);// move pointer to beginning of file
    VASSERT(fError == noErr, ("Problems with SetFPos = %d", fError));
 
    fError = ::FSWrite(fRefNum, &len, *h);      // write the handle to disk
    VASSERT(fError == noErr, ("Problems with FSWrite = %d", fError));
 
    fError = ::SetEOF(fRefNum, len);            // change size of file if needed
    VASSERT(fError == noErr, ("Problems with SetEOF = %d", fError));
 
    if (fFlushing)
    {
        fError = ::FlushVol(NULL, fFileSpec.vRefNum);
        VASSERT(fError == noErr, ("Problems with FlushVol = %d", fError));
    }
    return (fError == noErr);
}
 
 
#pragma segment File
Handle TDataFile::ReadHandle()
// Read handle from the file (the whole handle).
{
    Handle h = NULL;
    long len;
 
    fError = ::GetEOF(fRefNum, &len);           // get size of handle in file
    VASSERT(fError == noErr, ("Problems with GetEOF = %d", fError));
 
    h = ::NewHandle(len);                       // create a new handle
    if (h == NULL)                              // problems creating a handle 
    {
        ASSERT(fError == noErr, "\pProblems with NewHandle");
        goto ReadHandleFalse;
    }
 
    fError = ::SetFPos(fRefNum, fsFromStart, kNoOffset);
    VASSERT(fError == noErr, ("Problems with SetFPos = %d", fError));
 
    fError = ::FSRead(fRefNum, &len, *h);       // read into handle
    VASSERT(fError == noErr, ("Problems with SetFPos = %d", fError));
 
    return h;
ReadHandleFalse:return NULL;
}
 
 
#pragma segment File
Boolean TDataFile::Write(Ptr buffer,
                         long bytes)
// Write N bytes from buffer to file.
{
    fError = ::FSWrite(fRefNum, &bytes, buffer);
    VASSERT(fError == noErr, ("Problems with FSWrite = %d", fError));
    return (fError == noErr);
}
 
 
#pragma segment File
Boolean TDataFile::Read(Ptr buffer,
                        long bytes)
// Read N bytes from file to buffer.
{
    fError = ::FSRead(fRefNum, &bytes, buffer);
    VASSERT(fError == noErr, ("Problems with FSWrite = %d", fError));
    return (fError == noErr);
}
 
 
#pragma segment File
Boolean TDataFile::SetMark(short from,
                           long offset)
// Set file mark (beginning, end, offset).
{
    if (fOpened)                                // have an open file?
    {
        fError = ::SetFPos(fRefNum, from, offset);
        VASSERT(fError == noErr, ("Problems with SetFPos = %d", fError));
        goto SetMarkOK;
    }
    else
        return false;
SetMarkOK:return (fError == noErr);
}
 
 
#pragma segment File
long TDataFile::GetMark()
// Get file mark (offset).
{
    long offset = 0;
 
    fError = ::GetFPos(fRefNum, &offset);
    VASSERT(fError == noErr, ("Problems with GetFPos = %d", fError));
 
    return offset;
}
 
 
#pragma segment File
Boolean TDataFile::Reset()
// Set file mark to beginning of file.
{
    return (this->SetMark(fsFromStart, kNoOffset));// set mark to beginning of file
}
 
 
#pragma segment File
Boolean TDataFile::GotoEndOfFile()
// Set file mark to end of file.
{
    return (this->SetMark(fsFromLEOF, kNoOffset));// set mark to end of file
}
 
 
// _________________________________________________________________________________________________________ //
//  TResourceFile
// CONSTRUCTORS AND DESTRUCTORS
#pragma segment File
TResourceFile::TResourceFile(char* name) :
    TFile(name)
// Default destructor, create a TResourceFile object.
{
}
 
 
#pragma segment File
TResourceFile::~TResourceFile()
// Default destructor -- not used for the time being.
{
}
 
 
// MAIN INTERFACE
#pragma segment File
Boolean TResourceFile::Create()
// Create the actual resource file.
{
    if (!this->FileExists())
    {
        Boolean result = TFile::Create();       // call inherited create
        if (result)                             // if OK
        {
            ::HCreateResFile(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name);
            goto CreateResourceOK;
        }
        else
            goto CreateResourceFalse;           // result = false
    }
    else
        goto CreateResourceFalse;               // couldn't create a file that exists
 
CreateResourceFalse:return false;
CreateResourceOK:if (ResError() == noErr)
        return true;
    else
        return false;
}
 
 
#pragma segment File
Boolean TResourceFile::Open(SignedByte permission)
// Open the resource file.
{
    if (fOpened)
    {
        fRefNum = ::HOpenResFile(fFileSpec.vRefNum, fFileSpec.parID, fFileSpec.name, permission);
        VASSERT(fRefNum != -1, ("Problems with HOpenResFile = %d", ::ResError()));
        if (::ResError() == 0)
            goto ResourceFileOpenOK;
        else
            goto ResourceFileOpenFalse;
    }
    else
        goto ResourceFileOpenFalse;             // can't open an already open file
ResourceFileOpenFalse:return false;
ResourceFileOpenOK:fOpened = true;
    return true;
}
 
 
#pragma segment File
Boolean TResourceFile::Close()
// Close the resource file.
{
    if (fOpened)
    {
        ::CloseResFile(fRefNum);
        VASSERT(fRefNum != -1, ("Problems with CloseResFile = %d", ::ResError()));
        if (::ResError() == 0)
            goto ResourceFileCloseOK;
        else
            goto ResourceFileCloseFalse;
    }
ResourceFileCloseFalse:return false;
ResourceFileCloseOK:fRefNum = 0;
    fOpened = false;
    return true;
}
 
 
#pragma segment File
Boolean TResourceFile::HasResourceFork()
// Check if the supposed resource file actually has a resource fork.
{
    HFileParam pb;
 
    pb.ioNamePtr = fFileSpec.name;              // get the name
    pb.ioVRefNum = fFileSpec.vRefNum;           // and the volume
    pb.ioDirID = fFileSpec.parID;               // and the DirID
    pb.ioFDirIndex = 0;                         // zero this one
 
    fError = ::PBHGetFInfoSync((HParmBlkPtr) & pb);// call the right trap
    VASSERT(fError == noErr, ("Problems with PBHGetFInfo = %d", fError));
 
    return (pb.ioFlRLgLen != 0);                // if the resource fork is non-zero, then we got one
}
 
 
#pragma segment File
void TResourceFile::Update()
// Update the resource file.
{
    if (fOpened)
    {
        ::UpdateResFile(fRefNum);
        VASSERT(::ResError() == noErr, ("Problems with UpdateResFile = %d", ::ResError()));
        if (fFlushing)
        {
            fError = ::FlushVol(NULL, fFileSpec.vRefNum);
            VASSERT(fError == noErr, ("Problems with FlushVol = %d", fError));
        }
    }
}
 
 
#pragma segment File
void TResourceFile::Assign()
// Make sure that we are using this specified resource file.
{
    if (fOpened)
        ::UseResFile(fRefNum);
}
 
 
// _________________________________________________________________________________________________________ //
/*  Change History (most recent last):
  No        Init.   Date        Comment
  1         khs     12/27/92    New file
  2         khs     1/14/93     Cleanup
*/