ciderpress/app/DiskEditDialog.cpp
Andy McFadden 8c34eb1213 Volume name and font fixes
More volume name MOR conversions.  I think I got them all.

This also switches the "archive info", "add files", and "extract
files" dialogs to use the System Font.  We were using "MS Sans
Serif" before, which looks a bit ratty on Windows 7 because it
doesn't take advantage of ClearType.  (Apparently the ClearType
version is "Microsoft Sans Serif", though when you set the "use
system font" boolean to true it changes the font name to "MS Shell
Dlg".)  The old font also seems to be missing certain glyphs, e.g.
my HFS volume name had 'TM' in it, but that just showed up as a box
(which is why, in case you were wondering, these changes ended up
together).

The new font seems to work equally well on WinXP, so I may enable
it for all dialogs in a follow-up change.  As far as I can tell it
has the same font metrics -- I haven't seen anything weird looking
in the dialogs I've updated so far.

Also, bumped the version to 4.0.0-b3.
2015-01-15 11:35:48 -08:00

1418 lines
40 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Disk editor implementation.
*
* Note to self: it should be possible to open an image in "nibble" mode,
* switch to one of the various "sector" modes, and maybe even try out a
* "block" mode for a while. Locking the editor into one particular mode
* makes for a cumbersome interface when dealing with certain kinds of disks.
* It should also be possible to configure the "custom" NibbleDescr and then
* re-analyze the disk, possibly transferring the customization over to
* the main file listing. (Perhaps the customization affects a global slot?
* Probably want more than one set of custom nibble values, with the config
* dialog accessible from main menu and from within disk editor.)
*
* A track copier would be neat too.
*/
#include "stdafx.h"
#include "SubVolumeDialog.h"
#include "DEFileDialog.h"
#include "DiskEditDialog.h"
#include "../reformat/Charset.h"
/*
* ===========================================================================
* DiskEditDialog (base class)
* ===========================================================================
*/
BEGIN_MESSAGE_MAP(DiskEditDialog, CDialog)
ON_BN_CLICKED(IDC_DISKEDIT_DONE, OnDone)
ON_BN_CLICKED(IDC_DISKEDIT_HEX, OnHexMode)
ON_BN_CLICKED(IDC_DISKEDIT_DOREAD, OnDoRead)
ON_BN_CLICKED(IDC_DISKEDIT_DOWRITE, OnDoWrite)
ON_BN_CLICKED(IDC_DISKEDIT_PREV, OnReadPrev)
ON_BN_CLICKED(IDC_DISKEDIT_NEXT, OnReadNext)
ON_BN_CLICKED(IDC_DISKEDIT_SUBVOLUME, OnSubVolume)
ON_BN_CLICKED(IDC_DISKEDIT_OPENFILE, OnOpenFile)
ON_BN_CLICKED(IDHELP, OnHelp)
ON_CBN_SELCHANGE(IDC_DISKEDIT_NIBBLE_PARMS, OnNibbleParms)
ON_WM_HELPINFO()
END_MESSAGE_MAP()
BOOL DiskEditDialog::OnInitDialog(void)
{
ASSERT(!fFileName.IsEmpty());
ASSERT(fpDiskFS != NULL);
/*
* Disable the write button.
*/
if (fReadOnly) {
CButton* pButton = (CButton*) GetDlgItem(IDC_DISKEDIT_DOWRITE);
ASSERT(pButton != NULL);
pButton->EnableWindow(FALSE);
}
/*
* Use modified spin controls so we're not limited to 16 bits.
*/
ReplaceSpinCtrl(&fTrackSpinner, IDC_DISKEDIT_TRACKSPIN,
IDC_DISKEDIT_TRACK);
ReplaceSpinCtrl(&fSectorSpinner, IDC_DISKEDIT_SECTORSPIN,
IDC_DISKEDIT_SECTOR);
/*
* Configure the RichEdit control.
*/
CRichEditCtrl* pEdit = (CRichEditCtrl*) GetDlgItem(IDC_DISKEDIT_EDIT);
ASSERT(pEdit != NULL);
/* set the font to 10-point Courier New */
CHARFORMAT cf;
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask = CFM_FACE | CFM_SIZE;
wcscpy(cf.szFaceName, L"Courier New");
cf.yHeight = 10 * 20; // point size in twips
BOOL cc = pEdit->SetDefaultCharFormat(cf);
if (cc == FALSE) {
LOGI("SetDefaultCharFormat failed?");
ASSERT(FALSE);
}
/* set to read-only */
pEdit->SetReadOnly();
/* retain the selection even if we lose focus [can't do this in OnInit] */
pEdit->SetOptions(ECOOP_OR, ECO_SAVESEL);
/*
* Disable the sub-volume and/or file open buttons if the DiskFS doesn't
* have the appropriate stuff inside.
*/
if (fpDiskFS->GetNextFile(NULL) == NULL) {
CWnd* pWnd = GetDlgItem(IDC_DISKEDIT_OPENFILE);
pWnd->EnableWindow(FALSE);
}
if (fpDiskFS->GetNextSubVolume(NULL) == NULL) {
CWnd* pWnd = GetDlgItem(IDC_DISKEDIT_SUBVOLUME);
pWnd->EnableWindow(FALSE);
}
/*
* Configure the nibble parm drop-list in an appropriate fashion.
*/
InitNibbleParmList();
/*
* If this is a sub-volume edit window, pop us up slightly offset from the
* parent window so the user can see that there's more than one thing
* open.
*/
if (fPositionShift != 0) {
CRect rect;
GetWindowRect(&rect);
rect.top += fPositionShift;
rect.left += fPositionShift;
rect.bottom += fPositionShift;
rect.right += fPositionShift;
MoveWindow(&rect);
}
/*
* Set the window title.
*/
CString title("Disk Viewer - ");
title += fFileName;
if (fpDiskFS->GetVolumeID() != NULL) {
title += " (";
CStringA volumeIdA(fpDiskFS->GetVolumeID());
title += Charset::ConvertMORToUNI(volumeIdA);
title += ")";
}
SetWindowText(title);
return TRUE;
}
void DiskEditDialog::InitNibbleParmList(void)
{
ASSERT(fpDiskFS != NULL);
DiskImg* pDiskImg = fpDiskFS->GetDiskImg();
CComboBox* pCombo;
pCombo = (CComboBox*) GetDlgItem(IDC_DISKEDIT_NIBBLE_PARMS);
ASSERT(pCombo != NULL);
if (pDiskImg->GetHasNibbles()) {
const DiskImg::NibbleDescr* pTable;
const DiskImg::NibbleDescr* pCurrent;
int i, count;
pTable = pDiskImg->GetNibbleDescrTable(&count);
if (pTable == NULL || count <= 0) {
LOGI("WHOOPS: nibble parm got table=0x%08lx, count=%d",
(long) pTable, count);
return;
}
pCurrent = pDiskImg->GetNibbleDescr();
/* configure the selection to match the disk analysis */
int dflt = -1;
if (pCurrent != NULL) {
for (i = 0; i < count; i++) {
if (memcmp(&pTable[i], pCurrent, sizeof(*pCurrent)) == 0) {
LOGI(" NibbleParm match on entry %d", i);
dflt = i;
break;
}
}
if (dflt == -1) {
LOGI(" GLITCH: no match on nibble descr in table?!");
dflt = 0;
}
}
for (i = 0; i < count; i++) {
if (pTable[i].numSectors > 0) {
CString description(pTable[i].description);
pCombo->AddString(description);
} else {
/* only expecting this on the last, "custom" entry */
ASSERT(i == count-1);
}
}
pCombo->SetCurSel(dflt);
} else {
pCombo->AddString(L"Nibble Parms");
pCombo->SetCurSel(0);
pCombo->EnableWindow(FALSE);
}
}
int DiskEditDialog::ReplaceSpinCtrl(MySpinCtrl* pNewSpin, int idSpin, int idEdit)
{
CSpinButtonCtrl* pSpin;
// CRect rect;
DWORD style;
pSpin = (CSpinButtonCtrl*)GetDlgItem(idSpin);
if (pSpin == NULL)
return -1;
// pSpin->GetWindowRect(&rect);
// ScreenToClient(&rect);
style = pSpin->GetStyle();
style &= ~(UDS_SETBUDDYINT);
//style |= UDS_AUTOBUDDY;
ASSERT(!(style & UDS_AUTOBUDDY));
pSpin->DestroyWindow();
pNewSpin->Create(style, CRect(0,0,0,0), this, idSpin);
pNewSpin->SetBuddy(GetDlgItem(idEdit));
return 0;
}
BOOL DiskEditDialog::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN &&
pMsg->wParam == VK_RETURN)
{
//LOGI("RETURN!");
LoadData();
return TRUE;
}
return CDialog::PreTranslateMessage(pMsg);
}
void DiskEditDialog::OnDone(void)
{
LOGI("DiskEditDialog OnDone");
EndDialog(IDOK);
}
void DiskEditDialog::OnHexMode(void)
{
int base;
CButton* pButton = (CButton*) GetDlgItem(IDC_DISKEDIT_HEX);
ASSERT(pButton != NULL);
if (pButton->GetCheck() == 0)
base = 10;
else
base = 16;
SetSpinMode(IDC_DISKEDIT_TRACKSPIN, base);
SetSpinMode(IDC_DISKEDIT_SECTORSPIN, base);
}
void DiskEditDialog::OnSubVolume(void)
{
SubVolumeDialog subv(this);
bool showAsBlocks;
subv.Setup(fpDiskFS);
if (subv.DoModal() == IDOK) {
LOGI("SELECTED subv %d", subv.fListBoxIndex);
DiskFS::SubVolume* pSubVol = fpDiskFS->GetNextSubVolume(NULL);
if (pSubVol == NULL)
return;
while (subv.fListBoxIndex-- > 0) {
pSubVol = fpDiskFS->GetNextSubVolume(pSubVol);
}
ASSERT(pSubVol != NULL);
BlockEditDialog blockEdit;
SectorEditDialog sectorEdit;
DiskEditDialog* pEditDialog;
showAsBlocks = pSubVol->GetDiskImg()->ShowAsBlocks();
if (showAsBlocks)
pEditDialog = &blockEdit;
else
pEditDialog = &sectorEdit;
CStringA volumeIdA(fpDiskFS->GetVolumeID());
CString volumeId(Charset::ConvertMORToUNI(volumeIdA));
pEditDialog->Setup(pSubVol->GetDiskFS(), volumeId);
pEditDialog->SetPositionShift(8);
(void) pEditDialog->DoModal();
}
}
void DiskEditDialog::SetSpinMode(int id, int base)
{
CString valStr;
ASSERT(base == 10 || base == 16);
MySpinCtrl* pSpin = (MySpinCtrl*) GetDlgItem(id);
if (pSpin == NULL) {
// expected behavior in "block" mode for sector button
LOGI("Couldn't find spin button %d", id);
return;
}
long val = pSpin->GetPos();
if (val & 0xff000000) {
LOGI("NOTE: hex transition while value is invalid");
val = 0;
}
if (base == 10)
valStr.Format(L"%d", val);
else
valStr.Format(L"%X", val);
pSpin->SetBase(base);
pSpin->GetBuddy()->SetWindowText(valStr);
LOGI("Set spin button base to %d val=%d", base, val);
}
int DiskEditDialog::ReadSpinner(int id, long* pVal)
{
MySpinCtrl* pSpin = (MySpinCtrl*) GetDlgItem(id);
ASSERT(pSpin != NULL);
long val = pSpin->GetPos();
if (val & 0xff000000) {
/* error */
CString msg, err;
CheckedLoadString(&err, IDS_ERROR);
int lower, upper;
pSpin->GetRange32(lower, upper);
msg.Format(L"Please enter a value between %d and %d (0x%x and 0x%x).",
lower, upper, lower, upper);
MessageBox(msg, err, MB_OK|MB_ICONEXCLAMATION);
return -1;
}
*pVal = val;
return 0;
}
void DiskEditDialog::SetSpinner(int id, long val)
{
MySpinCtrl* pSpin = (MySpinCtrl*) GetDlgItem(id);
ASSERT(pSpin != NULL);
/* sanity check */
int lower, upper;
pSpin->GetRange32(lower, upper);
ASSERT(val >= lower && val <= upper);
pSpin->SetPos(val);
}
void DiskEditDialog::DisplayData(const uint8_t* srcBuf, int size)
{
WCHAR textBuf[80 * 16 * 2];
WCHAR* cp;
int i, j;
ASSERT(srcBuf != NULL);
ASSERT(size == kSectorSize || size == kBlockSize);
CRichEditCtrl* pEdit = (CRichEditCtrl*)GetDlgItem(IDC_DISKEDIT_EDIT);
ASSERT(pEdit != NULL);
/*
* If we have an alert message, show that instead.
*/
if (!fAlertMsg.IsEmpty()) {
const int kWidth = 72;
int indent = (kWidth/2) - (fAlertMsg.GetLength() / 2);
if (indent < 0)
indent = 0;
CString msg = L" "
L" ";
ASSERT(msg.GetLength() == kWidth);
msg = msg.Left(indent);
msg += fAlertMsg;
for (i = 0; i < (size / 16)-2; i += 2) {
textBuf[i] = '\r';
textBuf[i+1] = '\n';
}
wcscpy(&textBuf[i], msg);
pEdit->SetWindowText(textBuf);
return;
}
/*
* No alert, do the usual thing.
*/
cp = textBuf;
for (i = 0; i < size/16; i++) {
if (size == kSectorSize) {
/* two-nybble addr */
wsprintf(cp, L" %02x: %02x %02x %02x %02x %02x %02x %02x %02x "
L"%02x %02x %02x %02x %02x %02x %02x %02x ",
i * 16,
srcBuf[0], srcBuf[1], srcBuf[2], srcBuf[3],
srcBuf[4], srcBuf[5], srcBuf[6], srcBuf[7],
srcBuf[8], srcBuf[9], srcBuf[10], srcBuf[11],
srcBuf[12], srcBuf[13], srcBuf[14], srcBuf[15]);
} else {
/* three-nybble addr */
wsprintf(cp, L"%03x: %02x %02x %02x %02x %02x %02x %02x %02x "
L"%02x %02x %02x %02x %02x %02x %02x %02x ",
i * 16,
srcBuf[0], srcBuf[1], srcBuf[2], srcBuf[3],
srcBuf[4], srcBuf[5], srcBuf[6], srcBuf[7],
srcBuf[8], srcBuf[9], srcBuf[10], srcBuf[11],
srcBuf[12], srcBuf[13], srcBuf[14], srcBuf[15]);
}
ASSERT(wcslen(cp) == 54);
cp += 54; // strlen(cp)
for (j = 0; j < 16; j++)
*cp++ = PrintableChar(srcBuf[j]);
*cp++ = '\r';
*cp++ = '\n';
srcBuf += 16;
}
/* kill the last EOL, so the cursor doesn't move past that line */
cp--;
*cp = '\0';
pEdit->SetWindowText(textBuf);
}
void DiskEditDialog::DisplayNibbleData(const unsigned char* srcBuf, int size)
{
ASSERT(srcBuf != NULL);
ASSERT(size > 0);
ASSERT(fAlertMsg.IsEmpty());
int bufSize = ((size+15) / 16) * 80;
WCHAR* textBuf = new WCHAR[bufSize];
WCHAR* cp;
int i;
if (textBuf == NULL)
return;
cp = textBuf;
for (i = 0; size > 0; i++) {
if (size >= 16) {
wsprintf(cp, L"%04x: %02x %02x %02x %02x %02x %02x %02x %02x "
L"%02x %02x %02x %02x %02x %02x %02x %02x",
i * 16,
srcBuf[0], srcBuf[1], srcBuf[2], srcBuf[3],
srcBuf[4], srcBuf[5], srcBuf[6], srcBuf[7],
srcBuf[8], srcBuf[9], srcBuf[10], srcBuf[11],
srcBuf[12], srcBuf[13], srcBuf[14], srcBuf[15]);
ASSERT(wcslen(cp) == 53);
cp += 53; // strlen(cp)
} else {
wsprintf(cp, L"%04x:", i * 16);
cp += 5;
for (int j = 0; j < size; j++) {
wsprintf(cp, L" %02x", srcBuf[j]);
cp += 3;
}
}
*cp++ = '\r';
*cp++ = '\n';
srcBuf += 16;
size -= 16;
}
/* kill the last EOL, so the cursor doesn't move past that line */
cp--;
*cp = '\0';
CRichEditCtrl* pEdit = (CRichEditCtrl*)GetDlgItem(IDC_DISKEDIT_EDIT);
ASSERT(pEdit != NULL);
pEdit->SetWindowText(textBuf);
/*
* Handle resize of edit box. We have to do this late or the scroll bar
* won't appear under Win98. (Whatever.)
*/
if (fFirstResize) {
fFirstResize = false;
const int kStretchHeight = 249;
CRect rect;
GetWindowRect(&rect);
CRect inner;
pEdit->GetRect(&inner);
inner.bottom += kStretchHeight;
pEdit->GetWindowRect(&rect);
ScreenToClient(&rect);
rect.bottom += kStretchHeight;
pEdit->MoveWindow(&rect);
pEdit->SetRect(&inner);
}
delete[] textBuf;
}
DIError DiskEditDialog::OpenFile(const WCHAR* fileName, bool openRsrc,
A2File** ppFile, A2FileDescr** ppOpenFile)
{
A2File* pFile;
A2FileDescr* pOpenFile = NULL;
LOGI(" OpenFile '%ls' rsrc=%d", fileName, openRsrc);
CStringA fileNameA(fileName);
pFile = fpDiskFS->GetFileByName(fileNameA);
if (pFile == NULL) {
CString msg, failed;
msg.Format(IDS_DEFILE_FIND_FAILED, fileName);
CheckedLoadString(&failed, IDS_FAILED);
MessageBox(msg, failed, MB_OK | MB_ICONSTOP);
return kDIErrFileNotFound;
}
DIError dierr;
dierr = pFile->Open(&pOpenFile, true, openRsrc);
if (dierr != kDIErrNone) {
CString msg, failed;
msg.Format(IDS_DEFILE_OPEN_FAILED, fileName,
DiskImgLib::DIStrError(dierr));
CheckedLoadString(&failed, IDS_FAILED);
MessageBox(msg, failed, MB_OK | MB_ICONSTOP);
return dierr;
}
*ppFile = pFile;
*ppOpenFile = pOpenFile;
return kDIErrNone;
}
void DiskEditDialog::OnNibbleParms(void)
{
DiskImg* pDiskImg = fpDiskFS->GetDiskImg();
CComboBox* pCombo;
int sel;
ASSERT(pDiskImg != NULL);
ASSERT(pDiskImg->GetHasNibbles());
pCombo = (CComboBox*) GetDlgItem(IDC_DISKEDIT_NIBBLE_PARMS);
ASSERT(pCombo != NULL);
sel = pCombo->GetCurSel();
if (sel == CB_ERR)
return;
LOGI(" OnNibbleParms: entry %d now selected", sel);
const DiskImg::NibbleDescr* pNibbleTable;
int count;
pNibbleTable = pDiskImg->GetNibbleDescrTable(&count);
ASSERT(sel < count);
pDiskImg->SetNibbleDescr(sel);
LoadData();
}
#if 0
/*
* Make a "sparse" block in a file obvious by filling it with the word
* "sparse".
*/
void
DiskEditDialog::FillWithPattern(unsigned char* buf, int size,
const char* pattern)
{
const char* cp;
unsigned char* ucp;
ucp = buf;
cp = pattern;
while (ucp < buf+size) {
*ucp++ = *cp++;
if (*cp == '\0')
cp = pattern;
}
}
#endif
/*
* ===========================================================================
* SectorEditDialog
* ===========================================================================
*/
BOOL SectorEditDialog::OnInitDialog(void)
{
/*
* Do base-class construction.
*/
DiskEditDialog::OnInitDialog();
/*
* Change track/sector text.
*/
CString trackStr;
CWnd* pWnd;
trackStr.Format(L"Track (%d):", fpDiskFS->GetDiskImg()->GetNumTracks());
pWnd = GetDlgItem(IDC_STEXT_TRACK);
ASSERT(pWnd != NULL);
pWnd->SetWindowText(trackStr);
trackStr.Format(L"Sector (%d):", fpDiskFS->GetDiskImg()->GetNumSectPerTrack());
pWnd = GetDlgItem(IDC_STEXT_SECTOR);
ASSERT(pWnd != NULL);
pWnd->SetWindowText(trackStr);
/*
* Configure the spin buttons.
*/
MySpinCtrl* pSpin;
pSpin = (MySpinCtrl*)GetDlgItem(IDC_DISKEDIT_TRACKSPIN);
ASSERT(pSpin != NULL);
pSpin->SetRange32(0, fpDiskFS->GetDiskImg()->GetNumTracks()-1);
pSpin->SetPos(0);
pSpin = (MySpinCtrl*)GetDlgItem(IDC_DISKEDIT_SECTORSPIN);
ASSERT(pSpin != NULL);
pSpin->SetRange32(0, fpDiskFS->GetDiskImg()->GetNumSectPerTrack()-1);
pSpin->SetPos(0);
/* give us something to look at */
LoadData();
return TRUE;
}
int SectorEditDialog::LoadData(void)
{
//LOGI("SED LoadData");
ASSERT(fpDiskFS != NULL);
ASSERT(fpDiskFS->GetDiskImg() != NULL);
if (ReadSpinner(IDC_DISKEDIT_TRACKSPIN, &fTrack) != 0)
return -1;
if (ReadSpinner(IDC_DISKEDIT_SECTORSPIN, &fSector) != 0)
return -1;
LOGI("LoadData reading t=%d s=%d", fTrack, fSector);
fAlertMsg = "";
DIError dierr;
dierr = fpDiskFS->GetDiskImg()->ReadTrackSector(fTrack, fSector, fSectorData);
if (dierr != kDIErrNone) {
LOGI("SED sector read failed: %hs", DiskImgLib::DIStrError(dierr));
//CString msg;
//CString err;
//err.LoadString(IDS_ERROR);
//msg.Format(IDS_DISKEDIT_NOREADTS, fTrack, fSector);
//MessageBox(msg, err, MB_OK|MB_ICONSTOP);
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_BADSECTOR);
//return -1;
}
DisplayData();
return 0;
}
void SectorEditDialog::OnDoRead(void)
{
LoadData();
}
void SectorEditDialog::OnDoWrite(void)
{
MessageBox(L"Write!");
}
void SectorEditDialog::OnReadPrev(void)
{
if (fTrack == 0 && fSector == 0)
return;
if (fSector == 0) {
fSector = fpDiskFS->GetDiskImg()->GetNumSectPerTrack() -1;
fTrack--;
} else {
fSector--;
}
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fTrack);
SetSpinner(IDC_DISKEDIT_SECTORSPIN, fSector);
LoadData();
}
void SectorEditDialog::OnReadNext(void)
{
int numTracks = fpDiskFS->GetDiskImg()->GetNumTracks();
int numSects = fpDiskFS->GetDiskImg()->GetNumSectPerTrack();
if (fTrack == numTracks-1 && fSector == numSects-1)
return;
if (fSector == numSects-1) {
fSector = 0;
fTrack++;
} else {
fSector++;
}
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fTrack);
SetSpinner(IDC_DISKEDIT_SECTORSPIN, fSector);
LoadData();
}
void SectorEditDialog::OnOpenFile(void)
{
DEFileDialog fileDialog(this);
if (fileDialog.DoModal() == IDOK) {
SectorFileEditDialog fileEdit(this, this);
A2File* pFile;
A2FileDescr* pOpenFile = NULL;
DIError dierr;
dierr = OpenFile(fileDialog.fName, fileDialog.fOpenRsrcFork != 0,
&pFile, &pOpenFile);
if (dierr != kDIErrNone)
return;
fileEdit.SetupFile(fileDialog.fName, fileDialog.fOpenRsrcFork != 0,
pFile, pOpenFile);
fileEdit.SetPositionShift(8);
(void) fileEdit.DoModal();
pOpenFile->Close();
}
}
/*
* ===========================================================================
* SectorFileEditDialog
* ===========================================================================
*/
BOOL SectorFileEditDialog::OnInitDialog(void)
{
BOOL retval;
/* do base class first */
retval = SectorEditDialog::OnInitDialog();
/* disable direct entry of tracks and sectors */
CWnd* pWnd;
pWnd = GetDlgItem(IDC_DISKEDIT_TRACKSPIN);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_DISKEDIT_SECTORSPIN);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(FALSE);
/* disallow opening of sub-volumes and files */
pWnd = GetDlgItem(IDC_DISKEDIT_OPENFILE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_DISKEDIT_SUBVOLUME);
pWnd->EnableWindow(FALSE);
CEdit* pEdit;
pEdit = (CEdit*) GetDlgItem(IDC_DISKEDIT_TRACK);
ASSERT(pEdit != NULL);
pEdit->SetReadOnly(TRUE);
pEdit = (CEdit*) GetDlgItem(IDC_DISKEDIT_SECTOR);
ASSERT(pEdit != NULL);
pEdit->SetReadOnly(TRUE);
/* set the window title */
CString title;
CString rsrcIndic;
CheckedLoadString(&rsrcIndic, IDS_INDIC_RSRC);
title.Format(L"Disk Viewer - %hs%ls (%I64d bytes)",
(LPCSTR) fpFile->GetPathName(), // use fpFile version to get case
fOpenRsrcFork ? (LPCWSTR)rsrcIndic : L"", (LONGLONG) fLength);
SetWindowText(title);
return retval;
}
int SectorFileEditDialog::LoadData(void)
{
ASSERT(fpDiskFS != NULL);
ASSERT(fpDiskFS->GetDiskImg() != NULL);
DIError dierr;
LOGI("SFED LoadData reading index=%d", fSectorIdx);
#if 0
LOGI("LoadData reading offset=%d", fOffset);
size_t actual = 0;
dierr = fpFile->Seek(fOffset, EmbeddedFD::kSeekSet);
if (dierr == kDIErrNone) {
dierr = fpFile->Read(fSectorData, 1 /*kSectorSize*/, &actual);
}
if (dierr != kDIErrNone) {
CString msg, failed;
failed.LoadString(IDS_FAILED);
msg.Format(IDS_DISKEDIT_FIRDFAILED, DiskImg::DIStrError(dierr));
MessageBox(msg, failed, MB_OK);
// TO DO: mark contents as invalid, so editing fails
return -1;
}
if (actual != kSectorSize) {
LOGI(" SFED partial read of %d bytes", actual);
ASSERT(actual < kSectorSize && actual >= 0);
}
/*
* We've read the data, but we can't use it. We're a sector editor,
* not a file editor, and we need to get the actual sector data without
* EOF trimming or CP/M 0xe5 removal.
*/
fpFile->GetLastLocationRead(&fTrack, &fSector);
if (fTrack == A2File::kLastWasSparse && fSector == A2File::kLastWasSparse)
;
#endif
fAlertMsg = "";
dierr = fpOpenFile->GetStorage(fSectorIdx, &fTrack, &fSector);
if (dierr == kDIErrInvalidIndex && fSectorIdx == 0) {
// no first sector; should only happen on CP/M
//FillWithPattern(fSectorData, sizeof(fSectorData), _T("EMPTY "));
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_EMPTY);
} else if (dierr != kDIErrNone) {
CString msg, failed;
CheckedLoadString(&failed, IDS_FAILED);
msg.Format(IDS_DISKEDIT_FIRDFAILED, DiskImgLib::DIStrError(dierr));
MessageBox(msg, failed, MB_OK);
CheckedLoadString(&fAlertMsg, IDS_FAILED);
// TO DO: mark contents as invalid, so editing fails
return -1;
} else {
if (fTrack == 0 && fSector == 0) {
LOGI("LoadData Sparse sector");
//FillWithPattern(fSectorData, sizeof(fSectorData), _T("SPARSE "));
fAlertMsg.Format(IDS_DISKEDITMSG_SPARSE, fSectorIdx);
} else {
LOGI("LoadData reading T=%d S=%d", fTrack, fSector);
dierr = fpDiskFS->GetDiskImg()->ReadTrackSector(fTrack, fSector,
fSectorData);
if (dierr != kDIErrNone) {
//CString msg;
//CString err;
//err.LoadString(IDS_ERROR);
//msg.Format(IDS_DISKEDIT_NOREADTS, fTrack, fSector);
//MessageBox(msg, err, MB_OK|MB_ICONSTOP);
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_BADSECTOR);
//return -1;
}
}
}
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fTrack);
SetSpinner(IDC_DISKEDIT_SECTORSPIN, fSector);
CWnd* pWnd;
pWnd = GetDlgItem(IDC_DISKEDIT_PREV);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(fSectorIdx > 0);
if (!pWnd->IsWindowEnabled() && GetFocus() == NULL)
GetDlgItem(IDC_DISKEDIT_NEXT)->SetFocus();
pWnd = GetDlgItem(IDC_DISKEDIT_NEXT);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(fSectorIdx+1 < fpOpenFile->GetSectorCount());
if (!pWnd->IsWindowEnabled() && GetFocus() == NULL)
GetDlgItem(IDC_DISKEDIT_PREV)->SetFocus();
DisplayData();
return 0;
}
void SectorFileEditDialog::OnReadPrev(void)
{
if (fSectorIdx == 0)
return;
fSectorIdx--;
ASSERT(fSectorIdx >= 0);
LoadData();
}
void SectorFileEditDialog::OnReadNext(void)
{
if (fSectorIdx+1 >= fpOpenFile->GetSectorCount())
return;
fSectorIdx++;
ASSERT(fSectorIdx < fpOpenFile->GetSectorCount());
LoadData();
}
/*
* ===========================================================================
* BlockEditDialog
* ===========================================================================
*/
/*
* Rearrange the DiskEdit dialog (which defaults to SectorEdit mode) to
* accommodate block editing.
*/
BOOL BlockEditDialog::OnInitDialog(void)
{
/*
* Get rid of the "sector" input item, and change the "track" input
* item to accept blocks instead.
*/
CWnd* pWnd;
pWnd = GetDlgItem(IDC_STEXT_SECTOR);
pWnd->DestroyWindow();
pWnd = GetDlgItem(IDC_DISKEDIT_SECTOR);
pWnd->DestroyWindow();
pWnd = GetDlgItem(IDC_DISKEDIT_SECTORSPIN);
pWnd->DestroyWindow();
CString blockStr;
//blockStr.LoadString(IDS_BLOCK);
blockStr.Format(L"Block (%d):", fpDiskFS->GetDiskImg()->GetNumBlocks());
pWnd = GetDlgItem(IDC_STEXT_TRACK);
ASSERT(pWnd != NULL);
pWnd->SetWindowText(blockStr);
/*
* Increase the size of the window to accommodate the larger block size.
*/
const int kStretchHeight = 250;
CRect rect;
GetWindowRect(&rect);
rect.bottom += kStretchHeight;
MoveWindow(&rect);
CRichEditCtrl* pEdit = (CRichEditCtrl*)GetDlgItem(IDC_DISKEDIT_EDIT);
ASSERT(pEdit != NULL);
CRect inner;
pEdit->GetRect(&inner);
inner.bottom += kStretchHeight;
pEdit->GetWindowRect(&rect);
ScreenToClient(&rect);
rect.bottom += kStretchHeight;
pEdit->MoveWindow(&rect);
pEdit->SetRect(&inner);
MoveControl(this, IDC_DISKEDIT_DONE, 0, kStretchHeight);
MoveControl(this, IDC_DISKEDIT_OPENFILE, 0, kStretchHeight);
MoveControl(this, IDC_DISKEDIT_SUBVOLUME, 0, kStretchHeight);
MoveControl(this, IDHELP, 0, kStretchHeight);
MoveControl(this, IDC_DISKEDIT_NIBBLE_PARMS, 0, kStretchHeight);
/*
* Do base-class construction.
*/
DiskEditDialog::OnInitDialog();
/*
* Configure the spin button. We use the "track" spin button for blocks.
*/
MySpinCtrl* pSpin;
pSpin = (MySpinCtrl*)GetDlgItem(IDC_DISKEDIT_TRACKSPIN);
ASSERT(pSpin != NULL);
pSpin->SetRange32(0, fpDiskFS->GetDiskImg()->GetNumBlocks()-1);
pSpin->SetPos(0);
/* give us something to look at */
if (LoadData() != 0) {
LOGI("WHOOPS: LoadData() failed, but we're in OnInitDialog");
}
return TRUE;
}
#if 0
/*
* Move a control so it maintains its same position relative to the bottom
* and right edges.
*/
void
BlockEditDialog::MoveControl(int id, int deltaX, int deltaY)
{
CWnd* pWnd;
CRect rect;
pWnd = GetDlgItem(id);
ASSERT(pWnd != NULL);
pWnd->GetWindowRect(&rect);
ScreenToClient(&rect);
rect.left += deltaX;
rect.right += deltaX;
rect.top += deltaY;
rect.bottom += deltaY;
pWnd->MoveWindow(&rect, TRUE);
}
#endif
int BlockEditDialog::LoadData(void)
{
//LOGI("BED LoadData");
ASSERT(fpDiskFS != NULL);
ASSERT(fpDiskFS->GetDiskImg() != NULL);
if (ReadSpinner(IDC_DISKEDIT_TRACKSPIN, &fBlock) != 0)
return -1;
LOGI("LoadData reading block=%d", fBlock);
fAlertMsg = "";
DIError dierr;
dierr = fpDiskFS->GetDiskImg()->ReadBlock(fBlock, fBlockData);
if (dierr != kDIErrNone) {
LOGI("BED block read failed: %hs", DiskImgLib::DIStrError(dierr));
//CString msg;
//CString err;
//err.LoadString(IDS_ERROR);
//msg.Format(IDS_DISKEDIT_NOREADBLOCK, fBlock);
//MessageBox(msg, err, MB_OK|MB_ICONSTOP);
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_BADBLOCK);
//return -1;
}
DisplayData();
return 0;
}
void BlockEditDialog::OnDoRead(void)
{
LoadData();
}
void BlockEditDialog::OnDoWrite(void)
{
MessageBox(L"Write!");
}
void BlockEditDialog::OnReadPrev(void)
{
if (fBlock == 0)
return;
fBlock--;
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fBlock);
LoadData();
}
void
BlockEditDialog::OnReadNext(void)
{
ASSERT(fpDiskFS != NULL);
if (fBlock == fpDiskFS->GetDiskImg()->GetNumBlocks() - 1)
return;
fBlock++;
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fBlock);
LoadData();
}
void BlockEditDialog::OnOpenFile(void)
{
DEFileDialog fileDialog(this);
if (fileDialog.DoModal() == IDOK) {
BlockFileEditDialog fileEdit(this, this);
A2File* pFile;
A2FileDescr* pOpenFile = NULL;
DIError dierr;
dierr = OpenFile(fileDialog.fName, fileDialog.fOpenRsrcFork != 0,
&pFile, &pOpenFile);
if (dierr != kDIErrNone)
return;
fileEdit.SetupFile(fileDialog.fName, fileDialog.fOpenRsrcFork != 0,
pFile, pOpenFile);
fileEdit.SetPositionShift(8);
(void) fileEdit.DoModal();
pOpenFile->Close();
}
}
/*
* ===========================================================================
* BlockFileEditDialog
* ===========================================================================
*/
BOOL BlockFileEditDialog::OnInitDialog(void)
{
BOOL retval;
/* do base class first */
retval = BlockEditDialog::OnInitDialog();
/* disable direct entry of tracks and Blocks */
CWnd* pWnd;
pWnd = GetDlgItem(IDC_DISKEDIT_TRACKSPIN);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(FALSE);
/* disallow opening of sub-volumes and files */
pWnd = GetDlgItem(IDC_DISKEDIT_OPENFILE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_DISKEDIT_SUBVOLUME);
pWnd->EnableWindow(FALSE);
CEdit* pEdit;
pEdit = (CEdit*) GetDlgItem(IDC_DISKEDIT_TRACK);
ASSERT(pEdit != NULL);
pEdit->SetReadOnly(TRUE);
/* set the window title */
CString title;
CString rsrcIndic;
CheckedLoadString(&rsrcIndic, IDS_INDIC_RSRC);
title.Format(L"Disk Viewer - %hs%ls (%I64d bytes)",
(LPCSTR) fpFile->GetPathName(), // use fpFile version to get case
fOpenRsrcFork ? (LPCWSTR)rsrcIndic : L"", (LONGLONG) fLength);
SetWindowText(title);
return retval;
}
int BlockFileEditDialog::LoadData(void)
{
ASSERT(fpDiskFS != NULL);
ASSERT(fpDiskFS->GetDiskImg() != NULL);
DIError dierr;
LOGI("BFED LoadData reading index=%d", fBlockIdx);
#if 0
LOGI("LoadData reading offset=%d", fOffset);
size_t actual = 0;
dierr = fpFile->Seek(fOffset, EmbeddedFD::kSeekSet);
if (dierr == kDIErrNone) {
dierr = fpFile->Read(fBlockData, 1 /*kBlockSize*/, &actual);
}
if (dierr != kDIErrNone) {
CString msg, failed;
failed.LoadString(IDS_FAILED);
msg.Format(IDS_DISKEDIT_FIRDFAILED, DiskImg::DIStrError(dierr));
MessageBox(msg, failed, MB_OK);
// TO DO: mark contents as invalid, so editing fails
return -1;
}
if (actual != kBlockSize) {
LOGI(" BFED partial read of %d bytes", actual);
ASSERT(actual < kBlockSize && actual >= 0);
}
/*
* We've read the data, but we can't use it. We're a Block editor,
* not a file editor, and we need to get the actual Block data without
* EOF trimming or CP/M 0xe5 removal.
*/
fpFile->GetLastLocationRead(&fBlock);
if (fBlock == A2File::kLastWasSparse)
;
#endif
fAlertMsg = "";
dierr = fpOpenFile->GetStorage(fBlockIdx, &fBlock);
if (dierr == kDIErrInvalidIndex && fBlockIdx == 0) {
// no first sector; should only happen on CP/M
//FillWithPattern(fBlockData, sizeof(fBlockData), _T("EMPTY "));
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_EMPTY);
} else if (dierr != kDIErrNone) {
CString msg, failed;
CheckedLoadString(&failed, IDS_FAILED);
msg.Format(IDS_DISKEDIT_FIRDFAILED, DiskImgLib::DIStrError(dierr));
MessageBox(msg, failed, MB_OK);
CheckedLoadString(&fAlertMsg, IDS_FAILED);
// TO DO: mark contents as invalid, so editing fails
return -1;
} else {
if (fBlock == 0) {
LOGI("LoadData Sparse block");
//FillWithPattern(fBlockData, sizeof(fBlockData), _T("SPARSE "));
fAlertMsg.Format(IDS_DISKEDITMSG_SPARSE, fBlockIdx);
} else {
LOGI("LoadData reading B=%d", fBlock);
dierr = fpDiskFS->GetDiskImg()->ReadBlock(fBlock, fBlockData);
if (dierr != kDIErrNone) {
//CString msg;
//CString err;
//err.LoadString(IDS_ERROR);
//msg.Format(IDS_DISKEDIT_NOREADBLOCK, fBlock);
//MessageBox(msg, err, MB_OK|MB_ICONSTOP);
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_BADBLOCK);
//return -1;
}
}
}
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fBlock);
CWnd* pWnd;
pWnd = GetDlgItem(IDC_DISKEDIT_PREV);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(fBlockIdx > 0);
if (!pWnd->IsWindowEnabled() && GetFocus() == NULL)
GetDlgItem(IDC_DISKEDIT_NEXT)->SetFocus();
pWnd = GetDlgItem(IDC_DISKEDIT_NEXT);
ASSERT(pWnd != NULL);
pWnd->EnableWindow(fBlockIdx+1 < fpOpenFile->GetBlockCount());
if (!pWnd->IsWindowEnabled() && GetFocus() == NULL)
GetDlgItem(IDC_DISKEDIT_PREV)->SetFocus();
DisplayData();
return 0;
}
void BlockFileEditDialog::OnReadPrev(void)
{
if (fBlockIdx == 0)
return;
fBlockIdx--;
ASSERT(fBlockIdx >= 0);
LoadData();
}
void BlockFileEditDialog::OnReadNext(void)
{
if (fBlockIdx+1 >= fpOpenFile->GetBlockCount())
return;
fBlockIdx++;
ASSERT(fBlockIdx < fpOpenFile->GetBlockCount());
LoadData();
}
/*
* ===========================================================================
* NibbleEditDialog
* ===========================================================================
*/
BOOL NibbleEditDialog::OnInitDialog(void)
{
/*
* Get rid of the "sector" input item.
*/
CWnd* pWnd;
pWnd = GetDlgItem(IDC_STEXT_SECTOR);
pWnd->DestroyWindow();
pWnd = GetDlgItem(IDC_DISKEDIT_SECTOR);
pWnd->DestroyWindow();
pWnd = GetDlgItem(IDC_DISKEDIT_SECTORSPIN);
pWnd->DestroyWindow();
CString trackStr;
trackStr.Format(L"Track (%d):", fpDiskFS->GetDiskImg()->GetNumTracks());
pWnd = GetDlgItem(IDC_STEXT_TRACK);
ASSERT(pWnd != NULL);
pWnd->SetWindowText(trackStr);
/*
* Increase the size of the window so it's the same height as blocks.
*
* NOTE: using a pixel constant is probably bad. We want to use something
* like GetTextMetrics, but I'm not sure how to get that without a
* device context.
*/
CRichEditCtrl* pEdit = (CRichEditCtrl*)GetDlgItem(IDC_DISKEDIT_EDIT);
ASSERT(pEdit != NULL);
const int kStretchHeight = 249;
CRect rect;
GetWindowRect(&rect);
rect.bottom += kStretchHeight;
MoveWindow(&rect);
/*
* Must postpone resize of edit ctrl until after data has been loaded, or
* scroll bars fail to appear under Win98. Makes no sense whatsoever, but
* that's Windows for you.
*/
#if 0
CRect inner;
pEdit->GetRect(&inner);
inner.bottom += kStretchHeight;
pEdit->GetWindowRect(&rect);
ScreenToClient(&rect);
rect.bottom += kStretchHeight;
pEdit->MoveWindow(&rect);
pEdit->SetRect(&inner);
#endif
/* show the scroll bar */
pEdit->ShowScrollBar(SB_VERT);
MoveControl(this, IDC_DISKEDIT_DONE, 0, kStretchHeight);
MoveControl(this, IDC_DISKEDIT_OPENFILE, 0, kStretchHeight);
MoveControl(this, IDC_DISKEDIT_SUBVOLUME, 0, kStretchHeight);
MoveControl(this, IDHELP, 0, kStretchHeight);
MoveControl(this, IDC_DISKEDIT_NIBBLE_PARMS, 0, kStretchHeight);
/* disable opening of files and sub-volumes */
pWnd = GetDlgItem(IDC_DISKEDIT_OPENFILE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_DISKEDIT_SUBVOLUME);
pWnd->EnableWindow(FALSE);
/*
* Do base-class construction.
*/
DiskEditDialog::OnInitDialog();
/*
* This currently has no effect on the nibble editor. Someday we may
* want to highlight and/or decode address fields.
*/
pWnd = GetDlgItem(IDC_DISKEDIT_NIBBLE_PARMS);
pWnd->EnableWindow(FALSE);
/*
* Configure the track spin button.
*/
MySpinCtrl* pSpin;
pSpin = (MySpinCtrl*)GetDlgItem(IDC_DISKEDIT_TRACKSPIN);
ASSERT(pSpin != NULL);
pSpin->SetRange32(0, fpDiskFS->GetDiskImg()->GetNumTracks()-1);
pSpin->SetPos(0);
/* give us something to look at */
LoadData();
return TRUE;
}
int NibbleEditDialog::LoadData(void)
{
//LOGI("BED LoadData");
ASSERT(fpDiskFS != NULL);
ASSERT(fpDiskFS->GetDiskImg() != NULL);
if (ReadSpinner(IDC_DISKEDIT_TRACKSPIN, &fTrack) != 0)
return -1;
LOGI("LoadData reading track=%d", fTrack);
fAlertMsg = "";
DIError dierr;
dierr = fpDiskFS->GetDiskImg()->ReadNibbleTrack(fTrack, fNibbleData,
&fNibbleDataLen);
if (dierr != kDIErrNone) {
LOGI("NED track read failed: %hs", DiskImgLib::DIStrError(dierr));
CheckedLoadString(&fAlertMsg, IDS_DISKEDITMSG_BADTRACK);
}
DisplayData();
return 0;
}
void NibbleEditDialog::OnDoRead(void)
{
LoadData();
}
void NibbleEditDialog::OnDoWrite(void)
{
MessageBox(L"Write!");
}
void NibbleEditDialog::OnReadPrev(void)
{
if (fTrack == 0)
return;
fTrack--;
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fTrack);
LoadData();
}
void NibbleEditDialog::OnReadNext(void)
{
ASSERT(fpDiskFS != NULL);
if (fTrack == fpDiskFS->GetDiskImg()->GetNumTracks() - 1)
return;
fTrack++;
SetSpinner(IDC_DISKEDIT_TRACKSPIN, fTrack);
LoadData();
}