From 814872966e01eddba5342573ff5486646cb3c6da Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Tue, 13 Jan 2015 15:54:10 -0800 Subject: [PATCH] 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. --- app/ACUArchive.h | 3 +- app/AppleSingleArchive.h | 3 +- app/BNYArchive.h | 2 +- app/DiskArchive.cpp | 10 +- app/DiskArchive.h | 2 +- app/GenericArchive.h | 146 ++++++++++++------------ app/Main.cpp | 237 ++++++++++++++++----------------------- app/Main.h | 20 ++-- app/NufxArchive.h | 2 +- 9 files changed, 190 insertions(+), 235 deletions(-) diff --git a/app/ACUArchive.h b/app/ACUArchive.h index 4dec130..26e3142 100644 --- a/app/ACUArchive.h +++ b/app/ACUArchive.h @@ -105,8 +105,7 @@ public: virtual CString Reload(void) override; virtual bool IsReadOnly(void) const override { return true; }; virtual bool IsModified(void) const override { return false; } - virtual void GetDescription(CString* pStr) const override - { *pStr = L"AppleLink ACU"; } + virtual CString GetDescription() const override { return L"AppleLink ACU"; } virtual bool BulkAdd(ActionProgressDialog* pActionProgress, const AddFilesDialog* pAddOpts) override { ASSERT(false); return false; } diff --git a/app/AppleSingleArchive.h b/app/AppleSingleArchive.h index 172868a..dd90be9 100644 --- a/app/AppleSingleArchive.h +++ b/app/AppleSingleArchive.h @@ -121,8 +121,7 @@ public: virtual CString Reload(void) override; virtual bool IsReadOnly(void) const override { return true; }; virtual bool IsModified(void) const override { return false; } - virtual void GetDescription(CString* pStr) const override - { *pStr = L"AppleSingle"; } + virtual CString GetDescription() const override { return L"AppleSingle"; } virtual bool BulkAdd(ActionProgressDialog* pActionProgress, const AddFilesDialog* pAddOpts) override { ASSERT(false); return false; } diff --git a/app/BNYArchive.h b/app/BNYArchive.h index e1e9095..cd42332 100644 --- a/app/BNYArchive.h +++ b/app/BNYArchive.h @@ -91,7 +91,7 @@ public: virtual CString Reload(void) override; virtual bool IsReadOnly(void) const override { return fIsReadOnly; }; 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, const AddFilesDialog* pAddOpts) override { ASSERT(false); return false; } diff --git a/app/DiskArchive.cpp b/app/DiskArchive.cpp index 9b40942..52d4f81 100644 --- a/app/DiskArchive.cpp +++ b/app/DiskArchive.cpp @@ -885,14 +885,14 @@ bool DiskArchive::IsModified(void) const return fpPrimaryDiskFS->GetDiskImg()->GetDirtyFlag(); } -void DiskArchive::GetDescription(CString* pStr) const +CString DiskArchive::GetDescription() const { - if (fpPrimaryDiskFS == NULL) - return; + CString str = L"Disk Image"; - if (fpPrimaryDiskFS->GetVolumeID() != NULL) { - pStr->Format(L"Disk Image - %hs", fpPrimaryDiskFS->GetVolumeID()); + if (fpPrimaryDiskFS != NULL && fpPrimaryDiskFS->GetVolumeID() != NULL) { + str.Format(L"Disk Image - %hs", fpPrimaryDiskFS->GetVolumeID()); } + return str; } int DiskArchive::LoadContents(void) diff --git a/app/DiskArchive.h b/app/DiskArchive.h index e91dbcc..41ba8f5 100644 --- a/app/DiskArchive.h +++ b/app/DiskArchive.h @@ -164,7 +164,7 @@ public: * Return an description of the disk archive, suitable for display in the * main title bar. */ - virtual void GetDescription(CString* pStr) const override; + virtual CString GetDescription() const override; virtual bool BulkAdd(ActionProgressDialog* pActionProgress, const AddFilesDialog* pAddOpts) override; diff --git a/app/GenericArchive.h b/app/GenericArchive.h index a37aa06..d37fb6b 100644 --- a/app/GenericArchive.h +++ b/app/GenericArchive.h @@ -52,10 +52,10 @@ struct FileProps { */ class XferFileOptions { public: - XferFileOptions(void) : + XferFileOptions() : fTarget(NULL), fPreserveEmptyFolders(false), fpTargetFS(NULL) {} - ~XferFileOptions(void) {} + ~XferFileOptions() {} /* where the stuff is going */ GenericArchive* fTarget; @@ -81,8 +81,8 @@ public: */ class GenericEntry { public: - GenericEntry(void); - virtual ~GenericEntry(void); + GenericEntry(); + virtual ~GenericEntry(); /* kinds of files found in archives */ enum RecordKind { @@ -187,12 +187,12 @@ public: // 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; + virtual long GetSelectionSerial() const = 0; /* what operations are possible with this entry? */ virtual bool GetFeatureFlag(Feature feature) const = 0; - long GetIndex(void) const { return fIndex; } + long GetIndex() const { return fIndex; } void SetIndex(long idx) { fIndex = idx; } /* @@ -204,75 +204,75 @@ public: */ void SetPathNameMOR(const char* pathNameMOR); - const CStringA& GetPathNameMOR(void) const { return fPathNameMOR; } - const CString& GetPathNameUNI(void) const { return fPathNameUNI; } - const CString& GetFileName(void); - const CString& GetFileNameExtension(void); // returns e.g. ".SHK" - const CStringA& GetFileNameExtensionMOR(void); + const CStringA& GetPathNameMOR() const { return fPathNameMOR; } + const CString& GetPathNameUNI() const { return fPathNameUNI; } + const CString& GetFileName(); + const CString& GetFileNameExtension(); // returns e.g. ".SHK" + const CStringA& GetFileNameExtensionMOR(); /* * Returns the "display" name. This is a combination of the sub-volume * name and the path name. This string is intended for display only, * 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); - 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; } - uint32_t GetFileType(void) const { return fFileType; } + uint32_t GetFileType() const { return fFileType; } 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; } - uint32_t GetAccess(void) const { return fAccess; } + uint32_t GetAccess() const { return fAccess; } 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; } - time_t GetModWhen(void) const { return fModWhen; } + time_t GetModWhen() const { return fModWhen; } void SetModWhen(time_t when) { fModWhen = when; } - RecordKind GetRecordKind(void) const { return fRecordKind; } + RecordKind GetRecordKind() const { return fRecordKind; } 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! - LONGLONG GetCompressedLen(void) const { return fCompressedLen; } + LONGLONG GetCompressedLen() const { return fCompressedLen; } void SetCompressedLen(LONGLONG len) { fCompressedLen = len; } - LONGLONG GetUncompressedLen(void) const { + LONGLONG GetUncompressedLen() const { return fDataForkLen + fRsrcForkLen; } - LONGLONG GetDataForkLen(void) const { return fDataForkLen; } + LONGLONG GetDataForkLen() const { return fDataForkLen; } void SetDataForkLen(LONGLONG len) { fDataForkLen = len; } - LONGLONG GetRsrcForkLen(void) const { return fRsrcForkLen; } + LONGLONG GetRsrcForkLen() const { return fRsrcForkLen; } 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; } - bool GetHasDataFork(void) const { return fHasDataFork; } + bool GetHasDataFork() const { return fHasDataFork; } void SetHasDataFork(bool val) { fHasDataFork = val; } - bool GetHasRsrcFork(void) const { return fHasRsrcFork; } + bool GetHasRsrcFork() const { return fHasRsrcFork; } void SetHasRsrcFork(bool val) { fHasRsrcFork = val; } - bool GetHasDiskImage(void) const { return fHasDiskImage; } + bool GetHasDiskImage() const { return fHasDiskImage; } void SetHasDiskImage(bool val) { fHasDiskImage = val; } - bool GetHasComment(void) const { return fHasComment; } + bool GetHasComment() const { return fHasComment; } void SetHasComment(bool val) { fHasComment = val; } - bool GetHasNonEmptyComment(void) const { return fHasNonEmptyComment; } + bool GetHasNonEmptyComment() const { return fHasNonEmptyComment; } void SetHasNonEmptyComment(bool val) { fHasNonEmptyComment = val; } - bool GetDamaged(void) const { return fDamaged; } + bool GetDamaged() const { return fDamaged; } void SetDamaged(bool val) { fDamaged = val; } - bool GetSuspicious(void) const { return fSuspicious; } + bool GetSuspicious() const { return fSuspicious; } void SetSuspicious(bool val) { fSuspicious = val; } - GenericEntry* GetPrev(void) const { return fpPrev; } + GenericEntry* GetPrev() const { return fpPrev; } void SetPrev(GenericEntry* pEntry) { fpPrev = pEntry; } - GenericEntry* GetNext(void) const { return fpNext; } + GenericEntry* GetNext() const { return fpNext; } void SetNext(GenericEntry* pEntry) { fpNext = pEntry; } /* * 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. @@ -368,23 +368,23 @@ private: */ class GenericArchive { public: - GenericArchive(void) { + GenericArchive() { fPathName = NULL; fNumEntries = 0; fEntryHead = fEntryTail = NULL; fReloadFlag = true; //fEntryIndex = NULL; } - virtual ~GenericArchive(void) { + virtual ~GenericArchive() { //LOGI("Deleting GenericArchive"); DeleteEntries(); delete fPathName; } - virtual GenericEntry* GetEntries(void) const { + virtual GenericEntry* GetEntries() const { return fEntryHead; } - virtual long GetNumEntries(void) const { + virtual long GetNumEntries() const { return fNumEntries; } @@ -402,16 +402,16 @@ public: // 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; + virtual CString Flush() = 0; // Force a re-read from the underlying storage. - virtual CString Reload(void) = 0; + virtual CString Reload() = 0; // Do we allow modification? - virtual bool IsReadOnly(void) const = 0; + virtual bool IsReadOnly() const = 0; // 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 void ClearReloadFlag(void) { fReloadFlag = false; } + virtual bool GetReloadFlag() { return fReloadFlag; } + virtual void ClearReloadFlag() { fReloadFlag = false; } // One of these for every sub-class. enum ArchiveKind { @@ -424,10 +424,10 @@ public: }; // 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. - virtual void GetDescription(CString* pStr) const = 0; + virtual CString GetDescription() const = 0; // Do a bulk add. virtual bool BulkAdd(ActionProgressDialog* pActionProgress, @@ -496,7 +496,7 @@ public: // Preferences have changed, update library state as needed. Also called // the first time though. - virtual void PreferencesChanged(void) = 0; + virtual void PreferencesChanged() = 0; // Determine an archive's capabilities. This is specific to the object // instance, so this must not be made a static function. @@ -515,7 +515,7 @@ public: virtual long GetCapability(Capability cap) = 0; // 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. @@ -549,8 +549,8 @@ public: */ class LocalFileDetails { public: - LocalFileDetails(void); - virtual ~LocalFileDetails(void) {} + LocalFileDetails(); + virtual ~LocalFileDetails() {} /* * Set the various fields, based on the pathname and characteristics @@ -805,7 +805,7 @@ protected: /* * Delete the "entries" list. */ - virtual void DeleteEntries(void); + virtual void DeleteEntries(); void ReplaceFssep(WCHAR* str, char oldc, char newc, char newSubst); @@ -882,7 +882,7 @@ protected: bool fReloadFlag; // set after Reload called private: - //virtual void CreateIndex(void); + //virtual void CreateIndex(); //CString fNewPathHolder; //CString fOrigPathHolder; @@ -906,18 +906,18 @@ public: //fReformatName = ""; fpPrev = fpNext = NULL; } - ~SelectionEntry(void) {} + ~SelectionEntry() {} 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; } + GenericEntry* GetEntry() const { return fpEntry; } + //int GetThreadKind() const { return fThreadKind; } + //int GetFilter() const { return fFilter; } + //const char* GetReformatName() const { return fReformatName; } - SelectionEntry* GetPrev(void) const { return fpPrev; } + SelectionEntry* GetPrev() const { return fpPrev; } void SetPrev(SelectionEntry* pPrev) { fpPrev = pPrev; } - SelectionEntry* GetNext(void) const { return fpNext; } + SelectionEntry* GetNext() const { return fpNext; } void SetNext(SelectionEntry* pNext) { fpNext = pNext; } private: @@ -941,11 +941,11 @@ class ContentList; */ class SelectionSet { public: - SelectionSet(void) { + SelectionSet() { fNumEntries = 0; fEntryHead = fEntryTail = fIterCurrent = NULL; } - ~SelectionSet(void) { + ~SelectionSet() { DeleteEntries(); } @@ -955,49 +955,49 @@ public: void CreateFromAll(ContentList* pContentList, int threadMask); // get the head of the list - SelectionEntry* GetEntries(void) const { return fEntryHead; } + SelectionEntry* GetEntries() const { return fEntryHead; } - void IterReset(void) { + void IterReset() { fIterCurrent = NULL; } // move to the next or previous entry as part of iterating - SelectionEntry* IterPrev(void) { + SelectionEntry* IterPrev() { if (fIterCurrent == NULL) fIterCurrent = fEntryTail; else fIterCurrent = fIterCurrent->GetPrev(); return fIterCurrent; } - SelectionEntry* IterNext(void) { + SelectionEntry* IterNext() { if (fIterCurrent == NULL) fIterCurrent = fEntryHead; else fIterCurrent = fIterCurrent->GetNext(); return fIterCurrent; } - SelectionEntry* IterCurrent(void) { + SelectionEntry* IterCurrent() { return fIterCurrent; } - bool IterHasPrev(void) const { + bool IterHasPrev() const { if (fIterCurrent == NULL) return fEntryTail != NULL; else return (fIterCurrent->GetPrev() != NULL); } - bool IterHasNext(void) const { + bool IterHasNext() const { if (fIterCurrent == NULL) return fEntryHead != NULL; else return (fIterCurrent->GetNext() != NULL); } - int GetNumEntries(void) const { return fNumEntries; } + int GetNumEntries() 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); + void Dump(); private: /* @@ -1014,7 +1014,7 @@ private: /* * Delete the "entries" list. */ - void DeleteEntries(void); + void DeleteEntries(); int fNumEntries; SelectionEntry* fIterCurrent; diff --git a/app/Main.cpp b/app/Main.cpp index 71f11c7..9d16a2a 100644 --- a/app/Main.cpp +++ b/app/Main.cpp @@ -76,6 +76,7 @@ const WCHAR MainWindow::kOpenAll[] = const WCHAR MainWindow::kOpenEnd[] = L"|"; +/* used when guessing archive type from extension */ static const struct { WCHAR extension[4]; FilterIndex idx; @@ -88,14 +89,19 @@ static const struct { { L"bqy", kFilterIndexBinaryII }, { L"acu", kFilterIndexACU }, { L"as", kFilterIndexAppleSingle }, + { L"sdk", kFilterIndexDiskImage }, { L"dsk", kFilterIndexDiskImage }, { L"po", kFilterIndexDiskImage }, { L"do", kFilterIndexDiskImage }, { L"d13", kFilterIndexDiskImage }, { L"2mg", kFilterIndexDiskImage }, { L"img", kFilterIndexDiskImage }, - { L"sdk", kFilterIndexDiskImage }, + { L"nib", kFilterIndexDiskImage }, + { L"nb2", kFilterIndexDiskImage }, { L"raw", kFilterIndexDiskImage }, + { L"hdv", kFilterIndexDiskImage }, + { L"dc", kFilterIndexDiskImage }, + { L"dc6", kFilterIndexDiskImage }, { L"ddd", kFilterIndexDiskImage }, { L"app", kFilterIndexDiskImage }, { L"fdi", kFilterIndexDiskImage }, @@ -415,7 +421,7 @@ void MainWindow::ProcessCommandLine(void) */ const WCHAR* filename = NULL; const WCHAR* dispName = NULL; - int filterIndex = kFilterIndexGeneric; + FilterIndex filterIndex = kFilterIndexGeneric; bool temp = false; for (int i = 1; i < argc; i++) { @@ -482,7 +488,7 @@ void MainWindow::ProcessCommandLine(void) ext.Delete(0, 1); /* 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 */ if (temp) fOpenArchivePathName = path.GetFileName(); @@ -1191,7 +1197,6 @@ void MainWindow::OnFileOpen(void) openFilters += kOpenDiskImage; openFilters += kOpenAll; openFilters += kOpenEnd; - LOGD("filters: '%ls'", openFilters); CFileDialog dlg(TRUE, L"shk", NULL, OFN_FILEMUSTEXIST, openFilters, this); @@ -1206,8 +1211,14 @@ void MainWindow::OnFileOpen(void) saveFolder = saveFolder.Left(dlg.m_ofn.nFileOffset); 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(), - dlg.m_ofn.nFilterIndex, dlg.GetReadOnlyPref() != 0); + filterIndex, dlg.GetReadOnlyPref() != 0); bail: LOGD("--- OnFileOpen done"); @@ -1240,9 +1251,9 @@ void MainWindow::OnUpdateFileOpenVolume(CCmdUI* pCmdUI) } 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 */ fOpenArchivePathName = pathName; SetCPTitle(fOpenArchivePathName, fpOpenArchive); @@ -1881,16 +1892,28 @@ void MainWindow::DrawEmptyClientArea(CDC* pDC, const CRect& clientRect) 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 filterIndex, bool readOnly, bool createFile) + FilterIndex filterIndex, bool readOnly) { GenericArchive::OpenResult openResult; - int result = -1; + const FilterIndex origFilterIndex = filterIndex; 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); @@ -1898,25 +1921,8 @@ int MainWindow::LoadArchive(const WCHAR* fileName, const WCHAR* extension, CloseArchive(); /* - * If they used the "All Files (*.*)" filter, we have to guess based - * on the file type. - * - * 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 they used the "All Files (*.*)" filter, try guess based + * on the file extension. */ if (filterIndex == kFilterIndexGeneric) { 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; + } } -try_again: - if (filterIndex == kFilterIndexBinaryII) { - /* try Binary II and nothing else */ - ASSERT(!createFile); - LOGD(" Trying Binary II"); - pOpenArchive = new BnyArchive; - openResult = pOpenArchive->Open(fileName, readOnly, &errStr); - if (openResult != GenericArchive::kResultSuccess) { - if (!errStr.IsEmpty()) - ShowFailureMsg(this, errStr, IDS_FAILED); - result = -1; - goto bail; + /* + * Try to open the file according to the specified filter index. If + * it works, we're done. Trying this first ensures that you can choose + * to open, say, a .SDK file as either ShrinkIt or Disk Image. + */ + CString firstErrStr; + pOpenArchive = CreateArchiveInstance(filterIndex); + LOGD(" First try: %ls", (LPCWSTR) pOpenArchive->GetDescription()); + openResult = pOpenArchive->Open(fileName, readOnly, &firstErrStr); + if (openResult == GenericArchive::kResultSuccess) { + // success! + 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; - result = 0; - -bail: - if (pOpenArchive != NULL) { - ASSERT(result != 0); + pOpenArchive = CreateArchiveInstance((FilterIndex) i); + LOGD("Now trying: %ls", (LPCWSTR) pOpenArchive->GetDescription()); + CString dummyErrStr; + openResult = pOpenArchive->Open(fileName, readOnly, &dummyErrStr); + if (openResult == GenericArchive::kResultSuccess) { + // success! + SwitchContentList(pOpenArchive); + return 0; + } 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) @@ -2241,11 +2196,10 @@ void MainWindow::SetCPTitle(const WCHAR* pathname, GenericArchive* pOpenArchive) ASSERT(pathname != NULL); CString title; CString appName; - CString archiveDescription; CheckedLoadString(&appName, IDS_MB_APP_NAME); - pOpenArchive->GetDescription(&archiveDescription); + CString archiveDescription(pOpenArchive->GetDescription()); title.Format(L"%ls - %ls (%ls)", (LPCWSTR) appName, pathname, (LPCWSTR) archiveDescription); @@ -2287,17 +2241,16 @@ void MainWindow::SetCPTitle(void) CString MainWindow::GetPrintTitle(void) { CString title; - CString archiveDescription; - CString appName; if (fpOpenArchive == NULL) { ASSERT(false); return title; } + CString appName; CheckedLoadString(&appName, IDS_MB_APP_NAME); - fpOpenArchive->GetDescription(&archiveDescription); + CString archiveDescription(fpOpenArchive->GetDescription()); title.Format(L"%ls - %ls (%ls)", (LPCWSTR) appName, (LPCWSTR) fOpenArchivePathName, (LPCWSTR) archiveDescription); diff --git a/app/Main.h b/app/Main.h index 30d72f4..fa53b7d 100644 --- a/app/Main.h +++ b/app/Main.h @@ -26,12 +26,16 @@ #define WMU_START (WM_USER+1) // used by ActionProgressDialog enum FilterIndex { + kFilterIndexFIRST = 1, // first index, must be non-Generic kFilterIndexNuFX = 1, kFilterIndexBinaryII = 2, kFilterIndexACU = 3, kFilterIndexAppleSingle = 4, kFilterIndexDiskImage = 5, - kFilterIndexGeneric = 6 // *.* filter used + kFilterIndexLAST = 5, // last non-Generic index + + kFilterIndexGeneric = 6, // *.* filter used + kFilterIndexMAX = 6 // highest valid number }; struct FileCollectionEntry; // fwd @@ -518,23 +522,23 @@ private: int TmpExtractForExternal(GenericEntry* pEntry); 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 - * "createFile" is "true", a new archive file will be created (and must - * not already exist!). + * Load an archive, using the appropriate GenericArchive subclass. * * "filename" is the full path to the file, "extension" is the * filetype component of the name (without the leading '.'), "filterIndex" * is the offset into the set of filename filters used in the standard - * file dialog, "readOnly" reflects the state of the stdfile dialog - * checkbox, and "createFile" is set to true by the "New Archive" command. + * file dialog, and "readOnly" reflects the state of the stdfile dialog + * checkbox. * * Returns 0 on success, nonzero on failure. */ 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 diff --git a/app/NufxArchive.h b/app/NufxArchive.h index 6f61d59..ea03531 100644 --- a/app/NufxArchive.h +++ b/app/NufxArchive.h @@ -112,7 +112,7 @@ public: virtual CString Reload(void) override; virtual bool IsReadOnly(void) const override { return fIsReadOnly; }; 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, const AddFilesDialog* pAddOpts) override; virtual bool AddDisk(ActionProgressDialog* pActionProgress,