// _gcvt(dLatitude, 8, cLatitude); // convert double to string showing double
// dLatitude = strtod(cLatitude, 0); // convert string to double
// GetTextExtentPoint32(hdc, "W", 1, &size); // for where to put the date just after the month
// SetFilePointer(hFile, 0x1F4EEEDB, NULL, FILE_BEGIN);
#include <windows.h>
//#include <math.h>
#include <stdio.h>
#include <string.h>
#include "resource.h"
#include <math.h>
#include <malloc.h>

char Help[] = "\
Doug Cox\n\
http://jdmcox.com\n\
jdmcox@jdmcox.com\n\
\n\
Use the Arrow Keys,\n\
Page Up, Page Down,\n\
Ctrl-Home, Ctrl-End,\n\
Home, Esc\n\
\n\
D - display location and contents in decimal\n\
X - display location and contents in hexadecimal\n\
\n\
B - display contents as a byte\n\
W - display contents as a word (2 bytes)\n\
I - display contents as an integer (4 bytes)\n\
\n\
F2 - find\n\
F3 - find again from cursor (including zero)\n\
0 - find zero\n\
C - clear find highlight\n\
\n\
Decimal numbers must be preceeded by a \\\n\
\n\
Hexadecimal numbers must be preceeded by \\x\n\
A hexadecimal number can be a byte, word, triplet, or integer\n\
\n\
J - jump to a location\n\
\n\
E - edit text or numbers\n\
Ctrl-S - save changed file\n\
\n\
Ctrl-Right Arrow Key - DELETE character!";

                //012345678901234567890123456789012345678901234567890123456789012345
char TopLine[] = " Cursor Location: 00000     Contents: 00         Press F1 for Help                                                                                                                                      ";
//char TopLine[] = " Press F1 for Help   Contents: 00   Cursor Location: 00000                                                                                                                                                 ";
char Zero[] = "0         ";
char fileName[MAX_PATH];
BYTE String[62], String2[62];
float Float;
int chars;
int cxChar, cyChar, cxScreen, cyScreen, charsPerLine, linesPerScreen, totalLines;
int curRow = 0, vScrollPos = 0, bytes = 4, oldcurRow, Lines;
int ix, iy, iz, iloc, irow, icol;
DWORD w, x, y, z, row, col, X, Y, BufSize = 0, TempBufSize, uContents;
DWORD fileSize, Width, Height, MaxWidth, MaxHeight, curCol = 0;
unsigned char TempBuf[50], HexTempBuf[50];
char titleName[MAX_PATH];
char CmdLine;
//unsigned char *fileBuf, *fileBuf2, *fb;
BYTE *fileBuf, *fileBuf2, *fb;
DWORD FirstLetterLoc;
DWORD HexFindBuf;
DWORD dwBytesRead, dwBytesWritten;
BYTE Hex1, Hex2, Hex3, Hex4;
BOOL usedword = FALSE, first = TRUE, gotit, deleting = FALSE;
BOOL sendtoflg = TRUE, highlighted, itshex = TRUE, find = FALSE, changed = FALSE, itsigned = FALSE;
BOOL lbuttondown = FALSE, findzero = FALSE;
RECT rect ;
OPENFILENAME ofn ;
LOGFONT lf ;
HINSTANCE hInst ;
HANDLE hFile ;
HWND hwndButton, hwndFind ;
HWND hwnd ;
HDC hdc, hdcMem ;
PAINTSTRUCT ps ;
HBITMAP hBitmap;
HBRUSH hBrush;
RECT rect2, rect3;
COLORREF Color;
SIZE size;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
int CALLBACK EditProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK JumpProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK FindProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK SizeProc(HWND, UINT, WPARAM, LPARAM);
void ShowLocContents(void);
void GetNumbers(void);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT ("ViewAnything");
	MSG          msg ;
	WNDCLASS     wndclass ;
	hBrush = CreateSolidBrush(0xC0C0C0);

	wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject (LTGRAY_BRUSH);
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	if (!RegisterClass (&wndclass))
		return 0;

	if (szCmdLine[0] == 0)
		sendtoflg = FALSE;
	else {
		y = 0;
		CmdLine = '\x0';
		if (szCmdLine[0] == '"') {
			CmdLine = '"';
			y = 1;
		}
		for (x = 0; szCmdLine[y] != CmdLine ; x++, y++)
			fileName[x] = szCmdLine[y];
		fileName[x] = 0;
	}

	hwnd = CreateWindow (szAppName, szAppName,
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VSCROLL,
		0, 0, 0, 0,
		NULL, NULL, hInstance, NULL);

	hInst = hInstance;

	ShowWindow (hwnd, iCmdShow);
	UpdateWindow (hwnd);

	while (GetMessage (&msg, NULL, 0, 0)) {
		TranslateMessage (&msg);
		DispatchMessage (&msg);
	}
	return msg.wParam;
}

DWORD Atoi(char *ptr)
{
	DWORD x;

	for (x = 0; (*ptr >= '0') && (*ptr <= '9'); ptr++) {
		x *= 10;
		x += *ptr - '0';
	}
	if (*ptr != 0)
		MessageBox(hwnd, "Decimal number will be\ncutoff at a non-number", "", MB_OK);
	return x;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:
		for (x = 0; x < 62; x++)
			String2[x] = 0;
		ofn.lStructSize       = sizeof (OPENFILENAME) ;
		ofn.hwndOwner         = hwnd ;
		ofn.hInstance         = NULL ;
		ofn.lpstrFilter       = NULL ;
		ofn.lpstrCustomFilter = NULL ;
		ofn.nMaxCustFilter    = 0 ;
		ofn.nFilterIndex      = 0 ;
		ofn.lpstrFile         = fileName;// Set in Open and Close functions
		ofn.nMaxFile          = MAX_PATH ;
		ofn.lpstrFileTitle    = NULL ;// Set in Open and Close functions
		ofn.nMaxFileTitle     = MAX_PATH ;
		ofn.lpstrInitialDir   = NULL ;
		ofn.lpstrTitle        = NULL ;
		ofn.Flags             = 0 ;// Set in Open and Close functions
		ofn.nFileOffset       = 0 ;
		ofn.nFileExtension    = 0 ;
		ofn.lpstrDefExt       = NULL ;
		ofn.lCustData         = 0L ;
		ofn.lpfnHook          = NULL ;
		ofn.lpTemplateName    = NULL ;
		ofn.hwndOwner         = hwnd ;
		ofn.lpstrFileTitle    = titleName ;
		ofn.Flags             = OFN_HIDEREADONLY | OFN_CREATEPROMPT ;
		if (sendtoflg == FALSE) {
			if (0 == GetOpenFileName (&ofn)) {
				SendMessage(hwnd, WM_CLOSE, 0, 0) ;
				return 0;
			}
		}
		cxChar = 10;
		cyChar = 20;
		cxScreen = GetSystemMetrics(SM_CXSCREEN);
		cyScreen = GetSystemMetrics(SM_CYSCREEN);
		X = GetSystemMetrics(SM_CXVSCROLL) + 2*(GetSystemMetrics(SM_CXFIXEDFRAME));
		Y = GetSystemMetrics(SM_CYMENU) +  cyChar + 2*(GetSystemMetrics(SM_CYFIXEDFRAME));
		MaxWidth = (cxScreen - X) / cxChar;
		MaxHeight = (cyScreen - Y - 40) / cyChar;
		Width = MaxWidth;
		Height = MaxHeight;
		lf.lfCharSet = 255 ;
		lf.lfClipPrecision = 2 ;
		lf.lfEscapement = 0 ;
		lf.lfHeight = -(cyChar) ;
		lf.lfItalic = 0 ;
		lf.lfOrientation = 0 ;
		lf.lfOutPrecision = 1 ;
		lf.lfPitchAndFamily = '1' ;
		lf.lfQuality = 1 ;
		lf.lfStrikeOut = 0 ;
		lf.lfUnderline = 0 ;
		lf.lfWeight = 400 ;
		lf.lfWidth = 0 ;
		strcpy (lf.lfFaceName, "Terminal") ;
		hdc = GetDC(hwnd);
		SelectObject(hdc, CreateFontIndirect(&lf)) ;
		SelectObject(hdc, CreateFontIndirect(&lf)) ;
		ReleaseDC(hwnd, hdc);

		if ((hFile = CreateFile(fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
			if (fileSize = GetFileSize(hFile, NULL)) {
				if (fileSize < (Width * Height))
					x = Width * Height;
				else
					x = fileSize + Width;
				fileBuf = (BYTE*)malloc(1000000000); // 1,000,000,000
				if (fileBuf == NULL) {
					MessageBox(hwnd, "Couldn't reserve enough memory!", NULL, MB_OK);
					SendMessage(hwnd, WM_CLOSE, 0, 0);
					return 0;
				}
				fb = fileBuf;
				ReadFile(hFile, fileBuf, fileSize, &dwBytesRead, NULL);
				SetWindowText(hwnd, fileName);
				ShowLocContents();
			}
			else {
				MessageBox(hwnd, "File is empty", "Huh!", MB_OK);
				SendMessage(hwnd, WM_CLOSE, 0, 0);
			}
			CloseHandle(hFile);
		}
		else {
			MessageBox(hwnd, "File not found", "Oops", MB_OK) ;
			SendMessage(hwnd, WM_CLOSE, 0, 0) ;
		}
		return 0;

	case WM_SIZE:
		if (wParam != SIZE_MINIMIZED) {
//			MoveWindow(hwnd, (cxScreen/2)-((cxChar*Width)+X)/2 , (cyScreen/2)-((cyChar*Height)+Y)/2, (cxChar*Width)+X, (cyChar*Height)+Y+8, TRUE);
			MoveWindow(hwnd, (cxScreen/2)-((cxChar*Width)+X)/2 , 0, (cxChar*Width)+X, (cyChar*Height)+Y+8, TRUE);
			GetClientRect(hwnd, &rect);
			rect2.top = rect.top ;
			rect2.left = rect.left ;
			rect2.right = rect.right ;
			rect2.bottom = cyChar ;
			rect3.top = rect.top ;
			rect3.left = 10*cyChar ;
			rect3.right = rect.right ;
			rect3.bottom = cyChar ;
			charsPerLine = Width;
			Lines = fileSize / charsPerLine;
			linesPerScreen = Height;
			totalLines = fileSize / charsPerLine ;
			if (fileSize % charsPerLine)
				totalLines++;
			SetScrollRange(hwnd, SB_VERT, 0, totalLines - (linesPerScreen-1), FALSE);
			SetScrollPos(hwnd, SB_VERT, vScrollPos, TRUE);
			hdc = GetDC(hwnd);
			FillRect(hdc, &rect2, (HBRUSH)(COLOR_MENU+1)) ;
			if (first) {
				first = FALSE;
				hdcMem = CreateCompatibleDC(hdc);
				hBitmap = CreateCompatibleBitmap(hdc, rect.right-rect.left, rect.bottom-rect.top);
				SelectObject(hdcMem, hBitmap);
				SelectObject(hdcMem, CreateFontIndirect(&lf)) ;
				FillRect(hdcMem, &rect, hBrush);
			}
			ReleaseDC(hwnd, hdc);
		}
		return 0 ;

	case WM_VSCROLL:
		switch (LOWORD (wParam))
		{
		case SB_TOP:
			vScrollPos = 0;
			break;
		case SB_BOTTOM:
			vScrollPos = totalLines - linesPerScreen;
			break;
		case SB_LINEUP:
			vScrollPos -= 1;
			break;
		case SB_LINEDOWN:
			vScrollPos += 1;
			break;
		case SB_PAGEUP:
			vScrollPos -= linesPerScreen;
			break;
		case SB_PAGEDOWN:
			vScrollPos += linesPerScreen;
			break;
		case SB_THUMBPOSITION:
			vScrollPos = HIWORD (wParam);
			break;
		case 0xFFFF: // from 'J'
			vScrollPos = HexFindBuf / charsPerLine;
			curRow = 0;
			curCol = HexFindBuf % charsPerLine;
			break;
		}
		vScrollPos = max (0, min (vScrollPos, totalLines - (linesPerScreen)));
		if (vScrollPos != GetScrollPos(hwnd, SB_VERT))
			SetScrollPos(hwnd, SB_VERT, vScrollPos, TRUE);
		ShowLocContents();
		return 0;

	case WM_KEYDOWN:
		switch (wParam)
		{
		case 'J':
			findzero = FALSE;
			if (DialogBox(hInst, "HILIGHT", hwnd, JumpProc))
				SendMessage(hwnd, WM_VSCROLL, -1, 0);
			break;
		case 'Z':
			if (DialogBox(hInst, "SIZE", NULL, SizeProc))
				SendMessage(hwnd, WM_SIZE, 0, 0);
			break;
		case '0':
			findzero = TRUE;
			for (x = FirstLetterLoc; x < fileSize; x++) {
				if (fb[x] == 0) {
					y = 1;
					FirstLetterLoc = x;
					goto foundit2;
				}
			}
			break;
		case VK_F2:
			findzero = FALSE;
			if (FALSE == DialogBox(hInst, "FIND", NULL, FindProc))
				break;
			// fall thru...
		case VK_F3:
			FirstLetterLoc = curCol + (curRow+vScrollPos)*charsPerLine + 1;
			if (findzero) {
				for (x = FirstLetterLoc; x < fileSize; x++) {
					if (fb[x] == 0) {
						y = 1;
						FirstLetterLoc = x;
						goto foundit2;
					}
				}
			}
			if (usedword) {
				bytes = BufSize;
				gotit = FALSE;
				for (y = 0, x = FirstLetterLoc; x < fileSize; x++) {
					switch (BufSize)
					{
					case 1:
						if (Hex1 == fb[x])
							gotit = TRUE;
						break;
					case 2:
						if ((Hex1 == fb[x]) && (Hex2 == fb[x+1]))
							gotit = TRUE;
						break;
					case 3:
						if ((Hex1 == fb[x]) && (Hex2 == fb[x+1]) && (Hex3 == fb[x+2]))
							gotit = TRUE;
						break;
					case 4:
						if ((Hex1 == fb[x]) && (Hex2 == fb[x+1]) && (Hex3 == fb[x+2]) && (Hex4 == fb[x+3]))
							gotit = TRUE;
						break;
					}
					if (gotit) {
						y = BufSize;
						FirstLetterLoc = x;
						goto foundit2;
					}
				}
				if (x == fileSize) {
					if ((TempBuf[1] != 'x') && (TempBuf[1] != 'X'))
						MessageBox(hwnd, "Not found.", TempBuf, MB_OK);
					else
						MessageBox(hwnd, "Not found.", HexTempBuf, MB_OK);
				}
			}
			else { // if (!usedword)
				for (x = FirstLetterLoc; x < fileSize; x++) {
					if (HexTempBuf[0] == fb[x]) {
						for (y = 1, z = x+1; y < TempBufSize; z++, y++) {
							if ((HexTempBuf[y] != fb[z]))
								break;
						}
						if (y == TempBufSize) {
							FirstLetterLoc = z - y;
foundit2:					curCol = FirstLetterLoc % charsPerLine;
							if (curCol == -1)
								curCol = charsPerLine - 1;
							if (FirstLetterLoc <= (DWORD)(charsPerLine*linesPerScreen)) { // first screen
								curRow = FirstLetterLoc / charsPerLine;
								vScrollPos = 0;
							}
							else if ((fileSize - FirstLetterLoc) <= (DWORD)(charsPerLine*linesPerScreen)) { // last screen
								vScrollPos = totalLines - linesPerScreen;
								curRow = (FirstLetterLoc - (vScrollPos * charsPerLine)) / charsPerLine;
							}
							else {
								curRow = (linesPerScreen/2) - 1;
								vScrollPos = (FirstLetterLoc/charsPerLine) - ((linesPerScreen/2) - 1);
							}
							find = TRUE;
							SetScrollPos(hwnd, SB_VERT, vScrollPos, TRUE);
							ShowLocContents();
							break;//found it
						}
					}
				}
				if (x == fileSize) {
					if ((TempBuf[1] != 'x') && (TempBuf[1] != 'X'))
						MessageBox(hwnd, "Not found.", TempBuf, MB_OK);
					else
						MessageBox(hwnd, "Not found.", HexTempBuf, MB_OK);
				}
			} // endof else
			break;
		case 'E':
			DialogBox(hInst, "HILIGHT", hwnd, EditProc);
			break;
/*
		case 'S':
			if (GetKeyState(VK_CONTROL) < 0) { // Ctrl pressed
				if (changed) {
					changed = FALSE;
					if (IDOK == MessageBox(hwnd, "Save changes?", "", MB_OKCANCEL)) {
						changed = FALSE;
						hFile = CreateFile(fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
						WriteFile(hFile, fb, fileSize, &dwBytesWritten, NULL);
						CloseHandle(hFile);
					}
				}
			}
			else { // signed
				itsigned = TRUE;
				ShowLocContents();
			}
			break;
		case 'U': // unsigned
			itsigned = FALSE;
			ShowLocContents();
			break;
*/
		case 'C': // clear find highlights
			find = FALSE;
			InvalidateRect(hwnd, &rect, FALSE);
			break;
		case 'X':
			itshex = TRUE;
			ShowLocContents();
			break;
		case 'D':
			itshex = FALSE;
			ShowLocContents();
			break;
		case 'B'://byte
			bytes = 1;
			ShowLocContents();
			break;
		case 'W'://word
			bytes = 2;
			ShowLocContents();
			break;
		case 'I'://integer
			bytes = 4;
			ShowLocContents();
			break;
		case VK_F1:
			MessageBox(hwnd, Help, "ViewAnything", MB_OK);
			break;
		case VK_HOME:
			if (GetKeyState(VK_CONTROL) < 0) { // CTRL-PAGE UP
				curCol = 0;
				curRow = 0;
				SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0);
			}
			else {
				curCol = 0;
				ShowLocContents();
			}
			break;
		case VK_END:
			if (GetKeyState(VK_CONTROL) < 0) {
				curCol = (fileSize % charsPerLine) - 1;
				if (curCol == -1)
					curCol = charsPerLine - 1;
				if (fileSize > (Width * Height))
					curRow = Height-1;
				else
					curRow = fileSize / Width;
				SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);
			}
			break;
		case VK_DOWN:
			if ((curRow < linesPerScreen-1) && (curRow < totalLines-1)) {
				curRow++;
				ShowLocContents();
			}
			else if (curRow+vScrollPos < totalLines-1)
				SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
			break;
		case VK_UP:
			if (curRow > 0) {
				curRow--;
				ShowLocContents();
			}
			else
				SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
			break;
		case VK_RIGHT:
			if (GetKeyState(VK_CONTROL) < 0) { // DELETE!
				if (deleting) {
					changed = TRUE;
					fb[((curRow+vScrollPos) * charsPerLine) + curCol] = 0;
				}
				else {
					deleting = TRUE;
					MessageBox(hwnd, "Now whenever you press Ctrl-Right,\nyou will also delete what's at the cursor", "CAUTION!", MB_OK);
					break;
				}
			}
			if ((curCol+bytes) < Width)
				curCol += bytes;
			else { // at end of line
				curCol = 0;
				curRow++;
			}
			ShowLocContents();
			break;
		case VK_LEFT:
			if (curCol > 0)
				curCol -= bytes;
			else if ((curRow-bytes) > 0) { // at beginning of line
				curCol = Width - bytes;
				curRow--;
			}
			ShowLocContents();
			break;
		case VK_PRIOR:
			SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
			break;
		case VK_NEXT:
			SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
			break;

		case VK_ESCAPE:
			if (changed) {
				changed = FALSE;
				if (IDYES == MessageBox(hwnd, "Save changes?", "", MB_YESNO)) {
					hFile = CreateFile(fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
					WriteFile(hFile, fb, fileSize, &dwBytesWritten, NULL);
					CloseHandle(hFile);
				}
			}
			SendMessage(hwnd, WM_CLOSE, 0, 0);
			break;
		}
		return 0;

	case WM_LBUTTONDOWN:
		lbuttondown = TRUE;
		return 0;

	case WM_LBUTTONUP:
		if (lbuttondown) { // necessary to prevent a bug after selecting a file with a button click
			y = HIWORD(lParam);
			if ((int)y > cyChar) {
				x = LOWORD(lParam) / cxChar;
				curCol = Width - 1;
				if (curCol > x)
					curCol = x;
				curRow = (y / cyChar) - 1;
				ShowLocContents();
			}
		}
		return 0;

	case WM_PAINT:
		hdc = BeginPaint (hwnd, &ps) ;
		fileBuf = fb + (vScrollPos * charsPerLine) ;
		fileBuf2 = fileBuf;
		Color = 0xD0D0D0;//GetSysColor(COLOR_MENU);
		SetBkColor(hdcMem, Color) ;
		TextOut(hdcMem, 0, 0, TopLine, Width); // TopLine is 200 chars wide
		Color -= 0x101010;//1 level darker
		SetBkColor(hdcMem, Color);
		for (row = 1; row < (DWORD)(linesPerScreen+1); row++) {
			for (x = 0; x < Width; x++)//probably necessary because of a page-change in virtual memory
				TextOut(hdcMem, 10*x, 20*row, &fileBuf[x], 1);
			fileBuf += charsPerLine ;
		}
		if ((fileSize+(Width-(fileSize%Width))) > (curCol+(curRow*Width))) {
			SetBkColor(hdcMem, 0xFFFFFF) ; // for highlight at cursor
			TextOut(hdcMem, cxChar*curCol, cyChar*(curRow+1), &fileBuf2[curCol+(curRow*Width)], bytes);
		}
		if (find) {
			find = FALSE;
			SetBkColor(hdcMem, 0x00FFFF);//yellow
			if (usedword)
				TextOut(hdcMem, curCol*cxChar, (curRow+1)*cyChar, &fileBuf2[curCol+(curRow*Width)], bytes);
			else
				TextOut(hdcMem, curCol*cxChar, (curRow+1)*cyChar, TempBuf, TempBufSize);
		} // end of if (find)
		BitBlt(hdc, 0, 0, rect.right-rect.left, rect.bottom-rect.top, hdcMem, 0, 0, SRCCOPY);
		EndPaint (hwnd, &ps) ;
		return 0;

	case WM_CLOSE:
		if (changed) {
			if (IDYES == MessageBox(hwnd, "Save changes?", "", MB_YESNO)) {
				hFile = CreateFile(fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
				WriteFile(hFile, fb, fileSize, &dwBytesWritten, NULL);
				CloseHandle(hFile);
			}
		}
		DestroyWindow(hwnd);
		return 0;

	case WM_DESTROY:
		if (fileSize)
//			VirtualFree(fileBuf, 0, MEM_RELEASE);
			free(fileBuf);
		PostQuitMessage (0);
		return 0;
	}
	return DefWindowProc (hwnd, message, wParam, lParam);
}

int CALLBACK FindProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndFind;

	switch (message)
	{
	case WM_INITDIALOG:
		hwndFind = GetDlgItem(hwndDlg, IDC_EDIT1);
		SetFocus(hwndFind);
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			for (x = 0; x < 50; x++)
				TempBuf[x] = 0;
			TempBufSize = GetWindowText(hwndFind, TempBuf, 51); // 51 instead of 50 because GetWindowText includes ending 0, which it doesn't copy!
			if (0 == TempBufSize)
				break;
			GetNumbers();
			curCol = curRow = 0;
			EndDialog (hwndDlg, TRUE);
			return TRUE;

		case IDCANCEL:
			find = FALSE;
			EndDialog (hwndDlg, FALSE);
			return FALSE;
		}
	}
	return FALSE;
}

int CALLBACK EditProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{ // case 'E'
	static HWND hwndFind;
	
	switch (message)
	{
	case WM_INITDIALOG:
		hwndFind = GetDlgItem(hwndDlg, IDC_EDIT1);
		SetFocus(hwndFind);
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			for (x = 0; x < 50; x++)
				TempBuf[x] = 0;
			TempBufSize = GetWindowText(hwndFind, TempBuf, 50);
			if (TempBufSize == 0)
				break ;
			GetNumbers();
			x = ((curRow+vScrollPos)*charsPerLine) + curCol;
			if (usedword) {
				fb[x++] = Hex1;
				if (BufSize >= 2)
					fb[x++] = Hex2;
				if (BufSize >= 3)
					fb[x++] = Hex3;
				if (BufSize == 4)
					fb[x++] = Hex4;
			}
			else {
				for (y = 0; y < TempBufSize; x++, y++)
					fb[x] = TempBuf[y];
			}
			ShowLocContents(); // sends InvalidateRect
			changed = TRUE;
			EndDialog (hwndDlg, TRUE);
			return TRUE;

		case IDCANCEL:
			EndDialog (hwndDlg, FALSE);
			return FALSE;
		}
	}
	return FALSE;
}

int CALLBACK JumpProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndJump;
	
	switch (message)
	{
	case WM_INITDIALOG:
		hwndJump = GetDlgItem(hwndDlg, IDC_EDIT1);
		SetFocus(hwndJump);
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			for (x = 0; x < 50; x++)
				TempBuf[x] = 0;
			TempBufSize = GetWindowText(hwndJump, TempBuf, 51);
			if (TempBufSize == 0)
				break ;
			GetNumbers();
			if (!usedword || (HexFindBuf > fileSize)) {
				if (!usedword)
					MessageBox(hwnd, "That's not a number.", "", MB_OK);
				if (HexFindBuf > fileSize)
					MessageBox(hwnd, "That's past the end of the file.", "", MB_OK);
				break;
			}
			EndDialog (hwndDlg, TRUE);
			return TRUE;

		case IDCANCEL:
			EndDialog (hwndDlg, FALSE);
			return FALSE;
		}
	}
	return FALSE;
}

int CALLBACK SizeProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndWidth, hwndHeight;
	
	switch (message)
	{
	case WM_INITDIALOG:
		hwndWidth = GetDlgItem(hwndDlg, IDC_EDIT1);
		hwndHeight = GetDlgItem(hwndDlg, IDC_EDIT2);
		SetFocus(hwndWidth);
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDOK:
			TempBufSize = GetWindowText(hwndWidth, TempBuf, 51);
			if (TempBufSize) {
				Width = Atoi(TempBuf);
				if (Width > MaxWidth)
					Width = MaxWidth;
			}
			TempBufSize = GetWindowText(hwndHeight, TempBuf, 51);
			if (TempBufSize) {
				Height = Atoi(TempBuf);
				if (Height > MaxHeight)
					Height = MaxHeight;
			}
			EndDialog (hwndDlg, TRUE);
			return TRUE;

		case IDCANCEL:
			EndDialog (hwndDlg, FALSE);
			return FALSE;
		}
	}
	return FALSE;
}

void ShowLocContents(void)
{
	unsigned char iContents, ch;
	UINT w;

	irow = curRow+vScrollPos;
	icol = curCol;
	TopLine[37] = ' ';
	TopLine[38] = ' ';
	TopLine[39] = ' ';
	iloc = (irow * charsPerLine) + icol ;
	fileBuf = fb;
	for (ix = 0; ix < 25; ix++)
		TopLine[37+ix] = ' ';
	iy = iloc;
	if (itshex) {
		for (iz = 0; iz < 7; iz++) { // LOCATION
			ix = iy & 0xF ;
			if (ix <= 9) ix += 0x30 ;
			else ix += 0x37 ;
			TopLine[24-iz] = (char) ix ;
			iy >>= 4 ;
		}
		if (bytes == 1) { // CONTENTS
			iContents = fileBuf[iloc] ;
			ch = (iContents & 0xF) ;
			if (ch <= 9) ch += 0x30 ;
			else ch += 0x37 ;
			TopLine[38] = ch ;
			ch = ((iContents >> 4) & 0xF) ;
			if (ch <= 9) ch += 0x30 ;
			else ch += 0x37 ;
			TopLine[37] = ch ;
		}
		else if (bytes == 2) {
			for (iy = 37, iz = iloc+1; iz >= iloc; iy +=2, iz--) {
				iContents = fileBuf[iz] ;
				ch = (iContents & 0xF) ;
				if (ch <= 9) ch += 0x30 ;
				else ch += 0x37 ;
				TopLine[iy+1] = ch ;
				ch = ((iContents >> 4) & 0xF) ;
				if (ch <= 9) ch += 0x30 ;
				else ch += 0x37 ;
				TopLine[iy] = ch ;
			}
		}
		else if (bytes == 3) { //  at 0x2F4 \x324767 or /6768434
			for (iy = 37, iz = iloc+2; iz >= iloc; iy +=2, iz--) {
				iContents = fileBuf[iz] ;
				ch = (iContents & 0xF) ;
				if (ch <= 9) ch += 0x30 ;
				else ch += 0x37 ;
				TopLine[iy+1] = ch ;
				ch = ((iContents >> 4) & 0xF) ;
				if (ch <= 9) ch += 0x30 ;
				else ch += 0x37 ;
				TopLine[iy] = ch ;
			}
		}
		else if (bytes == 4) {
			for (iy = 37, iz = iloc+3; iz >= iloc; iy +=2, iz--) {
				iContents = fileBuf[iz] ;
				ch = (iContents & 0xF) ;
				if (ch <= 9) ch += 0x30 ;
				else ch += 0x37 ;
				TopLine[iy+1] = ch ;
				ch = ((iContents >> 4) & 0xF) ;
				if (ch <= 9) ch += 0x30 ;
				else ch += 0x37 ;
				TopLine[iy] = ch ;
			}
		}
	}
	else { // decimal
		iz = 18;
		for (ix = 0; ix < 10; ix++)
			TopLine[ix+iz] = Zero[ix];
		if (iloc != 0) {
			for (iy = 100000000; iy > (iloc*10); iy /= 10)//hundred million
				;
			while (iy > 1) {
				ix = iloc % iy;
				iy /= 10;
				TopLine[iz++] = (ix / iy) + '0'; // location
			}
		}
		iz =	37;
		for (ix = 0; ix < 10; ix++)
			TopLine[ix+iz] = ' ';
		if (bytes == 1) { // CONTENTS
			uContents = *(BYTE*)&fileBuf[iloc];
			if ((itsigned) && (uContents >= 0x80)) {
				uContents = 0xFF - uContents + 1;
				TopLine[iz++] = '-';
			}
		}
		else if (bytes == 2) {
			uContents = *(WORD*)&fileBuf[iloc];
			if ((itsigned) && (uContents >= 0x8000)) {
				uContents = 0xFFFF - uContents + 1;
				TopLine[iz++] = '-';
			}
		}
		else if (bytes == 4) {
			uContents = *(UINT*)&fileBuf[iloc];
			if ((itsigned) && (uContents >= 0x80000000)) {
				uContents = 0xFFFFFFFF - uContents + 1;
				TopLine[iz++] = '-';
			}
		}
		w = 1000000000; // one billion
		if (uContents >= 1000000000)
			TopLine[iz++] = (BYTE)(uContents / 1000000000) + '0';
		if (uContents <= (0xFFFFFFFF / 10)) {
			for ( ; w > (uContents *10); w /= 10)
				;
		}
		while (w > 1) {
			ix = uContents % w;
			w /= 10;
			TopLine[iz++] = (ix / w) + '0';
		}
	}
	uContents = *(UINT*)&fileBuf[iloc];
	Float = *(float*)&uContents;
	if ((Float != 0.0) && (Float >= -180.0) && (Float <= 180.0)) {
		chars = sprintf_s(String, 62, "%.4f", Float);
		strcpy(&TopLine[70], String);
	}
//	else if (Float = *(float*)&uContents)
//		x=x;
	else {
		for (x = 0; x < 62; x++)
			TopLine[70+x] = 0;
	}
	InvalidateRect(hwnd, &rect, FALSE);		
}

void AsciiToHex(void)
{
	int w, y, z;

	Hex1 = 0;
	for (z = 0, y = 2; (HexTempBuf[y] != 0) && (y < 10); y++) {
		w = HexTempBuf[y];
		if (w >= 0x61) // if lower case letter
			w -= 0x20; // make uppercase
		if (w > 0x46) // 'F'
			break; // only hexadecimal numbers
		w -= '0';
		if (w > 9) // if letter
			w -= 7;
		z <<= 4;
		z |= w;
	}
	HexFindBuf = z;
	if (Hex1 = HexFindBuf & 0xFF)
		BufSize = 1;
	if (Hex2 = (HexFindBuf >> 8) & 0xFF)
		BufSize = 2;
	if (Hex3 = (HexFindBuf >> 16) & 0xFF)
		BufSize = 3;
	if (Hex4 = (HexFindBuf >> 24) & 0xFF)
		BufSize = 4;
	usedword = TRUE;
}

void GetNumbers(void)
{
	HexFindBuf = 0;
	usedword = FALSE;
	strcpy (HexTempBuf, TempBuf);	
	if (TempBuf[0] == '\\') {
		if ((TempBuf[1] != 'x') && (TempBuf[1] != 'X')) {
			z = Atoi(&TempBuf[1]); // convert "\17607" to 17607
			if (z == 0)
				return;
			_snprintf(&HexTempBuf[2], 10, "%X", z); // convert 17607 to "0x44C7" (disregarding first 2 chars)
		}
		else
			strcpy (HexTempBuf, TempBuf);	
		AsciiToHex(); // convert "\17607" or "\x44C7" to \x44C7
	}
}
