home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
Borland
/
Cplus45
/
BC45
/
DOCVIEW.PAK
/
DUMPVIEW.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-29
|
14KB
|
550 lines
//----------------------------------------------------------------------------
// ObjectWindows - (C) Copyright 1993 by Borland International
// Implements class TDumpView
//----------------------------------------------------------------------------
#include <owl\owlpch.h>
#include <owl\docmanag.h>
#include <owl\filedoc.h>
#include <owl\listbox.h>
#include <owl\inputdia.h>
#include <owl\dc.h>
#include "dumpview.rc"
struct TDumpData;
class _DOCVIEWCLASS TDumpView : public TListBox, public TView {
public:
TDumpView(TDocument& doc, TWindow* parent = 0);
~TDumpView();
static LPCSTR StaticName() {return "Dump View";} // put in resource
//
// overridden virtuals from TView
//
LPCSTR GetViewName(){return StaticName();}
// const char far* GetViewName(){return StaticName();}
TWindow* GetWindow() {return (TWindow*)this;}
BOOL SetDocTitle(LPCSTR docname, int index)
// BOOL SetDocTitle(const char far* docname, int index)
{return TListBox::SetDocTitle(docname, index);}
//
// overridden virtuals from TWindow
//
BOOL Create();
BOOL CanClose() {return TListBox::CanClose() && Doc->CanClose();}
int MaxWidth; // maximum horizontal extent
protected:
long Origin;
long FileSize;
int UpdateMode; // 0=NotEditing, 1=HighNibble, 2=LowNibble, -1=Flushing
int CharWidth;
int CharHeight;
int EditByte;
int EditLine;
TDumpData* Changes;
void Init();
BOOL LoadData(int top, int sel);
void FormatLine(int index, TDumpData* data);
BOOL NewEditLine(int line, int byte);
void EndEditLine();
void KillChanges();
private:
//
// message response functions
//
BOOL VnCommit(BOOL force);
BOOL VnRevert(BOOL clear);
BOOL VnIsWindow(HWND hWnd) {return HWindow == hWnd;}
BOOL VnIsDirty();
BOOL VnDocClosed(int omode);
void CmEditUndo();
void CmEditItem();
void EvPaint();
void EvKeyDown(UINT key, UINT repeatCount, UINT flags);
void EvLButtonDown(UINT modKeys, TPoint& point);
void EvLButtonDblClk(UINT modKeys, TPoint& point);
void CmSelChange(){} // to prevent interpreting as unprocessed accelerator
DECLARE_RESPONSE_TABLE(TDumpView);
DECLARE_STREAMABLE(,TDumpView,1);
};
DIAG_DECLARE_GROUP(OwlDocView); // General Doc/View diagnostic group
const int DisplayLines = 16; // initial list box size
const int ListBoxMax = 100; // max number of lines stored in list box
const int DataWidth = 8; // number of data bytes per line
const int AddrWidth = 2; // number of bytes in address
const int LineWidth = AddrWidth*2 + 1 + DataWidth*3 + DataWidth;
struct TDumpData {
long Addr;
char Old[DataWidth];
char New[DataWidth];
int Count;
TDumpData* Next;
};
DEFINE_RESPONSE_TABLE1(TDumpView, TListBox)
EV_WM_KEYDOWN,
EV_COMMAND(CM_DUMPUNDO, CmEditUndo),
EV_COMMAND(CM_DUMPEDIT, CmEditItem),
EV_WM_PAINT,
EV_WM_LBUTTONDOWN,
EV_WM_LBUTTONDBLCLK,
EV_VN_DOCCLOSED,
EV_VN_ISWINDOW,
EV_VN_ISDIRTY,
EV_VN_COMMIT,
EV_VN_REVERT,
EV_NOTIFY_AT_CHILD(LBN_SELCHANGE, CmSelChange),
END_RESPONSE_TABLE;
TDumpView::TDumpView(TDocument& doc, TWindow* parent)
: TView(doc), TListBox(parent, GetNextViewId(), 0,0,0,0)
{
Init();
// Attr.Style &= ~(WS_BORDER | LBS_SORT);
Attr.Style &= ~(LBS_SORT);
Attr.Style |= LBS_DISABLENOSCROLL | LBS_NOINTEGRALHEIGHT;
Attr.AccelTable = IDA_DUMPVIEW;
SetViewMenu(new TMenuDescr(IDM_DUMPVIEW,0,1,0,0,0,1));
}
void
TDumpView::Init()
{
Origin = 0;
UpdateMode = 0;
Changes = 0;
}
BOOL
TDumpView::VnDocClosed(int omode)
{
if (UpdateMode == -1 || !(omode & ofWrite)) // make sure someone else's write
return FALSE;
int top = GetTopIndex();
int sel = GetSelIndex();
ClearList();
LoadData(top, sel);
return TRUE;
}
static char HexDigit(int i)
{
char c = char((i & 15) + '0');
if (c > '9')
c += char('A' - ('9' + 1));
return c;
}
void
TDumpView::FormatLine(int line, TDumpData* data)
{
char buf[LineWidth + 2];
int index;
char* pbuf;
char* pasc;
unsigned char chr;
long addr = data->Addr;
for (index = AddrWidth*2; --index >= 0; addr >>= 4)
buf[index] = HexDigit((int)addr);
pbuf = buf + AddrWidth*2;
*pbuf++ = ' ';
pasc = pbuf + DataWidth*3;
for (index = 0; index < DataWidth; index++) {
if (index < data->Count) {
chr = data->New[index];
*pbuf++ = HexDigit(chr >> 4);
*pbuf++ = HexDigit(chr);
pasc[index] = char((chr >= 0x20 && chr < 0x7F) ? chr : 0x7F);
} else {
*pbuf++ = ' ';
*pbuf++ = ' ';
pasc[index] = ' ';
}
*pbuf++ = ' ';
}
pasc[DataWidth] = 0; // null terminate buffer
InsertString(buf, line);
}
static long GetAddr(int index)
{
return index * DataWidth;
// need to add origin!
}
static int GetIndex(long addr)
{
return int(addr / DataWidth);
// need to subtract origin!
}
BOOL
TDumpView::LoadData(int top, int sel)
{
TDumpData data;
istream* inStream;
int count;
if ((inStream = Doc->InStream(ofRead | ofBinary)) == 0)
return FALSE;
for (count=0, data.Addr=0; count<ListBoxMax; count++,data.Addr+=DataWidth) {
inStream->read(data.New, DataWidth);
if ((data.Count = inStream->gcount()) == 0)
break;
FormatLine(-1, &data);
if (data.Count != DataWidth)
break;
}
SetTopIndex(top);
SetSelIndex(sel);
delete inStream; // close file in case process switch
return TRUE;
}
BOOL
TDumpView::Create()
{
TRect rect;
LOGFONT fontinfo;
HGDIOBJ font = GetStockObject(SYSTEM_FIXED_FONT);
TListBox::Create(); // throws exception TXInvalidWindow
SendMessage(WM_SETFONT, (UINT)font, 0L);
GetObject(font, sizeof(LOGFONT), &fontinfo);
CharWidth = fontinfo.lfWidth;
CharHeight = fontinfo.lfHeight;
GetClientRect(rect); // created with 0,0 size, .right is -scroll bar size
if (rect.right < 0) { // if new view, else streaming in presized window
rect.right = LineWidth * CharWidth + (-rect.right+2) + CharWidth/2;
rect.bottom = CharHeight * DisplayLines;
MoveWindow(rect);
//if (!Parent->IsFlagSet(wfMainWindow))// prevent parent shrink if main window
Parent->SetFlag(wfShrinkToClient);
}
if (!Doc->GetDocPath())
return TRUE; // new file, no data to display
if (!LoadData(0, 0))
NotOK();
return TRUE;
}
BOOL
TDumpView::VnCommit(BOOL /*force*/)
{
TDumpData* edit;
ostream* outStream;
EndEditLine();
if (!Changes)
return TRUE;
if ((outStream = Doc->OutStream(ofReadWrite | ofBinary)) == 0)
return FALSE;
while ((edit = Changes) != 0) {
outStream->seekp(edit->Addr);
outStream->write(edit->New, edit->Count);
// test goodbit
Changes = Changes->Next;
delete edit;
}
UpdateMode = -1; // to detect our own close notification
outStream->seekp(0,ios::end);
delete outStream;
return TRUE;
}
BOOL
TDumpView::VnRevert(BOOL clear)
{
EndEditLine();
KillChanges();
ClearList();
return (!clear && Doc->GetDocPath() != 0) ? LoadData(0, 0) : TRUE;
}
TDumpView::~TDumpView()
{
KillChanges();
}
BOOL
TDumpView::NewEditLine(int line, int byte)
{
istream* inStream;
TDumpData* edit;
TRect rect;
BOOL stat = TRUE;
if (line < 0)
return FALSE;
SetSelIndex(line); // restore index in case changes
if (UpdateMode > 0) {
return FALSE;
}
if ((inStream = Doc->InStream(ofRead | ofBinary)) == 0)
return FALSE;
if ((edit = new TDumpData) == 0)
return FALSE;
edit->Addr = GetAddr(line);
inStream->seekg(edit->Addr);
// test goodbit
inStream->read(edit->Old, DataWidth);
if ((edit->Count = inStream->gcount()) > 0) {
memcpy(edit->New, edit->Old, edit->Count);
UpdateMode = 1;
GetItemRect(line, rect);
InvalidateRect(rect);
edit->Next = Changes;
Changes = edit;
while (byte >= edit->Count)
byte--;
EditByte = byte;
EditLine = line;
} else {
delete edit;
stat = FALSE;
}
delete inStream;
return stat;
}
BOOL
TDumpView::VnIsDirty()
{
return (Changes
&& (Changes->Next
|| memcmp(Changes->New, Changes->Old, Changes->Count) != 0));
}
void
TDumpView::EndEditLine()
{
TDumpData* edit = Changes;
if (UpdateMode > 0) {
TRect rect;
GetItemRect(EditLine, rect);
InvalidateRect(rect);
if (memcmp(edit->New, edit->Old, edit->Count) == 0) {
Changes = Changes->Next;
delete edit;
}
}
UpdateMode = 0;
}
void
TDumpView::KillChanges()
{
TDumpData* edit;
while ((edit = Changes) != 0) {
Changes = Changes->Next;
delete edit;
}
}
void
TDumpView::EvLButtonDown(UINT modKeys, TPoint& point)
{
if (UpdateMode > 0) {
int line = point.y/CharHeight + GetTopIndex();
if (line != EditLine) {
EndEditLine();
TListBox::EvLButtonDown(modKeys, point);
return;
}
int index = ((point.x*2 - CharWidth)/(CharWidth*2) - AddrWidth*2)/3;
if (index >= 0 && index < Changes->Count) {
EditByte = index;
UpdateMode = 1;
TRect rect;
GetItemRect(EditLine, rect);
InvalidateRect(rect);
}
} else
TListBox::EvLButtonDown(modKeys, point);
}
void
TDumpView::EvLButtonDblClk(UINT /*modKeys*/, TPoint& point)
{
int index = ((point.x*2 - CharWidth)/(CharWidth*2) - AddrWidth*2)/3;
if (index < 0 || index >= DataWidth)
index = 0;
int line = point.y/CharHeight + GetTopIndex();
if (UpdateMode <= 0 || line != EditLine) {
// EndEditLine();
NewEditLine(line, index);
}
}
void
TDumpView::EvKeyDown(UINT key, UINT repeatCount, UINT flags)
{
char oldchr, newchr;
MSG msg;
if (UpdateMode <= 0) {
if (key != VK_LEFT && key != VK_RIGHT)
TListBox::EvKeyDown(key, repeatCount, flags);
return;
}
switch (key) {
case VK_ESCAPE: // abort changes to current line
CmEditUndo();
return;
case VK_RETURN: // enter changes for current line, not committed yet
EndEditLine();
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
key += ('0' + 10) - 'A'; // fall through to digit cases
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
newchr = char(key - '0');
oldchr = Changes->New[EditByte];
::PeekMessage(&msg, HWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
switch(UpdateMode) {
case 1:
newchr = char((oldchr & 0x0F) + (newchr<<4));
break;
case 2:
newchr = char((oldchr & 0xF0) + newchr);
break;
default:
return;
}
Changes->New[EditByte] = newchr;
DeleteString(EditLine);
FormatLine(EditLine, Changes);
SetSelIndex(EditLine);
if (UpdateMode++ == 2 && EditByte < Changes->Count-1) {
EditByte++;
UpdateMode = 1;
}
break;
case VK_UP:
case VK_DOWN:
case VK_PRIOR:
case VK_NEXT:
case VK_END:
case VK_HOME:
if (UpdateMode > 0)
return;
break;
case VK_LEFT:
if (UpdateMode <= 0 || EditByte == 0)
return;
UpdateMode = 1;
EditByte--;
break;
case VK_RIGHT:
if (UpdateMode <= 0 || EditByte >= (Changes->Count-1))
return;
UpdateMode = 1;
EditByte++;
break;
default:
break;
}
TRect rect;
GetItemRect(EditLine, rect);
InvalidateRect(rect);
}
void
TDumpView::EvPaint()
{
TRegion updateRgn;
GetUpdateRgn(updateRgn);
DefaultProcessing(); // predefined listbox class will paint, don't call TWindow
if (UpdateMode <= 0)
return;
if (GetSelIndex() != EditLine) {
//::MessageBeep(MB_ICONEXCLAMATION);
return;
}
if (GetTopIndex() > EditLine || (GetTopIndex()+DisplayLines) <= EditLine)
return;
TRect rect;
GetItemRect(EditLine, rect);
rect.left += CharWidth * (AddrWidth*2+1+EditByte*3) + 1;
rect.right = rect.left + CharWidth * 2;
// should check if in update region!
TClientDC dc(HWindow);
// dc.SelectClipRgn(updateRgn);
// dc.IntersectClipRect(rect);
// dc.InvertRgn(updateRgn);
dc.InvertRgn(updateRgn &= rect);
}
void
TDumpView::CmEditUndo()
{
TRect rect;
TDumpData* edit;
UpdateMode = 0;
if (!Changes)
return;
int index = GetIndex(Changes->Addr);
DeleteString(index);
memcpy(Changes->New, Changes->Old, Changes->Count);
FormatLine(index, Changes);
SetSelIndex(index);
edit = Changes;
Changes = Changes->Next;
delete edit;
GetItemRect(index, rect);
InvalidateRect(rect);
}
void
TDumpView::CmEditItem()
{
int line = GetSelIndex();
if (UpdateMode > 0) {
if (line == EditLine)
return;
EndEditLine();
}
NewEditLine(line, 0);
}
IMPLEMENT_STREAMABLE2(TDumpView, TListBox, TView);
void*
TDumpView::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
ReadBaseObject((TListBox*)GetObject(), is);
ReadBaseObject((TView*)GetObject(), is);
is >> GetObject()->Origin;
GetObject()->Init();
return GetObject();
}
void
TDumpView::Streamer::Write(opstream &os) const
{
WriteBaseObject((TListBox*)GetObject(), os);
WriteBaseObject((TView*)GetObject(), os);
os << GetObject()->Origin;
}
DEFINE_DOC_TEMPLATE_CLASS(TFileDocument, TDumpView, DumpTemplate);
DumpTemplate dumpTpl("DumpView, Binary files", "*.obj;*.res", 0, 0,
dtAutoDelete | dtUpdateDir);