ciderpress/diskimg/GenericFD.h
2007-03-27 17:47:10 +00:00

318 lines
9.7 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Declarations for GenericFD class and sub-classes.
*/
#ifndef __GENERIC_FD__
#define __GENERIC_FD__
#include "Win32BlockIO.h"
namespace DiskImgLib {
#if 0
/*
* Embedded file descriptor class, representing an open file on a disk image.
*
* Useful for opening disk images that are stored as files inside of other
* disk images. For stuff like UNIDOS images, which don't have a file
* associated with them, we can either open them as raw blocks, or create
* a "fake" file to access them. The latter is more general, and will work
* for sub-volumes of sub-volumes.
*/
class DISKIMG_API EmbeddedFD {
public:
EmbeddedFD(void) {
fpDiskFS = NULL;
fpA2File = NULL;
}
virtual ~EmbeddedFD(void) {}
typedef enum Fork { kForkData = 0, kForkRsrc = 1 } Fork;
// bit-flag values for Open call's "access" parameter
enum {
kAccessNone = 0, // somewhat useless
kAccessRead = 0x01, // O_RDONLY
kAccessWrite = 0x02, // O_WRONLY
kAccessCreate = 0x04, // O_CREAT
kAccessMustNotExist = 0x08, // O_EXCL, pointless w/o O_CREAT
kAccessReadWrite = (kAccessRead | kAccessWrite),
};
/*
* Standard set of calls.
*/
DIError Open(DiskFS* pDiskFS, const char* filename, Fork fork = kForkData,
int access = kAccessRead, int fileCreatePerms = 0);
DIError OpenBlocks(DiskFS* pDiskFS, long blockStart, long blockCount,
int access = kAccessRead);
DIError Read(void* buf, size_t length);
DIError Write(const void* buf, size_t length);
DIError Seek(di_off_t offset, DIWhence whence);
DIError Close(void);
private:
// prevent bitwise copying behavior
EmbeddedFD& operator=(const EmbeddedFD&);
EmbeddedFD(const EmbeddedFD&);
DiskFS* fpDiskFS;
A2File* fpA2File;
};
#endif
/*
* Generic file source base class. Allows us to treat files on disk, memory
* buffers, and files embedded inside disk images equally.
*
* The file represented by the class is available in its entirety; skipping
* past "wrapper headers" is expected to be done by the caller.
*
* The Read and Write calls take an optional parameter that allows the caller
* to see how much data was actually read or written. If the parameter is
* not specified (or specified as nil), then failure to return the exact
* amount of data requested results an error.
*
* This is not meant to be the end-all of file wrapper classes; in
* particular, it does not support file creation.
*
* Some libraries, such as NufxLib, require an actual filename to operate
* (bad architecture?). The GetPathName call will return the original
* filename if one exists, or nil if there isn't one. (At which point the
* caller has the option of creating a temp file, copying the data into
* it, and cranking up NufxLib or zlib on that.)
*
* NOTE to self: see fsopen() to control sharing.
*
* NOTE: the Seek() implementations currently do not consistently allow or
* disallow seeking past the current EOF of a file. When writing a file this
* can be very useful, so someday we should implement it for all classes.
*/
class GenericFD {
public:
GenericFD(void) : fReadOnly(true) {}
virtual ~GenericFD(void) {} /* = 0 */
// All sub-classes must provide these, plus a type-specific Open call.
virtual DIError Read(void* buf, size_t length,
size_t* pActual = nil) = 0;
virtual DIError Write(const void* buf, size_t length,
size_t* pActual = nil) = 0;
virtual DIError Seek(di_off_t offset, DIWhence whence) = 0;
virtual di_off_t Tell(void) = 0;
virtual DIError Truncate(void) = 0;
virtual DIError Close(void) = 0;
virtual const char* GetPathName(void) const = 0;
// Flush-data call, only needed for physical devices
virtual DIError Flush(void) { return kDIErrNone; }
// Utility functions.
virtual DIError Rewind(void) { return Seek(0, kSeekSet); }
virtual bool GetReadOnly(void) const { return fReadOnly; }
/*
typedef enum {
kGFDTypeUnknown = 0,
kGFDTypeFile,
kGFDTypeBuffer,
kGFDTypeWinVolume,
kGFDTypeGFD
} GFDType;
virtual GFDType GetGFDType(void) const = 0;
*/
/*
* Utility function to copy data from one GFD to another. Both GFDs must
* be seeked to their initial positions. "length" bytes will be copied.
*/
static DIError CopyFile(GenericFD* pDst, GenericFD* pSrc, di_off_t length,
unsigned long* pCRC = nil);
protected:
GenericFD& operator=(const GenericFD&);
GenericFD(const GenericFD&);
bool fReadOnly; // set when file is opened
};
class GFDFile : public GenericFD {
public:
#ifdef HAVE_FSEEKO
GFDFile(void) : fPathName(nil), fFp(nil) {}
#else
GFDFile(void) : fPathName(nil), fFd(-1) {}
#endif
virtual ~GFDFile(void) { Close(); delete[] fPathName; }
virtual DIError Open(const char* filename, bool readOnly);
virtual DIError Read(void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Write(const void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Seek(di_off_t offset, DIWhence whence);
virtual di_off_t Tell(void);
virtual DIError Truncate(void);
virtual DIError Close(void);
virtual const char* GetPathName(void) const { return fPathName; }
private:
char* fPathName;
#ifdef HAVE_FSEEKO
FILE* fFp;
#else
int fFd;
#endif
};
#ifdef _WIN32
class GFDWinVolume : public GenericFD {
public:
GFDWinVolume(void) : fPathName(nil), fCurrentOffset(0), fVolumeEOF(-1)
{}
virtual ~GFDWinVolume(void) { delete[] fPathName; }
virtual DIError Open(const char* deviceName, bool readOnly);
virtual DIError Read(void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Write(const void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Seek(di_off_t offset, DIWhence whence);
virtual di_off_t Tell(void);
virtual DIError Truncate(void) { return kDIErrNotSupported; }
virtual DIError Close(void);
virtual const char* GetPathName(void) const { return fPathName; }
virtual DIError Flush(void) { return fVolAccess.FlushCache(false); }
private:
char* fPathName; // for display only
Win32VolumeAccess fVolAccess;
di_off_t fCurrentOffset;
di_off_t fVolumeEOF;
int fBlockSize; // usually 512
};
#endif
class GFDBuffer : public GenericFD {
public:
GFDBuffer(void) : fBuffer(nil) {}
virtual ~GFDBuffer(void) { Close(); }
// If "doDelete" is set, the buffer will be freed with delete[] when
// Close is called. This should ONLY be used for storage allocated
// by the DiskImg library, as under Windows it can cause problems
// because DLLs can have their own heap.
//
// "doExpand" will cause writing past the end of the buffer to
// reallocate the buffer. Again, for internally-allocated storage
// only. We expect the initial size to be close to accurate, so we
// don't aggressively expand the buffer.
virtual DIError Open(void* buffer, di_off_t length, bool doDelete,
bool doExpand, bool readOnly);
virtual DIError Read(void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Write(const void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Seek(di_off_t offset, DIWhence whence);
virtual di_off_t Tell(void);
virtual DIError Truncate(void) {
fLength = (long) Tell();
return kDIErrNone;
}
virtual DIError Close(void);
virtual const char* GetPathName(void) const { return nil; }
// Back door; try not to use this.
void* GetBuffer(void) const { return fBuffer; }
private:
enum { kMaxReasonableSize = 256 * 1024 * 1024 };
void* fBuffer;
long fLength; // these sit in memory, so there's no
long fAllocLength; // value in using di_off_t here
bool fDoDelete;
bool fDoExpand;
di_off_t fCurrentOffset; // actually limited to (long)
};
#if 0
class GFDEmbedded : public GenericFD {
public:
GFDEmbedded(void) : fEFD(nil) {}
virtual ~GFDEmbedded(void) { Close(); }
virtual DIError Open(EmbeddedFD* pEFD, bool readOnly);
virtual DIError Read(void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Write(const void* buf, size_t length,
size_t* pActual = nil);
virtual DIError Seek(di_off_t offset, DIWhence whence);
virtual di_off_t Tell(void);
virtual DIError Close(void);
virtual const char* GetPathName(void) const { return nil; }
private:
EmbeddedFD* fEFD;
};
#endif
/* pass all requests straight through to another GFD (with offset bias) */
class GFDGFD : public GenericFD {
public:
GFDGFD(void) : fpGFD(nil), fOffset(0) {}
virtual ~GFDGFD(void) { Close(); }
virtual DIError Open(GenericFD* pGFD, di_off_t offset, bool readOnly) {
if (pGFD == nil)
return kDIErrInvalidArg;
if (!readOnly && pGFD->GetReadOnly())
return kDIErrAccessDenied; // can't convert to read-write
fpGFD = pGFD;
fOffset = offset;
fReadOnly = readOnly;
Seek(0, kSeekSet);
return kDIErrNone;
}
virtual DIError Read(void* buf, size_t length,
size_t* pActual = nil)
{
return fpGFD->Read(buf, length, pActual);
}
virtual DIError Write(const void* buf, size_t length,
size_t* pActual = nil)
{
return fpGFD->Write(buf, length, pActual);
}
virtual DIError Seek(di_off_t offset, DIWhence whence) {
return fpGFD->Seek(offset + fOffset, whence);
}
virtual di_off_t Tell(void) {
return fpGFD->Tell() -fOffset;
}
virtual DIError Truncate(void) {
return fpGFD->Truncate();
}
virtual DIError Close(void) {
/* do NOT close underlying descriptor */
fpGFD = nil;
return kDIErrNone;
}
virtual const char* GetPathName(void) const { return fpGFD->GetPathName(); }
private:
GenericFD* fpGFD;
di_off_t fOffset;
};
}; // namespace DiskImgLib
#endif /*__GENERIC_FD__*/