ciderpress/app/GenericArchive.h
Andy McFadden d8223dbcfd Relocate method comments
This moves method comments from the .cpp file to the .h file,
where users of the methods can find them.  This also makes it
possible for the IDE to show the comments when you mouse-hover over
the method name, though Visual Studio is a bit weak in this regard.

Also, added "override" keywords on overridden methods.  Reasonably
current versions of popular compilers seem to support this.

Also, don't have the return type on a separate line in the .cpp file.
The motivation for the practice -- quickly finding a method definition
with "^name" -- is less useful in C++ than C, and modern IDEs provide
more convenient ways to do the same thing.

Also, do some more conversion from unsigned types to uintXX_t.

This commit is primarily for the "app" directory.
2014-11-21 22:33:39 -08:00

871 lines
30 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Generic Apple II archive handling. In the beginning we only handled
* NuFX archives, and the code continues to reflect that heritage.
*
* These are abstract base classes.
*/
#ifndef APP_GENERICARCHIVE_H
#define APP_GENERICARCHIVE_H
#include "Preferences.h"
#include "../util/UtilLib.h"
#include "../diskimg/DiskImg.h"
#include "../nufxlib/NufxLib.h"
#include "../reformat/Reformat.h"
#include <time.h>
#include <string.h>
// this shouldn't be in a header file, but in here it's probably okay
using namespace DiskImgLib;
class ActionProgressDialog;
class AddFilesDialog;
class RecompressOptionsDialog;
class SelectionSet;
struct Win32dirent;
class GenericArchive;
const int kFileTypeTXT = 0x04;
const int kFileTypeBIN = 0x06;
const int kFileTypeSRC = 0xb0;
const int kFileTypeINT = 0xfa;
const int kFileTypeBAS = 0xfc;
/*
* Set of data allowed in file property "set file info" calls.
*/
typedef struct FileProps {
uint32_t fileType;
uint32_t auxType;
uint32_t access;
time_t createWhen;
time_t modWhen;
} FileProps;
/*
* Options for converting between file archives and disk archives.
*/
class XferFileOptions {
public:
XferFileOptions(void) :
fTarget(NULL), fPreserveEmptyFolders(false), fpTargetFS(NULL)
{}
~XferFileOptions(void) {}
/* where the stuff is going */
GenericArchive* fTarget;
/* these really only have meaning when converting disk to file */
//bool fConvDOSText;
//bool fConvPascalText;
bool fPreserveEmptyFolders;
/* only useful when converting files to a disk image */
//CString fStoragePrefix;
DiskImgLib::DiskFS* fpTargetFS;
};
/*
* Generic description of an Apple II file.
*
* Everything returned by the basic "get" calls for display in the ContentList
* must be held in local storage (i.e. not just pointers into DiskFS data).
* Otherwise, we run the risk of doing some DiskFS updates and having weird
* things happen in the ContentList.
*/
class GenericEntry {
public:
GenericEntry(void);
virtual ~GenericEntry(void);
/* kinds of files found in archives */
enum RecordKind {
kRecordKindUnknown = 0,
kRecordKindDisk,
kRecordKindFile,
kRecordKindForkedFile,
kRecordKindDirectory,
kRecordKindVolumeDir,
};
/*
* Threads we will view or extract (threadMask). This is no longer used
* for viewing files, but still plays a role when extracting.
*/
enum {
// create one entry for each matching thread
kDataThread = 0x01,
kRsrcThread = 0x02,
kDiskImageThread = 0x04,
kCommentThread = 0x08,
// grab any of the above threads
kAnyThread = 0x10,
// set this if we allow matches on directory entries
kAllowDirectory = 0x20,
// and volume directory entries
kAllowVolumeDir = 0x40,
// set to include "damaged" files
kAllowDamaged = 0x80,
};
/* EOL conversion mode for threads being extracted */
typedef enum ConvertEOL {
kConvertUnknown = 0, kConvertEOLOff, kConvertEOLOn, kConvertEOLAuto
} ConvertEOL;
typedef enum EOLType {
kEOLUnknown = 0, kEOLCR, kEOLLF, kEOLCRLF
};
/* high ASCII conversion mode for threads being extracted */
typedef enum ConvertHighASCII {
kConvertHAUnknown = 0, kConvertHAOff, kConvertHAOn, kConvertHAAuto
} ConvertHighASCII;
/* ProDOS access flags, used for all filesystems */
enum {
kAccessRead = 0x01,
kAccessWrite = 0x02,
kAccessInvisible = 0x04,
kAccessBackup = 0x20,
kAccessRename = 0x40,
kAccessDelete = 0x80
};
/* features supported by underlying archive */
typedef enum Feature {
kFeatureCanChangeType,
kFeaturePascalTypes,
kFeatureDOSTypes,
kFeatureHFSTypes,
kFeatureHasFullAccess,
kFeatureHasSimpleAccess, // mutually exclusive with FullAccess
kFeatureHasInvisibleFlag,
} Feature;
/*
* Extract data from an archive (NuFX, disk image, etc).
*
* If "*ppText" is non-NULL, the data will be read into the pointed-to buffer
* so long as it's shorter than *pLength bytes. The value in "*pLength"
* will be set to the actual length used.
*
* If "*ppText" is NULL, the uncompressed data will be placed into a buffer
* allocated with "new[]".
*
* Returns IDOK on success, IDCANCEL if the operation was cancelled by the
* user, and -1 value on failure. On failure, "*pErrMsg" holds an error
* message.
*
* "which" is an anonymous GenericArchive enum (e.g. "kDataThread").
*/
virtual int ExtractThreadToBuffer(int which, char** ppText, long* pLength,
CString* pErrMsg) const = 0;
/*
* Extract data from a thread or disk file to a Windows file. Since we're
* not copying to a buffer we can't assume that we're able to hold the
* entire file in memory all at once.
*
* Returns IDOK on success, IDCANCEL if the operation was cancelled by the
* user, and -1 value on failure. On failure, "*pMsg" holds an
* error message.
*/
virtual int ExtractThreadToFile(int which, FILE* outfp, ConvertEOL conv,
ConvertHighASCII convHA, CString* pErrMsg) const = 0;
// This helps us retain the ContentList selection across a Reload(). Only
// necessary for read-write archives, since those are the only ones that
// ever need to be reloaded. Value must be nonzero to be used.
virtual long GetSelectionSerial(void) const = 0;
/* are we allowed to change the file/aux type of this entry? */
/* (may need to generalize this to "changeable attrs" bitmask) */
virtual bool GetFeatureFlag(Feature feature) const = 0;
long GetIndex(void) const { return fIndex; }
void SetIndex(long idx) { fIndex = idx; }
const WCHAR* GetPathName(void) const { return fPathName; }
void SetPathName(const WCHAR* path);
const WCHAR* GetFileName(void);
const WCHAR* GetFileNameExtension(void); // returns e.g. ".SHK"
CStringA GetFileNameExtensionA(void);
void SetSubVolName(const WCHAR* name);
const WCHAR* GetSubVolName(void) const { return fSubVolName; }
const WCHAR* GetDisplayName(void) const; // not really "const"
char GetFssep(void) const { return fFssep; }
void SetFssep(char fssep) { fFssep = fssep; }
long GetFileType(void) const { return fFileType; }
void SetFileType(long type) { fFileType = type; }
long GetAuxType(void) const { return fAuxType; }
void SetAuxType(long type) { fAuxType = type; }
long GetAccess(void) const { return fAccess; }
void SetAccess(long access) { fAccess = access; }
time_t GetCreateWhen(void) const { return fCreateWhen; }
void SetCreateWhen(time_t when) { fCreateWhen = when; }
time_t GetModWhen(void) const { return fModWhen; }
void SetModWhen(time_t when) { fModWhen = when; }
RecordKind GetRecordKind(void) const { return fRecordKind; }
void SetRecordKind(RecordKind recordKind) { fRecordKind = recordKind; }
const WCHAR* GetFormatStr(void) const { return fFormatStr; }
void SetFormatStr(const WCHAR* str) { fFormatStr = str; } // arg not copied, must be static!
LONGLONG GetCompressedLen(void) const { return fCompressedLen; }
void SetCompressedLen(LONGLONG len) { fCompressedLen = len; }
LONGLONG GetUncompressedLen(void) const {
return fDataForkLen + fRsrcForkLen;
}
//void SetUncompressedLen(LONGLONG len) { fUncompressedLen = len; }
LONGLONG GetDataForkLen(void) const { return fDataForkLen; }
void SetDataForkLen(LONGLONG len) { fDataForkLen = len; }
LONGLONG GetRsrcForkLen(void) const { return fRsrcForkLen; }
void SetRsrcForkLen(LONGLONG len) { fRsrcForkLen = len; }
DiskImg::FSFormat GetSourceFS(void) const { return fSourceFS; }
void SetSourceFS(DiskImg::FSFormat fmt) { fSourceFS = fmt; }
bool GetHasDataFork(void) const { return fHasDataFork; }
void SetHasDataFork(bool val) { fHasDataFork = val; }
bool GetHasRsrcFork(void) const { return fHasRsrcFork; }
void SetHasRsrcFork(bool val) { fHasRsrcFork = val; }
bool GetHasDiskImage(void) const { return fHasDiskImage; }
void SetHasDiskImage(bool val) { fHasDiskImage = val; }
bool GetHasComment(void) const { return fHasComment; }
void SetHasComment(bool val) { fHasComment = val; }
bool GetHasNonEmptyComment(void) const { return fHasNonEmptyComment; }
void SetHasNonEmptyComment(bool val) { fHasNonEmptyComment = val; }
bool GetDamaged(void) const { return fDamaged; }
void SetDamaged(bool val) { fDamaged = val; }
bool GetSuspicious(void) const { return fSuspicious; }
void SetSuspicious(bool val) { fSuspicious = val; }
GenericEntry* GetPrev(void) const { return fpPrev; }
void SetPrev(GenericEntry* pEntry) { fpPrev = pEntry; }
GenericEntry* GetNext(void) const { return fpNext; }
void SetNext(GenericEntry* pEntry) { fpNext = pEntry; }
/*
* Get a string for this entry's filetype.
*/
const WCHAR* GetFileTypeString(void) const;
/*
* Check to see if this is a high-ASCII file.
*/
static bool CheckHighASCII(const uint8_t* buffer,
unsigned long count);
/*
* Decide, based on the contents of the buffer, whether we should do an
* EOL conversion on the data.
*
* Returns kConvEOLOff or kConvEOLOn.
*/
static ConvertEOL DetermineConversion(const uint8_t* buffer,
long count, EOLType* pSourceType, ConvertHighASCII* pConvHA);
/*
* Write data to a file, possibly converting EOL markers to Windows CRLF
* and stripping high ASCII.
*
* If "*pConv" is kConvertEOLAuto, this will try to auto-detect whether
* the input is a text file or not by scanning the input buffer.
*
* Ditto for "*pConvHA".
*
* "fp" is the output file, "buf" is the input, "len" is the buffer length.
* "*pLastCR" should initially be "false", and carried across invocations.
*
* Returns 0 on success, or an errno value on error.
*/
static int GenericEntry::WriteConvert(FILE* fp, const char* buf,
size_t len, ConvertEOL* pConv, ConvertHighASCII* pConvHA,
bool* pLastCR);
protected:
/*
* Convert spaces to underscores, modifying the string.
*/
static void SpacesToUnderscores(WCHAR* buf);
private:
WCHAR* fPathName;
const WCHAR* fFileName; // points within fPathName
const WCHAR* fFileNameExtension; // points within fPathName
char fFssep;
WCHAR* fSubVolName; // sub-volume prefix, or NULL if none
WCHAR* fDisplayName; // combination of sub-vol and path
long fFileType;
long fAuxType;
long fAccess;
time_t fCreateWhen;
time_t fModWhen;
RecordKind fRecordKind; // forked file, disk image, ??
const WCHAR* fFormatStr; // static str; compression or fs format
//LONGLONG fUncompressedLen;
LONGLONG fDataForkLen; // also for disk images
LONGLONG fRsrcForkLen; // set to 0 when nonexistent
LONGLONG fCompressedLen; // data/disk + rsrc
DiskImg::FSFormat fSourceFS; // if DOS3.3, text files have funky format
bool fHasDataFork;
bool fHasRsrcFork;
bool fHasDiskImage;
bool fHasComment;
bool fHasNonEmptyComment; // set if fHasComment and it isn't empty
bool fDamaged; // if set, don't try to open file
bool fSuspicious; // if set, file *might* be damaged
long fIndex; // serial index, for sorting "unsorted" view
GenericEntry* fpPrev;
GenericEntry* fpNext;
};
/*
* Generic representation of a collection of Apple II files.
*
* This raises the "reload" flag whenever its data is reloaded. Any code that
* keeps pointers to stuff (e.g. local copies of pointers to GenericEntry
* objects) needs to check the "reload" flag before dereferencing them.
*/
class GenericArchive {
public:
GenericArchive(void) {
fPathName = NULL;
fNumEntries = 0;
fEntryHead = fEntryTail = NULL;
fReloadFlag = true;
//fEntryIndex = NULL;
}
virtual ~GenericArchive(void) {
//LOGI("Deleting GenericArchive");
DeleteEntries();
delete fPathName;
}
virtual GenericEntry* GetEntries(void) const {
return fEntryHead;
}
virtual long GetNumEntries(void) const {
return fNumEntries;
}
typedef enum {
kResultUnknown = 0,
kResultSuccess, // open succeeded
kResultFailure, // open failed
kResultCancel, // open was cancelled by user
kResultFileArchive, // found a file archive rather than disk image
} OpenResult;
// Open an archive and do fun things with the innards.
virtual OpenResult Open(const WCHAR* filename, bool readOnly,
CString* pErrMsg) = 0;
// Create a new archive with the specified name.
virtual CString New(const WCHAR* filename, const void* options) = 0;
// Flush any unwritten data to disk
virtual CString Flush(void) = 0;
// Force a re-read from the underlying storage.
virtual CString Reload(void) = 0;
// Do we allow modification?
virtual bool IsReadOnly(void) const = 0;
// Does the underlying storage have un-flushed modifications?
virtual bool IsModified(void) const = 0;
virtual bool GetReloadFlag(void) { return fReloadFlag; }
virtual void ClearReloadFlag(void) { fReloadFlag = false; }
// One of these for every sub-class. This is used to ensure that, should
// we need to down-cast an object, we did it correctly (without needing
// to include RTTI support).
typedef enum {
kArchiveUnknown = 0,
kArchiveNuFX,
kArchiveBNY,
kArchiveACU,
kArchiveDiskImage,
} ArchiveKind;
virtual ArchiveKind GetArchiveKind(void) = 0;
// Get a nice description for the title bar.
virtual void GetDescription(CString* pStr) const = 0;
// Do a bulk add.
virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) = 0;
// Add a single disk to the archive.
virtual bool AddDisk(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) = 0;
// Create a subdirectory with name newName in pParentEntry.
virtual bool CreateSubdir(CWnd* pMsgWnd, GenericEntry* pParentEntry,
const WCHAR* newName) = 0;
// Test a set of files.
virtual bool TestSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) = 0;
// Delete a set of files.
virtual bool DeleteSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) = 0;
// Rename a set of files.
virtual bool RenameSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) = 0;
// Verify that a name is suitable. Called by RenameEntryDialog and
// CreateSubdirDialog.
//
// Tests for context-specific syntax and checks for duplicates.
//
// Returns an empty string on success, or an error message on failure.
virtual CString TestPathName(const GenericEntry* pGenericEntry,
const CString& basePath, const CString& newName, char newFssep) const = 0;
// Rename a volume (or sub-volume)
virtual bool RenameVolume(CWnd* pMsgWnd, DiskFS* pDiskFS,
const WCHAR* newName) = 0;
virtual CString TestVolumeName(const DiskFS* pDiskFS,
const WCHAR* newName) const = 0;
// Recompress a set of files.
virtual bool RecompressSelection(CWnd* pMsgWnd, SelectionSet* pSelSet,
const RecompressOptionsDialog* pRecompOpts) = 0;
// return result from XferSelection()
typedef enum {
kXferOK = 0, kXferFailed = 1, kXferCancelled = 2, kXferOutOfSpace = 3
} XferStatus;
// Transfer selected files out of this archive and into another.
virtual XferStatus XferSelection(CWnd* pMsgWnd, SelectionSet* pSelSet,
ActionProgressDialog* pActionProgress,
const XferFileOptions* pXferOpts) = 0;
// Extract a comment from the archive, converting line terminators to CRLF.
virtual bool GetComment(CWnd* pMsgWnd, const GenericEntry* pEntry,
CString* pStr) = 0;
// Set a comment on an entry.
virtual bool SetComment(CWnd* pMsgWnd, GenericEntry* pEntry,
const CString& str) = 0;
// Delete the comment from the entry.
virtual bool DeleteComment(CWnd* pMsgWnd, GenericEntry* pEntry) = 0;
// Set ProDOS file properties (file type, aux type, access flags).
virtual bool SetProps(CWnd* pMsgWnd, GenericEntry* pEntry,
const FileProps* pProps) = 0;
// Preferences have changed, update library state as needed. Also called
// the first time though.
virtual void PreferencesChanged(void) = 0;
// Determine an archive's capabilities. This is specific to the object
// instance, so this must not be made a static function.
typedef enum {
kCapUnknown = 0,
kCapCanTest, // NuFX, BNY
kCapCanRenameFullPath, // NuFX, BNY
kCapCanRecompress, // NuFX, BNY
kCapCanEditComment, // NuFX
kCapCanAddDisk, // NuFX
kCapCanConvEOLOnAdd, // Disk
kCapCanCreateSubdir, // Disk
kCapCanRenameVolume, // Disk
} Capability;
virtual long GetCapability(Capability cap) = 0;
// Get the pathname of the file we opened.
const WCHAR* GetPathName(void) const { return fPathName; }
/*
* Generate a temp name from a file name.
*/
static CString GenDerivedTempName(const WCHAR* filename);
/*
* Do a strcasecmp-like comparison, taking equivalent fssep chars into
* account.
*
* The tricky part is with files like "foo:bar" ':' -- "foo:bar" '/'. The
* names appear to match, but the fssep chars are different, so they don't.
* If we just return (char1 - char2), though, we'll be returning 0 because
* the ASCII values match even if the character *meanings* don't.
*
* This assumes that the fssep char is not affected by tolower().
*
* [This may not sort correctly...haven't verified that I'm returning the
* right thing for ascending ASCII sort.]
*/
static int ComparePaths(const CString& name1, char fssep1,
const CString& name2, char fssep2);
/*
* Add a new entry to the end of the list.
*/
void AddEntry(GenericEntry* pEntry);
/*
* This class holds details about a file that we're adding.
*
* It's based on the NuFileDetails class from NufxLib (which used to be
* used everywhere).
*
* TODO: xyzzy: NuFileDetails cast requires us to store pathnames with
* narrow strings.
*/
class FileDetails {
public:
FileDetails(void);
virtual ~FileDetails(void) {}
/*
* Automatic cast to NuFileDetails. The NuFileDetails structure will
* have a pointer to at least one of our strings, so structures
* filled out this way need to be short-lived. (Yes, this is
* annoying, but it's how NufxLib works.)
*/
operator const NuFileDetails() const;
/*
* Provide operator= and copy constructor. This'd be easier without
* the strings.
*/
FileDetails& operator=(const FileDetails& src) {
if (&src != this)
CopyFields(this, &src);
return *this;
}
FileDetails(const FileDetails& src) {
CopyFields(this, &src);
}
/*
* What kind of file this is. Files being added to NuFX from Windows
* can't be "BothForks" because each the forks are stored in
* separate files. However, files being transferred from a NuFX
* archive, a disk image, or in from the clipboard can be both.
*
* (NOTE: this gets embedded into clipboard data. If you change
* these values, update the version info in Clipboard.cpp.)
*/
typedef enum FileKind {
kFileKindUnknown = 0,
kFileKindDataFork,
kFileKindRsrcFork,
kFileKindDiskImage,
kFileKindBothForks,
kFileKindDirectory,
} FileKind;
/*
* Data fields. While transitioning from general use of NuFileDetails
* (v1.2.x to v2.0) I'm just going to leave these public.
*/
//NuThreadID threadID; /* data, rsrc, disk img? */
FileKind entryKind;
/*
* Original full pathname as found on Windows.
*/
CString origName;
/*
* "Normalized" pathname. This is the full path with any of our
* added bits removed (e.g. file type & fork identifiers). It has
* not been sanitized for any specific target filesystem. See also
* PathProposal::LocalToArchive().
*/
CString storageName;
//NuFileSysID fileSysID;
DiskImg::FSFormat fileSysFmt;
uint16_t fileSysInfo; /* fssep lurks here */
uint32_t access;
uint32_t fileType;
uint32_t extraType;
uint16_t storageType; /* "Unknown" or disk block size */
NuDateTime createWhen;
NuDateTime modWhen;
NuDateTime archiveWhen;
private:
/*
* Copy the contents of our object to a new object.
*
* Useful for operator= and copy construction.
*/
static void CopyFields(FileDetails* pDst, const FileDetails* pSrc);
};
// Prepare for file transfers.
virtual void XferPrepare(const XferFileOptions* pXferOpts) = 0;
// Transfer files, one at a time, into this archive from another. Called
// from XferSelection and clipboard "paste".
//
// "dataLen" and "rsrcLen" will be -1 if the corresponding fork doesn't exist.
// Returns 0 on success, nonzero on failure.
//
// On success, *pDataBuf and *pRsrcBuf are freed and set to NULL. (It's
// necessary for the interface to work this way because the NufxArchive
// version just tucks the pointers into NufxLib structures.)
virtual CString XferFile(FileDetails* pDetails, uint8_t** pDataBuf,
long dataLen, uint8_t** pRsrcBuf, long rsrcLen) = 0;
// Abort progress. Not all subclasses are capable of "undo".
virtual void XferAbort(CWnd* pMsgWnd) = 0;
// Transfer is finished.
virtual void XferFinish(CWnd* pMsgWnd) = 0;
/*
* Convert from time in seconds to Apple IIgs DateTime format.
*/
static void UNIXTimeToDateTime(const time_t* pWhen, NuDateTime *pDateTime);
protected:
/*
* Delete the "entries" list.
*/
virtual void DeleteEntries(void);
void ReplaceFssep(WCHAR* str, char oldc, char newc, char newSubst);
/*
* Set the contents of a NuFileDetails structure, based on the pathname
* and characteristics of the file.
*
* For efficiency and simplicity, the pathname fields are set to CStrings in
* the GenericArchive object instead of newly-allocated storage.
*/
NuError GetFileDetails(const AddFilesDialog* pAddOpts, const WCHAR* pathname,
struct _stat* psb, FileDetails* pDetails);
/*
* Prepare a directory for reading.
*
* Allocates a Win32dirent struct that must be freed by the caller.
*/
Win32dirent* OpenDir(const WCHAR* name);
/*
* Get an entry from an open directory.
*
* Returns a NULL pointer after the last entry has been read.
*/
Win32dirent* ReadDir(Win32dirent* dir);
/*
* Close a directory.
*/
void CloseDir(Win32dirent* dir);
/*
* Win32 recursive directory descent. Scan the contents of a directory.
* If a subdirectory is found, follow it; otherwise, call Win32AddFile to
* add the file.
*/
NuError Win32AddDirectory(const AddFilesDialog* pAddOpts,
const WCHAR* dirName, CString* pErrMsg);
/*
* Add a file to the list we're adding to the archive. If it's a directory,
* and the recursive descent feature is enabled, call Win32AddDirectory to
* add the contents of the dir.
*
* Returns with an error if the file doesn't exist or isn't readable.
*/
NuError Win32AddFile(const AddFilesDialog* pAddOpts,
const WCHAR* pathname, CString* pErrMsg);
/*
* External entry point; just calls the system-specific version.
*/
NuError AddFile(const AddFilesDialog* pAddOpts, const WCHAR* pathname,
CString* pErrMsg);
/*
* Each implementation must provide this. It's called from the generic
* AddFile function with the high-level add options, a partial pathname,
* and a FileDetails structure filled in using Win32 calls.
*
* One call to AddFile can result in multiple calls to DoAddFile if
* the subject of the AddFile call is a directory (and fIncludeSubdirs
* is set).
*
* DoAddFile is not called for subdirectories. The underlying code must
* create directories as needed.
*
* In some cases (such as renaming a file as it is being added) the
* information in "*pDetails" may be modified.
*/
virtual NuError DoAddFile(const AddFilesDialog* pAddOpts,
FileDetails* pDetails) = 0;
void SetPathName(const WCHAR* pathName) {
free(fPathName);
if (pathName != NULL) {
fPathName = _wcsdup(pathName);
} else {
fPathName = NULL;
}
}
bool fReloadFlag; // set after Reload called
private:
//virtual void CreateIndex(void);
//CString fNewPathHolder;
//CString fOrigPathHolder;
WCHAR* fPathName;
long fNumEntries;
GenericEntry* fEntryHead;
GenericEntry* fEntryTail;
//GenericEntry** fEntryIndex;
};
/*
* One entry in a SelectionSet.
*/
class SelectionEntry {
public:
SelectionEntry(GenericEntry* pEntry) {
fpEntry = pEntry;
//fThreadKind = threadKind;
//fFilter = filter;
//fReformatName = "";
fpPrev = fpNext = NULL;
}
~SelectionEntry(void) {}
int Reformat(ReformatHolder* pHolder);
GenericEntry* GetEntry(void) const { return fpEntry; }
//int GetThreadKind(void) const { return fThreadKind; }
//int GetFilter(void) const { return fFilter; }
//const char* GetReformatName(void) const { return fReformatName; }
SelectionEntry* GetPrev(void) const { return fpPrev; }
void SetPrev(SelectionEntry* pPrev) { fpPrev = pPrev; }
SelectionEntry* GetNext(void) const { return fpNext; }
void SetNext(SelectionEntry* pNext) { fpNext = pNext; }
private:
GenericEntry* fpEntry;
//int fThreadKind; // data, rsrc, etc (threadMask)
//int fFilter; // fAllowedFilters, really
//const char* fReformatName; // name of formatting actually applied
SelectionEntry* fpPrev;
SelectionEntry* fpNext;
};
class ContentList;
/*
* A set of selected files.
*
* Each entry represents one item that can be displayed, such as a data
* fork, resource fork, or comment thread. Thus, a single file may have
* multiple entries in the set.
*/
class SelectionSet {
public:
SelectionSet(void) {
fNumEntries = 0;
fEntryHead = fEntryTail = fIterCurrent = NULL;
}
~SelectionSet(void) {
DeleteEntries();
}
// create the set from the selected members of a ContentList
void CreateFromSelection(ContentList* pContentList, int threadMask);
// create the set from all members of a ContentList
void CreateFromAll(ContentList* pContentList, int threadMask);
// get the head of the list
SelectionEntry* GetEntries(void) const { return fEntryHead; }
void IterReset(void) {
fIterCurrent = NULL;
}
// move to the next or previous entry as part of iterating
SelectionEntry* IterPrev(void) {
if (fIterCurrent == NULL)
fIterCurrent = fEntryTail;
else
fIterCurrent = fIterCurrent->GetPrev();
return fIterCurrent;
}
SelectionEntry* IterNext(void) {
if (fIterCurrent == NULL)
fIterCurrent = fEntryHead;
else
fIterCurrent = fIterCurrent->GetNext();
return fIterCurrent;
}
SelectionEntry* IterCurrent(void) {
return fIterCurrent;
}
bool IterHasPrev(void) const {
if (fIterCurrent == NULL)
return fEntryTail != NULL;
else
return (fIterCurrent->GetPrev() != NULL);
}
bool IterHasNext(void) const {
if (fIterCurrent == NULL)
return fEntryHead != NULL;
else
return (fIterCurrent->GetNext() != NULL);
}
int GetNumEntries(void) const { return fNumEntries; }
// count the #of entries whose display name matches "prefix"
int CountMatchingPrefix(const WCHAR* prefix);
// debug dump the contents of the selection set
void Dump(void);
private:
/*
* Add a GenericEntry to the set, but only if we can find a thread that
* matches the flags in "threadMask".
*/
void AddToSet(GenericEntry* pEntry, int threadMask);
/*
* Add a new entry to the end of the list.
*/
void AddEntry(SelectionEntry* pEntry);
/*
* Delete the "entries" list.
*/
void DeleteEntries(void);
int fNumEntries;
SelectionEntry* fIterCurrent;
SelectionEntry* fEntryHead;
SelectionEntry* fEntryTail;
};
#endif /*APP_GENERICARCHIVE_H*/