This is a module of EuroTool program EuroView for Windows.
EUROASM CPU=X64,SIMD=Yes, Unicode=No, MaxInclusions=128, Debug=no
viewwing PROGRAM Format=COFF, Width=64 ,MaxExpansions=128K
%DROPMACRO *
INCLUDEHEAD argument.htm, viewmain.htm
INCLUDE1 winabi.htm,winsgui.htm,winsdlg.htm,winsfile.htm,winf64.htm, \
cpuext64.htm,cpuext.htm,status32.htm,memory64.htm,string64.htm,fastcall.htm,debug.htm
LINK winapi.lib
PUBLIC BufferCreate@RT
; Constants.
OptimalWidth = 640
MinimalWidth = 500
MinimalHeight = 440
FontSizeMax = 48
FontSizeDef = 16 ; Standard font height to begin with.
FontSizeMin = 10
CtrlStep = 5 ; Cursor keys move the screen by 1, or by CtrlStep characters when Ctrl is pressed.
WheelPerLine = 120 ; wParamHigh = 120 or -120 to scroll 1 row up or down.
;;IdEncoding = 0x8031
;;;IdHelp = 0x8040
IdBtnCancel = 0x8051
IdBtnFind = 0x8053
IdBtnClear = 0x8054
heBtnIO = 20 ; Position of Arg subwindows.
heFind = 106
heTitle1 = 18
wiBorder = 10
wiBtnIO = 90
wiFind = 480
;;;;wiHelp = 580
;;;;;;wiTitleEncoding = 480
yFindButton = 40
; B G R
ColorDump = 0x00D0D0D0 ; Dump.
ColorRem = 0x00D0FFFF ; Remark.
Color1 = 0x00D0FFD0 ; Level 1.
Color2 = 0x0030FFFF ; Level 2.
Color3 = 0x00D0D0FF ; Level 3.
Color4 = 0x00FFD0D0 ; Level 4.
BkColorFound = 0x00FFFFFF ; Found.
TextColorFound = 0x00FF00FF ; Found.
TextColorSelected = 0x00FFFFFF ; Selected.
BkColorSelected = 0x00C06733 ; Selected.
TopLine = ScrollInfo.nPos ; Ordinal of the listing line displayed in the top row of the window.
Rows = ScrollInfo.nPage ; Number of rows in the current window.
Lines = ScrollInfo.nMax ; Number of physical lines in listing.
[.rodata] ; Constant texts.
TitleWindowFind DB "EuroTextFind",0
Help:
DB 13,10
DB " EuroView is one of the EuroTool from https://euroassembler.eu/eurotool",13,10
DB " which can be used to inspect binary, object, library or executable ""InputFile"":",13,10
DB 9,"euroview.exe ""InputFile""",13,10,10
DB " It also accepts arguments from the command-line:",13,10
DB 9,"/InputFile= ",9,9,"Input file name to be inspected.",13,10
DB 9,"/FileFormat= ",9,9,"Default is Autodetect. /FF=? for the list of accepted formats.",13,10
DB 9,"/OutputFile= ",9,9,"Temporary file; default is ""%%TEMP%%\InputFile.lst"".",13,10
DB 9,"/LeaveTemporary=no",9, "Do not erase OutputFile when EuroView terminates.",13,10
DB 9,"/CodeWidth= ",9,9,"Set to 16 | 32 | 64 if not autodetected.",13,10
DB 9,"/CodeBegin= ",9,9,"File address where to begin the disassembly.",13,10
DB 9,"/CodeEnd= ",9,9,"File address where to end the disassembly.",13,10
DB 9,"/DataBegin= ",9,9,"File address where to begin the dumping as data.",13,10
DB 9,"/DataEnd= ",9,9,"File address where to end the dumping as data.",13,10
DB 10
DB " Accepted file formats:",13,10
%i %SETA 1
%WHILE "%FileFormats{%i}"
DB 9,"%FileFormats{%i+0}"
DB 9," %FileFormats{%i+1}"
DB 9," %FileFormats{%i+2}"
DB 9," %FileFormats{%i+3}"
DB 9," %FileFormats{%i+4}"
DB 9," %FileFormats{%i+5}"
%i %SETA %i+6
DB 13,10
%ENDWHILE
EndHelp:
DB 13,10," Keys:",13,10
DB 9,"F1 ",9,9,9,"this help screen",10
DB 9,"O ",9,9,9,"open another file",10
DB 9,"Shift Tab | Right button",9," increase nesting level (more compact)",10
DB 9,"Tab | Left button",9,9,"decrease nesting level (more detailed)",10
DB 9,"F | F7",9,9,9,"Find a string",10
DB 9,"N | F3",9,9,9,"Find the next occurence",10
DB 9,"P | Shift-F3",9,9,"Find the previous occurence",10
DB 9,"Left button drag",9,9,"mark a rectangular selection",10
DB 9,"Ctrl C",9,9,9,"copy the selection to clipboard",10
DB 9,"Ctrl + ",9,9,9,"increase font size",10
DB 9,"Ctrl - ",9,9,9,"decrease font size",10
DB 9,"Ctrl 0 ",9,9,9,"default font size",10
DB 9,"Home ",9,9,9,"beginning of the document",10
DB 9,"End ",9,9,9,"end of the document",10
DB 9,"PgUp | PgDn ",9,9,"page up | down",10
DB 9,"Up | Dn | Mouse scroll",9,"line up | down",10
DB 9,"Esc",9,9,9,"close window, terminate program.",10
DB 0
FormatNames:
FF %FOR %FileFormats
DB "%FF",0
%ENDFOR FF
EndFormatNames:
[.data] FoundCnt DD 0 ; How many time was Find$ found. FoundOffset DD 0 ; Offset of found string in line. FindUTF8Size DD 0 ; Size of the searched string in bytes. FindUTF8 DB MAX_PATH_SIZE * BYTE ; Text string to search for.
[.bss] ; Variable data. Msg DS MSG ; Window message. WndClassEx DS WNDCLASSEX ; Window class structure. InpFileDlg DS OPENFILENAME PaintStruct DS PAINTSTRUCT RectMainWindow DS RECT TextMetric DS TEXTMETRICA ScrollInfo DS SCROLLINFO LstIndex: DS LST_INDEX RectWindowMain DS RECT FileIni DS FILE64 FileInput DS FILE64 FileOutput:: DS FILE64 FileIndex:: DS FILE64 hWindowMain D QWORD ; Window handles. hWindowHelp D QWORD hWindowFind D QWORD hEditFind D QWORD hBtnFind D QWORD hBtnClear D QWORD hBtnCancel D QWORD hFont D QWORD hDC D QWORD ; Handle of device context. cxWindow D QWORD ; Horizontal coordinate in px. cyWindow D QWORD ; Vertical coordinate in px. IndexBegin D QWORD ; Pointer to array of LST_INDEX records in current levelN buffer. WindowWidth D DWORD ; Client area width in px. WindowHeight D DWORD ; Client area height in px. cxChar D DWORD ; Width of one character in px. cyChar D DWORD ; Height of one character in px. FontSize D DWORD ; Height of font in px. Cols D DWORD ; Number of cols in current window. WheelCnt D DWORD ; Accumulated WheelPerLine value when mouse wheel is rolled. WindowFindWidth D DWORD ; Number of characters in FindText. Level D DWORD ; What level of headers to display (0..4). LevelPrevious D DWORD ; To detect when level changes. DocRowStart D DWORD ; Start row when left MB down. 1,2,3,,, Used to mark selection for clipboard. DocColStart D DWORD ; Start col when left MB down. 0,1,2,,,Cols. The first selected. DocRowStop D DWORD ; Stop row when left MB up. 1,2,3,,,Lines. DocColStop D DWORD ; Stop col when left MB up. 0,1,2,,,Cols. The last selected. Spaces D 800 * B NameUTF16:: D 800 * UNICHAR ; Temporary working space for file names in UTF-16. NameUTF8:: D 32K * BYTE ; Temporary working space for file names in UTF-8 and for clipboard.
[.text] ; Program code.
Main:: PROC
StdOutput EuroView::, Version::, Eol=yes
; Try to load arguments from the configuration file "%AppData%\eurotool\euroview.ini".
WinABI GetEnvironmentVariableW,=U'AppData',NameUTF16,SIZE# NameUTF16
TEST RAX
JZ .10:
LEA RBX,[FileIni]
FileAssign RBX,NameUTF16,=U'\eurotool\euroview.ini',Unicode=yes
FileExists? RBX
JC .10:
CALL ReadFileIni ; Read arguments from the configuration file.
.10:; Read arguments from the command-line.
MOV EAX,[ArgNr::]
INC EAX ; The next argument.
MOV [ArgNr::],EAX
GetArg RAX, Unicode=yes ; RSI,RCX gets the line with one argument in UTF-16. Or return CF=1 when no more arguments.
JC .40: ; When they are no more arguments.
StripQuotes RSI,RCX,Unicode=yes
SHR ECX,1 ; Convert size from bytes to characters.
LEA RDI,[NameUTF8]
WinABI WideCharToMultiByte,65001,0,RSI,RCX,RDI,SIZE#NameUTF8/2,0,0 ; Convert to UTF-8 in NameUTF8.
MOVB [RDI+RAX],0
MOV RSI,RDI
GetLength$ RSI, Unicode=no
CALL ArgParse:: ; Use ArgParse to translate UTF-8 string RSI,RCX to a public symbol Arg***.
JNC .10: ; Parse the next argument when no error.
LEA RSI,[ErrorMessage::] ; Error in arguments.
GetLengthUTF8 RSI
WinABI MultiByteToWideChar,65001,0,RSI,RCX,NameUTF16,MAX_PATH_SIZE
StdOutput NameUTF16,Console=yes,Unicode=yes
JSt [Status::],ArgEnc?|ArgLoc?|ArgFF?,.30:
LEA RCX,[EndHelp::]
LEA RAX,[Help:]
SUB RCX,RAX
StdOutput Help, Size=RCX, Unicode=no ; On error write help and terminate.
.30:TerminateProgram 8
.40:; All arguments are accepted..
BufferCreate Size=64
JC ErrorAlloc
MOV [ExportBuffer::],RAX
BufferCreate Size=256K ; Create five level buffers.
JC ErrorAlloc
MOV [Level0Buffer::],RAX
lvl %FOR 1..4
BufferCreate Size=64K
JC ErrorAlloc:
MOV [Level%lvl{}Buffer::],RAX
%ENDFOR
LEA RAX,[FileIndexReopen:]
MOV [FileIndexReopenProc::],RAX
LEA RAX,[FileWriteOutput:]
MOV [FileWriteOutputProc::],RAX
MOVD [Level],0
MOVD [TopLine],1
CMPB [ArgInputFile::],0
JZ .50: ; Skip when no file was specified on the command line.
CALL ViewPrologue: ; Read the ArgInputFile, prepare output files.
JC ErrorFileInput: ; If error, InputFile not found etc.
CALL ViewCreate:: ; Generate FileIndex and write FileOutput.
CALL ViewEpilogue:
.50:CALL WndCreateMain ; Input file was indexed to buffers, start viewing it in a Window.
CALL WndResizeMain
CMPB [ArgInputFile::],0
JNZ .60:
WinABI PostMessage,[hWindowMain],WM_KEYDOWN,VK_F1,0 ; Display Help when no file specified.
.60:WinABI ShowWindow,[hWindowMain],SW_SHOW
WinABI UpdateWindow,[hWindowMain]
CALL WndTitle
.MsgLoop:
WinABI GetMessage, Msg,0,0,0
TEST RAX
JZ .MsgQuit: ; ZF signalizes message WM_QUIT - request for termination.
WinABI TranslateMessage, Msg ; Remap character keys from national keyboards.
WinABI DispatchMessage, Msg ; Let Windows call our WndProc.
JMP .MsgLoop: ; Wait for another message.
ErrorHelp::
StdOutput Help:,Eol=yes
JMP .90:
ErrorFileOutput:
LEA RSI,[FileOutput.Name]
JMP ErrorFile:
ErrorFileInput:
LEA RSI,[FileInput.Name]
JMP ErrorFile:
ErrorFileIndex:
LEA RSI,[FileOutput.Name]
ErrorFile:
StdOutput =U'File "',RSI,=U'" not found or empty.',Eol=yes,Unicode=yes,Console=yes
JMP .MsgQuit:
ErrorAlloc::
StdOutput =B"Error on memory allocation.",Eol=yes
.MsgQuit:
BufferDestroy [Level0Buffer::],[Level1Buffer::],[Level2Buffer::],[Level3Buffer::],[Level4Buffer::]
FileClose FileInput, FileOutput, FileIndex
JSt [Status::],ArgLeaveTemporary,.90:
FileDelete FileOutput, FileIndex ; Delete temporary files.
.90: TerminateProgram 0
ENDP Main
ArgOutputFile(if not empty) or
%TEMP%\ArgInputFileName.lst,
%TEMP%\ArgInputFileName.lst.index(if ArgOutputFile= is empty).
ViewPrologue: PROC
LEA RSI,[ArgInputFile::] ; Name of memory-maped FileInput.
CMPB [RSI],0
STC
JE .90:
FileClose FileInput, FileIndex, FileOutput
JSt [Status::],ArgLeaveTemporary, .10:
FileDelete FileIndex, FileOutput ; Delete temporary file from previous run.
.10:LEA RDI,[NameUTF16]
WinABI MultiByteToWideChar,65001,0,RSI,-1,RDI,SIZE# NameUTF16/2
LEA RBX,[FileInput]
FileAssign RBX, RDI, Unicode=yes
FileLoad RBX
JC .90:
TEST RAX
STC
JZ .90: ; Zero size of input file.
MOV [InputPtr::],RSI
MOV [InputSize::],RAX
LEA RDX,[RSI+RAX]
MOV [InputEnd::],RDX
BSR ECX,EAX ; Compute AddressDigits (4..8) from input file size in EAX.
SHR ECX,2
INC ECX
CMP ECX,4
JAE .20:
MOV ECX,4
.20:MOV [AddressDigits::],ECX
MOV EDX,[ArgFileFormat::] ; Find file format.
TEST EDX
JNZ .30:
CALL AutodetectFileFormat::
MOV [FormatProcPtr::],RAX ; Pointer to procedure FormatELF32, FormatBIN etc.
MOV [ArgFileFormat::],ECX ; Ordinal format number.
.30:MOV EDX,[ArgFileFormat::] ; Set by AutodetectFormat or by cmd-line argument.
LEA RDI,[FormatNames:]
MOV ECX,EndFormatNames-FormatNames
XOR EAX,EAX
.45:DEC EDX
JZ .40:
REPNE SCASB
JMP .45:
.40:MOV [FormatNamePtr::],RDI
LEA RDI,[NameUTF16] ; Create output and index files.
LEA RSI,[ArgOutputFile::]
WinABI MultiByteToWideChar,65001,0,RSI,RCX,RDI,SIZE# NameUTF16 /2
CMPW [RDI],0
JNZ .80: ; When ArgFileOutput is not empty, use it as is.
; If ArgOutputFile is not specified (default), use %TEMP% and filename without path for temporary names.
WinABI GetEnvironmentVariableW, =U"Temp", RDI, SIZE# NameUTF16
SAL EAX,1 ; Size in characters.
ADD RDI,RAX
MOV AX,'\'
CMP [RDI-2],AX
JE .50:
STOSW
.50:LEA RSI,[FileInput.Name]
MOV EAX,[FileInput.NameOffs]
ADD RSI,RAX ; Use the plain filename without path.
.60:LODSW
CMP AX,0
JE .70:
STOSW
JMP .60:
.70:LEA RSI,[=U".lst"]
MOV ECX,4+1
REP MOVSW
LEA RDI,[NameUTF16]
.80:FileAssign FileOutput, RDI, Unicode=yes
FileExists? FileOutput
JC .85:
n %FOR 1..9
FileAssign FileOutput,RDI,=U".lst", Unicode=yes
FileExists? FileOutput
JC .85:
%ENDFOR n
.85:FileCreate FileOutput
JC .90:
LEA RDX,[FileOutput.Name]
FileAssign FileIndex, RDX, =U".index", Unicode=yes
FileCreate FileIndex
.90:RET
ENDP ViewPrologue
ViewEpilogue: PROC
FileClose FileOutput, FileIndex
FileMapOpen FileOutput
JC ErrorFileOutput
MOV [OutputPtr::],RSI
MOV [OutputSize::],RAX
ADD RAX,RSI
MOV [OutputEnd::],RAX
FileMapOpen FileIndex
JC ErrorFileIndex
MOV [IndexPtr::],RSI
ADD RAX,RSI
MOV [IndexEnd::],RAX
CALL CreateLstIndex:: ; Toss the index to five memory buffers for levels 0..4.
MOVD [Level],0
MOVD [TopLine],1
RET
ENDP ViewEpilogue
FileIndexReopen: PROC
LEA RBX,[FileIndex]
FileClose RBX
FileMapCreate RBX ; Close and reopen FileIndex. Returns the contents in RDI,RAX.
JC ErrorFileIndex:
RET
ENDP FileIndexReopen:
FileWriteOutput: PROC
FileWrite FileOutput,RSI,RCX
JC ErrorFileOutput:
RET
ENDP FileWriteOutput:
WndCreateMain: PROC
MOV EAX,' '
LEA RDI,[Spaces]
MOV ECX,SIZE# Spaces / 4
REP STOSD
; Register WndClassEx for the main window.
MOVD [WndClassEx.cbSize],SIZE# WndClassEx
LEA RSI,[EuroView::]
MOVQ [WndClassEx.lpszClassName],RSI
MOVD [WndClassEx.style],CS_HREDRAW|CS_VREDRAW
MOVQ [WndClassEx.lpfnWndProc],WndProcMain
WinABI GetModuleHandle,0
MOVQ [WndClassEx.hInstance],RAX
WinABI LoadIcon,RAX,1 ; The 1st and only icon from [.rsrc] section.
MOVQ [WndClassEx.hIcon],RAX
WinABI LoadCursor,0,IDC_ARROW
MOVQ [WndClassEx.hCursor],RAX
MOVQ [WndClassEx.hbrBackground],COLOR_BTNFACE+1
WinABI RegisterClassExA, WndClassEx
; Create the main window.
WinABI CreateWindowExA,0, \
RSI,RSI,WS_OVERLAPPEDWINDOW|WS_VSCROLL, \
CW_USEDEFAULT,CW_USEDEFAULT,OptimalWidth*2,MinimalHeight*2,\
0, 0, [WndClassEx.hInstance], 0
MOV [hWindowMain],RAX
MOV RBX,RAX
MOV [ScrollInfo.cbSize], SIZE# SCROLLINFO
MOV [ScrollInfo.fMask], SIF_RANGE | SIF_PAGE
MOV [ScrollInfo.nMin],1
WinABI SetScrollInfo, RBX,SB_VERT,ScrollInfo,1
MOV [FontSize], FontSizeDef
CALL WndFont
; Initialize InpFileDlg.
MOV [InpFileDlg.lStructSize],SIZE# OPENFILENAME
MOV RAX,[WndClassEx.hInstance]
MOV RDX,[hWindowMain]
LEA RDI,[NameUTF16:]
MOVW [RDI],0
MOV [InpFileDlg.hInstance],RAX
MOV [InpFileDlg.hwndOwner],RDX
MOV [InpFileDlg.lpstrFile],RDI
MOV [InpFileDlg.nMaxFile],SIZE# NameUTF16 /2
SetSt [InpFileDlg.Flags],OFN_FILEMUSTEXIST+OFN_HIDEREADONLY
; Create Help window but don't show it yet.
LEA RCX,[Help:]
WinABI CreateWindowExA,WS_EX_OVERLAPPEDWINDOW + WS_EX_TOPMOST + WS_EX_TRANSPARENT, \
=B"STATIC",RCX, WS_CHILD, \
40,50,640,660, \
[hWindowMain], 0, [WndClassEx.hInstance], 0
MOV [hWindowHelp],RAX
; Register Find window class.
MOVQ [WndClassEx.lpszClassName],TitleWindowFind
MOVQ [WndClassEx.lpfnWndProc],WndProcFind
WinABI RegisterClassExA, WndClassEx
RET
ENDP WndCreateMain
WndCreateFind PROC
; Create the Find window.
WinABI CreateWindowExA,0, \
TitleWindowFind,=B"EuroView find",WS_OVERLAPPEDWINDOW, \
CW_USEDEFAULT,CW_USEDEFAULT,wiFind,heFind, \
0, 0, [WndClassEx.hInstance], 0
MOV [hWindowFind],RAX
; Create child windows of the WindowFind.
; Find edit.
MOV ESI,wiFind-2*wiBorder
WinABI CreateWindowExW,0,=U'EDIT',FindUTF8,WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
wiBorder,wiBorder,RSI,heTitle1,[hWindowFind],0,[WndClassEx.hInstance],0
MOV [hEditFind],RAX
WinABI SetWindowText,RAX,FindUTF8
WinABI SetFocus,[hEditFind]
MOV ECX,wiFind-wiBorder-wiBtnIO
WinABI CreateWindowExA,0,=B'BUTTON',=B"&Find",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP+BS_DEFPUSHBUTTON, \
RCX,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnFind,[WndClassEx.hInstance],0
MOV [hBtnFind],RAX ; Button Find.
WinABI CreateWindowExA,0,=B'BUTTON',=B"C&lear",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
wiBorder+wiBtnIO+wiBorder,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnClear,[WndClassEx.hInstance],0
MOV [hBtnClear],RAX ; Button Clear.
WinABI CreateWindowExA,0,=B'BUTTON',=B"&Cancel",WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP, \
wiBorder,yFindButton,wiBtnIO,heBtnIO,[hWindowFind],IdBtnCancel,[WndClassEx.hInstance],0
MOV [hBtnCancel],RAX ; Button Cancel.
RET
ENDP WndCreateFind
[%hWnd], [%uMsg], [%wParam], [%lParam]), too, in the entire WndProc body.
Messages obtained from Windows are dispatched by WndProcMain to their handlers.
Unhandled messages are passed to DefWindowProc.
WndProcMain Procedure hWnd, uMsg, wParam, lParam ; These parameters are provided in RCX,RDX,R8,R9.
Uses RBX,RBP,RSI,RDI ; It's only necessary if some of callee-save registers was used in this fastcalled procedure.
SaveToShadow
MOV RBX,RCX
MOV RAX,RDX
MOV RSI,R8
MOV RDI,R9 ; Preload msg attributes for handler's convenience.
; Fork message uMsg=RDX=RAX to its handler using macro Dispatch:
Dispatch EDX, WM_VSCROLL,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_RBUTTONDOWN,WM_RBUTTONUP, \
WM_MOUSEWHEEL,WM_MOUSEMOVE,WM_PAINT,WM_SIZE,WM_KEYDOWN,WM_DESTROY
.Def:WinABI DefWindowProc,[%hWnd],[%uMsg],[%wParam],[%lParam] ; Ignored messages go to DefWindowProc with unchanged arguments.
JMP .Ret: ; Go to EndProcedure with result value RAX as returned from DefWindowProc.
; All message handlers terminate with a jump to label .Def: or .Ret0:.
; Here are helper .subprocedures for keyboard and scrollbox event handlers:
.GetCtrl2ECX: ; Returns RCX=1 when Ctrl is pressed, otherwise RCX=0. RAX,RDX clobbered.
WinABI GetKeyState,VK_CONTROL ; Returns bit 15 of RAX set when Ctrl was pressed.
.GetCtrl2ECX.2:
XOR ECX,ECX
SAL AX,1 ; Shift MSbit to CF.
RCL ECX,1 ; Virtual key handlers receive RCX=1 when Ctrl or Shift was pressed, otherwise RCX=0.
RET
.GetShift2ECX: ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
WinABI GetAsyncKeyState,VK_SHIFT, Lib=user32.dll ; Returns bit 15 of RAX set when Shift was pressed.
JMP .GetCtrl2ECX.2:
.ScrollVer: PROC ; Scroll vertically until TopLine=ESI.
TEST ESI ; Saturate proposed TopLine=ESI to the acceptable range 1..Lines.
JS .v1:
CMP ESI,1
JAE .v2:
.v1:MOV ESI,1
.v2:CMP ESI,[Lines]
JB .v5:
MOV ESI,[Lines]
.v5:MOV [TopLine],ESI
WinABI SetScrollPos,[hWindowMain],SB_VERT,RSI,1
WinABI InvalidateRect,[hWindowMain],0,0
RET
ENDP .ScrollVer:
.Mouse2Char: PROC ; Convert mouse coordinates from R9=lParam to RAX (document Row) and RDX (document Col). Clobbers RCX.
MOV EAX,R9D ; xPos,yPos when clicked.
AND EAX,0xFFFF ; xPos of the mouse click.
XOR EDX,EDX
MOV ECX,[cxChar]
DIV RCX
PUSH RAX ; Column.
MOV EAX,R9D ; xPos,yPos when clicked.
SHR EAX,16 ; yPos of the mouse click.
XOR EDX,EDX
MOV ECX,[cyChar]
DIV RCX ; RAX is vertical position in characters.
ADD EAX,[TopLine]
POP RDX
RET
ENDP .Mouse2Char:
; Handle messages for the main window:
.WM_PAINT:
CALL WndPaintMain
JMP .Ret0:
.WM_SIZE:
CALL WndResizeMain
JMP .Def:
.VK_TAB: ; Tab pressed.
CALL .GetShift2ECX
TEST ECX
JZ .WM_LBUTTONUP:
.WM_RBUTTONUP: ; Shift-Tab: Increase level.
MOV ECX,[Level]
CMP ECX,4
JAE .Ret0:
INC ECX
.LevelChanged:
MOV [Level],ECX
CALL WndTitle:
WinABI InvalidateRect,[hWindowMain],0,0
.WM_RBUTTONDOWN:
JMP .Ret0:
.WM_LBUTTONDOWN: ; Left mouse button captures mouse and marks the text to be selected for clipboard.
MOV ECX,[Level]
JRCXZ .SelectionStart:
JMP .WM_RBUTTONDOWN: ; Do nothing when Level above 0. WM_LBUTTONUP will decrease it.
.SelectionStart:
SetSt [Status::],ArgMouseCaptured
CALL .Mouse2Char:
XOR ECX,ECX
MOV [DocRowStop],ECX
MOV [DocColStop],ECX
MOV [DocRowStart],EAX
MOV [DocColStart],EDX
JMP .Ret0:
.WM_LBUTTONUP: ; Decrease level. At Level=0, start or stop selection by mouse.
MOV ECX,[Level]
JRCXZ .Selection:
DEC ECX
JMP .LevelChanged:
.Selection:
RstSt [Status::],ArgMouseCaptured
CALL .Mouse2Char:
CMP EAX,[DocRowStart] ; Swap so DocStop is always greater than DocStart.
JAE .Se2:
XCHG EAX,[DocRowStart]
.Se2:MOV [DocRowStop],EAX
CMP EDX,[DocColStart]
JAE .Se4:
XCHG EDX,[DocColStart]
.Se4:MOV [DocColStop],EDX
WinABI InvalidateRect,[hWindowMain],0,0
JMP .Ret0:
.WM_MOUSEMOVE:
JNSt [Status::],ArgMouseCaptured, .Def:
CALL .Mouse2Char:
CMP EAX,[DocRowStart]
JA .M2:
XCHG EAX,[DocRowStart]
.M2: CMP EDX,[DocColStart]
JA .M4:
XCHG EDX,[DocColStart]
.M4: MOV [DocRowStop],EAX
MOV [DocColStop],EDX
WinABI InvalidateRect,[hWindowMain],0,0
JMP .Ret0:
.WM_MOUSEWHEEL: ; Rolled.
SAR ESI,16 ; RSI is now +40 or -40 on mouse-wheel roll.
ADD [WheelCnt],ESI ; Accumulate scroll requests.
MOV EDI,[WheelCnt]
.RollUp:
CMP EDI,WheelPerLine
JL .RollDown:
SUB EDI,WheelPerLine
MOV [WheelCnt],EDI
WinABI SendMessage,RBX,WM_VSCROLL,SB_LINEUP,0
JMP .RollUp:
.RollDown:
CMP EDI,0
JGE .Ret0:
ADD EDI,WheelPerLine
MOV [WheelCnt],EDI
WinABI SendMessage,RBX,WM_VSCROLL,SB_LINEDOWN,0
JMP .RollDown:
.WM_VSCROLL: ; User scrolled the window vertically.
CALL .GetCtrl2ECX
MOV EAX,0x0000_FFFF
AND EAX,ESI ; EAX is now scroll box action (clicked on the scrollbox).
SHR ESI,16 ; ESI is now scroll box position.
Dispatch EAX,SB_LINEUP,SB_LINEDOWN,SB_PAGEUP,SB_PAGEDOWN,SB_THUMBTRACK
JMP .Def:
.WM_KEYDOWN: ; Non-character hot key ESI=R8D=wParam was pressed.
CALL .GetCtrl2ECX ; Test if [Ctrl] was pressed. Set RCX=0 when not pressed.
Dispatch ESI,VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT,VK_HOME,VK_END,VK_TAB, \
VK_NUMPAD0,VK_ADD,VK_SUBTRACT,'O',VK_ESCAPE,'C','F',VK_F7,'N',VK_F3,'P',VK_RETURN
CMP ESI,VK_F1
JB .Def:
CMP ESI,VK_F12
JNA .VK_F1:
JMP .Def: ; Pass unhandled keys to WinABI DefWindowProc.
.SB_LINEDOWN: ; Vertical scrollbox line down.
.VK_DOWN: ; Down arrow.
MOV ESI,[TopLine]
INC ESI
JRCXZ .SB_THUMBTRACK: ; If Ctrl is not pressed.
ADD ESI,CtrlStep
JMP .SB_THUMBTRACK:
.SB_LINEUP: ; Vertical scrollbox line up.
.VK_UP: ; Up arrow.
MOV ESI,[TopLine]
DEC ESI
JRCXZ .SB_THUMBTRACK: ; If Ctrl is not pressed.
SUB ESI,CtrlStep
JMP .SB_THUMBTRACK:
.SB_THUMBTRACK: ; User dragged the tumbtrack to the position ESI.
CALL .ScrollVer:
JMP .Ret0:
.SB_PAGEUP: ; Vertical scrollbox page up.
.VK_PRIOR:
MOV ESI,[TopLine]
SUB ESI,[Rows]
INC ESI,ESI
JRCXZ .SB_THUMBTRACK: ; If Ctrl is not pressed.
SUB ESI,[Rows]
SUB ESI,[Rows]
SUB ESI,[Rows]
JMP .SB_THUMBTRACK:
.VK_HOME:
MOV ESI,1
JMP .SB_THUMBTRACK:
.SB_PAGEDOWN: ; Vertical scrollbox page down.
.VK_NEXT:
MOV ESI,[TopLine]
ADD ESI,[Rows]
DEC ESI,ESI
JRCXZ .SB_THUMBTRACK: ; If Ctrl is not pressed.
ADD ESI,[Rows]
ADD ESI,[Rows]
ADD ESI,[Rows]
JMP .SB_THUMBTRACK:
.VK_END:
MOV ESI,[Lines]
JMP .SB_THUMBTRACK:
.VK_NUMPAD0: ; Ctrl 0 restore font size.
MOV EDI,FontSizeDef
.SetFontEDI:
MOV [FontSize],EDI
CALL WndFont ; Get new [cxChar],[cyChar].
CALL WndResizeMain ; Recalculate Rows, Cols.
JMP .Ret0:
.VK_ADD: ; Ctrl + increase font size.
MOV EDI,[FontSize]
INC EDI
CMP EDI,FontSizeMax
JG .Ret0:
JMP .SetFontEDI:
.VK_SUBTRACT: ; Ctrl - decrease font size.
MOV EDI,[FontSize]
DEC EDI
CMP EDI,FontSizeMin
JL .Ret0:
JMP .SetFontEDI:
.O: MOV RDI,[InpFileDlg.lpstrFile] ; Open file.
MOVW [RDI],0
WinABI GetOpenFileNameW, InpFileDlg ; Open another input file.
TEST RAX
JZ .Ret0: ; If cancelled in the common dialogue or other error.
LEA RSI,[NameUTF16] ; InputFile selected from the common dialogue.
GetLength$ RSI, Unicode=yes
TEST ECX
JZ .Ret0: ; If nothing selected.
MOVD [ArgFileFormat::],0 ; Start with Autodetect file format.
LEA RDI,[ArgInputFile::]
WinABI WideCharToMultiByte,65001,0,RSI,RCX,RDI,SIZE#NameUTF8/2,0,0 ; Convert to UTF-8 in ArgInputFile.
CALL ViewPrologue: ; Read the input file, prepare output files.
JC .Ret0: ; If error, InputFile not found etc.
CALL ViewCreate:: ; Generate FileIndex and write FileOutput.
CALL ViewEpilogue:
CALL WndTitle:
WinABI InvalidateRect,[hWindowMain],0,0
JMP .Ret0:
.C: CALL .GetCtrl2ECX: ; Returns RCX=1 when Ctrl is pressed.
TEST ECX
JZ .Def:
CALL Copy2Clipboard:
JMP .Ret0:
.F: ; Key F (Find) pressed.
.VK_F7:
WinABI IsWindow,[hEditFind]
JZ .F3:
WinABI PostMessage,[hEditFind],EM_SETSEL,0,-1 ; Select all.
.F3: WinABI SetFocus,[hEditFind]
CALL MsgLoopFind
CALL WndTitle
.Inv:WinABI InvalidateRect,[hWindowMain],0,0
JMP .Ret0:
.N:
.VK_F3:
CALL .GetShift2ECX: ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
JRCXZ .N1:
JMP .P:
.N1: MOV EDX,[Level]
BufferRetrieve [Level0Buffer::+8*RDX] ; SIZE# LST_INDEX=8
MOV R10,RSI
MOV EDX,[TopLine] ; 1,2,3,,,Lines.
.N2: CMP EDX,[Lines]
JNB .Ret0:
LEA RSI,[R10+8*RDX] ; SIZE# LST_INDEX=8
LODSD
LODSD
INC EDX
SHR EAX,24
JZ .N2:
MOV [TopLine],EDX
WinABI InvalidateRect,[hWindowMain],0,0
JMP .Ret0:
.P: MOV EDX,[Level] ; Key P pressed.
BufferRetrieve [Level0Buffer::+8*RDX] ; SIZE# LST_INDEX=8
MOV R10,RSI
MOV EDX,[TopLine]
.P2: DEC EDX
JS .Ret0:
MOV [TopLine],EDX
LEA RSI,[R10+8*RDX]
LODSD
LODSD
SHR EAX,24
JZ .P2:
WinABI InvalidateRect,[hWindowMain],0,0
JMP .Ret0:
.VK_RETURN:
WinABI IsWindowVisible,[hEditFind]
TEST RAX
JZ .Ret0:
WinABI GetWindowTextA,[hEditFind],FindUTF8,254
JMP .Ret0:
.VK_F1: ; Show help window.
WinABI IsWindowVisible,[hWindowHelp]
TEST RAX
JNZ .Ret0: ; Ignore F1 when it is visible.
WinABI ShowWindow, [hWindowHelp], SW_SHOW
JMP .Ret0:
.VK_ESCAPE: ; Terminate window or program.
WinABI IsWindowVisible,[hWindowHelp]
TEST RAX
JZ .WM_DESTROY:
WinABI ShowWindow, [hWindowHelp], SW_HIDE
JMP .Ret0:
.WM_DESTROY: ; Program terminates.
WinABI DeleteObject,[hFont]
WinABI PostQuitMessage,0; Tell Windows to quit this program with errorlevel 0.
.Ret0:XOR EAX,EAX ; RAX=0 signalizes that the message was processed here.
.Ret:EndProcedure WndProcMain
WndResizeMain: PROC
LEA RBX,[RectMainWindow]
WinABI GetWindowRect,[hWindowMain],RBX
MOV ESI,[RBX+RECT.left]
MOV ECX,[RBX+RECT.right]
SUB ECX,ESI
CMP ECX,MinimalWidth
JA .10:
MOV ECX,MinimalWidth
.10:MOV [WindowWidth],ECX
MOV EDI,[RBX+RECT.top]
MOV EDX,[RBX+RECT.bottom]
SUB EDX,EDI
CMP EDX,MinimalHeight
JA .20:
MOV EDX,MinimalHeight
.20:MOV [WindowHeight],EDX
WinABI MoveWindow,[hWindowMain],RSI,RDI,RCX,RDX,-1
MOV EAX,[WindowWidth]
XOR EDX,EDX
MOV ECX,[cxChar]
TEST ECX
JZ .90:
DIV RCX
MOV [Cols],EAX ; Number of columns visible in window.
MOV EAX,[WindowHeight]
XOR EDX,EDX
MOV ECX,[cyChar]
JRCXZ .90:
DIV RCX
MOV [Rows],EAX ; Number of rows visible in window.
WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,1
WinABI InvalidateRect,[hWindowMain],0,1
.90:RET
ENDP WndResizeMain
TopLine.Level = 0
┌──────────────┐
│| line 4 │row 1 TopLine = 4
│| line 5 │row 2
│|## line 6 │row 3
│| line 7 │row 4
│| line 8 │row 5 Rows on screen = 5
└──────────────┘
| line 9
| line 10 Lines of listing = 10
WndPaintMain: PROC
XOR EAX,EAX
MOV [cxWindow],RAX
MOV [cyWindow],RAX
WinABI BeginPaint, [hWindowMain], PaintStruct
MOV [hDC],RAX
WinABI SelectObject, RAX, [hFont]
.10:MOV R12,[OutputPtr::]
TEST R12
JZ .90:
MOV EAX,[Level] ; 0..4
MOV EDX,[LevelPrevious]
CMP EAX,EDX
MOV [LevelPrevious],EAX
JE .43:
JB .35:
; Level is increasing from EDX to EAX. Calculate the new value of TopLine.
ADD R12,RAX
BufferRetrieve [Level0Buffer::+8*RDX] ; RSI,RCX are old LST_INDEX records.
MOV [IndexBegin],RSI
XOR EDX,EDX
MOV EDI,[TopLine]
.15:DEC EDI
JZ .20:
LODSD
CMPB [R12+RAX],'#' ; Is the line in new level?
LODSD
JNE .15:
INC EDX
JMP .15:
.20:TEST EDX
JNZ .25:
INC EDX
.25:CMP EDX,[TopLine]
JB .30:
INC EDX
.30:MOV [TopLine],EDX
JMP .10:
.35:; Level is decreasing from EDX to EAX. Calculate the new value of TopLine.
ADD R12,RDX
BufferRetrieve [Level0Buffer::+8*RAX] ; RSI,RCX are new LST_INDEX records.
MOV [IndexBegin],RSI
SHR ECX,3
JZ .90:
XOR EDI,EDI ; Line counter in new buffer.
MOV EDX,[TopLine]
.40:INC EDI
LODSD
CMPB [R12+RAX],'#'
LODSD
JNE .40:
DEC EDX
JNZ .40:
MOV [TopLine],EDI
JMP .10:
.43:; Level EAX is unchanged.
BufferRetrieve [Level0Buffer::+8*RAX] ; RSI,RCX are LST_INDEX records.
MOV [IndexBegin],RSI
SHR ECX,3 ; SIZE# LST_INDEX = 8
MOV [Lines],ECX
MOV EDI,[TopLine]
CMP EDI,[Lines]
JBE .47:
MOV EDI,[Lines]
.47:MOV [TopLine],EDI
WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,-1
SUB RSI,SIZE# LST_INDEX
XOR EDX,EDX
.50:INC EDX ; RDX is line number 1,2,3,,,Lines.
ADD RSI,SIZE# LST_INDEX
CMP EDX,EDI ; Reached TopLine?
JB .50:
MOV R14D,[Rows] ; R14 is number of rows on screen.
CMP EDX,[Lines] ; Reached the end of lines?
JA .80:
MOV R15D,[AddressDigits::] ; 4..8.
ADD R15D,38 ; R15 is the number of gray characters in dump, including address and |.
.55:; Display lines indexed by RSI=LST_INDEX until EDX>[Lines] (out of lines) or until R14=0 (all rows displayed).
LODSD ; LST_INDEX.FA
LEA RBX,[R12+RAX] ; RBX is now pointer to the line in mapped listing. R12 is OutputPtr.
LODSD ; LST_INDEX.Size + shifted FoundOffset, if found on this line.
MOV ECX,EAX
SHR ECX,24 ; ECX is now offset of found string in the line RBX.
MOV [FoundOffset],ECX
AND EAX,NoFlags ; Get rid of FAFound bits.
MOV ECX,EAX ; RCX is line size in bytes, without spaces.
MOV EDX,[cxChar] ; Width of one character in pixels.
MUL RDX ; RAX is line width in pixels, without spaces.
MOV R13,RAX ; R13 is cxWindow at the start of spaces.
MOV EDI,[Cols] ; RDI is columns in the window, including padding spaces.
SUB EDI,ECX ; EDI is the number of spaces following the remark in listing line.
MOV EAX,Color4
CMPD [RBX+1],'####'
JE .60:
MOV EAX,Color3
CMPB [RBX+3],'#'
JE .60
MOV EAX,Color2
CMPW [RBX+1],'##'
JE .60:
MOV EAX,Color1
CMPB [RBX+1],'#'
JE .60:
; Current line is dump line Level0 , gray 38+AddressDigits chars wide, plus color Remark + same color spaces.
; Example of a line: gray column | color column remark Spaces_to_pad_the_line
;|0000:7F454C46 020100100 00000000 00000000| DD 0x464C457F,0x00010102,0x000000,0x000000 ; Signature ELF64______________________
; Line is mapped in memory at RBX,RCX. Its index is RSI.
PUSH RCX ; Number of characters in this listing line, without padding spaces.
WinABI SetBkColor,[hDC],ColorDump ; Level0 gray column. ; R15 is size of gray characters between | |.
WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,R15 ; Display gray part of the line pointed to with RBX.
WinABI SetBkColor,[hDC],ColorRem ; Yellish color.
ADD RBX,R15 ; Add the width of the dump column. RBX points to the remark.
MOV EAX,[cxChar] ; Width of one character.
MUL R15 ; Let RAX=width of already displayed characters.
POP RCX
SUB RCX,R15 ; Subtract the number of already displayed characters.
JNA .65:
WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX ; Print the remark.
JMP .65:
.60:; Current line is Level1, Level2, Level3 or Level4 in color EAX. No gray column.
WinABI SetBkColor,[hDC],RAX ; RAX is LevelX color.
WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,RCX ; Display RCX characters at RBX.
.65:WinABI TextOutA,[hDC],R13,[cyWindow],Spaces,RDI ; Display EDI spaces on the same line as padding.
; Line is now displayed, but without the found string and without the selected string.
MOV ECX,[FoundOffset] ; 0 (nothing found) or 1,2,3,,, for offset 0,1,2,,,
TEST ECX,ECX
JZ .70: ; Skip when the string was not found in this line.
; Display the found string again in different color TextColorFound+BkColorFound.
WinABI GetTextColor,[hDC]
MOV R10,RAX
WinABI SetBkColor,[hDC],BkColorFound ; Bright white.
WinABI SetTextColor,[hDC],TextColorFound
MOV EBX,[RSI-SIZE# LST_INDEX+LST_INDEX.FA] ; Offset of the start of the line again.
MOV ECX,[FoundOffset] ; Offset 1,2,3,,, again.
DEC ECX
ADD EBX,ECX ; Offset of the start of the found string.
ADD RBX,R12 ; Start of the found string in line RBX. R12 is OutputPtr.
MOV EDX,[cxChar] ; Width of one character in pixels.
MOV EAX,[FoundOffset] ; Number of bytes from the start of line.
DEC EAX
MUL EDX
ADD EAX,[cxWindow]
MOV ECX,[FindUTF8Size]
WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX ; Display the found string in magenta on white.
WinABI SetTextColor,[hDC],R10 ; Restore original text color.
.70:; Check if the current line indexed by RSI will match Doc* (specified by left button mouse capture).
; In this case display the selected string again with TextColorSelected+BkColorSelected.
MOV RAX,RSI ; Get current line number.
SUB RAX,[IndexBegin]
SHR EAX,3 ; EAX is now this line number (0..Lines).
CMP EAX,[DocRowStart]
JB .78:
CMP EAX,[DocRowStop]
JA .78:
; This line RSI is selected. Display again the selected text between [DocColStart]..[DocColStop].
WinABI GetTextColor,[hDC]
MOV R10,RAX
WinABI SetBkColor,[hDC],BkColorSelected
WinABI SetTextColor,[hDC],TextColorSelected
MOV EBX,[DocColStart] ; 0,1,2,,,Cols.
MOV ECX,[DocColStop] ; 0,1,2,,,Cols.
MOV EAX,[RSI-SIZE# LST_INDEX+LST_INDEX.Size]
AND EAX,NoFlags
CMP EAX,ECX
JA .73:
MOV ECX,EAX
.73: ; RCX is the smaller of DocColStop and line size.
MOV EAX,[cxChar]
MUL RBX
MOV EBX,[RSI - SIZE# LST_INDEX + LST_INDEX.FA]
MOV EDX,[DocColStart]
ADD EBX,EDX
SUB ECX,EDX
ADD RBX,R12 ; R12=OutputPtr.
INC ECX
WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX
WinABI SetTextColor,[hDC],R10 ; Restore original text color.
.78:MOV EAX,[cyChar] ; Height of one character in pixels.
ADD [cyWindow],EAX
DEC R14 ; Number of remaining rows on screen.
JNZ .55:
.80:TEST R14,R14
JZ .90:
DEC R14
WinABI TextOutA,[hDC],[cxWindow],[cyWindow],Spaces,[Cols] ; Display spaces on the entire line.
MOV EAX,[cyChar]
ADD [cyWindow],EAX
JMP .80:
.90:WinABI EndPaint, [hWindowMain], PaintStruct
RET
ENDP WndPaintMain:
WndFont: PROC
MOV RCX,[hFont]
JRCXZ .10:
WinABI DeleteObject,RCX,Lib=gdi32.dll
.10:WinABI CreateFontW, [FontSize], 0, 0, 0, FW_DONTCARE, 0, 0, 0, ANSI_CHARSET, \
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, \
FIXED_PITCH | FF_SWISS, 0
MOV [hFont],RAX
MOV RBX,[hWindowMain]
WinABI GetDC,RBX
MOV RDI,RAX ; Device context,
WinABI SelectObject,RDI,[hFont]
WinABI GetTextMetrics,RDI,TextMetric
WinABI ReleaseDC,RBX,RDI
MOV EAX,[TextMetric.tmHeight]
MOV ECX,[TextMetric.tmAveCharWidth]
ADD EAX,[TextMetric.tmExternalLeading]
MOV [cxChar],ECX
MOV [cyChar],EAX
RET
ENDP WndFont:
EuroView "input.bin" as ELFX64 level 0. Found 0× "" and then converted to UTF-16 for SetWindowTextW.
WndTitle PROC
LEA RDI,[NameUTF8]
LEA RSI,[EuroView::]
MOV ECX,8
REP MOVSB
MOV AX,' "'
STOSW
LEA RSI,[ArgInputFile::]
TEST RSI
JZ .40:
.30:LODSB
CMP AL,0
JE .40:
STOSB
JMP .30:
.40:MOV AL,'"'
STOSB
MOV EAX,' as '
STOSD
MOV RSI,[FormatNamePtr::]
TEST RSI
JZ .60:
.50:LODSB
CMP AL,0
JE .60:
STOSB
JMP .50:
.60:LEA RSI,[=B', level ']
MOV CL,8
REP MOVSB
MOV AL,'0'
OR AL,[Level]
STOSB
LEA RSI,[=B', found ']
.65:LODSB
CMP AL,0
JE .70:
STOSB
JMP .65:
.70:MOV EAX,[FoundCnt]
StoD RDI
MOV EAX,0x222097C3 ; × " in UTF-8.
STOSD
LEA RSI,[FindUTF8]
.75:LODSB
CMP AL,0
JE .78:
STOSB
JMP .75:
.78:MOV AX,'"'
STOSW ; Copy FindUTF8 to NameUTF8.
MOV RCX,RDI
LEA RSI,[NameUTF8]
SUB RCX,RSI
LEA RDI,[NameUTF16]
WinABI MultiByteToWideChar,65001,0,RSI,RCX,RDI,SIZE# NameUTF16 /2 ; Convert NameUTF8 to NameUTF16.
WinABI SetWindowTextW,[hWindowMain],RDI
RET
ENDP WndTitle
.Size, add .Size to .FA, clear .Level and
.Rem in this variable.
SaveViewIndex:: PROC
PUSH RCX
FileWrite FileIndex, RBX, SIZE# VIEW_INDEX
MOV EAX,[RBX+VIEW_INDEX.Size]
MOV ECX,EAX
AND EAX,0x0FFF_FFFF
MOV [RBX+VIEW_INDEX.Size],EAX ; Keep .Size unchanged for the next element.
SHR ECX,28 ; Isolate level.
JNZ .50:
ADD [RBX+VIEW_INDEX.FA],EAX ; Add previous .Size to this .FA, but keep .FA unchanged when .Level >0.
.50: XOR EAX,EAX
MOV [RBX+VIEW_INDEX.Rem],RAX ; Always clear .Rem field.
POP RCX
RET
ENDP SaveViewIndex::
ReadFileIni:: PROC
SetSt [Status::],ArgFromFile ; Tell ArgParse that arguments may not begin with / or -.
StdOutput =U'Configuration "',FileIni.Name,Console=yes,Unicode=yes
.10:FileStreamOpen FileIni,BufSize=4K
JNC .20:
StdOutput =U'" was not found.',Eol=yes,Console=yes,Unicode=yes
JMP .90:
.20:FileStreamReadLn FileIni
JBE .80:
MOV ECX,EAX
; The first line may begin with BOM.
MOV AX,[RSI]
CMPW AX,0xBBEF ; UTF-8 BOM?
JNE .50:
ADD RSI,3 ; Skip the BOM.
SUB ECX,3
JB .80:
JMP .50:
.30:FileStreamReadLn FileIni
JBE .80:
MOV ECX,EAX
.50:CALL ArgParse::
JNC .30:
StdOutput Help:,Unicode=no
TerminateProgram 8
.80:FileClose FileIni
StdOutput =U'" was accepted.',Eol=yes,Console=yes,Unicode=yes
.90:RstSt [Status::],ArgFromFile
RET
ENDP ReadFileIni
CreateLstIndex: PROC
BufferClear [Level0Buffer::],[Level1Buffer::],[Level2Buffer::],[Level3Buffer::],[Level4Buffer::]
MOV RBX,[OutputPtr::] ; Start of the listing in memory.
XOR ECX,ECX
MOV AL,10
DEC RCX
MOV RDX,RBX
.10:MOV RDI,RDX
CMP RDI,[OutputEnd::]
JNB .80:
MOV RSI,RDI
REPNE SCASB ; Find the end of line.
MOV RDX,RDI
SUB RDI,RSI ; Size.
SUB RSI,RBX ; FA.
SUB EDI,2 ; Omit CR+LF.
MOV [LstIndex.FA],ESI
MOV [LstIndex.Size],EDI
BufferStore [Level0Buffer::],LstIndex,SIZE# LstIndex
JC ErrorAlloc::
CMPB [RBX+RSI+1],'#' ; Is the line in Level1?
JNE .10:
BufferStore [Level1Buffer::],LstIndex,SIZE# LstIndex
JC ErrorAlloc::
CMPW [RBX+RSI+1],'##' ; Is the line in Level2?
JNE .10:
BufferStore [Level2Buffer::],LstIndex,SIZE# LstIndex
CMPB [RBX+RSI+3],'#' ; Is the line in Level3?
JNE .10:
BufferStore [Level3Buffer::],LstIndex,SIZE# LstIndex
CMPD [RBX+RSI+1],'####' ; Is the line in Level4?
JNE .10:
BufferStore [Level4Buffer::],LstIndex,SIZE# LstIndex
JMP .10:
.80:BufferRetrieve [Level0Buffer::]
SHR ECX,3 ; SIZE# LstIndex = 8
MOV [ListingLines::],ECX
CLC
RET
ENDP CreateLstIndex
WndProcFind Procedure hWnd, uMsg, wParam, lParam ; These parameters are provided in RCX,RDX,R8,R9.
SaveToShadow
Uses RBX,RSI,RDI,R12,R13,R14,R15 ; It's only necessary if some of callee-save registers was used in this fastcalled procedure.
CALL .GetShift2ECX:
; Fork message uMsg=RDX to its handler using macro Dispatch:
Dispatch EDX, WM_DESTROY, WM_SIZE, WM_KEYDOWN, WM_SYSKEYDOWN, WM_COMMAND
.Def:WinABI DefWindowProc,[%hWnd],[%uMsg],[%wParam],[%lParam] ; Pass ignored event to DefWindowProc with unchanged arguments.
JMP .Ret: ; Go to EndProcedure with result value RAX as returned from DefWindowProc.
; All message handlers terminate with a jump to label .Def: or .Ret0:.
.GetShift2ECX PROC ; Returns RCX=1 when Shift is pressed, otherwise RCX=0. RAX,RDX clobbered.
WinABI GetAsyncKeyState,VK_SHIFT ; Returns bit 15 of RAX set when Shift was pressed.
XOR ECX,ECX
SAL AX,1 ; Shift MSbit to CF.
RCL ECX,1 ; Virtual key handlers receive RCX=1 when Shift was pressed, otherwise RCX=0.
RET
ENDP .GetShift2ECX
.WM_SIZE:
CALL WndResizeFind
JMP .Ret0:
.WM_KEYDOWN: ; Non-character hot key R8D=wParam was pressed.
Dispatch R8D, VK_ESCAPE,VK_RETURN,VK_TAB,'C','L','F'
JMP .Def: ; Pass unhandled keys to WinABI DefWindowProc.
.WM_SYSKEYDOWN: ; A key pressed together with Alt.
Dispatch R8D,'C','L','F',VK_RETURN,VK_ESCAPE
JMP .Def: ; Pass unhandled keys to WinABI DefWindowProc.
.WM_COMMAND: ; Window element Id=LOWORD R8 was activated.
MOVZX EDX,R8W
Dispatch EDX,IdBtnFind, IdBtnClear, IdBtnCancel
JMP .Def: ; Let other commands handle by DefWindowProc().
.VK_TAB:
TEST ECX
JZ .Back:
WinABI SetFocus,[hBtnFind]
JMP .Def:
.L: ; Hotkey 'L' pressed.
.IdBtnClear: ; Button Clear clicked.
MOVB [FindUTF8],0
WinABI SetWindowTextA,[hEditFind],FindUTF8
CALL Search
CALL WndTitle
WinABI SetFocus,[hEditFind]
JMP .Ret0:
.Back:WinABI SetFocus,[hEditFind] ; Shift-Tab pressed inside Find dialog.
JMP .Def:
.VK_RETURN: ; Enter pressed.
.F: ; Hotkey 'F' pressed.
.IdBtnFind: ; Button Find clicked.
LEA RDI,[FindUTF8]
WinABI GetWindowTextA,[hEditFind],RDI,MAX_PATH_SIZE
CALL Search
CALL WndTitle
WinABI InvalidateRect,[hWindowMain],0,0
.C: ; HotKey 'C' pressed (Cancel).
.IdBtnCancel: ; Button Cancel clicked.
.VK_ESCAPE: ; Terminate thread.
.WM_DESTROY: ; Thread terminates.
WinABI ShowWindow,[hWindowFind],SW_HIDE
.Ret0:XOR EAX,EAX ; RAX=0 signalizes that the message was processed here.
.Ret:EndProcedure WndProcFind
WndResizeFind PROC
LEA RBX,[RectWindowMain]
WinABI GetWindowRect,[hWindowFind],RBX
MOV ESI,[RBX+RECT.left]
MOV ECX,[RBX+RECT.right]
SUB ECX,ESI
MOV [WindowFindWidth],ECX
MOV EDI,[RBX+RECT.top]
MOV EDX,[RBX+RECT.bottom]
SUB EDX,EDI
CMP EDX,120
JA .20:
MOV EDX,120
.20:WinABI MoveWindow,[hWindowFind],RSI,RDI,RCX,RDX,-1
MOV ESI,[WindowFindWidth]; Button input file select.
SUB ESI,3*wiBorder
WinABI MoveWindow,[hEditFind],wiBorder,wiBorder,RSI,heTitle1,1
SUB ESI,wiBtnIO ; Button Find.f
WinABI MoveWindow,[hBtnFind],RSI,yFindButton,wiBtnIO,heBtnIO,1
RET
ENDP WndResizeFind
FindTextUTF8 in OutputFile. When found, it marks LST_INDEX.Size
of its line with FAFound. Repeat for each of LevelNBuffer.
Search PROC
LEA RDI,[FindUTF8]
MOV [FoundCnt],0
GetLength$ RDI
MOV [FindUTF8Size],ECX
JRCXZ .90:
XOR R11,R11 ; FoundCnt.
MOV AL,[RDI] ; 1st byte of the needle.
LEA R8,[RDI+1] ; R8 is pointer to 2nd byte of the needle.
LEA R9,[RCX-1] ; R9 is size of the needle - 1.
MOV RBX,[Level0Buffer]
CALL .SearchBuffer
MOV [FoundCnt],R11D
MOV RBX,[Level1Buffer]
CALL .SearchBuffer
MOV RBX,[Level2Buffer]
CALL .SearchBuffer
MOV RBX,[Level3Buffer]
CALL .SearchBuffer
MOV RBX,[Level4Buffer]
CALL .SearchBuffer
.90:RET
.SearchBuffer PROC ; RBX=^Buffer
BufferRetrieve RBX
LEA RDX,[RSI+RCX]
SUB RSI,SIZE#LST_INDEX
.1: ADD RSI,SIZE#LST_INDEX
CMP RSI,RDX
JNB .9:
MOV EDI,[RSI+LST_INDEX.FA] ; Offset from OutputPtr.
MOV ECX,[RSI+LST_INDEX.Size]
ADD RDI,[OutputPtr]
AND ECX,NoFlags
MOV [RSI+LST_INDEX.Size],ECX
LEA R10,[RDI+RCX] ; R10 is pointer to the end of line.
.3: REPNE SCASB ; Search for 1st byte of the needle.
JNE .1:
TEST R9
JZ .6:
PUSH RCX,RSI,RDI
LEA RSI,[RDI+R9] ; RSI is temporary pointer to the end of needle.
CMP RSI,R10
JA .5: ; Needle oversizes end of line. Not found.
MOV RSI,R8 ; Pointer to 2nd byte of needle.
MOV RCX,R9 ; Size of needle - 1.
REPE CMPSB
.5: POP RDI,RSI,RCX
JNE .3: ; Go to continue the search of 1st byte.
.6: DEC RDI ; Pointer to needle found,
SUB RDI,[OutputPtr] ; Offset from start of file.
SUB RDI,[RSI+LST_INDEX.FA]
INC EDI ; Offset + 1.
SHL EDI,24 ; Offset+1 from the start of line.
OR [RSI+LST_INDEX.Size],EDI
INC R11 ; FoundCnt.
JMP .1:
.9: RET
ENDP .SearchBuffer
ENDP Search
MsgLoopFind PROC
WinABI IsWindow,[hWindowFind]
TEST EAX
JNZ .10:
CALL WndCreateFind ; Window for retrieving searched text.
.10: WinABI PostMessage,[hEditFind],EM_SETSEL,0,-1 ; Select all searched string..
WinABI ShowWindow,[hWindowFind],SW_SHOW
WinABI UpdateWindow,[hWindowFind]
.MsgLoop:
WinABI GetMessage, Msg,0,0,0
TEST RAX
JZ .MsgQuit: ; ZF signalizes message WM_QUIT - request for cancel and termination.
CMPD [Msg.wParam],VK_ESCAPE
JNE .30:
WinABI PostMessage,[hWindowFind],WM_KEYDOWN,VK_ESCAPE,0
JMP .MsgQuit:
.30: CMPD [Msg.wParam],VK_RETURN
JNE .40:
WinABI PostMessage,[hWindowFind],WM_KEYDOWN,VK_RETURN,0
WinABI PostMessage,[hWindowMain],WM_KEYDOWN,0x4E,0 ; Simulate key "N".
JMP .MsgQuit:
.40: WinABI IsDialogMessage,[hWindowFind],Msg ; Let Windows handle TAB keys.
TEST RAX
JNZ .MsgLoop:
.50: WinABI TranslateMessage, Msg ; Remap character keys from national keyboards.
WinABI DispatchMessage, Msg ; Let Windows call our WndProc.
JMP .MsgLoop: ; Wait for another message.
.MsgQuit:
WinABI ShowWindow,[hWindowFind],SW_HIDE
XOR EAX,EAX
RET ; Return to CUI module.
ENDP MsgLoopFind
[DocRowStart],[DocColStart]..[DocRowStop],[DocColStop]
from OutpuFile to NameUTF8 and then to Windows clipboard.
Copy2Clipboard PROC
MOV R12,[OutputPtr::]
BufferRetrieve [Level0Buffer] ; Get the buffers contents to RSI,RCX.
MOV R8,RSI ; R8=RSI now points to an array of LST_VIEW records.
LEA RDI,[NameUTF8] ; RDI points to a temporary buffer which will concatenate selected text.
MOV R10D,[DocRowStart] ; R10D will grow from DocRowStart to DocRowStop.
LEA R9,[RDI+SIZE# NameUTF8] ; R9 points at the end of temporary buffer.
.10: CMP RDI,R9
JNB .50:
MOV EAX,R10D ; Line number, starting with DocRowStart (0,1,2,,,DocRowStop).
CMP EAX,[DocRowStop]
JA .50:
DEC EAX
MOV EBX,[R8+8*RAX+LST_INDEX.FA] ; EBX is file address of the selected line.
MOV EAX,[R8+8*RAX+LST_INDEX.Size]
AND EAX,NoFlags ; EAX is size of the selected line.
LEA RSI,[R12+RBX] ; R12 is pointer to memory-mapped lines.
MOV EDX,[DocColStart] ; Entire selected line is RSI,RAX.
MOV ECX,[DocColStop]
INC ECX
CMP EAX,ECX
JA .30:
XCHG EAX,ECX
.30: SUB ECX,EDX ; ECX is the less of EAX,ECX.
JNA .50:
ADD RSI,RDX
REP MOVSB
MOV AX,0x0A0D
STOSW
INC R10D
JMP .10:
.50: XOR EAX,EAX ; End of concatenation.
STOSB
MOV R12,RDI
LEA RSI,[NameUTF8]
SUB R12,RSI ; R12 is size of the string.
WinABI GlobalAlloc,GMEM_FIXED|GMEM_SHARE,R12
TEST RAX
JZ .90:
MOV R13,RAX
WinABI GlobalLock,RAX
MOV RDI,RAX
MOV RCX,R12
REP MOVSB
WinABI GlobalUnlock,R13
WinABI OpenClipboard,[hWindowMain]
WinABI EmptyClipboard
WinABI SetClipboardData,CF_TEXT,R13
TEST RAX
JNZ .80:
WinABI GlobalFree,R13
.80: WinABI CloseClipboard
.90: RET
ENDP Copy2Clipboard
%IF %^Debug INCLUDE1 winabi.htm DebugOutput proc StdOutput rsi,Size=rcx ret ENDP DebugOutput %ENDIF ENDPROGRAM viewwing