This is a module of EuroTool program EuroView for Windows.
EUROASM CPU=X64,SIMD=Yes, Unicode=No, MaxInclusions=128
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,
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.
ColorDump = 0x00D0D0D0 ; Dump.
ColorRem = 0x00D0FFFF ; Remark.
Color1 = 0x00D0FFD0 ; Level 1.
Color2 = 0x0030FFFF ; Level 2.
Color3 = 0x00D0D0FF ; Level 3.
Color4 = 0x00FFD0D0 ; Level 4.
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.
Help:
DB 13,10
DB "EuroView version %^DATE",13,10,10
DB " Use to inspect binary, object, library",10
DB " or executable ""InputFile"":",9,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,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",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,"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",10
DB 0
FormatNames:
FF %FOR %FileFormats
DB "%FF",0
%ENDFOR FF
EndFormatNames:
[.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 FileIni DS FILE64 FileInput DS FILE64 FileOutput:: DS FILE64 FileIndex DS FILE64 hWindowMain D QWORD ; Window handles. hWindowHelp 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. 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. Level D DWORD ; What level of headers to display (0..4). LevelPrevious D DWORD Spaces D 800 * B NameUTF16:: D 800 * UNICHAR ; Temporary working space for file names in UTF-16. NameUTF8:: D 800 * BYTE ; Temporary working space for file names in UTF-8.
[.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.
JC .40: ; When they are no more arguments.
SHR ECX,1 ; Size in bytes.
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
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=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
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'Error in file "',RSI,=U'"',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
.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::] ; Memory-map 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
FileMapOpen RBX
JC .90:
MOV [InputPtr::],RSI
MOV [InputSize::],RAX
LEA RDX,[RSI+RAX]
MOV [InputEnd::],RDX
BSR ECX,EAX
MOV EDX,4
ADD ECX,EDX
SHR ECX,2
CMP ECX,EDX ; Number of address digits (4..8) in listing.
JA .20:
MOV ECX,EDX
.20:MOV [AddressDigits::],ECX
MOV EDX,[ArgFileFormat::] ; Find file format.
TEST EDX
JNZ .30:
CALL AutodetectFileFormat::
MOV [FormatProcPtr::],RAX ; 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
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 ; Reopen and sort 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
LEA RCX,[Help:] ; Create Help window but don't show it yet.
WinABI CreateWindowExA,WS_EX_OVERLAPPEDWINDOW + WS_EX_TOPMOST + WS_EX_TRANSPARENT, \
=B"STATIC",RCX, WS_CHILD, \
40,80,640,520, \
[hWindowMain], 0, [WndClassEx.hInstance], 0
MOV [hWindowHelp],RAX
RET
ENDP WndCreateMain
[%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=RAX to its handler using macro Dispatch:
MOV RSI,R8
Dispatch EDX, WM_VSCROLL,WM_LBUTTONUP,WM_RBUTTONUP,WM_PAINT,WM_SIZE,WM_MOUSEWHEEL,WM_KEYDOWN,WM_DESTROY
.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:.
; Here are two helper subprocedures for keyboard and scrollbox event handlers:
.GetCtrl2ECX: PROC ; 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.
XOR ECX,ECX
SAL AX,1 ; Shift MSbit to CF.
RCL ECX,1 ; Virtual key handlers receive RCX=1 when Ctrl was pressed, otherwise RCX=0.
RET
ENDP .GetCtrl2ECX:
.GetShift2ECX: PROC ; 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.
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:
.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:
; Handle messages for the main window:
.WM_PAINT:
CALL WndPaintMain
JMP .Ret0:
.WM_SIZE:
CALL WndResizeMain
JMP .Def:
.VK_TAB: ; Tab pressed.
CALL .GetShift2ECX
JRCXZ .WM_LBUTTONUP:
.WM_RBUTTONUP: ; Increase level.
MOV EAX,[Level]
CMP EAX,4
JAE .Ret0:
INC EAX
JMPS .LB:
.WM_LBUTTONUP: ; Decrease level.
MOV EAX,[Level]
TEST EAX
JZ .Ret0:
DEC EAX
.LB:MOV [Level],EAX
CALL WndTitle:
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
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]
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:
.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 .50:
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.
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.
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:
.50:; Level EAX is unchanged.
BufferRetrieve [Level0Buffer::+8*RAX] ; RSI,RCX are LST_INDEX records.
SHR ECX,3 ; SIZE# LST_INDEX = 8
MOV [Lines],ECX
MOV EDI,[TopLine]
CMP EDI,[Lines]
JBE .55:
MOV EDI,[Lines]
.55:MOV [TopLine],EDI
WinABI SetScrollInfo,[hWindowMain],SB_VERT,ScrollInfo,-1
SUB RSI,SIZE# LST_INDEX
XOR EDX,EDX
.60:INC EDX ; Line number 1,2,3,,,Lines.
ADD RSI,SIZE# LST_INDEX
CMP EDX,EDI ; Reached TopLine?
JB .60:
MOV R14D,[Rows] ; Number of rows on screen.
CMP EDX,[Lines] ; Reached the end of lines?
JA .80:
MOV R15D,[AddressDigits::]
ADD R15D,38 ; R15 is the number of gray characters in dump, including address and |.
.65:; Display lines indexed by RSI until EDX>[Lines] (out of lines) or until R14=0 (all rows displayed).
LODSD ; LST_INDEX.FA
LEA RBX,[R12+RAX] ; RBX is pointer to the line in mapped listing.
LODSD ; LST_INDEX.Size
MOV ECX,EAX
MOV EDX,[cxChar]
MUL RDX
MOV R13,RAX ; R13=cxWindow at the start of spaces.
MOV EDI,[Cols] ; Columns in the window.
SUB EDI,ECX ; EDI is the number of spaces after the listing line.
MOV EAX,Color4
CMPD [RBX+1],'####'
JE .70:
MOV EAX,Color3
CMPB [RBX+3],'#'
JE .70
MOV EAX,Color2
CMPW [RBX+1],'##'
JE .70:
MOV EAX,Color1
CMPB [RBX+1],'#'
JE .70:
; Current line is dump line Level0 , 38+AddressDigits chars wide, plus Remark.
PUSH RCX ; Number of characters in this listing line.
WinABI SetBkColor,[hDC],ColorDump ; Level0
WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,R15
WinABI SetBkColor,[hDC],ColorRem
ADD RBX,R15 ; Add the width of the dump column.
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 .75:
WinABI TextOutA,[hDC],RAX,[cyWindow],RBX,RCX ; Print the remark.
JMP .75:
.70:WinABI SetBkColor,[hDC],RAX ; LevelX.
WinABI TextOutA,[hDC],[cxWindow],[cyWindow],RBX,RCX
.75:WinABI TextOutA,[hDC],R13,[cyWindow],Spaces,RDI ; Display EDI spaces on the same line.
MOV EAX,[cyChar]
ADD [cyWindow],EAX
DEC R14
JNZ .65:
.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:
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,7
REP MOVSB
MOV AX,'0'
OR AL,[Level]
STOSW
MOV RCX,RDI
LEA RSI,[NameUTF8]
SUB RCX,RSI
LEA RDI,[NameUTF16]
WinABI MultiByteToWideChar,65001,0,RSI,RCX,RDI,SIZE# NameUTF16 /2
WinABI SetWindowTextW,[hWindowMain],RDI
RET
ENDP WndTitle
.Size, add .Size to .FA, clear .Level and
.Rem in this vairable.
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
ENDPROGRAM viewwing