/
// CHexEdit window
class CHexEdit : public CEdit
{
// Construction
public:
CHexEdit();
enum EDITMODE{
EDIT_NONE,
EDIT_ASCII,
EDIT_HIGH,
EDIT_LOW
} ;
// Attributes
public:
LPBYTE m_pData;
int m_length;
int m_topindex;
int m_currentAddress;
EDITMODE m_currentMode;
int m_selStart;
int m_selEnd;
int m_bpr;
int m_lpp;
BOOL m_bShowAddress;
BOOL m_bShowAscii;
BOOL m_bShowHex;
BOOL m_bAddressIsWide;
BOOL m_bNoAddressChange;
BOOL m_bHalfPage;
CFont m_Font;
int m_lineHeight;
int m_nullWidth;
BOOL m_bUpdate;
int m_offHex,
m_offAscii,
m_offAddress;
CPoint m_editPos;
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CHexEdit)
public:
virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
// Implementation
public:
void Clear();
void AppendData(LPBYTE p, int addlen);
int GetData(LPBYTE p, int len);
void SetData(LPBYTE p, int len);
CSize GetSel(void);
void SetSel(int s, int e);
void SetBPR(int bpr);
void SetOptions(BOOL a, BOOL h, BOOL c, BOOL w);
virtual ~CHexEdit();
protected:
void ScrollIntoView(int p);
void RepositionCaret(int p);
void Move(int x, int y);
inline BOOL IsSelected(void);
void UpdateScrollbars(void);
void CreateEditCaret(void);
void CreateAddressCaret(void);
CPoint CalcPos(int x, int y);
void SelInsert(int s, int l);
void SelDelete(int s, int e);
inline void NormalizeSel(void);
afx_msg void OnContextMenu(CWnd*, CPoint point);
//{{AFX_MSG(CHexEdit)
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnPaint();
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg UINT OnGetDlgCode();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnEditClear();
afx_msg void OnEditCopy();
afx_msg void OnEditCut();
afx_msg void OnEditPaste();
afx_msg void OnEditSelectAll();
afx_msg void OnEditUndo();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// HexEdit.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "HexEditCtrl.h"
#include
#include
#include
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
char hextable[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
#define TOHEX(a, b) {*b++ = hextable[a >> 4];*b++ = hextable[a&0xf];}
/
// CHexEdit
CHexEdit::CHexEdit()
{
#if !defined(DEMO)
m_pData = NULL;
m_length = 0;
#else
m_pData = (LPBYTE)malloc(0x40);
for(int i = 0; i < 0x40; i++)
m_pData[i] = i;
#endif
m_length = 0x40;
m_topindex = 0;
m_bpr = 16;
m_lpp = 1;
m_bShowHex = TRUE;
m_bShowAscii = TRUE;
m_bShowAddress = TRUE;
m_bAddressIsWide= TRUE;
m_offAddress = 0;
m_offHex = 0;
m_offAscii = 0;
m_bUpdate = TRUE;
m_bNoAddressChange = FALSE;
m_currentMode = EDIT_NONE;
m_editPos.x = m_editPos.y = 0;
m_currentAddress = 0;
m_bHalfPage = TRUE;
m_selStart = 0xffffffff;
m_selEnd = 0xffffffff;
m_Font.CreateFont(-12, 0,0,0,0,0,0,0,0,0,0,0,0, "Courier New");
AfxOleInit();
}
CHexEdit::~CHexEdit()
{
}
BEGIN_MESSAGE_MAP(CHexEdit, CEdit)
ON_WM_CONTEXTMENU()
//{{AFX_MSG_MAP(CHexEdit)
ON_WM_CHAR()
ON_WM_KILLFOCUS()
ON_WM_PAINT()
ON_WM_SETFOCUS()
ON_WM_SIZE()
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_GETDLGCODE()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_KEYDOWN()
ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CHexEdit message handlers
void CHexEdit::OnPaint()
{
CPaintDC pdc(this); // device context for painting
CRect rc;
GetClientRect(rc);
CDC dc;
dc.CreateCompatibleDC(CDC::FromHandle(pdc.m_ps.hdc));
CBitmap bm;
bm.CreateCompatibleBitmap(CDC::FromHandle(pdc.m_ps.hdc), rc.Width(), rc.Height());
dc.SelectObject(bm);
CBrush b;
b.CreateSolidBrush(RGB(0xff,0xff,0xff));
dc.FillRect(rc, &b);
ASSERT(m_currentAddress >= 0);
ASSERT(m_topindex >= 0);
dc.SelectObject(m_Font);
int height = 0;
int x,y;
char buf[256];
x = rc.TopLeft().x;
y = rc.TopLeft().y;
dc.SetBoundsRect(&rc, DCB_DISABLE);
if(m_pData)
{
if(m_bUpdate)
{
dc.GetCharWidth('0', '0', &m_nullWidth);
CSize sz = dc.GetTextExtent("0", 1);
m_lineHeight = sz.cy;
m_offHex = m_bShowAddress ? (m_bAddressIsWide ? m_nullWidth * 9 : m_nullWidth * 5) : 0;
m_offAscii = m_bShowAddress ? (m_bAddressIsWide ? m_nullWidth * 9 : m_nullWidth * 5) : 0;
m_offAscii += m_bShowHex ? (m_bpr * 3 * m_nullWidth) : 0;
m_lpp = rc.Height() / m_lineHeight;
m_bHalfPage = FALSE;
if(m_lpp * m_bpr > m_length)
{
m_lpp = (m_length + (m_bpr/2)) / m_bpr ;
if(m_length % m_bpr != 0)
{
m_bHalfPage = TRUE;
m_lpp++;
}
}
m_bUpdate = FALSE;
UpdateScrollbars();
}
TRACE("%i %i/n", m_topindex, m_selStart);
height = rc.Height() / m_lineHeight;
height *= m_lineHeight;
if(m_bShowAddress)
{
char fmt[8] = {'%','0','8','l','X'};
fmt[2] = m_bAddressIsWide ? '8' : '4';
int w = m_bAddressIsWide ? 8 : 4;
y = 0;
CRect rcd = rc;
rcd.TopLeft().x = m_offAddress;
for(int i = m_topindex; (i < m_length) && (rcd.TopLeft().y < height); i+= m_bpr)
{
sprintf(buf, fmt, i);
dc.DrawText(buf, w, rcd, DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
rcd.TopLeft().y += m_lineHeight;
}
}
if(m_bShowHex)
{
y = 0;
CRect rcd = rc;
rcd.TopLeft().x = x = m_offHex;
if(m_selStart != 0xffffffff && (m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW))
{
int i;
int n = 0;
int selStart = m_selStart, selEnd = m_selEnd;
if(selStart > selEnd)
selStart ^= selEnd ^= selStart ^= selEnd;
for(i = m_topindex; (i < selStart) && (y < height); i++)
{
char* p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
dc.TextOut(x, y, buf, 3);
x += m_nullWidth * 3;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offHex;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
for(; (i < selEnd) && (i < m_length) && (y < height); i++)
{
char* p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
dc.TextOut(x, y, buf, 3);
x += m_nullWidth * 3;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offHex;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
for(; (i < m_length) && (y < height); i++)
{
char* p = &buf[0];
TOHEX(m_pData[i], p);
*p++ = ' ';
dc.TextOut(x, y, buf, 3);
x += m_nullWidth * 3;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offHex;
y += m_lineHeight;
}
}
}
else
{
for(int i = m_topindex; (i < m_length) && (rcd.TopLeft().y < height);)
{
char* p = &buf[0];
for(int n = 0; (n < m_bpr) && (i < m_length); n++)
{
TOHEX(m_pData[i], p);
*p++ = ' ';
i++;
}
while(n < m_bpr)
{
*p++ = ' '; *p++ = ' '; *p++ = ' ';
n++;
}
dc.DrawText(buf, m_bpr*3, rcd, DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
rcd.TopLeft().y += m_lineHeight;
}
}
}
if(m_bShowAscii)
{
y = 0;
CRect rcd = rc;
rcd.TopLeft().x = x = m_offAscii;
if(m_selStart != 0xffffffff && m_currentMode == EDIT_ASCII)
{
int i;
int n = 0;
int selStart = m_selStart, selEnd = m_selEnd;
if(selStart > selEnd)
selStart ^= selEnd ^= selStart ^= selEnd;
for(i = m_topindex; (i < selStart) && (y < height); i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
dc.TextOut(x, y, buf, 1);
x += m_nullWidth;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offAscii;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
for(; (i < selEnd) && (y < height); i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
dc.TextOut(x, y, buf, 1);
x += m_nullWidth;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offAscii;
y += m_lineHeight;
}
}
dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
dc.SetBkColor(GetSysColor(COLOR_WINDOW));
for(; (i < m_length) && y < height; i++)
{
buf[0] = isprint(m_pData[i]) ? m_pData[i] : '.';
dc.TextOut(x, y, buf, 1);
x += m_nullWidth;
n++;
if(n == m_bpr)
{
n = 0;
x = m_offAscii;
y += m_lineHeight;
}
}
}
else
{
for(int i = m_topindex; (i < m_length) && (rcd.TopLeft().y < height);)
{
char* p = &buf[0];
for(int n = 0; (n < m_bpr) && (i < m_length); n++)
{
*p++ = isprint(m_pData[i]) ? m_pData[i] : '.';
i++;
}
dc.DrawText(buf, n, rcd, DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
rcd.TopLeft().y += m_lineHeight;
}
}
}
}
pdc.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, 0, 0, SRCCOPY);
}
void CHexEdit::OnSetFocus(CWnd* pOldWnd)
{
if(m_pData && !IsSelected())
{
if(m_editPos.x == 0 && m_bShowAddress)
CreateAddressCaret();
else
CreateEditCaret();
SetCaretPos(m_editPos);
ShowCaret();
}
CWnd::OnSetFocus(pOldWnd);
}
void CHexEdit::OnKillFocus(CWnd* pNewWnd)
{
DestroyCaret();
CWnd::OnKillFocus(pNewWnd);
}
void CHexEdit::OnSize(UINT nType, int cx, int cy)
{
CEdit::OnSize(nType, cx, cy);
}
void CHexEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
pScrollBar;
if(!m_pData)
return;
int oa = m_topindex;
switch(nSBCode)
{
case SB_LINEDOWN:
if(m_topindex < m_length - m_lpp*m_bpr)
{
m_topindex += m_bpr;
RedrawWindow();
}
break;
case SB_LINEUP:
if(m_topindex > 0)
{
m_topindex -= m_bpr;
RedrawWindow();
}
break;
case SB_PAGEDOWN:
if(m_topindex < m_length - m_lpp*m_bpr)
{
m_topindex += m_bpr * m_lpp;
if(m_topindex > m_length - m_lpp*m_bpr)
m_topindex = m_length - m_lpp*m_bpr;
RedrawWindow();
}
break;
case SB_PAGEUP:
if(m_topindex > 0)
{
m_topindex -= m_bpr * m_lpp;
if(m_topindex < 0)
m_topindex = 0;
RedrawWindow();
}
break;
case SB_THUMBTRACK:
m_topindex = nPos * m_bpr;
RedrawWindow();
break;
}
::SetScrollPos(this->m_hWnd, SB_VERT, m_topindex / m_bpr, TRUE);
if(!m_bNoAddressChange)
m_currentAddress += (m_topindex - oa);
RepositionCaret(m_currentAddress);
}
void CHexEdit::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
nSBCode;nPos; pScrollBar;
}
UINT CHexEdit::OnGetDlgCode()
{
return DLGC_WANTALLKEYS;
}
BOOL CHexEdit::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_HSCROLL|WS_VSCROLL;
return CEdit::PreCreateWindow(cs);
}
BOOL CHexEdit::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
dwStyle |= WS_HSCROLL|WS_VSCROLL;
BOOL bRet = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
if(bRet)
SetFont(&m_Font);
return bRet;
}
BOOL CHexEdit::OnEraseBkgnd(CDC* pDC)
{
pDC;
return TRUE;
}
void CHexEdit::SetOptions(BOOL a, BOOL h, BOOL c, BOOL w)
{
m_bShowHex = h;
m_bShowAscii = c;
m_bShowAddress = a;
m_bAddressIsWide= w;
m_bUpdate = TRUE;
}
void CHexEdit::SetBPR(int bpr)
{
m_bpr = bpr;
m_bUpdate = TRUE;
}
void CHexEdit::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
if(!m_pData)
return;
if(nFlags & MK_SHIFT)
{
m_selStart = m_currentAddress;
}
CPoint pt = CalcPos(point.x, point.y);
if(pt.x > -1)
{
m_editPos = pt;
pt.x *= m_nullWidth;
pt.y *= m_lineHeight;
if(pt.x == 0 && m_bShowAddress)
CreateAddressCaret();
else
CreateEditCaret();
SetCaretPos(pt);
if(nFlags & MK_SHIFT)
{
m_selEnd = m_currentAddress;
if(m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW)
m_selEnd++;
RedrawWindow();
}
}
if(!(nFlags & MK_SHIFT))
{
if(DragDetect(this->m_hWnd, point))
{
m_selStart = m_currentAddress;
m_selEnd = m_selStart;
SetCapture();
}
else
{
BOOL bsel = m_selStart != 0xffffffff;
m_selStart = 0xffffffff;
m_selEnd = 0xffffffff;
if(bsel)
RedrawWindow();
}
}
if(!IsSelected())
{
ShowCaret();
}
}
void CHexEdit::OnLButtonDblClk(UINT nFlags, CPoint point)
{
nFlags; point;
}
CPoint CHexEdit::CalcPos(int x, int y)
{
y /= m_lineHeight;
if(y < 0 || y > m_lpp)
return CPoint(-1, -1);
if(y * m_bpr > m_length)
return CPoint(-1, -1);
x += m_nullWidth;
x /= m_nullWidth;
int xp;
if(m_bShowAddress && x <= (m_bAddressIsWide ? 8 : 4))
{
m_currentAddress = m_topindex + (m_bpr * y);
m_currentMode = EDIT_NONE;
return CPoint(0, y);
}
xp = (m_offHex / m_nullWidth) + m_bpr * 3;
if(m_bShowHex && x < xp)
{
if(x%3)
x--;
m_currentAddress = m_topindex + (m_bpr * y) + (x - (m_offHex / m_nullWidth)) / 3;
m_currentMode = ((x%3) & 0x01) ? EDIT_LOW : EDIT_HIGH;
return CPoint(x, y);
}
xp = (m_offAscii / m_nullWidth) + m_bpr;
if(m_bShowAscii && x <= xp)
{
m_currentAddress = m_topindex + (m_bpr * y) + (x - (m_offAscii / m_nullWidth));
m_currentMode = EDIT_ASCII;
return CPoint(x, y);
}
return CPoint(-1,-1);
}
void CHexEdit::CreateAddressCaret()
{
DestroyCaret();
CreateSolidCaret(m_nullWidth * (m_bAddressIsWide ? 8 : 4), m_lineHeight);
}
void CHexEdit::CreateEditCaret()
{
DestroyCaret();
CreateSolidCaret(m_nullWidth, m_lineHeight);
}
void CHexEdit::OnMouseMove(UINT nFlags, CPoint point)
{
if(!m_pData)
return;
if(nFlags & MK_LBUTTON && m_selStart != 0xffffffff)
{
CRect rc;
GetClientRect(&rc);
if(!rc.PtInRect(point))
{
if(point.y < 0)
{
OnVScroll(SB_LINEUP, 0, NULL);
point.y = 0;
}
else if(point.y > rc.Height())
{
OnVScroll(SB_LINEDOWN, 0, NULL);
point.y = rc.Height() -1;
}
}
int seo = m_selEnd;
CPoint pt = CalcPos(point.x, point.y);
if(pt.x > -1)
{
m_selEnd = m_currentAddress;
if(m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW)
m_selEnd++;
}
if(IsSelected())
DestroyCaret();
if(seo != m_selEnd)
RedrawWindow();
}
}
void CHexEdit::UpdateScrollbars()
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = (m_length / m_bpr) - 1;
si.nPage = m_lpp;
si.nPos = m_topindex / m_bpr;
::SetScrollInfo(this->m_hWnd, SB_VERT, &si, TRUE);
if(si.nMax > (int)si.nPage)
::EnableScrollBar(this->m_hWnd, SB_VERT, ESB_ENABLE_BOTH);
CRect rc;
GetClientRect(&rc);
si.nMin = 0;
si.nMax =((m_bShowAddress ? (m_bAddressIsWide ? 8 : 4) : 0) +
(m_bShowHex ? m_bpr * 3 : 0) +
(m_bShowAscii ? m_bpr : 0) ) * m_nullWidth;
si.nPage = 1;
si.nPos = 0;
::SetScrollInfo(this->m_hWnd, SB_HORZ, &si, TRUE);
}
inline BOOL CHexEdit::IsSelected()
{
return m_selStart != 0xffffffff;
}
void CHexEdit::OnLButtonUp(UINT nFlags, CPoint point)
{
if(IsSelected())
ReleaseCapture();
CWnd::OnLButtonUp(nFlags, point);
}
void CHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
nFlags;nRepCnt;
if(!m_pData)
return;
if(nChar == '/t')
return;
if(GetKeyState(VK_CONTROL) & 0x80000000)
{
switch(nChar)
{
case 0x03:
if(IsSelected())
OnEditCopy();
return;
case 0x16:
OnEditPaste();
return;
case 0x18:
if(IsSelected())
OnEditCut();
return;
case 0x1a:
OnEditUndo();
return;
}
}
if(nChar == 0x08)
{
if(m_currentAddress > 0)
{
m_currentAddress--;
SelDelete(m_currentAddress, m_currentAddress+1);
RepositionCaret(m_currentAddress);
RedrawWindow();
}
return;
}
SetSel(-1, -1);
switch(m_currentMode)
{
case EDIT_NONE:
return;
case EDIT_HIGH:
case EDIT_LOW:
if((nChar >= '0' && nChar <= '9') || (nChar >= 'a' && nChar <= 'f'))
{
UINT b = nChar - '0';
if(b > 9)
b = 10 + nChar - 'a';
if(m_currentMode == EDIT_HIGH)
{
m_pData[m_currentAddress] = (unsigned char)((m_pData[m_currentAddress] & 0x0f) | (b << 4));
}
else
{
m_pData[m_currentAddress] = (unsigned char)((m_pData[m_currentAddress] & 0xf0) | b);
}
Move(1,0);
}
break;
case EDIT_ASCII:
m_pData[m_currentAddress] = (unsigned char)nChar;
Move(1,0);
break;
}
RedrawWindow();
}
void CHexEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
nFlags; nRepCnt;
BOOL bShift = GetKeyState(VK_SHIFT) & 0x80000000;
BOOL bac = m_bNoAddressChange;
m_bNoAddressChange = TRUE;
switch(nChar)
{
case VK_DOWN:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
Move(0,1);
m_selEnd = m_currentAddress;
if(m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW)
m_selEnd++;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
Move(0,1);
break;
case VK_UP:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
Move(0,-1);
m_selEnd = m_currentAddress;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
Move(0,-1);
break;
case VK_LEFT:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
Move(-1,0);
m_selEnd = m_currentAddress;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
Move(-1,0);
break;
case VK_RIGHT:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
Move(1,0);
m_selEnd = m_currentAddress;
if(m_currentMode == EDIT_HIGH || m_currentMode == EDIT_LOW)
m_selEnd++;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
Move(1,0);
break;
case VK_PRIOR:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
OnVScroll(SB_PAGEUP, 0, NULL);
Move(0,0);
m_selEnd = m_currentAddress;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
OnVScroll(SB_PAGEUP, 0, NULL);
Move(0,0);
break;
case VK_NEXT:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
OnVScroll(SB_PAGEDOWN, 0, NULL);
Move(0,0);
m_selEnd = m_currentAddress;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
OnVScroll(SB_PAGEDOWN, 0, NULL);
Move(0,0);
break;
case VK_HOME:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
if(GetKeyState(VK_CONTROL) & 0x80000000)
{
OnVScroll(SB_THUMBTRACK, 0, NULL);
Move(0,0);
}
else
{
m_currentAddress /= m_bpr;
m_currentAddress *= m_bpr;
Move(0,0);
}
m_selEnd = m_currentAddress;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
if(GetKeyState(VK_CONTROL) & 0x80000000)
{
OnVScroll(SB_THUMBTRACK, 0, NULL);
m_currentAddress = 0;
Move(0,0);
}
else
{
m_currentAddress /= m_bpr;
m_currentAddress *= m_bpr;
Move(0,0);
}
break;
case VK_END:
if(bShift)
{
if(!IsSelected())
{
m_selStart = m_currentAddress;
}
if(GetKeyState(VK_CONTROL) & 0x80000000)
{
m_currentAddress = m_length-1;
OnVScroll(SB_THUMBTRACK, ((m_length+(m_bpr/2)) / m_bpr) - m_lpp, NULL);
Move(0,0);
}
else
{
m_currentAddress /= m_bpr;
m_currentAddress *= m_bpr;
m_currentAddress += m_bpr - 1;
if(m_currentAddress > m_length)
m_currentAddress = m_length-1;
Move(0,0);
}
m_selEnd = m_currentAddress;
RedrawWindow();
break;
}
else
SetSel(-1, -1);
if(GetKeyState(VK_CONTROL) & 0x80000000)
{
m_currentAddress = m_length-1;
if(m_bHalfPage)
OnVScroll(SB_THUMBTRACK, 0, NULL);
else
OnVScroll(SB_THUMBTRACK, ((m_length+(m_bpr/2)) / m_bpr) - m_lpp, NULL);
Move(0,0);
}
else
{
m_currentAddress /= m_bpr;
m_currentAddress *= m_bpr;
m_currentAddress += m_bpr - 1;
if(m_currentAddress > m_length)
m_currentAddress = m_length-1;
Move(0,0);
}
break;
case VK_INSERT:
SelInsert(m_currentAddress, max(1, m_selEnd-m_selStart));
RedrawWindow();
break;
case VK_DELETE:
if(IsSelected())
{
OnEditClear();
}
else
{
SelDelete(m_currentAddress, m_currentAddress+1);
RedrawWindow();
}
break;
case '/t':
switch(m_currentMode)
{
case EDIT_NONE:
m_currentMode = EDIT_HIGH;
break;
case EDIT_HIGH:
case EDIT_LOW:
m_currentMode = EDIT_ASCII;
break;
case EDIT_ASCII:
m_currentMode = EDIT_HIGH;
break;
}
Move(0,0);
break;
}
m_bNoAddressChange = bac;
}
void CHexEdit::Move(int x, int y)
{
switch(m_currentMode)
{
case EDIT_NONE:
return;
case EDIT_HIGH:
if(x != 0)
m_currentMode = EDIT_LOW;
if(x == -1)
m_currentAddress --;
m_currentAddress += y* m_bpr;
break;
case EDIT_LOW:
if(x != 0)
m_currentMode = EDIT_HIGH;
if(x == 1)
m_currentAddress++;
m_currentAddress += y* m_bpr;
break;
case EDIT_ASCII:
{
m_currentAddress += x;
m_currentAddress += y*m_bpr;
}
break;
}
if(m_currentAddress < 0)
m_currentAddress = 0;
if(m_currentAddress >= m_length)
{
m_currentAddress -= x;
m_currentAddress -= y*m_bpr;
}
m_bNoAddressChange = TRUE;
if(m_currentAddress < m_topindex)
{
OnVScroll(SB_LINEUP, 0, NULL);
}
if(m_currentAddress >= m_topindex + m_lpp*m_bpr)
{
OnVScroll(SB_LINEDOWN, 0, NULL);
}
m_bNoAddressChange = FALSE;
RepositionCaret(m_currentAddress);
}
void CHexEdit::SetSel(int s, int e)
{
DestroyCaret();
m_selStart = s;
m_selEnd = e;
RedrawWindow();
if(m_editPos.x == 0 && m_bShowAddress)
CreateAddressCaret();
else
CreateEditCaret();
SetCaretPos(m_editPos);
ShowCaret();
}
void CHexEdit::RepositionCaret(int p)
{
int x, y;
y = (p - m_topindex) / m_bpr;
x = (p - m_topindex) % m_bpr;
switch(m_currentMode)
{
case EDIT_NONE:
CreateAddressCaret();
x = 0;
break;
case EDIT_HIGH:
CreateEditCaret();
x *= m_nullWidth*3;
x += m_offHex;
break;
case EDIT_LOW:
CreateEditCaret();
x *= m_nullWidth*3;
x += m_nullWidth;
x += m_offHex;
break;
case EDIT_ASCII:
CreateEditCaret();
x *= m_nullWidth;
x += m_offAscii;
break;
}
m_editPos.x = x;
m_editPos.y = y*m_lineHeight;
CRect rc;
GetClientRect(&rc);
if(rc.PtInRect(m_editPos))
{
SetCaretPos(m_editPos);
ShowCaret();
}
}
void CHexEdit::ScrollIntoView(int p)
{
if(p < m_topindex || p > m_topindex + m_lpp*m_bpr)
{
m_topindex = (p/m_bpr) * m_bpr;
m_topindex -= (m_lpp / 3) * m_bpr;
if(m_topindex < 0)
m_topindex = 0;
UpdateScrollbars();
RedrawWindow();
}
}
void CHexEdit::OnContextMenu(CWnd*, CPoint point)
{
{
if (point.x == -1 && point.y == -1)
{
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
point = rect.TopLeft();
point.Offset(5, 5);
}
CMenu menu;
VERIFY(menu.LoadMenu(CG_IDR_POPUP_HEX_EDIT));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
pPopup->EnableMenuItem(ID_EDIT_UNDO, MF_GRAYED|MF_DISABLED|MF_BYCOMMAND);
if(!IsSelected())
{
pPopup->EnableMenuItem(ID_EDIT_CLEAR, MF_GRAYED|MF_DISABLED|MF_BYCOMMAND);
pPopup->EnableMenuItem(ID_EDIT_CUT, MF_GRAYED|MF_DISABLED|MF_BYCOMMAND);
pPopup->EnableMenuItem(ID_EDIT_COPY, MF_GRAYED|MF_DISABLED|MF_BYCOMMAND);
}
{
COleDataObject obj;
if (obj.AttachClipboard())
{
if(!obj.IsDataAvailable(CF_TEXT) && !obj.IsDataAvailable(RegisterClipboardFormat("BinaryData")))
pPopup->EnableMenuItem(ID_EDIT_PASTE, MF_GRAYED|MF_DISABLED|MF_BYCOMMAND);
}
}
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
this);
}
}
void CHexEdit::OnEditClear()
{
m_currentAddress = m_selStart;
SelDelete(m_selStart, m_selEnd);
RepositionCaret(m_currentAddress);
RedrawWindow();
}
void CHexEdit::OnEditCopy()
{
COleDataSource* pSource = new COleDataSource();
EmptyClipboard();
if(m_currentMode != EDIT_ASCII)
{
int dwLen = (m_selEnd-m_selStart);
HGLOBAL hMemb = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT, m_selEnd-m_selStart);
HGLOBAL hMema = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT, (dwLen) * 3);
if (!hMema)
return;
// copy binary
LPBYTE p = (BYTE*)::GlobalLock(hMemb);
memcpy(p, m_pData+m_selStart, dwLen);
::GlobalUnlock(hMemb);
// copy ascii
p = (BYTE*)::GlobalLock(hMema);
for(int i = 0; i < dwLen;)
{
TOHEX(m_pData[m_selStart+i], p);
*p++ = ' ';
i++;
}
::GlobalUnlock(hMema);
pSource->CacheGlobalData(RegisterClipboardFormat("BinaryData"), hMemb);
pSource->CacheGlobalData(CF_TEXT, hMema);
}
else
{
HGLOBAL hMemb = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT, m_selEnd-m_selStart);
HGLOBAL hMema = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT, m_selEnd-m_selStart);
if (!hMemb || !hMema)
return;
// copy binary
LPBYTE p = (BYTE*)::GlobalLock(hMemb);
int dwLen = m_selEnd-m_selStart;
memcpy(p, m_pData+m_selStart, dwLen);
::GlobalUnlock(hMemb);
// copy ascii
p = (BYTE*)::GlobalLock(hMema);
memcpy(p, m_pData+m_selStart, dwLen);
for(int i = 0; i < dwLen; p++, i++)
if(!isprint(*p))
*p = '.';
::GlobalUnlock(hMema);
pSource->CacheGlobalData(RegisterClipboardFormat("BinaryData"), hMemb);
pSource->CacheGlobalData(CF_TEXT, hMema);
}
pSource->SetClipboard();
}
void CHexEdit::OnEditCut()
{
OnEditCopy();
SelDelete(m_selStart, m_selEnd);
RedrawWindow();
}
void CHexEdit::OnEditPaste()
{
COleDataObject obj;
if (obj.AttachClipboard())
{
HGLOBAL hmem = NULL;
if (obj.IsDataAvailable(RegisterClipboardFormat("BinaryData")))
{
hmem = obj.GetGlobalData(RegisterClipboardFormat("BinaryData"));
}
else if (obj.IsDataAvailable(CF_TEXT))
{
hmem = obj.GetGlobalData(CF_TEXT);
}
if(hmem)
{
LPBYTE p = (BYTE*)::GlobalLock(hmem);
DWORD dwLen = ::GlobalSize(hmem);
int insert;
int oa = m_currentAddress;
NormalizeSel();
if(m_selStart == 0xffffffff)
{
if(m_currentMode == EDIT_LOW)
m_currentAddress++;
insert = m_currentAddress;
SelInsert(m_currentAddress, dwLen);
}
else
{
insert = m_selStart;
SelDelete(m_selStart, m_selEnd);
SelInsert(insert, dwLen);
SetSel(-1, -1);
}
memcpy(m_pData+insert, p, dwLen);
m_currentAddress = oa;
RedrawWindow();
::GlobalUnlock(hmem);
}
}
}
void CHexEdit::OnEditSelectAll()
{
m_selStart = 0;
m_selEnd = m_length;
DestroyCaret();
RedrawWindow();
}
void CHexEdit::OnEditUndo()
{
// TODO: Add your command handler code here
}
void CHexEdit::NormalizeSel()
{
if(m_selStart > m_selEnd)
m_selStart ^= m_selEnd ^= m_selStart ^= m_selEnd;
}
void CHexEdit::SelDelete(int s, int e)
{
LPBYTE p = (LPBYTE) malloc(m_length - (e-s)+1);
memcpy(p, m_pData, s);
if(s < m_length-(e-s))
memcpy(p+s, m_pData+e, (m_length -e));
free(m_pData);
SetSel(-1, -1);
m_pData = p;
m_length = m_length-(e-s);
if(m_currentAddress > m_length)
{
m_currentAddress = m_length;
RepositionCaret(m_currentAddress);
}
m_bUpdate = TRUE;
}
void CHexEdit::SelInsert(int s, int l)
{
LPBYTE p = (LPBYTE) calloc(m_length + l, 1);
memcpy(p, m_pData, s);
memcpy(p+s+l, m_pData+s, (m_length-s));
free(m_pData);
SetSel(-1, -1);
m_pData = p;
m_length = m_length+l;
m_bUpdate = TRUE;
}
CSize CHexEdit::GetSel()
{
return CSize(m_selStart, m_selEnd);
}
void CHexEdit::SetData(LPBYTE p, int len)
{
free(m_pData);
m_pData = (LPBYTE) malloc(len);
memcpy(m_pData, p, len);
SetSel(-1, -1);
m_length = len;
m_currentAddress = 0;
m_editPos.x = m_editPos.y = 0;
m_currentMode = EDIT_HIGH;
m_topindex = 0;
m_bUpdate = TRUE;
}
int CHexEdit::GetData(LPBYTE p, int len)
{
memcpy(p, m_pData, min(len, m_length));
return m_length;
}
void CHexEdit::AppendData(LPBYTE p, int addlen)
{
LPBYTE oldData=m_pData;
int oldlen=m_length;
m_pData = (LPBYTE) malloc(oldlen+addlen);
m_length = oldlen+addlen;
memcpy(m_pData, oldData, oldlen);
free(oldData);
memcpy(m_pData+oldlen,p,addlen);
SetSel(oldlen, m_length);
m_currentAddress = oldlen;
m_editPos.x = m_editPos.y = 0;
m_currentMode = EDIT_HIGH;
m_topindex = 0;
m_bUpdate = TRUE;
}
void CHexEdit::Clear()
{
free(m_pData);
m_pData = NULL; // pointer to data
m_length = 0;
m_selStart = 0xffffffff;
m_selEnd = 0xffffffff;
m_bUpdate=TRUE;
}