ciderpress/app/NufxArchive.h
Andy McFadden 814872966e 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.
2015-01-13 15:54:10 -08:00

257 lines
9.0 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* NuFX archive support.
*/
#ifndef APP_NUFXARCHIVE_H
#define APP_NUFXARCHIVE_H
#include "GenericArchive.h"
#include "../nufxlib/NufxLib.h" // ideally this wouldn't be here, only in .cpp
/*
* One file in an NuFX archive.
*/
class NufxEntry : public GenericEntry {
public:
NufxEntry(NuArchive* pArchive) : fpArchive(pArchive)
{}
virtual ~NufxEntry(void) {}
NuRecordIdx GetRecordIdx(void) const { return fRecordIdx; }
void SetRecordIdx(NuRecordIdx idx) { fRecordIdx = idx; }
virtual int ExtractThreadToBuffer(int which, char** ppText, long* pLength,
CString* pErrMsg) const override;
virtual int ExtractThreadToFile(int which, FILE* outfp, ConvertEOL conv,
ConvertHighASCII convHA, CString* pErrMsg) const override;
virtual long GetSelectionSerial(void) const override { return fRecordIdx; }
virtual bool GetFeatureFlag(Feature feature) const override {
if (feature == kFeaturePascalTypes || feature == kFeatureDOSTypes ||
feature == kFeatureHasSimpleAccess)
{
return false;
} else {
return true;
}
}
/*
* Analyzes the contents of a record to determine if it's a disk, file,
* or "other". Computes the total compressed and uncompressed lengths
* of all data threads. Fills out several GenericEntry fields.
*/
void AnalyzeRecord(const NuRecord* pRecord);
friend class NufxArchive;
private:
/*
* Find info for the thread we're about to extract.
*
* Given the NuRecordIdx stored in the object, find the thread whose
* ThreadID matches "which". Copies the NuThread structure into
* "*pThread".
*
* On entry *pErrMsg must be an empty string. On failure, it will
* contain an error message describing the problem.
*/
void FindThreadInfo(int which, NuThread* pThread, CString* pErrMsg) const;
NuRecordIdx fRecordIdx; // unique record index
NuArchive* fpArchive;
};
/*
* A generic archive plus NuFX-specific goodies.
*/
class NufxArchive : public GenericArchive {
public:
NufxArchive(void) :
fpArchive(NULL),
fIsReadOnly(false),
fProgressAsRecompress(false),
fNumAdded(-1),
fpMsgWnd(NULL),
fpAddOpts(NULL)
{}
virtual ~NufxArchive(void) { (void) Close(); }
/*
* Perform one-time initialization of the NufxLib library.
*
* Returns with an error if the NufxLib version is off. Major version must
* match (since it indicates an interface change), minor version must be
* >= what we expect (in case we're relying on recent behavior changes).
*
* Returns 0 on success, nonzero on error.
*/
static CString AppInit(void);
/*
* Finish instantiating a NufxArchive object by opening an existing file.
*/
virtual OpenResult Open(const WCHAR* filename, bool readOnly,
CString* pErrMsg) override;
/*
* Finish instantiating a NufxArchive object by creating a new archive.
*
* Returns an error string on failure, or "" on success.
*/
virtual CString New(const WCHAR* filename, const void* options) override;
virtual CString Flush(void) override { return ""; }
virtual CString Reload(void) override;
virtual bool IsReadOnly(void) const override { return fIsReadOnly; };
virtual bool IsModified(void) const override { return false; }
virtual CString GetDescription() const override { return L"NuFX"; }
virtual bool BulkAdd(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override;
virtual bool AddDisk(ActionProgressDialog* pActionProgress,
const AddFilesDialog* pAddOpts) override;
virtual bool CreateSubdir(CWnd* pMsgWnd, GenericEntry* pParentEntry,
const WCHAR* newName) override
{ ASSERT(false); return false; }
virtual bool TestSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) override;
virtual bool DeleteSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) override;
virtual bool RenameSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) override;
virtual CString TestPathName(const GenericEntry* pGenericEntry,
const CString& basePath, const CString& newName,
char newFssep) const override;
virtual bool RenameVolume(CWnd* pMsgWnd, DiskFS* pDiskFS,
const WCHAR* newName) override
{ ASSERT(false); return false; }
virtual CString TestVolumeName(const DiskFS* pDiskFS,
const WCHAR* newName) const override
{ ASSERT(false); return L"!"; }
virtual bool RecompressSelection(CWnd* pMsgWnd, SelectionSet* pSelSet,
const RecompressOptionsDialog* pRecompOpts) override;
virtual XferStatus XferSelection(CWnd* pMsgWnd, SelectionSet* pSelSet,
ActionProgressDialog* pActionProgress,
const XferFileOptions* pXferOpts) override;
virtual bool GetComment(CWnd* pMsgWnd, const GenericEntry* pEntry,
CString* pStr) override;
virtual bool SetComment(CWnd* pMsgWnd, GenericEntry* pEntry,
const CString& str) override;
virtual bool DeleteComment(CWnd* pMsgWnd, GenericEntry* pEntry) override;
virtual bool SetProps(CWnd* pMsgWnd, GenericEntry* pEntry,
const FileProps* pProps) override;
virtual void PreferencesChanged(void) override;
virtual long GetCapability(Capability cap) override;
// try not to use this
NuArchive* GetNuArchivePointer(void) const { return fpArchive; }
// determine whether a particular type of compression is supported
static bool IsCompressionSupported(NuThreadFormat format);
// convert from DateTime format to time_t
static time_t DateTimeToSeconds(const NuDateTime* pDateTime);
private:
virtual CString Close(void) {
if (fpArchive != NULL) {
LOGI("Closing archive (aborting any un-flushed changes)");
NuAbort(fpArchive);
NuClose(fpArchive);
fpArchive = NULL;
}
return L"";
}
// recompress one thread
bool RecompressThread(NufxEntry* pEntry, int threadKind,
const RecompressOptionsDialog* pRecompOpts, long* pSizeInMemory,
CString* pErrMsg);
virtual void XferPrepare(const XferFileOptions* pXferOpts) override;
virtual CString XferFile(LocalFileDetails* pDetails, uint8_t** pDataBuf,
long dataLen, uint8_t** pRsrcBuf, long rsrcLen) override;
virtual void XferAbort(CWnd* pMsgWnd) override;
virtual void XferFinish(CWnd* pMsgWnd) override;
virtual ArchiveKind GetArchiveKind(void) override { return kArchiveNuFX; }
// prepare to add files
void AddPrep(CWnd* pWnd, const AddFilesDialog* pAddOpts);
/*
* Reset some things after we finish adding files. We don't necessarily
* want these to stay in effect for other operations, e.g. extracting.
*/
void AddFinish(void);
virtual NuError DoAddFile(const AddFilesDialog* pAddOpts,
LocalFileDetails* pDetails) override;
/*
* Error handler callback for "bulk" adds.
*/
static NuResult BulkAddErrorHandler(NuArchive* pArchive, void* vErrorStatus);
/*
* Decide whether or not to replace an existing file (during extract)
* or record (during add).
*/
NuResult HandleReplaceExisting(const NuErrorStatus* pErrorStatus);
/*
* A file that used to be there isn't anymore.
*
* This should be exceedingly rare.
*/
NuResult HandleAddNotFound(const NuErrorStatus* pErrorStatus);
/*
* Load the contents of an archive into the GenericEntry/NufxEntry list.
*/
NuError LoadContents(void);
/*
* Reload the contents of the archive, showing an error message if the
* reload fails.
*/
NuError InternalReload(CWnd* pMsgWnd);
/*
* Static callback function. Used for scanning the contents of an archive.
*/
static NuResult ContentFunc(NuArchive* pArchive, void* vpRecord);
/*
* Set some standard callbacks and feature flags.
*/
NuError SetCallbacks(void);
// handle progress update messages
static NuResult ProgressUpdater(NuArchive* pArchive, void* vpProgress);
// handle error and debug messages from NufxLib.
static NuResult NufxErrorMsgHandler(NuArchive* pArchive,
void* vErrorMessage);
// handle a DataSource resource release request; used for memory allocated
// with new[]
static NuResult ArrayDeleteHandler(NuArchive* pArchive, void* ptr);
NuArchive* fpArchive;
bool fIsReadOnly;
bool fProgressAsRecompress; // tweak progress updater
/* state while adding files */
int fNumAdded;
CWnd* fpMsgWnd;
const AddFilesDialog* fpAddOpts;
};
#endif /*APP_NUFXARCHIVE_H*/