view src/win32/MemoryViewer.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 // MemoryViewer.cpp : implementation file
2 //
4 #include "stdafx.h"
5 #include "resource.h"
6 #include "MemoryViewer.h"
8 extern int emulating;
10 /////////////////////////////////////////////////////////////////////////////
11 // MemoryViewer
13 bool MemoryViewer::isRegistered = false;
15 MemoryViewer::MemoryViewer()
16 {
17 address = 0;
18 addressSize = 0;
19 dataSize = 0;
20 editAddress = 0;
21 editNibble = 0;
22 displayedLines = 0;
23 hasCaret = false;
24 maxNibble = 0;
25 font = (HFONT)GetStockObject(SYSTEM_FIXED_FONT);
26 fontSize.cx = fontSize.cy = 0;
27 beginAscii = 0;
28 beginHex = 0;
29 dlg = NULL;
30 registerClass();
31 }
33 MemoryViewer::~MemoryViewer()
34 {}
36 BEGIN_MESSAGE_MAP(MemoryViewer, CWnd)
37 //{{AFX_MSG_MAP(MemoryViewer)
38 ON_WM_ERASEBKGND()
39 ON_WM_PAINT()
40 ON_WM_VSCROLL()
41 ON_WM_GETDLGCODE()
42 ON_WM_LBUTTONDOWN()
43 ON_WM_SETFOCUS()
44 ON_WM_KILLFOCUS()
45 ON_WM_KEYDOWN()
46 //}}AFX_MSG_MAP
47 ON_MESSAGE(WM_CHAR, OnWMChar)
48 END_MESSAGE_MAP()
50 /////////////////////////////////////////////////////////////////////////////
51 // MemoryViewer message handlers
53 void MemoryViewer::setDialog(IMemoryViewerDlg *d)
54 {
55 dlg = d;
56 }
58 void MemoryViewer::setAddress(u32 a)
59 {
60 address = a;
61 if (displayedLines)
62 {
63 if (addressSize)
64 {
65 u16 addr = address;
66 if ((u16)((addr+(displayedLines<<4)) & 0xFFFF) < addr)
67 {
68 address = 0xffff - (displayedLines<<4) + 1;
69 }
70 }
71 else
72 {
73 if ((address+(displayedLines<<4)) < address)
74 {
75 address = 0xffffffff - (displayedLines<<4) + 1;
76 }
77 }
78 }
79 if (addressSize)
80 address &= 0xffff;
81 setCaretPos();
82 InvalidateRect(NULL, TRUE);
83 }
85 void MemoryViewer::setSize(int s)
86 {
87 dataSize = s;
88 if (s == 0)
89 maxNibble = 1;
90 else if (s == 1)
91 maxNibble = 3;
92 else
93 maxNibble = 7;
95 InvalidateRect(NULL, TRUE);
96 }
98 void MemoryViewer::setDecimal(bool decimalDisplayMode)
99 {
100 decimalDisplay = decimalDisplayMode;
101 InvalidateRect(NULL, TRUE);
102 }
104 BOOL MemoryViewer::OnEraseBkgnd(CDC*pDC)
105 {
106 return TRUE;
107 }
109 void MemoryViewer::updateScrollInfo(int lines)
110 {
111 int page = lines * 16;
112 SCROLLINFO si;
113 ZeroMemory(&si, sizeof(si));
114 si.cbSize = sizeof(si);
115 si.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL | SIF_POS;
116 si.nMin = 0;
117 if (addressSize)
118 {
119 si.nMax = 0x10000/page;
120 si.nPage = 1;
121 }
122 else
123 {
124 si.nMax = 0xa000000 / page;
125 si.nPage = page;
126 }
128 si.nPos = address / page;
129 SetScrollInfo(SB_VERT,
130 &si,
131 TRUE);
132 }
134 void MemoryViewer::OnPaint()
135 {
136 CPaintDC dc(this); // device context for painting
138 RECT rect;
139 GetClientRect(&rect);
140 int w = rect.right - rect.left;
141 int h = rect.bottom - rect.top - 6;
143 CDC memDC;
144 memDC.CreateCompatibleDC(&dc);
145 CBitmap bitmap, *pOldBitmap;
146 bitmap.CreateCompatibleBitmap(&dc, w, rect.bottom - rect.top);
147 pOldBitmap = memDC.SelectObject(&bitmap);
149 memDC.FillRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
150 memDC.DrawEdge(&rect, EDGE_ETCHED, BF_RECT);
152 CFont *oldFont = memDC.SelectObject(CFont::FromHandle(font));
154 fontSize = memDC.GetTextExtent("0", 1);
156 int lines = h / fontSize.cy;
158 displayedLines = lines;
160 updateScrollInfo(lines);
162 u32 addr = address;
164 memDC.SetTextColor(RGB(0, 0, 0));
166 u8 data[32];
168 RECT r;
169 r.top = 3;
170 r.left = 3;
171 r.bottom = r.top+fontSize.cy;
172 r.right = rect.right-3;
174 int line = 0;
176 for (int i = 0; i < lines; i++)
177 {
178 CString buffer;
179 if (addressSize)
180 buffer.Format("%04X", addr);
181 else
182 buffer.Format("%08X", addr);
183 memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
184 r.left += 10*fontSize.cx;
185 beginHex = r.left;
186 readData(addr, 16, data);
188 int j;
190 if (dataSize == 0)
191 {
192 for (j = 0; j < 16; j++)
193 {
194 const int nextRLeft = r.left + 3*fontSize.cx;
195 if (!decimalDisplay)
196 buffer.Format("%02X", data[j]);
197 else
198 {
199 const signed char num = data[j];
200 if (num < -9 || num > 99)
201 r.left -= fontSize.cx;
202 if (num >= -99 && num <= 99)
203 buffer.Format("%2d", num);
204 else
205 buffer.Format("");
206 }
207 memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
208 r.left = nextRLeft;
209 }
210 }
211 if (dataSize == 1)
212 {
213 for (j = 0; j < 16; j += 2)
214 {
215 const int nextRLeft = r.left + 5*fontSize.cx;
216 if (!decimalDisplay)
217 buffer.Format("%04X", data[j] | data[j+1]<<8);
218 else
219 {
220 const signed short num = data[j] | data[j+1]<<8;
221 if (num < -999 || num > 9999)
222 r.left -= fontSize.cx;
223 if (num >= -9999 && num <= 9999)
224 buffer.Format("%4d", num);
225 else
226 buffer.Format("");
227 }
228 memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
229 r.left = nextRLeft;
230 }
231 }
232 if (dataSize == 2)
233 {
234 for (j = 0; j < 16; j += 4)
235 {
236 if (!decimalDisplay)
237 buffer.Format("%08X", data[j] | data[j+1]<<8 | data[j+2] << 16 | data[j+3] << 24);
238 else
239 {
240 const signed long num = data[j] | data[j+1]<<8 | data[j+2] << 16 | data[j+3] << 24;
241 if (num >= -9999999 && num <= 99999999)
242 buffer.Format("%8d", num);
243 else
244 buffer.Format("");
245 }
246 memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
247 r.left += 9*fontSize.cx;
248 }
249 }
251 line = r.left;
253 r.left += fontSize.cx;
254 beginAscii = r.left;
255 buffer.Empty();
256 for (j = 0; j < 16; j++)
257 {
258 char c = data[j];
259 if (c >= 32 && c <= 127)
260 {
261 buffer += c;
262 }
263 else
264 buffer += '.';
265 }
267 memDC.DrawText(buffer, &r, DT_TOP | DT_LEFT | DT_NOPREFIX);
268 addr += 16;
269 if (addressSize)
270 addr &= 0xffff;
271 r.top += fontSize.cy;
272 r.bottom += fontSize.cy;
273 r.left = 3;
274 }
275 CPen pen;
276 pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
277 CPen *old = memDC.SelectObject(&pen);
279 memDC.MoveTo(3+fontSize.cx*9, 3);
280 memDC.LineTo(3+fontSize.cx*9, 3+displayedLines*fontSize.cy);
282 memDC.MoveTo(line, 3);
283 memDC.LineTo(line, 3+displayedLines*fontSize.cy);
285 memDC.SelectObject(old);
286 pen.DeleteObject();
288 memDC.SelectObject(oldFont);
290 dc.BitBlt(0, 0, w, rect.bottom - rect.top, &memDC, 0, 0, SRCCOPY);
292 memDC.SelectObject(pOldBitmap);
293 memDC.DeleteDC();
294 bitmap.DeleteObject();
295 }
297 void MemoryViewer::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*pScrollBar)
298 {
299 int address = this->address;
300 switch (nSBCode)
301 {
302 case SB_BOTTOM:
303 address = 0xffffff00;
304 break;
305 case SB_LINEDOWN:
306 address += 0x10;
307 break;
308 case SB_LINEUP:
309 address -= 0x10;
310 break;
311 case SB_PAGEDOWN:
312 address += (displayedLines<<4);
313 break;
314 case SB_PAGEUP:
315 address -= (displayedLines<<4);
316 break;
317 case SB_TOP:
318 address = 0;
319 break;
320 case SB_THUMBTRACK:
321 {
322 int page = displayedLines * 16;
323 SCROLLINFO si;
324 ZeroMemory(&si, sizeof(si));
325 si.cbSize = sizeof(si);
326 si.fMask = SIF_TRACKPOS;
327 GetScrollInfo(SB_VERT, &si);
328 address = page * si.nTrackPos;
329 break;
330 }
331 }
332 setAddress(address);
333 }
335 UINT MemoryViewer::OnGetDlgCode()
336 {
337 return DLGC_WANTALLKEYS;
338 }
340 void MemoryViewer::createEditCaret(int w, int h)
341 {
342 if (!hasCaret || caretWidth != w || caretHeight != h)
343 {
344 hasCaret = true;
345 caretWidth = w;
346 caretHeight = h;
347 ::CreateCaret(m_hWnd, (HBITMAP)0, w, h);
348 }
349 }
351 void MemoryViewer::destroyEditCaret()
352 {
353 hasCaret = false;
354 DestroyCaret();
355 }
357 void MemoryViewer::setCaretPos()
358 {
359 if (GetFocus() != this)
360 {
361 destroyEditCaret();
362 return;
363 }
365 if (dlg)
366 dlg->setCurrentAddress(editAddress);
368 if (editAddress < address || editAddress > (address -1 + (displayedLines<<4)))
369 {
370 destroyEditCaret();
371 return;
372 }
374 int subAddress = (editAddress - address);
376 int x = 3+10*fontSize.cx+editNibble*fontSize.cx;
377 int y = 3+fontSize.cy*((editAddress-address)>>4);
379 if (editAscii)
380 {
381 x = beginAscii + fontSize.cx*(subAddress&15);
382 }
383 else
384 {
385 switch (dataSize)
386 {
387 case 0:
388 x += 3*fontSize.cx*(subAddress & 15);
389 break;
390 case 1:
391 x += 5*fontSize.cx*((subAddress>>1) & 7);
392 break;
393 case 2:
394 x += 9*fontSize.cx*((subAddress>>2) & 3);
395 break;
396 }
397 }
399 RECT r;
400 GetClientRect(&r);
401 r.right -= 3;
402 if (x >= r.right)
403 {
404 destroyEditCaret();
405 return;
406 }
407 int w = fontSize.cx;
408 if ((x+fontSize.cx) >= r.right)
409 w = r.right - x;
410 createEditCaret(w, fontSize.cy);
411 ::SetCaretPos(x, y);
412 ShowCaret();
413 }
415 void MemoryViewer::OnLButtonDown(UINT nFlags, CPoint point)
416 {
417 int x = point.x;
418 int y = point.y;
419 int line = (y-3)/fontSize.cy;
420 int beforeAscii = beginHex;
421 int inc = 1;
422 int sub = 3*fontSize.cx;
423 switch (dataSize)
424 {
425 case 0:
426 beforeAscii += 47*fontSize.cx;
427 break;
428 case 1:
429 beforeAscii += 39*fontSize.cx;
430 inc = 2;
431 sub = 5*fontSize.cx;
432 break;
433 case 2:
434 beforeAscii += 35*fontSize.cx;
435 inc = 4;
436 sub = 9*fontSize.cx;
437 break;
438 }
440 editAddress = address + (line<<4);
441 if (x >= beginHex && x < beforeAscii)
442 {
443 x -= beginHex;
444 editNibble = 0;
445 while (x > 0)
446 {
447 x -= sub;
448 if (x >= 0)
449 editAddress += inc;
450 else
451 {
452 editNibble = (x + sub)/fontSize.cx;
453 }
454 }
455 editAscii = false;
456 }
457 else if (x >= beginAscii)
458 {
459 int afterAscii = beginAscii+16*fontSize.cx;
460 if (x >= afterAscii)
461 x = afterAscii-1;
462 editAddress += (x-beginAscii)/fontSize.cx;
463 editNibble = 0;
464 editAscii = true;
465 }
466 else
467 {
468 return;
469 }
471 if (editNibble > maxNibble)
472 editNibble = maxNibble;
473 SetFocus();
474 setCaretPos();
475 }
477 void MemoryViewer::OnSetFocus(CWnd*pOldWnd)
478 {
479 setCaretPos();
480 InvalidateRect(NULL, TRUE);
481 }
483 void MemoryViewer::OnKillFocus(CWnd*pNewWnd)
484 {
485 destroyEditCaret();
486 InvalidateRect(NULL, TRUE);
487 }
489 void MemoryViewer::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
490 {
491 bool isShift = (GetKeyState(VK_SHIFT) & 0x80000000) == 0x80000000;
493 switch (nChar)
494 {
495 case VK_RIGHT:
496 if (editAscii)
497 moveAddress(1, 0);
498 else if (isShift)
499 moveAddress((maxNibble+1)>>1, 0);
500 else
501 moveAddress(0, 1);
502 break;
503 case VK_LEFT:
504 if (editAscii)
505 moveAddress(-1, 0);
506 else if (isShift)
507 moveAddress(-((maxNibble+1)>>1), 0);
508 else
509 moveAddress(0, -1);
510 break;
511 case VK_DOWN:
512 moveAddress(16, 0);
513 break;
514 case VK_UP:
515 moveAddress(-16, 0);
516 break;
517 case VK_TAB:
518 GetNextDlgTabItem(GetParent(), isShift)->SetFocus();
519 break;
520 }
521 }
523 void MemoryViewer::moveAddress(s32 offset, int nibbleOff)
524 {
525 if (offset == 0)
526 {
527 if (nibbleOff == -1)
528 {
529 editNibble--;
530 if (editNibble == -1)
531 {
532 editAddress -= (maxNibble + 1) >> 1;
533 editNibble = maxNibble;
534 }
535 if (address == 0 && (editAddress >= (u32)(displayedLines<<4)))
536 {
537 editAddress = 0;
538 editNibble = 0;
539 beep();
540 }
541 if (editAddress < address)
542 setAddress(address - 16);
543 }
544 else
545 {
546 editNibble++;
547 if (editNibble > maxNibble)
548 {
549 editNibble = 0;
550 editAddress += (maxNibble + 1) >> 1;
551 }
552 if (editAddress < address)
553 {
554 editAddress -= (maxNibble + 1) >> 1;
555 editNibble = maxNibble;
556 beep();
557 }
558 if (editAddress >= (address+(displayedLines<<4)))
559 setAddress(address+16);
560 }
561 }
562 else
563 {
564 editAddress += offset;
565 if (offset < 0 && editAddress > (address-1+(displayedLines<<4)))
566 {
567 editAddress -= offset;
568 beep();
569 return;
570 }
571 if (offset > 0 && (editAddress < address))
572 {
573 editAddress -= offset;
574 beep();
575 return;
576 }
577 if (editAddress < address)
578 {
579 if (offset & 15)
580 setAddress((address+offset-16) & ~15);
581 else
582 setAddress(address+offset);
583 }
584 else if (editAddress > (address - 1 + (displayedLines<<4)))
585 {
586 if (offset & 15)
587 setAddress((address+offset+16) & ~15);
588 else
589 setAddress(address+offset);
590 }
591 }
593 setCaretPos();
594 }
596 LRESULT MemoryViewer::OnWMChar(WPARAM wParam, LPARAM LPARAM)
597 {
598 if (OnEditInput(wParam))
599 return 0;
600 return 1;
601 }
603 bool MemoryViewer::OnEditInput(UINT c)
604 {
605 if (c > 255 || !emulating)
606 {
607 beep();
608 return false;
609 }
611 if (!editAscii)
612 c = tolower(c);
614 u32 value = 256;
616 if (c >= 'a' && c <= 'f')
617 value = 10 + (c - 'a');
618 else if (c >= '0' && c <= '9')
619 value = (c - '0');
620 if (editAscii)
621 {
622 editData(editAddress, 8, 0, c);
623 moveAddress(1, 0);
624 InvalidateRect(NULL, TRUE);
625 }
626 else
627 {
628 if (value != 256)
629 {
630 value <<= 4*(maxNibble-editNibble);
631 u32 mask = ~(15 << 4*(maxNibble - editNibble));
632 switch (dataSize)
633 {
634 case 0:
635 editData(editAddress, 8, mask, value);
636 break;
637 case 1:
638 editData(editAddress, 16, mask, value);
639 break;
640 case 2:
641 editData(editAddress, 32, mask, value);
642 break;
643 }
644 moveAddress(0, 1);
645 InvalidateRect(NULL, TRUE);
646 }
647 }
648 return true;
649 }
651 void MemoryViewer::beep()
652 {
653 MessageBeep((UINT)-1);
654 }
656 void MemoryViewer::registerClass()
657 {
658 if (!isRegistered)
659 {
660 WNDCLASS wc;
661 ZeroMemory(&wc, sizeof(wc));
662 wc.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
663 wc.lpfnWndProc = (WNDPROC) ::DefWindowProc;
664 wc.hInstance = AfxGetInstanceHandle();
665 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
666 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
667 wc.lpszMenuName = NULL;
668 wc.lpszClassName = "VbaMemoryViewer";
669 AfxRegisterClass(&wc);
670 isRegistered = true;
671 }
672 }
674 void MemoryViewer::setAddressSize(int s)
675 {
676 addressSize = s;
677 }
679 u32 MemoryViewer::getCurrentAddress()
680 {
681 return editAddress;
682 }
684 int MemoryViewer::getSize()
685 {
686 return dataSize;
687 }