/* * CiderPress * Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved. * See the file LICENSE for distribution terms. */ /* * AppleLink Compression Utility archive support. */ #ifndef APP_ACUARCHIVE_H #define APP_ACUARCHIVE_H #include "GenericArchive.h" class AcuArchive; /* * One file in an ACU archive. */ class AcuEntry : public GenericEntry { public: AcuEntry(AcuArchive* pArchive) : fpArchive(pArchive), fIsSqueezed(false), fOffset(-1) {} virtual ~AcuEntry(void) {} // retrieve thread data virtual int ExtractThreadToBuffer(int which, char** ppText, long* pLength, CString* pErrMsg) const; virtual int ExtractThreadToFile(int which, FILE* outfp, ConvertEOL conv, ConvertHighASCII convHA, CString* pErrMsg) const; virtual long GetSelectionSerial(void) const { return -1; } // doesn't matter virtual bool GetFeatureFlag(Feature feature) const { if (feature == kFeaturePascalTypes || feature == kFeatureDOSTypes || feature == kFeatureHasSimpleAccess) return false; else return true; } NuError TestEntry(CWnd* pMsgWnd); bool GetSqueezed(void) const { return fIsSqueezed; } void SetSqueezed(bool val) { fIsSqueezed = val; } long GetOffset(void) const { return fOffset; } void SetOffset(long offset) { fOffset = offset; } private: NuError CopyData(FILE* outfp, ConvertEOL conv, ConvertHighASCII convHA, CString* pMsg) const; //NuError BNYUnSqueeze(ExpandBuffer* outExp) const; AcuArchive* fpArchive; // holds FILE* for archive bool fIsSqueezed; long fOffset; }; /* * ACU archive definition. */ class AcuArchive : public GenericArchive { public: AcuArchive(void) : fIsReadOnly(false), fFp(nil) {} virtual ~AcuArchive(void) { (void) Close(); } // One-time initialization; returns an error string. static CString AppInit(void); virtual OpenResult Open(const WCHAR* filename, bool readOnly, CString* pErrMsg); virtual CString New(const WCHAR* filename, const void* options); virtual CString Flush(void) { return ""; } virtual CString Reload(void); virtual bool IsReadOnly(void) const { return fIsReadOnly; }; virtual bool IsModified(void) const { return false; } virtual void GetDescription(CString* pStr) const { *pStr = "AppleLink ACU"; } virtual bool BulkAdd(ActionProgressDialog* pActionProgress, const AddFilesDialog* pAddOpts) { ASSERT(false); return false; } virtual bool AddDisk(ActionProgressDialog* pActionProgress, const AddFilesDialog* pAddOpts) { ASSERT(false); return false; } virtual bool CreateSubdir(CWnd* pMsgWnd, GenericEntry* pParentEntry, const WCHAR* newName) { ASSERT(false); return false; } virtual bool TestSelection(CWnd* pMsgWnd, SelectionSet* pSelSet); virtual bool DeleteSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) { ASSERT(false); return false; } virtual bool RenameSelection(CWnd* pMsgWnd, SelectionSet* pSelSet) { ASSERT(false); return false; } virtual bool RenameVolume(CWnd* pMsgWnd, DiskFS* pDiskFS, const WCHAR* newName) { ASSERT(false); return false; } virtual CString TestVolumeName(const DiskFS* pDiskFS, const WCHAR* newName) const { ASSERT(false); return "!"; } virtual CString TestPathName(const GenericEntry* pGenericEntry, const CString& basePath, const CString& newName, char newFssep) const { ASSERT(false); return "!"; } virtual bool RecompressSelection(CWnd* pMsgWnd, SelectionSet* pSelSet, const RecompressOptionsDialog* pRecompOpts) { ASSERT(false); return false; } virtual XferStatus XferSelection(CWnd* pMsgWnd, SelectionSet* pSelSet, ActionProgressDialog* pActionProgress, const XferFileOptions* pXferOpts) { ASSERT(false); return kXferFailed; } virtual bool GetComment(CWnd* pMsgWnd, const GenericEntry* pEntry, CString* pStr) { ASSERT(false); return false; } virtual bool SetComment(CWnd* pMsgWnd, GenericEntry* pEntry, const CString& str) { ASSERT(false); return false; } virtual bool DeleteComment(CWnd* pMsgWnd, GenericEntry* pEntry) { ASSERT(false); return false; } virtual bool SetProps(CWnd* pMsgWnd, GenericEntry* pEntry, const FileProps* pProps) { ASSERT(false); return false; } virtual void PreferencesChanged(void) {} virtual long GetCapability(Capability cap); friend class AcuEntry; private: virtual CString Close(void) { if (fFp != nil) { fclose(fFp); fFp = nil; } return ""; } virtual void XferPrepare(const XferFileOptions* pXferOpts) { ASSERT(false); } virtual CString XferFile(FileDetails* pDetails, unsigned char** pDataBuf, long dataLen, unsigned char** pRsrcBuf, long rsrcLen) { ASSERT(false); return "!"; } virtual void XferAbort(CWnd* pMsgWnd) { ASSERT(false); } virtual void XferFinish(CWnd* pMsgWnd) { ASSERT(false); } virtual ArchiveKind GetArchiveKind(void) { return kArchiveACU; } virtual NuError DoAddFile(const AddFilesDialog* pAddOpts, FileDetails* pDetails) { ASSERT(false); return kNuErrGeneric; } enum { kAcuMaxFileName = 256, // nice big number kAcuMasterHeaderLen = 20, kAcuEntryHeaderLen = 54, }; /* * The header at the front of an ACU archive. */ typedef struct AcuMasterHeader { unsigned short fileCount; unsigned short unknown1; // 0x01 00 -- might be "version 1?" unsigned char fZink[6]; // "fZink", low ASCII unsigned char unknown2[11]; // 0x01 36 00 00 00 00 00 00 00 00 dd } AcuMasterHeader; /* * An entry in an ACU archive. Each archive is essentially a stream * of files; only the "filesToFollow" value gives any indication that * something else follows this entry. * * We read this from the archive and then unpack the interesting parts * into GenericEntry fields in an AcuEntry. */ struct AcuFileEntry; friend struct AcuFileEntry; typedef struct AcuFileEntry { unsigned char compressionType; unsigned short dataChecksum; // ?? unsigned short blockCount; // total blocks req'd to hold file unsigned long dataStorageLen; // length of data within archive unsigned short access; unsigned short fileType; unsigned long auxType; unsigned char storageType; unsigned long dataEof; unsigned short prodosModDate; unsigned short prodosModTime; NuDateTime modWhen; // computed from previous two fields unsigned short prodosCreateDate; unsigned short prodosCreateTime; NuDateTime createWhen; // computed from previous two fields unsigned short fileNameLen; unsigned short headerChecksum; // ?? char fileName[kAcuMaxFileName+1]; // possibilities for mystery fields: // - OS type (note ProDOS is $00) // - forked file support } AcuFileEntry; /* known compression types */ enum CompressionType { kAcuCompNone = 0, kAcuCompSqueeze = 3, }; int LoadContents(void); int ReadMasterHeader(int* pNumEntries); NuError ReadFileHeader(AcuFileEntry* pEntry); void DumpFileHeader(const AcuFileEntry* pEntry); int CreateEntry(const AcuFileEntry* pEntry); bool IsDir(const AcuFileEntry* pEntry); NuError AcuRead(void* buf, size_t nbyte); NuError AcuSeek(long offset); void AcuConvertDateTime(unsigned short prodosDate, unsigned short prodosTime, NuDateTime* pWhen); FILE* fFp; bool fIsReadOnly; }; #endif /*APP_ACUARCHIVE_H*/