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,