Rewrote "open archive" logic

The previous code was a stickler for only opening files whose type
matched what was selected in the filter pop-up.  The original goal
was to allow you to choose whether a BXY or SDK file was interpreted
as Binary II, ShrinkIt, or disk image, since they could go either
way.  Unfortunately, its refusal to consider types other than what
was selected made it kind of annoying.

The new code will start by trying to open the file with the selected
filter, so that it's still possible to choose how SDK and BXY files
are opened.  However, it now continues on, trying all other types
before finally giving up.

If the generic ("*.*") filter is selected, CiderPress will start by
trying to open the file as a disk image.

This seems to produce good results with a variety of known and
unknown files.
This commit is contained in:
Andy McFadden 2015-01-13 15:54:10 -08:00
parent 432b1c4cc6
commit 814872966e
9 changed files with 190 additions and 235 deletions

View File

@ -105,8 +105,7 @@ public:
virtual CString Reload(void) override; virtual CString Reload(void) override;
virtual bool IsReadOnly(void) const override { return true; }; virtual bool IsReadOnly(void) const override { return true; };
virtual bool IsModified(void) const override { return false; } virtual bool IsModified(void) const override { return false; }
virtual void GetDescription(CString* pStr) const override virtual CString GetDescription() const override { return L"AppleLink ACU"; }
{ *pStr = L"AppleLink ACU"; }
virtual bool BulkAdd(ActionProgressDialog* pActionProgress, virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override const AddFilesDialog* pAddOpts) override
{ ASSERT(false); return false; } { ASSERT(false); return false; }

View File

@ -121,8 +121,7 @@ public:
virtual CString Reload(void) override; virtual CString Reload(void) override;
virtual bool IsReadOnly(void) const override { return true; }; virtual bool IsReadOnly(void) const override { return true; };
virtual bool IsModified(void) const override { return false; } virtual bool IsModified(void) const override { return false; }
virtual void GetDescription(CString* pStr) const override virtual CString GetDescription() const override { return L"AppleSingle"; }
{ *pStr = L"AppleSingle"; }
virtual bool BulkAdd(ActionProgressDialog* pActionProgress, virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override const AddFilesDialog* pAddOpts) override
{ ASSERT(false); return false; } { ASSERT(false); return false; }

View File

@ -91,7 +91,7 @@ public:
virtual CString Reload(void) override; virtual CString Reload(void) override;
virtual bool IsReadOnly(void) const override { return fIsReadOnly; }; virtual bool IsReadOnly(void) const override { return fIsReadOnly; };
virtual bool IsModified(void) const override { return false; } virtual bool IsModified(void) const override { return false; }
virtual void GetDescription(CString* pStr) const override { *pStr = "Binary II"; } virtual CString GetDescription() const override { return L"Binary II"; }
virtual bool BulkAdd(ActionProgressDialog* pActionProgress, virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override const AddFilesDialog* pAddOpts) override
{ ASSERT(false); return false; } { ASSERT(false); return false; }

View File

@ -885,14 +885,14 @@ bool DiskArchive::IsModified(void) const
return fpPrimaryDiskFS->GetDiskImg()->GetDirtyFlag(); return fpPrimaryDiskFS->GetDiskImg()->GetDirtyFlag();
} }
void DiskArchive::GetDescription(CString* pStr) const CString DiskArchive::GetDescription() const
{ {
if (fpPrimaryDiskFS == NULL) CString str = L"Disk Image";
return;
if (fpPrimaryDiskFS->GetVolumeID() != NULL) { if (fpPrimaryDiskFS != NULL && fpPrimaryDiskFS->GetVolumeID() != NULL) {
pStr->Format(L"Disk Image - %hs", fpPrimaryDiskFS->GetVolumeID()); str.Format(L"Disk Image - %hs", fpPrimaryDiskFS->GetVolumeID());
} }
return str;
} }
int DiskArchive::LoadContents(void) int DiskArchive::LoadContents(void)

View File

@ -164,7 +164,7 @@ public:
* Return an description of the disk archive, suitable for display in the * Return an description of the disk archive, suitable for display in the
* main title bar. * main title bar.
*/ */
virtual void GetDescription(CString* pStr) const override; virtual CString GetDescription() const override;
virtual bool BulkAdd(ActionProgressDialog* pActionProgress, virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override; const AddFilesDialog* pAddOpts) override;

View File

@ -52,10 +52,10 @@ struct FileProps {
*/ */
class XferFileOptions { class XferFileOptions {
public: public:
XferFileOptions(void) : XferFileOptions() :
fTarget(NULL), fPreserveEmptyFolders(false), fpTargetFS(NULL) fTarget(NULL), fPreserveEmptyFolders(false), fpTargetFS(NULL)
{} {}
~XferFileOptions(void) {} ~XferFileOptions() {}
/* where the stuff is going */ /* where the stuff is going */
GenericArchive* fTarget; GenericArchive* fTarget;
@ -81,8 +81,8 @@ public:
*/ */
class GenericEntry { class GenericEntry {
public: public:
GenericEntry(void); GenericEntry();
virtual ~GenericEntry(void); virtual ~GenericEntry();
/* kinds of files found in archives */ /* kinds of files found in archives */
enum RecordKind { enum RecordKind {
@ -187,12 +187,12 @@ public:
// This helps us retain the ContentList selection across a Reload(). Only // This helps us retain the ContentList selection across a Reload(). Only
// necessary for read-write archives, since those are the only ones that // necessary for read-write archives, since those are the only ones that
// ever need to be reloaded. Value must be nonzero to be used. // ever need to be reloaded. Value must be nonzero to be used.
virtual long GetSelectionSerial(void) const = 0; virtual long GetSelectionSerial() const = 0;
/* what operations are possible with this entry? */ /* what operations are possible with this entry? */
virtual bool GetFeatureFlag(Feature feature) const = 0; virtual bool GetFeatureFlag(Feature feature) const = 0;
long GetIndex(void) const { return fIndex; } long GetIndex() const { return fIndex; }
void SetIndex(long idx) { fIndex = idx; } void SetIndex(long idx) { fIndex = idx; }
/* /*
@ -204,75 +204,75 @@ public:
*/ */
void SetPathNameMOR(const char* pathNameMOR); void SetPathNameMOR(const char* pathNameMOR);
const CStringA& GetPathNameMOR(void) const { return fPathNameMOR; } const CStringA& GetPathNameMOR() const { return fPathNameMOR; }
const CString& GetPathNameUNI(void) const { return fPathNameUNI; } const CString& GetPathNameUNI() const { return fPathNameUNI; }
const CString& GetFileName(void); const CString& GetFileName();
const CString& GetFileNameExtension(void); // returns e.g. ".SHK" const CString& GetFileNameExtension(); // returns e.g. ".SHK"
const CStringA& GetFileNameExtensionMOR(void); const CStringA& GetFileNameExtensionMOR();
/* /*
* Returns the "display" name. This is a combination of the sub-volume * Returns the "display" name. This is a combination of the sub-volume
* name and the path name. This string is intended for display only, * name and the path name. This string is intended for display only,
* and may include characters that aren't legal on the filesystem. * and may include characters that aren't legal on the filesystem.
*/ */
const CString& GetDisplayName(void) const; const CString& GetDisplayName() const;
void SetSubVolName(const WCHAR* name); void SetSubVolName(const WCHAR* name);
const CString& GetSubVolName(void) const { return fSubVolName; } const CString& GetSubVolName() const { return fSubVolName; }
char GetFssep(void) const { return fFssep; } char GetFssep() const { return fFssep; }
void SetFssep(char fssep) { fFssep = fssep; } void SetFssep(char fssep) { fFssep = fssep; }
uint32_t GetFileType(void) const { return fFileType; } uint32_t GetFileType() const { return fFileType; }
void SetFileType(uint32_t type) { fFileType = type; } void SetFileType(uint32_t type) { fFileType = type; }
uint32_t GetAuxType(void) const { return fAuxType; } uint32_t GetAuxType() const { return fAuxType; }
void SetAuxType(uint32_t type) { fAuxType = type; } void SetAuxType(uint32_t type) { fAuxType = type; }
uint32_t GetAccess(void) const { return fAccess; } uint32_t GetAccess() const { return fAccess; }
void SetAccess(uint32_t access) { fAccess = access; } void SetAccess(uint32_t access) { fAccess = access; }
time_t GetCreateWhen(void) const { return fCreateWhen; } time_t GetCreateWhen() const { return fCreateWhen; }
void SetCreateWhen(time_t when) { fCreateWhen = when; } void SetCreateWhen(time_t when) { fCreateWhen = when; }
time_t GetModWhen(void) const { return fModWhen; } time_t GetModWhen() const { return fModWhen; }
void SetModWhen(time_t when) { fModWhen = when; } void SetModWhen(time_t when) { fModWhen = when; }
RecordKind GetRecordKind(void) const { return fRecordKind; } RecordKind GetRecordKind() const { return fRecordKind; }
void SetRecordKind(RecordKind recordKind) { fRecordKind = recordKind; } void SetRecordKind(RecordKind recordKind) { fRecordKind = recordKind; }
const WCHAR* GetFormatStr(void) const { return fFormatStr; } const WCHAR* GetFormatStr() const { return fFormatStr; }
void SetFormatStr(const WCHAR* str) { fFormatStr = str; } // arg not copied, must be static! void SetFormatStr(const WCHAR* str) { fFormatStr = str; } // arg not copied, must be static!
LONGLONG GetCompressedLen(void) const { return fCompressedLen; } LONGLONG GetCompressedLen() const { return fCompressedLen; }
void SetCompressedLen(LONGLONG len) { fCompressedLen = len; } void SetCompressedLen(LONGLONG len) { fCompressedLen = len; }
LONGLONG GetUncompressedLen(void) const { LONGLONG GetUncompressedLen() const {
return fDataForkLen + fRsrcForkLen; return fDataForkLen + fRsrcForkLen;
} }
LONGLONG GetDataForkLen(void) const { return fDataForkLen; } LONGLONG GetDataForkLen() const { return fDataForkLen; }
void SetDataForkLen(LONGLONG len) { fDataForkLen = len; } void SetDataForkLen(LONGLONG len) { fDataForkLen = len; }
LONGLONG GetRsrcForkLen(void) const { return fRsrcForkLen; } LONGLONG GetRsrcForkLen() const { return fRsrcForkLen; }
void SetRsrcForkLen(LONGLONG len) { fRsrcForkLen = len; } void SetRsrcForkLen(LONGLONG len) { fRsrcForkLen = len; }
DiskImg::FSFormat GetSourceFS(void) const { return fSourceFS; } DiskImg::FSFormat GetSourceFS() const { return fSourceFS; }
void SetSourceFS(DiskImg::FSFormat fmt) { fSourceFS = fmt; } void SetSourceFS(DiskImg::FSFormat fmt) { fSourceFS = fmt; }
bool GetHasDataFork(void) const { return fHasDataFork; } bool GetHasDataFork() const { return fHasDataFork; }
void SetHasDataFork(bool val) { fHasDataFork = val; } void SetHasDataFork(bool val) { fHasDataFork = val; }
bool GetHasRsrcFork(void) const { return fHasRsrcFork; } bool GetHasRsrcFork() const { return fHasRsrcFork; }
void SetHasRsrcFork(bool val) { fHasRsrcFork = val; } void SetHasRsrcFork(bool val) { fHasRsrcFork = val; }
bool GetHasDiskImage(void) const { return fHasDiskImage; } bool GetHasDiskImage() const { return fHasDiskImage; }
void SetHasDiskImage(bool val) { fHasDiskImage = val; } void SetHasDiskImage(bool val) { fHasDiskImage = val; }
bool GetHasComment(void) const { return fHasComment; } bool GetHasComment() const { return fHasComment; }
void SetHasComment(bool val) { fHasComment = val; } void SetHasComment(bool val) { fHasComment = val; }
bool GetHasNonEmptyComment(void) const { return fHasNonEmptyComment; } bool GetHasNonEmptyComment() const { return fHasNonEmptyComment; }
void SetHasNonEmptyComment(bool val) { fHasNonEmptyComment = val; } void SetHasNonEmptyComment(bool val) { fHasNonEmptyComment = val; }
bool GetDamaged(void) const { return fDamaged; } bool GetDamaged() const { return fDamaged; }
void SetDamaged(bool val) { fDamaged = val; } void SetDamaged(bool val) { fDamaged = val; }
bool GetSuspicious(void) const { return fSuspicious; } bool GetSuspicious() const { return fSuspicious; }
void SetSuspicious(bool val) { fSuspicious = val; } void SetSuspicious(bool val) { fSuspicious = val; }
GenericEntry* GetPrev(void) const { return fpPrev; } GenericEntry* GetPrev() const { return fpPrev; }
void SetPrev(GenericEntry* pEntry) { fpPrev = pEntry; } void SetPrev(GenericEntry* pEntry) { fpPrev = pEntry; }
GenericEntry* GetNext(void) const { return fpNext; } GenericEntry* GetNext() const { return fpNext; }
void SetNext(GenericEntry* pEntry) { fpNext = pEntry; } void SetNext(GenericEntry* pEntry) { fpNext = pEntry; }
/* /*
* Get a string for this entry's filetype. * Get a string for this entry's filetype.
*/ */
const WCHAR* GetFileTypeString(void) const; const WCHAR* GetFileTypeString() const;
/* /*
* Check to see if this is a high-ASCII file. * Check to see if this is a high-ASCII file.
@ -368,23 +368,23 @@ private:
*/ */
class GenericArchive { class GenericArchive {
public: public:
GenericArchive(void) { GenericArchive() {
fPathName = NULL; fPathName = NULL;
fNumEntries = 0; fNumEntries = 0;
fEntryHead = fEntryTail = NULL; fEntryHead = fEntryTail = NULL;
fReloadFlag = true; fReloadFlag = true;
//fEntryIndex = NULL; //fEntryIndex = NULL;
} }
virtual ~GenericArchive(void) { virtual ~GenericArchive() {
//LOGI("Deleting GenericArchive"); //LOGI("Deleting GenericArchive");
DeleteEntries(); DeleteEntries();
delete fPathName; delete fPathName;
} }
virtual GenericEntry* GetEntries(void) const { virtual GenericEntry* GetEntries() const {
return fEntryHead; return fEntryHead;
} }
virtual long GetNumEntries(void) const { virtual long GetNumEntries() const {
return fNumEntries; return fNumEntries;
} }
@ -402,16 +402,16 @@ public:
// Create a new archive with the specified name. // Create a new archive with the specified name.
virtual CString New(const WCHAR* filename, const void* options) = 0; virtual CString New(const WCHAR* filename, const void* options) = 0;
// Flush any unwritten data to disk // Flush any unwritten data to disk
virtual CString Flush(void) = 0; virtual CString Flush() = 0;
// Force a re-read from the underlying storage. // Force a re-read from the underlying storage.
virtual CString Reload(void) = 0; virtual CString Reload() = 0;
// Do we allow modification? // Do we allow modification?
virtual bool IsReadOnly(void) const = 0; virtual bool IsReadOnly() const = 0;
// Does the underlying storage have un-flushed modifications? // Does the underlying storage have un-flushed modifications?
virtual bool IsModified(void) const = 0; virtual bool IsModified() const = 0;
virtual bool GetReloadFlag(void) { return fReloadFlag; } virtual bool GetReloadFlag() { return fReloadFlag; }
virtual void ClearReloadFlag(void) { fReloadFlag = false; } virtual void ClearReloadFlag() { fReloadFlag = false; }
// One of these for every sub-class. // One of these for every sub-class.
enum ArchiveKind { enum ArchiveKind {
@ -424,10 +424,10 @@ public:
}; };
// Returns the kind of archive this is (disk image, NuFX, BNY, etc). // Returns the kind of archive this is (disk image, NuFX, BNY, etc).
virtual ArchiveKind GetArchiveKind(void) = 0; virtual ArchiveKind GetArchiveKind() = 0;
// Get a nice description for the title bar. // Get a nice description for the title bar.
virtual void GetDescription(CString* pStr) const = 0; virtual CString GetDescription() const = 0;
// Do a bulk add. // Do a bulk add.
virtual bool BulkAdd(ActionProgressDialog* pActionProgress, virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
@ -496,7 +496,7 @@ public:
// Preferences have changed, update library state as needed. Also called // Preferences have changed, update library state as needed. Also called
// the first time though. // the first time though.
virtual void PreferencesChanged(void) = 0; virtual void PreferencesChanged() = 0;
// Determine an archive's capabilities. This is specific to the object // Determine an archive's capabilities. This is specific to the object
// instance, so this must not be made a static function. // instance, so this must not be made a static function.
@ -515,7 +515,7 @@ public:
virtual long GetCapability(Capability cap) = 0; virtual long GetCapability(Capability cap) = 0;
// Get the pathname of the file we opened. // Get the pathname of the file we opened.
const WCHAR* GetPathName(void) const { return fPathName; } const WCHAR* GetPathName() const { return fPathName; }
/* /*
* Generate a temp name from a file name. * Generate a temp name from a file name.
@ -549,8 +549,8 @@ public:
*/ */
class LocalFileDetails { class LocalFileDetails {
public: public:
LocalFileDetails(void); LocalFileDetails();
virtual ~LocalFileDetails(void) {} virtual ~LocalFileDetails() {}
/* /*
* Set the various fields, based on the pathname and characteristics * Set the various fields, based on the pathname and characteristics
@ -805,7 +805,7 @@ protected:
/* /*
* Delete the "entries" list. * Delete the "entries" list.
*/ */
virtual void DeleteEntries(void); virtual void DeleteEntries();
void ReplaceFssep(WCHAR* str, char oldc, char newc, char newSubst); void ReplaceFssep(WCHAR* str, char oldc, char newc, char newSubst);
@ -882,7 +882,7 @@ protected:
bool fReloadFlag; // set after Reload called bool fReloadFlag; // set after Reload called
private: private:
//virtual void CreateIndex(void); //virtual void CreateIndex();
//CString fNewPathHolder; //CString fNewPathHolder;
//CString fOrigPathHolder; //CString fOrigPathHolder;
@ -906,18 +906,18 @@ public:
//fReformatName = ""; //fReformatName = "";
fpPrev = fpNext = NULL; fpPrev = fpNext = NULL;
} }
~SelectionEntry(void) {} ~SelectionEntry() {}
int Reformat(ReformatHolder* pHolder); int Reformat(ReformatHolder* pHolder);
GenericEntry* GetEntry(void) const { return fpEntry; } GenericEntry* GetEntry() const { return fpEntry; }
//int GetThreadKind(void) const { return fThreadKind; } //int GetThreadKind() const { return fThreadKind; }
//int GetFilter(void) const { return fFilter; } //int GetFilter() const { return fFilter; }
//const char* GetReformatName(void) const { return fReformatName; } //const char* GetReformatName() const { return fReformatName; }
SelectionEntry* GetPrev(void) const { return fpPrev; } SelectionEntry* GetPrev() const { return fpPrev; }
void SetPrev(SelectionEntry* pPrev) { fpPrev = pPrev; } void SetPrev(SelectionEntry* pPrev) { fpPrev = pPrev; }
SelectionEntry* GetNext(void) const { return fpNext; } SelectionEntry* GetNext() const { return fpNext; }
void SetNext(SelectionEntry* pNext) { fpNext = pNext; } void SetNext(SelectionEntry* pNext) { fpNext = pNext; }
private: private:
@ -941,11 +941,11 @@ class ContentList;
*/ */
class SelectionSet { class SelectionSet {
public: public:
SelectionSet(void) { SelectionSet() {
fNumEntries = 0; fNumEntries = 0;
fEntryHead = fEntryTail = fIterCurrent = NULL; fEntryHead = fEntryTail = fIterCurrent = NULL;
} }
~SelectionSet(void) { ~SelectionSet() {
DeleteEntries(); DeleteEntries();
} }
@ -955,49 +955,49 @@ public:
void CreateFromAll(ContentList* pContentList, int threadMask); void CreateFromAll(ContentList* pContentList, int threadMask);
// get the head of the list // get the head of the list
SelectionEntry* GetEntries(void) const { return fEntryHead; } SelectionEntry* GetEntries() const { return fEntryHead; }
void IterReset(void) { void IterReset() {
fIterCurrent = NULL; fIterCurrent = NULL;
} }
// move to the next or previous entry as part of iterating // move to the next or previous entry as part of iterating
SelectionEntry* IterPrev(void) { SelectionEntry* IterPrev() {
if (fIterCurrent == NULL) if (fIterCurrent == NULL)
fIterCurrent = fEntryTail; fIterCurrent = fEntryTail;
else else
fIterCurrent = fIterCurrent->GetPrev(); fIterCurrent = fIterCurrent->GetPrev();
return fIterCurrent; return fIterCurrent;
} }
SelectionEntry* IterNext(void) { SelectionEntry* IterNext() {
if (fIterCurrent == NULL) if (fIterCurrent == NULL)
fIterCurrent = fEntryHead; fIterCurrent = fEntryHead;
else else
fIterCurrent = fIterCurrent->GetNext(); fIterCurrent = fIterCurrent->GetNext();
return fIterCurrent; return fIterCurrent;
} }
SelectionEntry* IterCurrent(void) { SelectionEntry* IterCurrent() {
return fIterCurrent; return fIterCurrent;
} }
bool IterHasPrev(void) const { bool IterHasPrev() const {
if (fIterCurrent == NULL) if (fIterCurrent == NULL)
return fEntryTail != NULL; return fEntryTail != NULL;
else else
return (fIterCurrent->GetPrev() != NULL); return (fIterCurrent->GetPrev() != NULL);
} }
bool IterHasNext(void) const { bool IterHasNext() const {
if (fIterCurrent == NULL) if (fIterCurrent == NULL)
return fEntryHead != NULL; return fEntryHead != NULL;
else else
return (fIterCurrent->GetNext() != NULL); return (fIterCurrent->GetNext() != NULL);
} }
int GetNumEntries(void) const { return fNumEntries; } int GetNumEntries() const { return fNumEntries; }
// count the #of entries whose display name matches "prefix" // count the #of entries whose display name matches "prefix"
int CountMatchingPrefix(const WCHAR* prefix); int CountMatchingPrefix(const WCHAR* prefix);
// debug dump the contents of the selection set // debug dump the contents of the selection set
void Dump(void); void Dump();
private: private:
/* /*
@ -1014,7 +1014,7 @@ private:
/* /*
* Delete the "entries" list. * Delete the "entries" list.
*/ */
void DeleteEntries(void); void DeleteEntries();
int fNumEntries; int fNumEntries;
SelectionEntry* fIterCurrent; SelectionEntry* fIterCurrent;

View File

@ -76,6 +76,7 @@ const WCHAR MainWindow::kOpenAll[] =
const WCHAR MainWindow::kOpenEnd[] = const WCHAR MainWindow::kOpenEnd[] =
L"|"; L"|";
/* used when guessing archive type from extension */
static const struct { static const struct {
WCHAR extension[4]; WCHAR extension[4];
FilterIndex idx; FilterIndex idx;
@ -88,14 +89,19 @@ static const struct {
{ L"bqy", kFilterIndexBinaryII }, { L"bqy", kFilterIndexBinaryII },
{ L"acu", kFilterIndexACU }, { L"acu", kFilterIndexACU },
{ L"as", kFilterIndexAppleSingle }, { L"as", kFilterIndexAppleSingle },
{ L"sdk", kFilterIndexDiskImage },
{ L"dsk", kFilterIndexDiskImage }, { L"dsk", kFilterIndexDiskImage },
{ L"po", kFilterIndexDiskImage }, { L"po", kFilterIndexDiskImage },
{ L"do", kFilterIndexDiskImage }, { L"do", kFilterIndexDiskImage },
{ L"d13", kFilterIndexDiskImage }, { L"d13", kFilterIndexDiskImage },
{ L"2mg", kFilterIndexDiskImage }, { L"2mg", kFilterIndexDiskImage },
{ L"img", kFilterIndexDiskImage }, { L"img", kFilterIndexDiskImage },
{ L"sdk", kFilterIndexDiskImage }, { L"nib", kFilterIndexDiskImage },
{ L"nb2", kFilterIndexDiskImage },
{ L"raw", kFilterIndexDiskImage }, { L"raw", kFilterIndexDiskImage },
{ L"hdv", kFilterIndexDiskImage },
{ L"dc", kFilterIndexDiskImage },
{ L"dc6", kFilterIndexDiskImage },
{ L"ddd", kFilterIndexDiskImage }, { L"ddd", kFilterIndexDiskImage },
{ L"app", kFilterIndexDiskImage }, { L"app", kFilterIndexDiskImage },
{ L"fdi", kFilterIndexDiskImage }, { L"fdi", kFilterIndexDiskImage },
@ -415,7 +421,7 @@ void MainWindow::ProcessCommandLine(void)
*/ */
const WCHAR* filename = NULL; const WCHAR* filename = NULL;
const WCHAR* dispName = NULL; const WCHAR* dispName = NULL;
int filterIndex = kFilterIndexGeneric; FilterIndex filterIndex = kFilterIndexGeneric;
bool temp = false; bool temp = false;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
@ -482,7 +488,7 @@ void MainWindow::ProcessCommandLine(void)
ext.Delete(0, 1); ext.Delete(0, 1);
/* load the archive, mandating read-only if it's a temporary file */ /* load the archive, mandating read-only if it's a temporary file */
if (LoadArchive(filename, ext, filterIndex, temp, false) == 0) { if (LoadArchive(filename, ext, filterIndex, temp) == 0) {
/* success, update title bar */ /* success, update title bar */
if (temp) if (temp)
fOpenArchivePathName = path.GetFileName(); fOpenArchivePathName = path.GetFileName();
@ -1191,7 +1197,6 @@ void MainWindow::OnFileOpen(void)
openFilters += kOpenDiskImage; openFilters += kOpenDiskImage;
openFilters += kOpenAll; openFilters += kOpenAll;
openFilters += kOpenEnd; openFilters += kOpenEnd;
LOGD("filters: '%ls'", openFilters);
CFileDialog dlg(TRUE, L"shk", NULL, CFileDialog dlg(TRUE, L"shk", NULL,
OFN_FILEMUSTEXIST, openFilters, this); OFN_FILEMUSTEXIST, openFilters, this);
@ -1206,8 +1211,14 @@ void MainWindow::OnFileOpen(void)
saveFolder = saveFolder.Left(dlg.m_ofn.nFileOffset); saveFolder = saveFolder.Left(dlg.m_ofn.nFileOffset);
fPreferences.SetPrefString(kPrOpenArchiveFolder, saveFolder); fPreferences.SetPrefString(kPrOpenArchiveFolder, saveFolder);
FilterIndex filterIndex = (FilterIndex) dlg.m_ofn.nFilterIndex;
if (filterIndex < kFilterIndexFIRST || filterIndex > kFilterIndexMAX) {
ASSERT(false);
LOGW("invalid filterIndex %d", filterIndex);
filterIndex = kFilterIndexGeneric;
}
DoOpenArchive(dlg.GetPathName(), dlg.GetFileExt(), DoOpenArchive(dlg.GetPathName(), dlg.GetFileExt(),
dlg.m_ofn.nFilterIndex, dlg.GetReadOnlyPref() != 0); filterIndex, dlg.GetReadOnlyPref() != 0);
bail: bail:
LOGD("--- OnFileOpen done"); LOGD("--- OnFileOpen done");
@ -1240,9 +1251,9 @@ void MainWindow::OnUpdateFileOpenVolume(CCmdUI* pCmdUI)
} }
void MainWindow::DoOpenArchive(const WCHAR* pathName, const WCHAR* ext, void MainWindow::DoOpenArchive(const WCHAR* pathName, const WCHAR* ext,
int filterIndex, bool readOnly) FilterIndex filterIndex, bool readOnly)
{ {
if (LoadArchive(pathName, ext, filterIndex, readOnly, false) == 0) { if (LoadArchive(pathName, ext, filterIndex, readOnly) == 0) {
/* success, update title bar */ /* success, update title bar */
fOpenArchivePathName = pathName; fOpenArchivePathName = pathName;
SetCPTitle(fOpenArchivePathName, fpOpenArchive); SetCPTitle(fOpenArchivePathName, fpOpenArchive);
@ -1881,16 +1892,28 @@ void MainWindow::DrawEmptyClientArea(CDC* pDC, const CRect& clientRect)
pDC->SelectObject(pOldPen); pDC->SelectObject(pOldPen);
} }
GenericArchive* MainWindow::CreateArchiveInstance(FilterIndex filterIndex) const
{
GenericArchive* pOpenArchive = NULL;
switch (filterIndex) {
case kFilterIndexNuFX: pOpenArchive = new NufxArchive; break;
case kFilterIndexBinaryII: pOpenArchive = new BnyArchive; break;
case kFilterIndexACU: pOpenArchive = new AcuArchive; break;
case kFilterIndexAppleSingle: pOpenArchive = new AppleSingleArchive; break;
case kFilterIndexDiskImage: pOpenArchive = new DiskArchive; break;
default: ASSERT(false); break;
}
return pOpenArchive;
}
int MainWindow::LoadArchive(const WCHAR* fileName, const WCHAR* extension, int MainWindow::LoadArchive(const WCHAR* fileName, const WCHAR* extension,
int filterIndex, bool readOnly, bool createFile) FilterIndex filterIndex, bool readOnly)
{ {
GenericArchive::OpenResult openResult; GenericArchive::OpenResult openResult;
int result = -1; const FilterIndex origFilterIndex = filterIndex;
GenericArchive* pOpenArchive = NULL; GenericArchive* pOpenArchive = NULL;
const int origFilterIndex = filterIndex;
CString errStr, appName;
CheckedLoadString(&appName, IDS_MB_APP_NAME);
LOGI("LoadArchive: '%ls' ro=%d idx=%d", fileName, readOnly, filterIndex); LOGI("LoadArchive: '%ls' ro=%d idx=%d", fileName, readOnly, filterIndex);
@ -1898,25 +1921,8 @@ int MainWindow::LoadArchive(const WCHAR* fileName, const WCHAR* extension,
CloseArchive(); CloseArchive();
/* /*
* If they used the "All Files (*.*)" filter, we have to guess based * If they used the "All Files (*.*)" filter, try guess based
* on the file type. * on the file extension.
*
* IDEA: change the current "filterIndex ==" stuff to a type-specific
* model, then do type-scanning here. Code later on takes the type
* and opens it. That way we can do the trivial "it must be" handling
* up here, and maybe do a little "open it up and see" stuff as well.
* In general, though, if we don't recognize the extension, it's
* probably a disk image.
*
* TODO: different idea: always pass the file to each of the different
* archive handlers, which will provide an "is this your file" method.
* If the filter matches, open according to the filter. If it doesn't,
* open it according to whatever stepped up to claim it. Consider
* altering the UI to offer a disambiguation dialog that shows all the
* things it could possibly be (though that might be annoying if it comes
* up every time on e.g. .SDK files). The ultimate goal is to avoid
* saying, "I can't open that", when we actually could if the filter was
* set to the right thing.
*/ */
if (filterIndex == kFilterIndexGeneric) { if (filterIndex == kFilterIndexGeneric) {
int i; int i;
@ -1928,120 +1934,69 @@ int MainWindow::LoadArchive(const WCHAR* fileName, const WCHAR* extension,
} }
} }
if (i == NELEM(gExtensionToIndex)) if (i == NELEM(gExtensionToIndex)) {
// no match found, use "disk image" as initial guess
filterIndex = kFilterIndexDiskImage; filterIndex = kFilterIndexDiskImage;
}
} }
try_again: /*
if (filterIndex == kFilterIndexBinaryII) { * Try to open the file according to the specified filter index. If
/* try Binary II and nothing else */ * it works, we're done. Trying this first ensures that you can choose
ASSERT(!createFile); * to open, say, a .SDK file as either ShrinkIt or Disk Image.
LOGD(" Trying Binary II"); */
pOpenArchive = new BnyArchive; CString firstErrStr;
openResult = pOpenArchive->Open(fileName, readOnly, &errStr); pOpenArchive = CreateArchiveInstance(filterIndex);
if (openResult != GenericArchive::kResultSuccess) { LOGD(" First try: %ls", (LPCWSTR) pOpenArchive->GetDescription());
if (!errStr.IsEmpty()) openResult = pOpenArchive->Open(fileName, readOnly, &firstErrStr);
ShowFailureMsg(this, errStr, IDS_FAILED); if (openResult == GenericArchive::kResultSuccess) {
result = -1; // success!
goto bail; SwitchContentList(pOpenArchive);
return 0;
} else if (openResult == GenericArchive::kResultFileArchive) {
if (wcsicmp(extension, L"zip") == 0) {
// we could probably just return in this case
firstErrStr = L"Zip archives with multiple files are not supported";
} else {
firstErrStr = L"This appears to be a file archive.";
} }
} else
if (filterIndex == kFilterIndexACU) {
/* try ACU and nothing else */
ASSERT(!createFile);
LOGD(" Trying ACU");
pOpenArchive = new AcuArchive;
openResult = pOpenArchive->Open(fileName, readOnly, &errStr);
if (openResult != GenericArchive::kResultSuccess) {
if (!errStr.IsEmpty())
ShowFailureMsg(this, errStr, IDS_FAILED);
result = -1;
goto bail;
}
} else
if (filterIndex == kFilterIndexAppleSingle) {
/* try AppleSingle and nothing else */
ASSERT(!createFile);
LOGD(" Trying AppleSingle");
pOpenArchive = new AppleSingleArchive;
openResult = pOpenArchive->Open(fileName, readOnly, &errStr);
if (openResult != GenericArchive::kResultSuccess) {
if (!errStr.IsEmpty())
ShowFailureMsg(this, errStr, IDS_FAILED);
result = -1;
goto bail;
}
} else
if (filterIndex == kFilterIndexDiskImage) {
/* try various disk image formats */
ASSERT(!createFile);
LOGD(" Trying disk images");
pOpenArchive = new DiskArchive;
openResult = pOpenArchive->Open(fileName, readOnly, &errStr);
if (openResult == GenericArchive::kResultCancel) {
result = -1;
goto bail;
} else if (openResult == GenericArchive::kResultFileArchive) {
delete pOpenArchive;
pOpenArchive = NULL;
if (wcsicmp(extension, L"zip") == 0) {
errStr = "ZIP archives with multiple files are not supported.";
MessageBox(errStr, appName, MB_OK|MB_ICONINFORMATION);
result = -1;
goto bail;
} else {
/* assume some variation of a ShrinkIt archive */
// msg.LoadString(IDS_OPEN_AS_NUFX); <-- with MB_OKCANCEL
filterIndex = kFilterIndexNuFX;
goto try_again;
}
} else if (openResult != GenericArchive::kResultSuccess) {
//if (filterIndex != origFilterIndex) {
// /*
// * Kluge: assume we guessed disk image and were wrong.
// */
// errStr = L"File doesn't appear to be a valid archive"
// L" or disk image.";
//}
if (!errStr.IsEmpty())
ShowFailureMsg(this, errStr, IDS_FAILED);
result = -1;
goto bail;
}
} else
if (filterIndex == kFilterIndexNuFX) {
/* try NuFX (including its embedded-in-BNY form) */
LOGD(" Trying NuFX");
pOpenArchive = new NufxArchive;
openResult = pOpenArchive->Open(fileName, readOnly, &errStr);
if (openResult != GenericArchive::kResultSuccess) {
if (!errStr.IsEmpty())
ShowFailureMsg(this, errStr, IDS_FAILED);
result = -1;
goto bail;
}
} else {
ASSERT(FALSE);
result = -1;
goto bail;
} }
delete pOpenArchive;
SwitchContentList(pOpenArchive); /*
* That didn't work. Try the others.
*/
for (int i = kFilterIndexFIRST; i <= kFilterIndexLAST; i++) {
if (i == filterIndex) continue;
pOpenArchive = NULL; pOpenArchive = CreateArchiveInstance((FilterIndex) i);
result = 0; LOGD("Now trying: %ls", (LPCWSTR) pOpenArchive->GetDescription());
CString dummyErrStr;
bail: openResult = pOpenArchive->Open(fileName, readOnly, &dummyErrStr);
if (pOpenArchive != NULL) { if (openResult == GenericArchive::kResultSuccess) {
ASSERT(result != 0); // success!
SwitchContentList(pOpenArchive);
return 0;
}
delete pOpenArchive; delete pOpenArchive;
} }
return result;
/*
* Nothing worked. Show the original error message so that it matches
* up with the chosen filter index -- if they seemed to be trying to
* open an AppleSingle, don't tell them we failed because the file isn't
* a disk image.
*
* If they were using the Generic filter, they'll get the message from
* the disk image library. It might make more sense to just say "we
* couldn't figure out what this was", but most of the time people are
* trying to open disk images anyway.
*/
if (firstErrStr.IsEmpty()) {
firstErrStr = L"Unable to determine what kind of file this is.";
}
ShowFailureMsg(this, firstErrStr, IDS_FAILED);
return -1;
} }
int MainWindow::DoOpenVolume(CString drive, bool readOnly) int MainWindow::DoOpenVolume(CString drive, bool readOnly)
@ -2241,11 +2196,10 @@ void MainWindow::SetCPTitle(const WCHAR* pathname, GenericArchive* pOpenArchive)
ASSERT(pathname != NULL); ASSERT(pathname != NULL);
CString title; CString title;
CString appName; CString appName;
CString archiveDescription;
CheckedLoadString(&appName, IDS_MB_APP_NAME); CheckedLoadString(&appName, IDS_MB_APP_NAME);
pOpenArchive->GetDescription(&archiveDescription); CString archiveDescription(pOpenArchive->GetDescription());
title.Format(L"%ls - %ls (%ls)", (LPCWSTR) appName, pathname, title.Format(L"%ls - %ls (%ls)", (LPCWSTR) appName, pathname,
(LPCWSTR) archiveDescription); (LPCWSTR) archiveDescription);
@ -2287,17 +2241,16 @@ void MainWindow::SetCPTitle(void)
CString MainWindow::GetPrintTitle(void) CString MainWindow::GetPrintTitle(void)
{ {
CString title; CString title;
CString archiveDescription;
CString appName;
if (fpOpenArchive == NULL) { if (fpOpenArchive == NULL) {
ASSERT(false); ASSERT(false);
return title; return title;
} }
CString appName;
CheckedLoadString(&appName, IDS_MB_APP_NAME); CheckedLoadString(&appName, IDS_MB_APP_NAME);
fpOpenArchive->GetDescription(&archiveDescription); CString archiveDescription(fpOpenArchive->GetDescription());
title.Format(L"%ls - %ls (%ls)", (LPCWSTR) appName, title.Format(L"%ls - %ls (%ls)", (LPCWSTR) appName,
(LPCWSTR) fOpenArchivePathName, (LPCWSTR) archiveDescription); (LPCWSTR) fOpenArchivePathName, (LPCWSTR) archiveDescription);

View File

@ -26,12 +26,16 @@
#define WMU_START (WM_USER+1) // used by ActionProgressDialog #define WMU_START (WM_USER+1) // used by ActionProgressDialog
enum FilterIndex { enum FilterIndex {
kFilterIndexFIRST = 1, // first index, must be non-Generic
kFilterIndexNuFX = 1, kFilterIndexNuFX = 1,
kFilterIndexBinaryII = 2, kFilterIndexBinaryII = 2,
kFilterIndexACU = 3, kFilterIndexACU = 3,
kFilterIndexAppleSingle = 4, kFilterIndexAppleSingle = 4,
kFilterIndexDiskImage = 5, kFilterIndexDiskImage = 5,
kFilterIndexGeneric = 6 // *.* filter used kFilterIndexLAST = 5, // last non-Generic index
kFilterIndexGeneric = 6, // *.* filter used
kFilterIndexMAX = 6 // highest valid number
}; };
struct FileCollectionEntry; // fwd struct FileCollectionEntry; // fwd
@ -518,23 +522,23 @@ private:
int TmpExtractForExternal(GenericEntry* pEntry); int TmpExtractForExternal(GenericEntry* pEntry);
void DoOpenArchive(const WCHAR* pathName, const WCHAR* ext, void DoOpenArchive(const WCHAR* pathName, const WCHAR* ext,
int filterIndex, bool readOnly); FilterIndex filterIndex, bool readOnly);
GenericArchive* CreateArchiveInstance(FilterIndex filterIndex) const;
/* /*
* Load an archive, using the appropriate GenericArchive subclass. If * Load an archive, using the appropriate GenericArchive subclass.
* "createFile" is "true", a new archive file will be created (and must
* not already exist!).
* *
* "filename" is the full path to the file, "extension" is the * "filename" is the full path to the file, "extension" is the
* filetype component of the name (without the leading '.'), "filterIndex" * filetype component of the name (without the leading '.'), "filterIndex"
* is the offset into the set of filename filters used in the standard * is the offset into the set of filename filters used in the standard
* file dialog, "readOnly" reflects the state of the stdfile dialog * file dialog, and "readOnly" reflects the state of the stdfile dialog
* checkbox, and "createFile" is set to true by the "New Archive" command. * checkbox.
* *
* Returns 0 on success, nonzero on failure. * Returns 0 on success, nonzero on failure.
*/ */
int LoadArchive(const WCHAR* filename, const WCHAR* extension, int LoadArchive(const WCHAR* filename, const WCHAR* extension,
int filterIndex, bool readOnly, bool createFile); FilterIndex filterIndex, bool readOnly);
/* /*
* Open a raw disk volume. Useful for ProDOS-formatted 1.44MB floppy disks * Open a raw disk volume. Useful for ProDOS-formatted 1.44MB floppy disks

View File

@ -112,7 +112,7 @@ public:
virtual CString Reload(void) override; virtual CString Reload(void) override;
virtual bool IsReadOnly(void) const override { return fIsReadOnly; }; virtual bool IsReadOnly(void) const override { return fIsReadOnly; };
virtual bool IsModified(void) const override { return false; } virtual bool IsModified(void) const override { return false; }
virtual void GetDescription(CString* pStr) const override { *pStr = L"NuFX"; } virtual CString GetDescription() const override { return L"NuFX"; }
virtual bool BulkAdd(ActionProgressDialog* pActionProgress, virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override; const AddFilesDialog* pAddOpts) override;
virtual bool AddDisk(ActionProgressDialog* pActionProgress, virtual bool AddDisk(ActionProgressDialog* pActionProgress,