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 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; }

View File

@ -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; }

View File

@ -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; }

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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,