mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-29 20:49:27 +00:00
4235b47748
Windows' default behavior is apparently to fill the display with the app window, capped at 1920x1200. This is annoyingly large for most situations. We now save the main window rect (LTRB) and maximization status in the configuration area of the registry. The window placement calls are supposed to do something reasonable when the window would be completely off-screen (e.g. because a secondary monitor was disabled).
947 lines
32 KiB
C++
947 lines
32 KiB
C++
/*
|
|
* CiderPress
|
|
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
|
|
* See the file LICENSE for distribution terms.
|
|
*/
|
|
/*
|
|
* Application UI classes.
|
|
*/
|
|
#ifndef APP_MAIN_H
|
|
#define APP_MAIN_H
|
|
|
|
#include "ContentList.h"
|
|
#include "GenericArchive.h"
|
|
#include "PrefsDialog.h"
|
|
#include "ActionProgressDialog.h"
|
|
#include "ProgressCounterDialog.h"
|
|
#include "AddFilesDialog.h"
|
|
#include "ExtractOptionsDialog.h"
|
|
#include "ConvFileOptionsDialog.h"
|
|
#include "DiskConvertDialog.h"
|
|
#include "FileNameConv.h"
|
|
//#include "ProgressCancelDialog.h"
|
|
|
|
/* user-defined window messages */
|
|
#define WMU_LATE_INIT (WM_USER+0)
|
|
#define WMU_START (WM_USER+1) // used by ActionProgressDialog
|
|
|
|
// The filter index is saved in the registry, so if you reorder this list
|
|
// you will briefly annoy existing users.
|
|
enum FilterIndex {
|
|
kFilterIndexFIRST = 1, // first index, must be non-Generic
|
|
kFilterIndexNuFX = 1,
|
|
kFilterIndexBinaryII = 2,
|
|
kFilterIndexACU = 3,
|
|
kFilterIndexAppleSingle = 4,
|
|
kFilterIndexDiskImage = 5,
|
|
kFilterIndexLASTNG = 5, // last non-Generic index
|
|
|
|
kFilterIndexGeneric = 6, // *.* filter used
|
|
kFilterIndexMAX = 6 // highest valid number
|
|
};
|
|
|
|
struct FileCollectionEntry; // fwd
|
|
|
|
/*
|
|
* The main UI window.
|
|
*/
|
|
class MainWindow : public CFrameWnd
|
|
{
|
|
public:
|
|
MainWindow(void);
|
|
~MainWindow(void);
|
|
|
|
/*
|
|
* Override the pre-create function to tweak the window style.
|
|
*/
|
|
virtual BOOL PreCreateWindow(CREATESTRUCT& cs) override;
|
|
|
|
/*
|
|
* Override GetClientRect so we can factor in the status and tool bars.
|
|
*
|
|
* (The method in question isn't declared virtual, so we're not actually
|
|
* overriding it.)
|
|
*/
|
|
void GetClientRect(LPRECT lpRect) const;
|
|
|
|
// get a pointer to the preferences
|
|
const Preferences* GetPreferences(void) const { return &fPreferences; }
|
|
Preferences* GetPreferencesWr(void) { return &fPreferences; }
|
|
// apply an update from the Preferences pages
|
|
void ApplyNow(PrefsSheet*);
|
|
|
|
// get the text of the next file in the selection list
|
|
//int GetPrevFileText(ReformatHolder* pHolder, CString* pTitle);
|
|
//int GetNextFileText(ReformatHolder* pHolder, CString* pTitle);
|
|
|
|
// update the progress meter
|
|
void SetProgressBegin(void);
|
|
int SetProgressUpdate(int percent, const WCHAR* oldName,
|
|
const WCHAR* newName);
|
|
void SetProgressEnd(void);
|
|
|
|
/*
|
|
* Set a number in the "progress counter". Useful for loading large archives
|
|
* where we're not sure how much stuff is left, so showing a percentage is
|
|
* hard.
|
|
*
|
|
* Pass in -1 to erase the counter.
|
|
*
|
|
* Returns "true" if we'd like things to continue.
|
|
*/
|
|
bool SetProgressCounter(const WCHAR* fmt, long val);
|
|
|
|
/*
|
|
* Handle a double-click in the content view.
|
|
*
|
|
* Individual items get special treatment, multiple items just get handed off
|
|
* to the file viewer.
|
|
*/
|
|
void HandleDoubleClick(void);
|
|
|
|
// do some idle processing
|
|
void DoIdle(void);
|
|
|
|
/*
|
|
* Come up with a title to put at the top of a printout. This is essentially
|
|
* the same as the window title, but without some flags (e.g. "read-only").
|
|
*/
|
|
CString GetPrintTitle(void);
|
|
|
|
// raise flag to abort the current print job
|
|
void SetAbortPrinting(bool val) { fAbortPrinting = val; }
|
|
bool GetAbortPrinting(void) const { return fAbortPrinting; }
|
|
|
|
/*
|
|
* Printer abort procedure; allows us to abort a print job. The DC
|
|
* SetAbortProc() function calls here periodically. The return value from
|
|
* this function determine whether or not printing halts.
|
|
*
|
|
* This checks a global "print cancel" variable, which is set by our print
|
|
* cancel button dialog.
|
|
*
|
|
* If this returns TRUE, printing continues; FALSE, and printing aborts.
|
|
*/
|
|
static BOOL CALLBACK PrintAbortProc(HDC hDC, int nCode);
|
|
|
|
bool fAbortPrinting;
|
|
// track printer choice
|
|
HANDLE fhDevMode;
|
|
HANDLE fhDevNames;
|
|
|
|
// set flag to abort current operation
|
|
//void SetAbortOperation(bool val) { fAbortOperation = val; }
|
|
//bool fAbortOperation;
|
|
|
|
/*
|
|
* Go to sleep for a little bit, waking up 100x per second to check
|
|
* the idle loop. Used for debugging.
|
|
*/
|
|
void EventPause(int duration);
|
|
|
|
ContentList* GetContentList(void) const { return fpContentList; }
|
|
|
|
void SetActionProgressDialog(ActionProgressDialog* pActionProgress) {
|
|
fpActionProgress = pActionProgress;
|
|
}
|
|
void SetProgressCounterDialog(ProgressCounterDialog* pProgressCounter) {
|
|
fpProgressCounter = pProgressCounter;
|
|
}
|
|
GenericArchive* GetOpenArchive(void) const { return fpOpenArchive; }
|
|
|
|
/*
|
|
* Extract every part of the file into "ReformatHolder". Does not try to
|
|
* reformat anything, just extracts the parts.
|
|
*
|
|
* Returns IDOK on success, IDCANCEL if the user cancelled, or -1 on error.
|
|
* On error, the reformatted text buffer gets the error message.
|
|
*/
|
|
int GetFileParts(const GenericEntry* pEntry,
|
|
ReformatHolder** ppHolder) const;
|
|
|
|
/*
|
|
* Allow events to flow through the message queue whenever the
|
|
* progress meter gets updated. This will allow us to redraw with
|
|
* reasonable frequency.
|
|
*
|
|
* Calling this can result in other code being called, such as Windows
|
|
* message handlers, which can lead to reentrancy problems. Make sure
|
|
* you're adequately semaphored before calling here.
|
|
*
|
|
* Returns TRUE if all is well, FALSE if we're trying to quit.
|
|
*/
|
|
BOOL PeekAndPump();
|
|
|
|
/*
|
|
* After successful completion of a command, make a happy noise (but only
|
|
* if we're configured to do so).
|
|
*/
|
|
void SuccessBeep(void);
|
|
|
|
/*
|
|
* If something fails, make noise if we're configured for loudness.
|
|
*/
|
|
void FailureBeep(void);
|
|
|
|
/*
|
|
* Remove a file. Returns a helpful error string on failure.
|
|
*
|
|
* The absence of the file is not considered an error.
|
|
*/
|
|
CString RemoveFile(const WCHAR* fileName);
|
|
|
|
/*
|
|
* Figure out where they want to add files.
|
|
*
|
|
* If the volume directory of a disk is chosen, *ppTargetSubdir will
|
|
* be set to NULL.
|
|
*/
|
|
bool ChooseAddTarget(DiskImgLib::A2File** ppTargetSubdir,
|
|
DiskImgLib::DiskFS** ppDiskFS);
|
|
|
|
/*
|
|
* Put up the ImageFormatDialog and apply changes to "pImg".
|
|
*
|
|
* "*pDisplayFormat" gets the result of user changes to the display format.
|
|
* If "pDisplayFormat" is NULL, the "query image format" feature will be
|
|
* disabled.
|
|
*
|
|
* Returns IDCANCEL if the user cancelled out of the dialog, IDOK otherwise.
|
|
* On error, "*pErrMsg" will be non-empty.
|
|
*/
|
|
int TryDiskImgOverride(DiskImg* pImg, const WCHAR* fileSource,
|
|
DiskImg::FSFormat defaultFormat, int* pDisplayFormat,
|
|
bool allowUnknown, CString* pErrMsg);
|
|
|
|
/*
|
|
* Do a block copy or track copy from one disk image to another.
|
|
*
|
|
* If "bulk" is set, warning dialogs are suppressed. If "partial" is set,
|
|
* copies between volumes of different sizes are allowed.
|
|
*/
|
|
DIError CopyDiskImage(DiskImg* pDstImg, DiskImg* pSrcImg, bool bulk,
|
|
bool partial, ProgressCancelDialog* pPCDialog);
|
|
|
|
// Determine whether path matches the pathname of the currently open archive.
|
|
bool IsOpenPathName(const WCHAR* path);
|
|
|
|
// raise a flag to cause a full reload of the open file
|
|
void SetReopenFlag(void) { fNeedReopen = true; }
|
|
|
|
/*
|
|
* Configure a ReformatHolder based on the current preferences.
|
|
*/
|
|
static void ConfigureReformatFromPreferences(ReformatHolder* pReformat);
|
|
|
|
/*
|
|
* Convert a DiskImg format spec into a ReformatHolder SourceFormat.
|
|
*/
|
|
static ReformatHolder::SourceFormat ReformatterSourceFormat(DiskImg::FSFormat format);
|
|
|
|
/*
|
|
* Saves a buffer of data as a file in a disk image or file archive.
|
|
* Utility function used by cassette import.
|
|
*
|
|
* May modify contents of *pDetails.
|
|
*
|
|
* On failure, returns with an error message in errMsg.
|
|
*/
|
|
static bool SaveToArchive(GenericArchive::LocalFileDetails* pDetails,
|
|
const uint8_t* dataBuf, long dataLen,
|
|
const uint8_t* rsrcBuf, long rsrcLen,
|
|
CString* pErrMsg, CWnd* pDialog);
|
|
|
|
static const WCHAR kOpenNuFX[];
|
|
static const WCHAR kOpenBinaryII[];
|
|
static const WCHAR kOpenACU[];
|
|
static const WCHAR kOpenAppleSingle[];
|
|
static const WCHAR kOpenDiskImage[];
|
|
static const WCHAR kOpenAll[];
|
|
static const WCHAR kOpenEnd[];
|
|
|
|
private:
|
|
static const WCHAR kModeNuFX[];
|
|
static const WCHAR kModeBinaryII[];
|
|
static const WCHAR kModeACU[];
|
|
static const WCHAR kModeAppleSingle[];
|
|
static const WCHAR kModeDiskImage[];
|
|
|
|
// Command handlers
|
|
afx_msg int OnCreate(LPCREATESTRUCT lpcs);
|
|
afx_msg void OnClose();
|
|
afx_msg LONG OnLateInit(UINT, LONG);
|
|
afx_msg void OnSize(UINT nType, int cx, int cy);
|
|
afx_msg void OnGetMinMaxInfo(MINMAXINFO* pMMI);
|
|
afx_msg void OnPaint(void);
|
|
afx_msg void OnSetFocus(CWnd* pOldWnd);
|
|
afx_msg BOOL OnHelpInfo(HELPINFO* lpHelpInfo);
|
|
afx_msg BOOL OnQueryEndSession(void);
|
|
afx_msg void OnEndSession(BOOL bEnding);
|
|
afx_msg LRESULT OnFindDialogMessage(WPARAM wParam, LPARAM lParam);
|
|
afx_msg void OnFileNewArchive(void);
|
|
afx_msg void OnFileOpen(void);
|
|
afx_msg void OnFileOpenVolume(void);
|
|
afx_msg void OnUpdateFileOpenVolume(CCmdUI* pCmdUI);
|
|
afx_msg void OnFileReopen(void);
|
|
afx_msg void OnUpdateFileReopen(CCmdUI* pCmdUI);
|
|
afx_msg void OnFileSave(void);
|
|
afx_msg void OnUpdateFileSave(CCmdUI* pCmdUI);
|
|
afx_msg void OnFileClose(void);
|
|
afx_msg void OnUpdateFileClose(CCmdUI* pCmdUI);
|
|
afx_msg void OnFileArchiveInfo(void);
|
|
afx_msg void OnUpdateFileArchiveInfo(CCmdUI* pCmdUI);
|
|
afx_msg void OnFilePrint(void);
|
|
afx_msg void OnUpdateFilePrint(CCmdUI* pCmdUI);
|
|
afx_msg void OnFileExit(void);
|
|
|
|
/*
|
|
* Copy data to the clipboard.
|
|
*/
|
|
afx_msg void OnEditCopy(void);
|
|
afx_msg void OnUpdateEditCopy(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Paste data from the clipboard, using the configured defaults.
|
|
*/
|
|
afx_msg void OnEditPaste(void);
|
|
afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Paste data from the clipboard, giving the user the opportunity to select
|
|
* how the files are handled.
|
|
*/
|
|
afx_msg void OnEditPasteSpecial(void);
|
|
afx_msg void OnUpdateEditPasteSpecial(CCmdUI* pCmdUI);
|
|
|
|
afx_msg void OnEditFind(void);
|
|
afx_msg void OnUpdateEditFind(CCmdUI* pCmdUI);
|
|
afx_msg void OnEditSelectAll(void);
|
|
afx_msg void OnUpdateEditSelectAll(CCmdUI* pCmdUI);
|
|
afx_msg void OnEditInvertSelection(void);
|
|
afx_msg void OnUpdateEditInvertSelection(CCmdUI* pCmdUI);
|
|
afx_msg void OnEditPreferences(void);
|
|
afx_msg void OnEditSort(UINT id);
|
|
afx_msg void OnUpdateEditSort(CCmdUI* pCmdUI);
|
|
/*
|
|
* View a file stored in the archive.
|
|
*
|
|
* Control bounces back through Get*FileText() to get the actual
|
|
* data to view.
|
|
*/
|
|
afx_msg void OnActionsView(void);
|
|
afx_msg void OnUpdateActionsView(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* View a file stored in the archive.
|
|
*
|
|
* Control bounces back through Get*FileText() to get the actual
|
|
* data to view.
|
|
*/
|
|
afx_msg void OnActionsOpenAsDisk(void);
|
|
afx_msg void OnUpdateActionsOpenAsDisk(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Add files to an archive.
|
|
*/
|
|
afx_msg void OnActionsAddFiles(void);
|
|
afx_msg void OnUpdateActionsAddFiles(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Add a disk to an archive. Not all archive formats support disk images.
|
|
*
|
|
* We open a single disk archive file as a DiskImg, get the format
|
|
* figured out, then write it block-by-block into a file chosen by the user.
|
|
* Standard open/save dialogs work fine here.
|
|
*/
|
|
afx_msg void OnActionsAddDisks(void);
|
|
afx_msg void OnUpdateActionsAddDisks(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Create a subdirectory inside another subdirectory (or volume directory).
|
|
*
|
|
* Simply asserting that an existing subdir be selected in the list does
|
|
* away with all sorts of testing. Creating subdirs on DOS disks and NuFX
|
|
* archives is impossible because neither has subdirs. Nested volumes are
|
|
* selected for us by the user.
|
|
*/
|
|
afx_msg void OnActionsCreateSubdir(void);
|
|
afx_msg void OnUpdateActionsCreateSubdir(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Extract files.
|
|
*/
|
|
afx_msg void OnActionsExtract(void);
|
|
afx_msg void OnUpdateActionsExtract(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Test files.
|
|
*/
|
|
afx_msg void OnActionsTest(void);
|
|
afx_msg void OnUpdateActionsTest(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Delete archive entries.
|
|
*/
|
|
afx_msg void OnActionsDelete(void);
|
|
afx_msg void OnUpdateActionsDelete(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Rename archive entries. Depending on the structure of the underlying
|
|
* archive, we may only allow the user to alter the filename component.
|
|
* Anything else would constitute moving the file around in the filesystem.
|
|
*/
|
|
afx_msg void OnActionsRename(void);
|
|
afx_msg void OnUpdateActionsRename(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Edit a comment, creating it if necessary.
|
|
*/
|
|
afx_msg void OnActionsEditComment(void);
|
|
afx_msg void OnUpdateActionsEditComment(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Edit file properties.
|
|
*
|
|
* This causes a reload of the list, which isn't really necessary. We
|
|
* do need to re-evaluate the sort order if one of the fields they modified
|
|
* is the current sort key, but it would be nice if we could at least retain
|
|
* the selection. Since we're not reloading the GenericArchive, we *can*
|
|
* remember the selection.
|
|
*/
|
|
afx_msg void OnActionsEditProps(void);
|
|
afx_msg void OnUpdateActionsEditProps(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Change a volume name or volume number.
|
|
*/
|
|
afx_msg void OnActionsRenameVolume(void);
|
|
afx_msg void OnUpdateActionsRenameVolume(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Recompress files.
|
|
*/
|
|
afx_msg void OnActionsRecompress(void);
|
|
afx_msg void OnUpdateActionsRecompress(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Select files to convert.
|
|
*/
|
|
afx_msg void OnActionsConvDisk(void);
|
|
afx_msg void OnUpdateActionsConvDisk(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Select files to convert.
|
|
*/
|
|
afx_msg void OnActionsConvFile(void);
|
|
afx_msg void OnUpdateActionsConvFile(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Convert BAS, INT, or BIN to a cassette-audio WAV file.
|
|
* (not implemented)
|
|
*/
|
|
afx_msg void OnActionsConvToWav(void);
|
|
afx_msg void OnUpdateActionsConvToWav(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Convert a WAV file with a digitized Apple II cassette tape into an
|
|
* Apple II file, and add it to the current disk.
|
|
*/
|
|
afx_msg void OnActionsConvFromWav(void);
|
|
afx_msg void OnUpdateActionsConvFromWav(CCmdUI* pCmdUI);
|
|
|
|
/*
|
|
* Import an Applesoft BASIC program from a text file.
|
|
*
|
|
* We currently allow the user to select a single file for import. Someday
|
|
* we may want to allow multi-file import.
|
|
*/
|
|
afx_msg void OnActionsImportBAS(void);
|
|
afx_msg void OnUpdateActionsImportBAS(CCmdUI* pCmdUI);
|
|
|
|
// edit a disk
|
|
afx_msg void OnToolsDiskEdit(void);
|
|
// convert a disk image from one format to another
|
|
afx_msg void OnToolsDiskConv(void);
|
|
// bulk disk conversion
|
|
afx_msg void OnToolsBulkDiskConv(void);
|
|
// merge two SST images into a single NIB image
|
|
afx_msg void OnToolsSSTMerge(void);
|
|
afx_msg void OnToolsVolumeCopierVolume(void);
|
|
afx_msg void OnToolsVolumeCopierFile(void);
|
|
// scan and report on the end-of-line markers found in a file
|
|
afx_msg void OnToolsEOLScanner(void);
|
|
// edit the properties (but not the disk image inside) a .2MG disk image
|
|
afx_msg void OnToolsTwoImgProps(void);
|
|
// create a new disk image
|
|
afx_msg void OnToolsDiskImageCreator(void);
|
|
afx_msg void OnHelpContents(void);
|
|
afx_msg void OnHelpWebSite(void);
|
|
afx_msg void OnHelpOrdering(void);
|
|
afx_msg void OnHelpAbout(void);
|
|
afx_msg void OnRtClkDefault(void);
|
|
|
|
// Handle command-line arguments.
|
|
void ProcessCommandLine(void);
|
|
|
|
void ResizeClientArea(void);
|
|
|
|
/*
|
|
* Draw what looks like an empty client area.
|
|
*/
|
|
void DrawEmptyClientArea(CDC* pDC, const CRect& clientRect);
|
|
|
|
/*
|
|
* Save/restore main window placement. The restore function will move
|
|
* the window if the previous placement is no longer visible (e.g. a
|
|
* secondary monitor was removed).
|
|
*/
|
|
void SaveWinPlacement();
|
|
void RestoreWinPlacement();
|
|
|
|
/*
|
|
* Extract a record to the temp folder and open it with a new instance of
|
|
* CiderPress. We might want to extract disk images as 2MG files to take
|
|
* the mystery out of opening them, but since they're coming out of a
|
|
* ShrinkIt archive they're pretty un-mysterious anyway.
|
|
*
|
|
* We tell the new instance to open it read-only, and flag it for
|
|
* deletion on exit.
|
|
*
|
|
* Returns 0 on success, nonzero error status on failure.
|
|
*/
|
|
int TmpExtractAndOpen(GenericEntry* pEntry, int threadKind,
|
|
const WCHAR* modeStr);
|
|
|
|
/*
|
|
* Extract a record to the temp folder and open it with an external viewer.
|
|
* The file must be created with the correct extension so ShellExecute
|
|
* does the right thing.
|
|
*
|
|
* The files will be added to the "delete on exit" list, so that they will
|
|
* be cleaned up when CiderPress exits (assuming the external viewer no longer
|
|
* has them open).
|
|
*
|
|
* The GetTempFileName function creates a uniquely-named temp file. We
|
|
* create a file that has that name plus an extension. To ensure that we
|
|
* don't try to use the same temp filename twice, we have to hold off on
|
|
* deleting the unused .tmp files until we're ready to delete the
|
|
* corresponding .gif (or whatever) files. Thus, each invocation of this
|
|
* function creates two files and two entries in the delete-on-exit set.
|
|
*
|
|
* Returns 0 on success, nonzero error status on failure.
|
|
*/
|
|
int TmpExtractForExternal(GenericEntry* pEntry);
|
|
|
|
void DoOpenArchive(const WCHAR* pathName, const WCHAR* ext,
|
|
FilterIndex filterIndex, bool readOnly);
|
|
|
|
GenericArchive* CreateArchiveInstance(FilterIndex filterIndex) const;
|
|
|
|
/*
|
|
* 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, 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,
|
|
FilterIndex filterIndex, bool readOnly);
|
|
|
|
/*
|
|
* Open a raw disk volume. Useful for ProDOS-formatted 1.44MB floppy disks
|
|
* and CFFA flash cards.
|
|
*
|
|
* Assume it's a disk image -- it'd be a weird place for a ShrinkIt archive.
|
|
* CFFA cards can actually hold multiple volumes, but that's all taken care
|
|
* of inside the diskimg DLL.
|
|
*
|
|
* Returns 0 on success, nonzero on failure.
|
|
*/
|
|
int DoOpenVolume(CString drive, bool readOnly);
|
|
|
|
/*
|
|
* Switch the content list to a new archive, closing the previous if one
|
|
* was already open.
|
|
*/
|
|
void SwitchContentList(GenericArchive* pOpenArchive);
|
|
|
|
/*
|
|
* Close the existing archive file, but don't try to shut down the child
|
|
* windows. This should only be used from the destructor.
|
|
*/
|
|
void CloseArchiveWOControls(void);
|
|
|
|
/*
|
|
* Close the existing archive file, and throw out the control we're
|
|
* using to display it.
|
|
*/
|
|
void CloseArchive(void);
|
|
|
|
/*
|
|
* Set the title bar on the main window.
|
|
*
|
|
* "pathname" is often different from pOpenArchive->GetPathName(), especially
|
|
* when we were launched from another instance of CiderPress and handed a
|
|
* temp file whose name we're trying to conceal.
|
|
*/
|
|
void SetCPTitle(const WCHAR* pathname, GenericArchive* pArchive);
|
|
|
|
/*
|
|
* Set the title bar to something boring when nothing is open.
|
|
*/
|
|
void SetCPTitle(void);
|
|
|
|
/*
|
|
* Get the one selected item from the current display. Primarily useful
|
|
* for the double-click handler, but also used for "action" menu items
|
|
* that insist on operating on a single menu item (edit prefs, create subdir).
|
|
*
|
|
* Returns NULL if the item couldn't be found or if more than one item was
|
|
* selected.
|
|
*/
|
|
GenericEntry* GetSelectedItem(ContentList* pContentList);
|
|
|
|
/*
|
|
* Handle a request to view stuff.
|
|
*
|
|
* If "query" pref is set, we ask the user to confirm some choices. If
|
|
* not, we just go with the defaults.
|
|
*
|
|
* We include "damaged" files so that we can show the user a nice message
|
|
* about how the file is damaged.
|
|
*/
|
|
void HandleView(void);
|
|
|
|
//void DeleteFileOnExit(const WCHAR* name);
|
|
|
|
/*
|
|
* Close and re-open the current archive.
|
|
*/
|
|
void ReopenArchive(void);
|
|
|
|
/*
|
|
* ===== Actions.cpp =====
|
|
*/
|
|
|
|
/*
|
|
* Load the requested part.
|
|
*/
|
|
void GetFilePart(const GenericEntry* pEntry, int whichThread,
|
|
ReformatHolder* pHolder) const;
|
|
|
|
/*
|
|
* Handle a bulk extraction.
|
|
*/
|
|
void DoBulkExtract(SelectionSet* pSelSet,
|
|
const ExtractOptionsDialog* pExtOpts);
|
|
|
|
/*
|
|
* Extract a single entry.
|
|
*
|
|
* If pHolder is non-NULL, it holds the data from the file, and can be
|
|
* used for formatted or non-formatted output. If it's NULL, we need to
|
|
* extract the data ourselves.
|
|
*
|
|
* Returns true on success, false on failure.
|
|
*/
|
|
bool ExtractEntry(GenericEntry* pEntry, int thread,
|
|
ReformatHolder* pHolder, const ExtractOptionsDialog* pExtOpts,
|
|
bool* pOverwriteExisting, bool* pOvwrForAll);
|
|
|
|
/*
|
|
* Open an output file.
|
|
*
|
|
* "outputPath" holds the name of the file to create. "origPath" is the
|
|
* name as it was stored in the archive. "pOverwriteExisting" tells us
|
|
* if we should just go ahead and overwrite the existing file, while
|
|
* "pOvwrForAll" tells us if a "To All" button was hit previously.
|
|
*
|
|
* If the file exists, *pOverwriteExisting is false, and *pOvwrForAll
|
|
* is false, then we will put up the "do you want to overwrite?" dialog.
|
|
* One possible outcome of the dialog is renaming the output path.
|
|
*
|
|
* On success, *pFp will be non-NULL, and IDOK will be returned. On
|
|
* failure, IDCANCEL will be returned. The values in *pOverwriteExisting
|
|
* and *pOvwrForAll may be updated, and *pOutputPath will change if
|
|
* the user chose to rename the file.
|
|
*/
|
|
int OpenOutputFile(CString* pOutputPath, const PathProposal& pathProp,
|
|
time_t arcFileModWhen, bool* pOverwriteExisting, bool* pOvwrForAll,
|
|
FILE** pFp);
|
|
|
|
bool DoBulkRecompress(ActionProgressDialog* pActionProgress,
|
|
SelectionSet* pSelSet, const RecompressOptionsDialog* pRecompOpts);
|
|
|
|
/*
|
|
* Compute the total size of all files in the GenericArchive.
|
|
*/
|
|
void CalcTotalSize(LONGLONG* pUncomp, LONGLONG* pComp) const;
|
|
|
|
/*
|
|
* Print a ContentList.
|
|
*/
|
|
void PrintListing(const ContentList* pContentList);
|
|
|
|
/*
|
|
* ===== Clipboard.cpp =====
|
|
*/
|
|
|
|
/*
|
|
* Create a list of selected files.
|
|
*
|
|
* The returned string uses tab-delineated fields with CSV-style quoting
|
|
* around the filename (so that double quotes in the filename don't confuse
|
|
* applications like MS Excel).
|
|
*/
|
|
CString CreateFileList(SelectionSet* pSelSet);
|
|
|
|
/*
|
|
* Double-up all double quotes.
|
|
*/
|
|
static CString DblDblQuote(const WCHAR* str);
|
|
|
|
/*
|
|
* Compute the size of everything currently on the clipboard.
|
|
*/
|
|
long GetClipboardContentLen(void);
|
|
|
|
/*
|
|
* Create the file collection.
|
|
*/
|
|
HGLOBAL CreateFileCollection(SelectionSet* pSelSet);
|
|
|
|
/*
|
|
* Copy the contents of the file referred to by "pEntry" into the buffer
|
|
* "*pBuf", which has "*pBufLen" bytes in it.
|
|
*
|
|
* The call fails if "*pBufLen" isn't large enough.
|
|
*
|
|
* Returns an empty string on success, or an error message on failure.
|
|
* On success, "*pBuf" will be advanced past the data added, and "*pBufLen"
|
|
* will be reduced by the amount of data copied into "buf".
|
|
*/
|
|
CString CopyToCollection(GenericEntry* pEntry, void** pBuf, long* pBufLen);
|
|
|
|
/*
|
|
* Do some prep work and then call ProcessClipboard to copy files in.
|
|
*/
|
|
void DoPaste(bool pasteJunkPaths);
|
|
|
|
/*
|
|
* Process the data in the clipboard.
|
|
*
|
|
* Returns an empty string on success, or an error message on failure.
|
|
*/
|
|
CString ProcessClipboard(const void* vbuf, long bufLen,
|
|
bool pasteJunkPaths);
|
|
|
|
/*
|
|
* Process a single clipboard entry.
|
|
*
|
|
* On entry, "buf" points to the start of the first chunk of data (either
|
|
* data fork or resource fork). If the file has empty forks or is a
|
|
* subdirectory, then "buf" is actually pointing at the start of the
|
|
* next entry.
|
|
*/
|
|
CString ProcessClipboardEntry(const FileCollectionEntry* pCollEnt,
|
|
const WCHAR* pathName, const uint8_t* buf, long remLen);
|
|
|
|
/*
|
|
* ===== Tools.cpp =====
|
|
*/
|
|
|
|
/*
|
|
* Determines the settings we need to pass into DiskImgLib to create the
|
|
* desired disk image format.
|
|
*
|
|
* Returns 0 on success, -1 on failure.
|
|
*/
|
|
int DetermineImageSettings(int convertIdx, bool addGzip,
|
|
DiskImg::OuterFormat* pOuterFormat, DiskImg::FileFormat* pFileFormat,
|
|
DiskImg::PhysicalFormat* pPhysicalFormat,
|
|
DiskImg::SectorOrder* pSectorOrder);
|
|
|
|
/*
|
|
* Converts one image during a bulk conversion.
|
|
*
|
|
* On failure, the reason for failure is stuffed into "*pErrMsg".
|
|
*/
|
|
void BulkConvertImage(const WCHAR* pathName, const WCHAR* targetDir,
|
|
const DiskConvertDialog& convDlg, CString* pErrMsg);
|
|
|
|
/*
|
|
* Opens one of the SST images. Configures "pDiskImg" appropriately.
|
|
*
|
|
* Returns 0 on success, nonzero on failure.
|
|
*/
|
|
int SSTOpenImage(int seqNum, DiskImg* pDiskImg);
|
|
|
|
/*
|
|
* Copies 17.5 tracks of data from the SST image to a .NIB image.
|
|
*
|
|
* Data is stored in all 16 sectors of track 0, followed by the first
|
|
* 12 sectors of track 1, then on to track 2. Total of $1a00 bytes.
|
|
*
|
|
* Returns 0 on success, -1 on failure.
|
|
*/
|
|
int SSTLoadData(int seqNum, DiskImg* pDiskImg, uint8_t* trackBuf,
|
|
long* pBadCount);
|
|
|
|
/*
|
|
* Compute the destination file offset for a particular source track. The
|
|
* track number ranges from 0 to 69 inclusive. Sectors from two adjacent
|
|
* "cooked" tracks are combined into a single "raw nibbilized" track.
|
|
*
|
|
* The data is ordered like this:
|
|
* track 1 sector 15 --> track 1 sector 4 (12 sectors)
|
|
* track 0 sector 13 --> track 0 sector 0 (14 sectors)
|
|
*
|
|
* Total of 26 sectors, or $1a00 bytes.
|
|
*/
|
|
long SSTGetBufOffset(int track);
|
|
|
|
/*
|
|
* Count the number of "bad" bytes in the sector.
|
|
*
|
|
* Strictly speaking, a "bad" byte is anything that doesn't appear in the
|
|
* 6&2 decoding table, 5&3 decoding table, special list (D5, AA), and
|
|
* can't be used as a 4+4 encoding value.
|
|
*
|
|
* We just use $80 - $92, which qualify for all of the above.
|
|
*/
|
|
long SSTCountBadBytes(const uint8_t* sctBuf, int count);
|
|
|
|
/*
|
|
* Run through the data, adding 0x80 everywhere and re-aligning the
|
|
* tracks so that the big clump of sync bytes is at the end.
|
|
*/
|
|
void SSTProcessTrackData(uint8_t* trackBuf);
|
|
|
|
/*
|
|
* Select a volume and then invoke the volcopy dialog.
|
|
*/
|
|
void VolumeCopier(bool openFile);
|
|
|
|
/*
|
|
* Edit the properties of a 2MG file.
|
|
*
|
|
* Returns "true" if the file was modified, "false" if not.
|
|
*/
|
|
bool EditTwoImgProps(const WCHAR* fileName);
|
|
|
|
|
|
// set when one of the tools modifies the file we have open
|
|
bool fNeedReopen;
|
|
|
|
CToolBar fToolBar;
|
|
CStatusBar fStatusBar;
|
|
|
|
// currently-open archive, if any
|
|
GenericArchive* fpOpenArchive;
|
|
// name of open archive, for display only -- if this is a temporary
|
|
// file launched from another instance of CP, this won't be the name
|
|
// of an actual file on disk.
|
|
CString fOpenArchivePathName; // for display only
|
|
|
|
// archive viewer, open when file is open
|
|
// NOTE: make a super-class for a tree-structured display or other
|
|
// kinds of display, so we can avoid the if/then/else. Rename
|
|
// ContentList to DetailList or FlatList or something.
|
|
ContentList* fpContentList;
|
|
|
|
// currently selected set of goodies; used when viewing, extracting, etc.
|
|
//SelectionSet* fpSelSet;
|
|
|
|
// action progress meter, if any
|
|
ActionProgressDialog* fpActionProgress;
|
|
|
|
// progress counter meter, if any
|
|
ProgressCounterDialog* fpProgressCounter;
|
|
|
|
// modeless standard "find" dialog
|
|
CFindReplaceDialog* fpFindDialog;
|
|
CString fFindLastStr;
|
|
bool fFindDown;
|
|
bool fFindMatchCase;
|
|
bool fFindMatchWholeWord;
|
|
|
|
// our preferences
|
|
Preferences fPreferences;
|
|
|
|
/*
|
|
* Manage a list of files that must be deleted before we exit.
|
|
*/
|
|
class DeleteList {
|
|
private:
|
|
class DeleteListNode {
|
|
public:
|
|
DeleteListNode(const CString& name) : fName(name),
|
|
fPrev(NULL), fNext(NULL) {}
|
|
~DeleteListNode(void) {}
|
|
|
|
DeleteListNode* fPrev;
|
|
DeleteListNode* fNext;
|
|
CString fName;
|
|
};
|
|
|
|
public:
|
|
DeleteList(void) { fHead = NULL; }
|
|
~DeleteList(void) {
|
|
LOGD("Processing DeleteList (head=0x%p)", fHead);
|
|
DeleteListNode* pNode = fHead;
|
|
DeleteListNode* pNext;
|
|
|
|
while (pNode != NULL) {
|
|
pNext = pNode->fNext;
|
|
if (_wunlink(pNode->fName) != 0) {
|
|
LOGW(" WARNING: delete of '%ls' failed, err=%d",
|
|
(LPCWSTR) pNode->fName, errno);
|
|
} else {
|
|
LOGI(" Deleted '%ls'", (LPCWSTR) pNode->fName);
|
|
}
|
|
delete pNode;
|
|
pNode = pNext;
|
|
}
|
|
LOGD("Processing DeleteList completed");
|
|
}
|
|
|
|
void Add(const CString& name) {
|
|
DeleteListNode* pNode = new DeleteListNode(name);
|
|
if (fHead != NULL) {
|
|
fHead->fPrev = pNode;
|
|
pNode->fNext = fHead;
|
|
}
|
|
fHead = pNode;
|
|
LOGI("Delete-on-exit '%ls'", (LPCWSTR) name);
|
|
}
|
|
|
|
DeleteListNode* fHead;
|
|
};
|
|
DeleteList fDeleteList;
|
|
|
|
DECLARE_MESSAGE_MAP()
|
|
};
|
|
|
|
#define GET_MAIN_WINDOW() ((MainWindow*)::AfxGetMainWnd())
|
|
|
|
#define SET_PROGRESS_BEGIN() ((MainWindow*)::AfxGetMainWnd())->SetProgressBegin()
|
|
#define SET_PROGRESS_UPDATE(perc) \
|
|
((MainWindow*)::AfxGetMainWnd())->SetProgressUpdate(perc, NULL, NULL)
|
|
#define SET_PROGRESS_UPDATE2(perc, oldName, newName) \
|
|
((MainWindow*)::AfxGetMainWnd())->SetProgressUpdate(perc, oldName, newName)
|
|
#define SET_PROGRESS_END() ((MainWindow*)::AfxGetMainWnd())->SetProgressEnd()
|
|
|
|
#define SET_PROGRESS_COUNTER(val) \
|
|
((MainWindow*)::AfxGetMainWnd())->SetProgressCounter(NULL, val)
|
|
#define SET_PROGRESS_COUNTER_2(fmt, val) \
|
|
((MainWindow*)::AfxGetMainWnd())->SetProgressCounter(fmt, val)
|
|
|
|
#define GET_PREFERENCES() ((MainWindow*)::AfxGetMainWnd())->GetPreferences()
|
|
#define GET_PREFERENCES_WR() ((MainWindow*)::AfxGetMainWnd())->GetPreferencesWr()
|
|
|
|
#endif /*APP_MAIN_H*/
|