www.pudn.com > Irp-Files.rar > hexview.c
#include#include "hexview.h" #define xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s)) #define xfree(p) HeapFree(GetProcessHeap(), 0, (p)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define EM_TEXT 0 #define EM_HEX_HIGH 1 #define EM_HEX_LOW 2 #define GWL_HEXINFO 0 #define WM_MOUSEWHEEL 0x020A #define HV_COLOR_DEFAULT 0 #define HV_COLOR_RED 1 #define HV_COLOR_SBGRAY 2 #define HV_COLOR_GREEN 3 #define HV_COLOR_BLUE 4 typedef struct _HV_PRINTFMT { BYTE x; BYTE y; BYTE color : 7; BYTE highlight : 1; BYTE len; BYTE data[]; } HV_PRINTFMT, *PHV_PRINTFMT; typedef struct _HV_MODIFYLOG { int nLog; int nBack; int nMaxUndoLog; int nMaxRedoLog; PBYTE pLog; PBYTE pLogBuf; DWORD nLogBufLen; DWORD nMaxLogBuf; PBYTE pOrgBuf; DWORD nOrgBufLen; } HV_MODIFYLOG, *PHV_MODIFYLOG; typedef struct _HEXVIEW { BOOL TextOnly; BOOL ReadOnly; BOOL NoCursor; PBYTE Buffer; DWORD Length; DWORD BaseAddress; ULONG SelStart; ULONG SelEnd; DWORD PageOffset; DWORD PageLength; DWORD PageMaxLength; UINT LineWidth; UINT AddressWidth; UINT CharWidth; UINT CharHeight; DWORD EditMode; int Cursor; HV_MODIFYLOG hv_modl; DWORD color[10]; } HEXVIEW, *PHEXVIEW; void *HV_MemSearchR(void *m1, size_t n1, void *m2, size_t n2) { unsigned char *s1 = m1; unsigned char *s2 = m2; size_t i, index[256]; if (n1 < n2) return NULL; if (n2 == 0) return m1; for (i = 0; i < 256; i++) index[i] = n2 + 1; for (i = 0; i < n2; i++) index[s2[i]] = n2 - i; do { for (i = 0; s1[i] == s2[i]; i++) { if (i == n2 - 1) return s1; } s1 += index[s1[n2]]; } while (s1 + n2 <= (char *)m1 + n1); return NULL; } void *HV_MemSearchL(void *m1, size_t n1, void *m2, size_t n2) { unsigned char *s1 = m1; unsigned char *s2 = m2; size_t i, index[256]; if (n1 < n2) return NULL; if (n2 == 0) return m1; for (i = 0; i < 256; i++) index[i] = n2 + 1; for (i = n2 - 1; i >= 0; i--) index[s2[i]] = n2 - i; do { for (i = n2 - 1; s1[i] == s2[i]; i--) { if (i == 0) return s1; } s1 -= index[*(s1 - 1)]; } while (s1 >= (char *)m1 + n2); return NULL; } int HV_InitModifyLog(PHV_MODIFYLOG hv_modl, PBYTE pOrgBuf, DWORD pOrgLen) { hv_modl->nLog = 0; hv_modl->nBack = 0; hv_modl->nMaxUndoLog = 0; hv_modl->nMaxRedoLog = 0; hv_modl->pOrgBuf = pOrgBuf; hv_modl->nOrgBufLen = pOrgLen; hv_modl->nMaxLogBuf = 0x200000; hv_modl->nLogBufLen = 0x8000; hv_modl->pLogBuf = VirtualAlloc(NULL, hv_modl->nMaxLogBuf, MEM_RESERVE, PAGE_READWRITE); hv_modl->pLog = hv_modl->pLogBuf; if (hv_modl->pLogBuf == NULL) return -1; VirtualAlloc(hv_modl->pLogBuf, hv_modl->nLogBufLen, MEM_COMMIT, PAGE_READWRITE); return 0; } int HV_AddModifyLog(PHV_MODIFYLOG hv_modl, DWORD offset, DWORD length, PBYTE pData) {//* int n; PBYTE p; DWORD l; if (hv_modl->nLog < 0) { hv_modl->nBack += -hv_modl->nLog; hv_modl->nMaxUndoLog -= -hv_modl->nLog; hv_modl->nLog = 0; } p = hv_modl->pLog; n = hv_modl->nLog; for (; n > 0; n--) p += *(PDWORD)p + sizeof(DWORD) + sizeof(DWORD); if (hv_modl->nLogBufLen - (p - hv_modl->pLogBuf) < length + sizeof(DWORD) + sizeof(DWORD)) { l = MAX(0x8000, length + sizeof(DWORD) + sizeof(DWORD)); l = (l + 0x7fff) & ~0x7fff; if (hv_modl->nLogBufLen + l > hv_modl->nMaxLogBuf) return -1; hv_modl->nLogBufLen += l; VirtualAlloc(hv_modl->pLogBuf, hv_modl->nLogBufLen, MEM_COMMIT, PAGE_READWRITE); } *((PDWORD)p)++ = length; *((PDWORD)p)++ = offset; memcpy(p, pData, length); hv_modl->nLog++; hv_modl->nMaxRedoLog = hv_modl->nLog;//*/ return 0; } int HV_GetModifyData(PHV_MODIFYLOG hv_modl, DWORD nStart, PBYTE pBuffer, DWORD nSize) { int n, x; PBYTE pUndoLog = hv_modl->pLog; PBYTE pRedoLog = hv_modl->pLog; DWORD off, len; DWORD nEnd = nStart + nSize; if (hv_modl->nLog > hv_modl->nMaxRedoLog || hv_modl->nLog < hv_modl->nMaxUndoLog) return -1; x = MIN(hv_modl->nOrgBufLen - nStart, nSize); memcpy(pBuffer, hv_modl->pOrgBuf + nStart, x); //拷贝原始数据 for (n = 0; n < hv_modl->nBack; n++) { len = *((PDWORD)pUndoLog - 1); off = *((PDWORD)pUndoLog - 2); pUndoLog -= len + sizeof(DWORD) + sizeof(DWORD); if (off >= nStart && off < nEnd) { int l = MIN(len, nSize - (off - nStart)); memcpy(pBuffer + (off - nStart), pUndoLog, l); } else if (off >= nStart && off <= nEnd) { int l = MIN(nEnd - off, len); memcpy(pBuffer + off - nStart, pUndoLog, l); } } if (hv_modl->nLog >= 0) { for (n = 0; n < hv_modl->nLog; n++) { len = *((PDWORD)pRedoLog)++; off = *((PDWORD)pRedoLog)++; if (off >= nStart && off < nEnd) { int l = MIN(len, nSize - (off - nStart)); memcpy(pBuffer + (off - nStart), pRedoLog, l); } else if (off >= nStart && off <= nEnd) { int l = MIN(nEnd - off, len); memcpy(pBuffer + off - nStart, pRedoLog, l); } pRedoLog += len; } } else { for (n = 0; n > hv_modl->nLog; n--) { len = *((PDWORD)pUndoLog - 1); off = *((PDWORD)pUndoLog - 2); pUndoLog -= len + sizeof(DWORD) + sizeof(DWORD); if (off >= nStart && off < nEnd) { int l = MIN(len, nSize - (off - nStart)); memcpy(pBuffer + (off - nStart), pUndoLog, l); } else if (off >= nStart && off <= nEnd) { int l = MIN(nEnd - off, len); memcpy(pBuffer + off - nStart, pUndoLog, l); } } } return x;//*/ } void HV_ApplyModifyLog(PHV_MODIFYLOG hv_modl, PBYTE pNewBuffer) { int i, j; PBYTE pUndoLog = hv_modl->pLog; PBYTE pRedoLog = hv_modl->pLog; if (pNewBuffer) { memcpy(pNewBuffer, hv_modl->pOrgBuf, hv_modl->nOrgBufLen); hv_modl->pOrgBuf = pNewBuffer; } if (hv_modl->nLog == 0 && hv_modl->nBack == 0) return; for (i = 0; i < hv_modl->nBack; i++) { DWORD len = *((PDWORD)pUndoLog - 1); DWORD off = *((PDWORD)pUndoLog - 2); pUndoLog -= sizeof(DWORD) + sizeof(DWORD) + len; for (j = 0; (DWORD)j < len; j++) hv_modl->pOrgBuf[off + j] = pUndoLog[j]; } if (hv_modl->nLog >= 0) { for (i = 0 ; i < hv_modl->nLog; i++) { DWORD len = *((PDWORD)pRedoLog)++; DWORD off = *((PDWORD)pRedoLog)++; for (j = 0; (DWORD)j < len; j++) { pUndoLog[j] = hv_modl->pOrgBuf[off + j]; hv_modl->pOrgBuf[off + j] = pRedoLog[j]; } pUndoLog += len; pRedoLog += len; *((PDWORD)pUndoLog)++ = off; *((PDWORD)pUndoLog)++ = len; } } else { for (i = 0 ; i > hv_modl->nLog; i--) { DWORD len = *--((PDWORD)pUndoLog); DWORD off = *--((PDWORD)pUndoLog); pUndoLog -= len; pRedoLog -= len; for (j = 0; (DWORD)j < len; j++) { pRedoLog[j] = hv_modl->pOrgBuf[off + j]; hv_modl->pOrgBuf[off + j] = pUndoLog[j]; } *--((PDWORD)pRedoLog) = off; *--((PDWORD)pRedoLog) = len; } } hv_modl->pLog = pUndoLog; hv_modl->nMaxRedoLog -= hv_modl->nLog; hv_modl->nMaxUndoLog += -hv_modl->nLog; hv_modl->nLog = 0; hv_modl->nBack = 0; } int HV_DelModifyLog(PHV_MODIFYLOG hv_modl) { if (hv_modl->nLog < 0) { PBYTE p = hv_modl->pLog; int i, j; for (i = hv_modl->nLog; i < 0; i++) { DWORD len = *((PDWORD)p - 1); DWORD off = *((PDWORD)p - 2); p -= sizeof(DWORD) + sizeof(DWORD) + len; for (j = len; j > 0; j--) p[sizeof(DWORD) + sizeof(DWORD) + j] = p[j]; *((PDWORD)p + 0) = len; *((PDWORD)p + 1) = off; } hv_modl->pLog = p; hv_modl->nMaxRedoLog = -hv_modl->nLog; hv_modl->nMaxUndoLog -= hv_modl->nLog; hv_modl->nLog = 0; } else { hv_modl->nMaxRedoLog = hv_modl->nLog; } return 0; } void HV_FreeModifyLog(PHV_MODIFYLOG hv_modl) { hv_modl->nLog = 0; hv_modl->nBack = 0; hv_modl->nMaxUndoLog = 0; hv_modl->nMaxRedoLog = 0; hv_modl->pLog = NULL; hv_modl->pOrgBuf = NULL; hv_modl->nOrgBufLen = 0; hv_modl->nMaxLogBuf = 0; hv_modl->nLogBufLen = 0; VirtualFree(hv_modl->pLogBuf, 0, MEM_RELEASE); hv_modl->pLogBuf = NULL; } void HV_ResetModifyLog(PHV_MODIFYLOG hv_modl, PBYTE pOrgBuf, DWORD pOrgLen) { hv_modl->nLog = 0; hv_modl->nBack = 0; hv_modl->nMaxUndoLog = 0; hv_modl->nMaxRedoLog = 0; hv_modl->pOrgBuf = pOrgBuf; hv_modl->nOrgBufLen = pOrgLen; } int HV_LogUndo(HWND hWnd, BOOL bTest) { PHEXVIEW p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); NMHDR n; if (p->hv_modl.nLog > p->hv_modl.nMaxUndoLog) { if (bTest == TRUE) return 1; else { p->hv_modl.nLog--; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_CHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); return 1; } } return 0; } int HV_LogRedo(HWND hWnd, BOOL bTest) { PHEXVIEW p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); NMHDR n; if (p->hv_modl.nLog < p->hv_modl.nMaxRedoLog) { if (bTest == TRUE) return 1; else { p->hv_modl.nLog++; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_CHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); return 1; } } return 0; } int HV_Compare(PBYTE s1, PBYTE s2, int n) { int i = n; if (*s1 == *s2) { while (--n && *++s1 == *++s2); return i - n; } else { while (--n && *++s1 != *++s2); return n - i; } } void HV_FormatForPrint(int lineWidth, int maxLine, DWORD startAddr, PVOID allModify, PBYTE data, DWORD selStart, DWORD selEnd, PBYTE output) { PHV_PRINTFMT hv_pfmt; PBYTE buf = output; BYTE text[64 * 32]; int i, j, k, l, w, dlen; BOOL bModify, bHighLight; lineWidth = MAX(lineWidth, 1); lineWidth = MIN(lineWidth, 32); maxLine = MAX(maxLine, 1); maxLine = MIN(maxLine, 64); dlen = HV_GetModifyData(allModify, startAddr, text, lineWidth * maxLine); maxLine = dlen / lineWidth; maxLine += (dlen % lineWidth) == 0 ? 0 : 1; w = lineWidth; for (i = 0; i < maxLine; i++) { hv_pfmt = (PHV_PRINTFMT)buf; //输出地址 hv_pfmt->x = 1; hv_pfmt->y = i; hv_pfmt->color = HV_COLOR_ADDR; hv_pfmt->highlight = 0; hv_pfmt->len = 8; buf += sizeof(HV_PRINTFMT); for (l = 3; l >= 0; l--) { *buf++ = "0123456789ABCDEF"[(startAddr >> (l * 8 + 4)) & 15]; *buf++ = "0123456789ABCDEF"[(startAddr >> (l * 8 + 0)) & 15]; } if (i == maxLine - 1) { if (dlen % lineWidth) w = dlen % lineWidth; } for (j = 0; j < w; j += k) { k = HV_Compare(data + startAddr + j, text + i * lineWidth + j, w - j); if (k > 0) { bModify = FALSE; } else { bModify = TRUE; k = -k; } bHighLight = FALSE; if (selEnd != -1) { if (j + startAddr < selStart) { k = MIN((DWORD)k, selStart - (j + startAddr)); bHighLight = FALSE; } else if ((DWORD)j + startAddr == selStart) { k = MIN((DWORD)k, selEnd - (j + startAddr) + 1); bHighLight = TRUE; } else if ((DWORD)j + startAddr <= selEnd) { k = MIN((DWORD)k, selEnd - (j + startAddr) + 1); bHighLight = TRUE; } } hv_pfmt = (PHV_PRINTFMT)buf; //输出十六进制 hv_pfmt->x = (1 + 8 + 1 + j * 3); hv_pfmt->y = i; hv_pfmt->color = bModify ? HV_COLOR_MODIFY : HV_COLOR_HEX; hv_pfmt->highlight = bHighLight ? 1 : 0; hv_pfmt->len = k * 3; buf += sizeof(HV_PRINTFMT); for (l = 0; l < k; l++) { *buf++ = "0123456789ABCDEF"[(text[i * lineWidth + j + l] >> 4) & 15]; *buf++ = "0123456789ABCDEF"[(text[i * lineWidth + j + l] >> 0) & 15]; *buf++ = ' '; } if (j + k >= lineWidth - 1 || (bHighLight && j + startAddr + k == selEnd + 1)) { hv_pfmt->len -= 1; buf--; } hv_pfmt = (PHV_PRINTFMT)buf; //输出文本 hv_pfmt->x = (1 + 8 + lineWidth * 3 + 4 + j); hv_pfmt->y = i; hv_pfmt->color = bModify ? HV_COLOR_MODIFY : HV_COLOR_TEXT; hv_pfmt->highlight = bHighLight ? 1 : 0; hv_pfmt->len = k; buf += sizeof(HV_PRINTFMT) + hv_pfmt->len; for (l = 0; l < k; l++) hv_pfmt->data[l] = text[i * lineWidth + j + l] < 0x20 ? '.' : text[i * lineWidth + j + l]; } startAddr += lineWidth; } hv_pfmt = (PHV_PRINTFMT)buf; //输出结束 hv_pfmt->x = 0; hv_pfmt->y = 0; hv_pfmt->color = 0; hv_pfmt->len = 0; } VOID HV_PrintHexView(HDC hDC, PHEXVIEW pHex, DWORD nWidth, DWORD nHeight) { TCHAR HexTitle[] = " OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F "; HFONT hFont, hOldFont; HBRUSH hbr; PHV_PRINTFMT hv_pfmt; DWORD lastBgColor = -1, lastColor = -1; UINT nCharWidth, nCharHeight; PVOID fmt; RECT rc; LONG SelStart, SelEnd; hFont = CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Courier New"); hOldFont = SelectObject(hDC, hFont); nCharWidth = pHex->CharWidth; nCharHeight = pHex->CharHeight; rc.top = 0; rc.left = 0; rc.bottom = nHeight; rc.right = nWidth; hbr = CreateSolidBrush(pHex->color[HV_COLOR_BG0]); FillRect(hDC, &rc, hbr); DeleteObject(hbr); SetBkColor(hDC, RGB(0, 255, 255)); TextOut(hDC, nCharWidth, 0, HexTitle, 9 + pHex->LineWidth * 3); fmt = VirtualAlloc(NULL, 0x5000, MEM_COMMIT, PAGE_READWRITE); if (fmt == NULL) return; SelStart = MIN(pHex->SelStart, pHex->SelEnd); SelEnd = MAX(pHex->SelStart, pHex->SelEnd); HV_FormatForPrint( pHex->LineWidth, nHeight / nCharHeight - 1, pHex->PageOffset, &pHex->hv_modl, pHex->Buffer, SelStart, SelEnd, fmt); do { hv_pfmt = (PHV_PRINTFMT)fmt; (PBYTE)fmt += sizeof(HV_PRINTFMT) + hv_pfmt->len; if (hv_pfmt->len == 0) break; if (pHex->color[hv_pfmt->color] != lastColor) { SetTextColor(hDC, pHex->color[hv_pfmt->color]); lastColor = pHex->color[hv_pfmt->color]; } if (pHex->color[hv_pfmt->highlight] != lastBgColor) { SetBkColor(hDC, pHex->color[hv_pfmt->highlight]); lastBgColor = pHex->color[hv_pfmt->highlight]; } TextOut( hDC, hv_pfmt->x * nCharWidth, hv_pfmt->y * nCharHeight + nCharHeight, hv_pfmt->data, hv_pfmt->len); } while (1); VirtualFree(fmt, 0, MEM_RELEASE); SelectObject(hDC, hOldFont); DeleteObject(hFont); } ULONG HV_GetCurrentCursor(PHEXVIEW pHex, short x, short y, PDWORD pEditMode) { UINT nCharWidth, nCharHeight; int lenHex, lenAscii; int bx, by, mx, my, middle; DWORD dwEditMode; nCharWidth = pHex->CharWidth; nCharHeight = pHex->CharHeight; bx = x / (int)nCharWidth; by = y / (int)nCharHeight - 1; bx -= pHex->AddressWidth * 2 + 2; middle = pHex->LineWidth * 3 + 1; lenHex = pHex->LineWidth * 3 - 1; lenAscii = pHex->LineWidth; mx = pHex->PageLength % pHex->LineWidth; my = pHex->PageLength / pHex->LineWidth; mx = pHex->LineWidth - mx; if (by < 0) by = 0; if (by > my) by = my; if (mx != 0 && by == my) { lenHex -= mx * 3; lenAscii -= mx; } if (bx >= middle) { bx -= middle + 2; if (bx < 0) { bx = 0; } else if (bx >= lenAscii) { bx = lenAscii - 1; } dwEditMode = EM_TEXT; } else { if (bx < 0) { bx = 0; } if ((bx + 1) % 3 == 0) { if (x % nCharWidth < nCharWidth / 2) { bx--; } else { bx++; } } if (bx >= lenHex) { bx = lenHex - 1; } if ((bx + 1) % 3 == 1) dwEditMode = EM_HEX_HIGH; else dwEditMode = EM_HEX_LOW; bx = (bx + 1) / 3; } if (pEditMode != NULL) *pEditMode = dwEditMode; return bx + by * pHex->LineWidth + pHex->PageOffset; } VOID HV_OnPaint(HWND hWnd) { UINT nWndWidth, nWndHeight; HDC hDC, hMemDC; HBITMAP hBitmap; RECT rect; PAINTSTRUCT ps; GetClientRect(hWnd, &rect); nWndWidth = rect.right - rect.left; nWndHeight = rect.bottom - rect.top; hDC = BeginPaint(hWnd, &ps); hMemDC = CreateCompatibleDC(hDC); hBitmap = CreateCompatibleBitmap(hDC, nWndWidth, nWndHeight); SelectObject(hMemDC, hBitmap); HV_PrintHexView( hMemDC, (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO), nWndWidth, nWndHeight); BitBlt(hDC, 0, 0, nWndWidth, nWndHeight, hMemDC, 0, 0, SRCCOPY); DeleteDC(hMemDC); DeleteObject(hBitmap); EndPaint(hWnd, &ps); } int HV_MoveCursor(PHEXVIEW pHex, int lx, int ly) { if (lx != 0) { switch (pHex->EditMode) { case EM_TEXT: pHex->Cursor += lx; break; case EM_HEX_HIGH: if (lx > 0) { pHex->EditMode = lx & 1 ? EM_HEX_LOW : EM_HEX_HIGH; pHex->Cursor += lx / 2; } else { pHex->EditMode = lx & 1 ? EM_HEX_LOW : EM_HEX_HIGH; pHex->Cursor += (lx - 1) / 2; } break; case EM_HEX_LOW: if (lx > 0) { pHex->EditMode = lx & 1 ? EM_HEX_HIGH : EM_HEX_LOW; pHex->Cursor += (lx + 1) / 2; } else { pHex->EditMode = lx & 1 ? EM_HEX_HIGH : EM_HEX_LOW; pHex->Cursor += lx / 2; } break; } } pHex->Cursor += ly * pHex->LineWidth; if (pHex->Cursor >= (int)(pHex->Length)) { pHex->Cursor = pHex->Length - 1; pHex->EditMode = pHex->EditMode == EM_TEXT ? EM_TEXT : EM_HEX_LOW; } else if (pHex->Cursor < 0) { pHex->Cursor = 0; pHex->EditMode = pHex->EditMode == EM_TEXT ? EM_TEXT : EM_HEX_HIGH; } if (pHex->Cursor >= (int)(pHex->PageOffset + pHex->PageLength)) { int n = pHex->Cursor / pHex->LineWidth; n -= pHex->PageMaxLength / pHex->LineWidth - 1; pHex->PageOffset = n * pHex->LineWidth; pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); return n; } else if (pHex->Cursor < (int)pHex->PageOffset) { int n = pHex->Cursor / pHex->LineWidth; pHex->PageOffset = n * pHex->LineWidth; pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); return n; } return -1; } VOID HV_UpdatePage(HWND hWnd, int n) { SCROLLINFO si; if (n != -1) { si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; SetScrollPos(hWnd, SB_VERT, n, TRUE); } RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); } VOID HV_OnChar(HWND hWnd, WPARAM wParam) { char ch = (char)wParam, ch1; PHEXVIEW pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); DWORD off = pHex->Cursor; int i; NMHDR n; if (pHex->EditMode == EM_TEXT) { HV_AddModifyLog(&pHex->hv_modl, off, 1, &ch); i = HV_MoveCursor(pHex, 1, 0); HV_UpdatePage(hWnd, i); } else { switch (ch = toupper(ch)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ch -= '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': ch -= 'A' - 0x0a; break; default: return; } HV_GetModifyData(&pHex->hv_modl, off, &ch1, 1); if (pHex->EditMode != EM_HEX_HIGH) { if (ch != (ch1 & 0x0f)) { ch |= ch1 & 0xf0; HV_AddModifyLog(&pHex->hv_modl, off, 1, &ch); } } else { ch <<= 4; if (ch != (ch1 & 0xf0)) { ch |= ch1 & 0x0f; HV_AddModifyLog(&pHex->hv_modl, off, 1, &ch); } } i = HV_MoveCursor(pHex, 1, 0); HV_UpdatePage(hWnd, i); } RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_CHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); } VOID CALLBACK HV_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) { int t, x, y, w, h; HDC hDC; PHEXVIEW pHex; pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); w = pHex->CharWidth; h = pHex->CharHeight; if (pHex->NoCursor == TRUE) return; t = pHex->Cursor - pHex->PageOffset; if (t < 0 || t >= (int)pHex->PageLength) return; switch (pHex->EditMode) { case EM_TEXT: x = t % pHex->LineWidth; x += pHex->AddressWidth * 2 + pHex->LineWidth * 3 + 3 + 2; break; case EM_HEX_HIGH: x = t % pHex->LineWidth * 3; x += pHex->AddressWidth * 2 + 2; break; case EM_HEX_LOW: x = t % pHex->LineWidth * 3 + 1; x += pHex->AddressWidth * 2 + 2; break; } x *= pHex->CharWidth; y = (t / pHex->LineWidth + 1) * pHex->CharHeight; hDC = GetDC(hWnd); BitBlt(hDC, x, y, w, h, NULL, 0, 0, DSTINVERT); ReleaseDC(hWnd, hDC); } VOID HV_LButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { PHEXVIEW pHex; ULONG i; NMHDR n; pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); i = HV_GetCurrentCursor(pHex, LOWORD(lParam), HIWORD(lParam), &pHex->EditMode); pHex->SelStart = i; pHex->SelEnd = -1; pHex->Cursor = i; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_SELCHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); } VOID HV_OnVscroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PHEXVIEW pHex; int i; SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(hWnd, SB_VERT, &si); pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); switch (LOWORD(wParam)) { case SB_LINEUP: i = si.nPos - 1; break; case SB_LINEDOWN: i = si.nPos + 1; break; case SB_PAGEUP: i = si.nPos - si.nPage; break; case SB_PAGEDOWN: i = si.nPos + si.nPage; break; case SB_THUMBPOSITION: case SB_THUMBTRACK: i = HIWORD(wParam); break; default: return; } i = MAX(i, si.nMin); i = MIN(i, MAX(0, (int)(si.nMax - si.nPage + 1))); pHex->PageOffset = pHex->LineWidth * i; pHex->PageLength = MIN(pHex->Length - pHex->PageOffset, pHex->PageMaxLength); SetScrollPos(hWnd, SB_VERT, i, TRUE); RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); } VOID HV_OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { PHEXVIEW pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); int i; NMHDR n; if (pHex->NoCursor == TRUE) { switch ((TCHAR)wParam) { case VK_UP: if (pHex->PageOffset > 0) pHex->PageOffset -= pHex->LineWidth; break; case VK_DOWN: if (pHex->PageLength >= pHex->LineWidth) pHex->PageOffset += pHex->LineWidth; break; } RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); } else { switch ((TCHAR)wParam) { case VK_UP: i = HV_MoveCursor(pHex, 0, -1); break; case VK_DOWN: i = HV_MoveCursor(pHex, 0, 1); break; case VK_LEFT: i = HV_MoveCursor(pHex, -1, 0); break; case VK_RIGHT: i = HV_MoveCursor(pHex, 1, 0); break; default: return; } pHex->SelEnd = -1; HV_UpdatePage(hWnd, i); n.code = HV_EN_SELCHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); } } VOID HV_MouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam) { PHEXVIEW pHex; ULONG i; INT TopPos, BottomPos; NMHDR n; if (wParam & MK_LBUTTON) { pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); TopPos = pHex->CharHeight; BottomPos = (pHex->PageMaxLength / pHex->LineWidth) * pHex->CharHeight; if ((short)HIWORD(lParam) < TopPos) { HV_OnVscroll(hWnd, SB_LINEUP, 0); //SendMessage(hWnd, WM_MOUSEMOVE, wParam, lParam); } if ((short)HIWORD(lParam) >= BottomPos) { HV_OnVscroll(hWnd, SB_LINEDOWN, 0); //SendMessage(hWnd, WM_MOUSEMOVE, wParam, lParam); } i = HV_GetCurrentCursor(pHex, LOWORD(lParam), HIWORD(lParam), NULL); pHex->SelEnd = i; pHex->Cursor = i; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_SELCHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); } } VOID HV_ResetSize(HWND hWnd) { HDC hDC; HFONT hFont, hOldFont; SIZE charSize; RECT rect; UINT nWndHeight; PHEXVIEW pHex; SCROLLINFO si; pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); hFont = CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Courier New"); hDC = GetDC(hWnd); hOldFont = SelectObject(hDC, hFont); GetTextExtentPoint32(hDC, "0", 1, &charSize); pHex->CharWidth = charSize.cx; pHex->CharHeight = charSize.cy; SelectObject(hDC, hOldFont); DeleteObject(hFont); ReleaseDC(hWnd, hDC); GetClientRect(hWnd, &rect); nWndHeight = rect.bottom - rect.top; pHex->PageMaxLength = (nWndHeight / pHex->CharHeight - 1) * pHex->LineWidth; pHex->PageLength = MIN(pHex->Length - pHex->PageOffset, pHex->PageMaxLength); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = pHex->Length / pHex->LineWidth + (pHex->Length % pHex->LineWidth == 0 ? 0 : 1); si.nPage = pHex->PageMaxLength / pHex->LineWidth + 1; si.nPos = 0; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); if (pHex->Length > pHex->PageMaxLength) { EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH); } else { EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH); } } int HV_FindText(HWND hWnd, PHV_FIND hv_find) { PBYTE p1, p2, pp; DWORD i, n, count; PHEXVIEW pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); NMHDR nm; if (hv_find->nLen > 0x8000) return -1; if (pHex->Length == 0) return -1; if (hv_find->dwFlags & ~HV_FIND_MATCHCASE) { n = MIN(pHex->Length, 0x10000); p1 = VirtualAlloc( NULL, n + hv_find->nLen, MEM_COMMIT, PAGE_READWRITE); if (p1 == NULL) return -1; p2 = p1 + n; pp = hv_find->pMem; for (i = 0; i < hv_find->nLen; i++) { if (pp[i] >= 'a' && pp[i] <= 'z') p2[i] = pp[i] - 'a' + 'A'; else p2[i] = pp[i]; } } else { n = MIN(pHex->Length, 0x10000); p1 = VirtualAlloc( NULL, n, MEM_COMMIT, PAGE_READWRITE); if (p1 == NULL) return -1; p2 = hv_find->pMem; } for (count = hv_find->cpMin;;) { n = MIN(pHex->Length - count, 0x10000); HV_GetModifyData(&pHex->hv_modl, count, p1, n); if (hv_find->dwFlags & ~HV_FIND_MATCHCASE) { for (i = 0; i < n; i++) { if (p1[i] >= 'a' && p1[i] <= 'z') p1[i] -= 'a' - 'A'; } } pp = HV_MemSearchR(p1, n, p2, hv_find->nLen); if (pp != NULL) { n = pp - p1 + count; pHex->SelStart = n; pHex->SelEnd = n + hv_find->nLen - 1; pHex->Cursor = n; if (n >= pHex->PageOffset + pHex->PageLength) { n /= pHex->LineWidth; n -= pHex->PageMaxLength / pHex->LineWidth - 1; pHex->PageOffset = n * pHex->LineWidth; pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); HV_UpdatePage(hWnd, n); } else if (n < pHex->PageOffset) { n /= pHex->LineWidth; pHex->PageOffset = n * pHex->LineWidth; pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); HV_UpdatePage(hWnd, n); } nm.code = HV_EN_SELCHANGE; nm.idFrom = GetDlgCtrlID(hWnd); nm.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&nm); break; } if (pHex->Length - i > 0x10000) { i += 0x10000 - hv_find->nLen; } else break; } VirtualFree(p1, 0, MEM_RELEASE); return 0; } LRESULT CALLBACK HV_HexViewProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PHEXVIEW p; HGLOBAL hGlobal; PBYTE pGlobal, pSource; LONG i, SelLength, MemSize; NMHDR n; switch (uMsg) { case WM_MOUSEMOVE: HV_MouseMove(hWnd, wParam, lParam); break; case WM_LBUTTONDOWN: SetCapture(hWnd); SetFocus(hWnd); HV_LButtonDown(hWnd, wParam, lParam); break; case WM_LBUTTONUP: ReleaseCapture(); break; case WM_VSCROLL: HV_OnVscroll(hWnd, wParam, lParam); break; case WM_MOUSEWHEEL: if ((short)HIWORD(wParam) > 0) { HV_OnVscroll(hWnd, SB_LINEUP, 0); } else { HV_OnVscroll(hWnd, SB_LINEDOWN, 0); } break; case WM_PAINT: HV_OnPaint(hWnd); break; case WM_CHAR: HV_OnChar(hWnd, wParam); break; case WM_KEYDOWN: HV_OnKeyDown(hWnd, wParam, lParam); break; case WM_SETFOCUS: SetTimer(hWnd, WM_TIMER, 500, HV_TimerProc); break; case WM_KILLFOCUS: KillTimer(hWnd, WM_TIMER); RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); break; case WM_SIZE: HV_ResetSize(hWnd); break; case HV_SETHANDLE: if ((ULONG)wParam < 512 * 1024 * 1024) { p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); p->Buffer = (LPSTR)lParam; p->Length = (ULONG)wParam; p->PageOffset = 0; p->SelEnd = -1; p->Cursor = 0; p->EditMode = EM_HEX_HIGH; HV_ResetModifyLog(&p->hv_modl, p->Buffer, p->Length); HV_AddModifyLog(&p->hv_modl, 39, 3, "324"); HV_AddModifyLog(&p->hv_modl, 41, 7, "abcdefg"); HV_AddModifyLog(&p->hv_modl, 22, 14, "happy new year"); p->hv_modl.nLog = 0; HV_ResetSize(hWnd); RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_CHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); n.code = HV_EN_SELCHANGE; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); } break; case HV_CANUNDO: return HV_LogUndo(hWnd, TRUE); case HV_CANREDO: return HV_LogRedo(hWnd, TRUE); case HV_UNDO: return HV_LogUndo(hWnd, FALSE); case HV_REDO: return HV_LogRedo(hWnd, FALSE); case HV_GETSEL: p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); *(DWORD *)wParam = p->SelStart; *(DWORD *)lParam = p->SelEnd; break; case HV_SETSEL: p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); p->SelStart = (DWORD)wParam; p->SelEnd = (DWORD)lParam; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_SELCHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); break; case HV_SELALL: p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); p->SelStart = 0; p->SelEnd = p->Length; p->Cursor = (p->Length << 1) - 1; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); n.code = HV_EN_SELCHANGE; n.idFrom = GetDlgCtrlID(hWnd); n.hwndFrom = hWnd; SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); break; case HV_COPY: p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); SelLength = p->SelEnd - p->SelStart; SelLength = MAX(SelLength, -SelLength) + 1; hGlobal = GlobalAlloc(GHND | GMEM_SHARE, SelLength + 1); if (hGlobal == NULL) break; pGlobal = GlobalLock(hGlobal); pSource = p->Buffer + MIN(p->SelEnd, p->SelStart); strncpy(pGlobal, pSource, SelLength); GlobalUnlock(hGlobal); OpenClipboard(hWnd); EmptyClipboard(); SetClipboardData(CF_TEXT, hGlobal); CloseClipboard(); break; case HV_COPYHEX: p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); SelLength = p->SelEnd - p->SelStart; SelLength = MAX(SelLength, -SelLength) + 1; MemSize = SelLength * 3 + SelLength / 16; hGlobal = GlobalAlloc(GHND | GMEM_SHARE, MemSize + 1); if (hGlobal == NULL) break; pGlobal = GlobalLock(hGlobal); pSource = p->Buffer + MIN(p->SelEnd, p->SelStart); for (i = 0; i < SelLength;) { *pGlobal++ = "0123456789ABCDEF"[pSource[i] >> 4]; *pGlobal++ = "0123456789ABCDEF"[pSource[i] & 15]; *pGlobal++ = ' '; if (!(++i & 15)) { *(pGlobal - 1) = '\r'; *pGlobal++ = '\n'; } } *pGlobal = '\0'; GlobalUnlock(hGlobal); OpenClipboard(hWnd); EmptyClipboard(); SetClipboardData(CF_TEXT, hGlobal); CloseClipboard(); break; case HV_SETCOLOR: if ((DWORD)wParam < 10) { p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); p->color[(DWORD)wParam] = lParam; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); } break; case HV_APPLYMODIFY: p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); HV_ApplyModifyLog(&p->hv_modl, (PBYTE)lParam); if ((PBYTE)lParam != NULL) p->Buffer = (PBYTE)lParam; RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); break; case HV_FINDTEXT: HV_FindText(hWnd, (PHV_FIND)lParam); break; case WM_CREATE: p = xmalloc(sizeof(HEXVIEW)); p->NoCursor = FALSE; p->ReadOnly = TRUE; p->BaseAddress = 0; p->PageOffset = 0; p->Length = 0; p->Buffer = NULL; p->AddressWidth = 4; p->LineWidth = 16; p->SelStart = 0; p->SelEnd = -1; p->color[HV_COLOR_BG0] = RGB(255, 255, 255); p->color[HV_COLOR_BG1] = RGB(192, 192, 192); p->color[HV_COLOR_ADDR] = RGB(0, 0, 255); p->color[HV_COLOR_HEX] = RGB(0, 0, 0); p->color[HV_COLOR_TEXT] = RGB(0, 0, 0); p->color[HV_COLOR_MODIFY] = RGB(255, 0, 0); SetWindowLong(hWnd, GWL_HEXINFO, (LONG)p); HV_ResetSize(hWnd); HV_InitModifyLog(&p->hv_modl, p->Buffer, p->Length); break; case WM_DESTROY: p = (void *)GetWindowLong(hWnd, GWL_HEXINFO); HV_FreeModifyLog(&p->hv_modl); xfree(p); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } BOOL InitHexViewClass(VOID) { LPSTR lpClass = "HexView"; WNDCLASS wc; HINSTANCE hInstance; hInstance = GetModuleHandle(NULL); wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = (WNDPROC)HV_HexViewProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(void *); wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = lpClass; if (!RegisterClass(&wc)) { if (!GetClassInfo(hInstance, lpClass, &wc)) return FALSE; if (wc.lpfnWndProc != (WNDPROC)HV_HexViewProc) return FALSE; } return TRUE; }