I was looking for string parsing code and extracted something from the board that I modified to suit my needs. (what do you call this? a byte scanner? I think so, because it checks every byte for what you want.) Anyway, can anyone make this faster? And if you do, tell me how you did it and what it is doing so I can learn from it? I am not worried about size cause I am converting a VB program and no matter what I do, this code will still be smaller :)

Here is what I have:
I have a file in which I save "config" info into. each line holds a structure of MRUInfo:


MRUInfo STRUCT
DisplayName BYTE 50 dup (?)
MRUPath BYTE MAX_PATH dup (?)
ParseType BYTE 4 dup (?)
SectionName BYTE 20 dup (?)
ValueName BYTE 20 dup (?)
ValueBase BYTE 5 dup (?)
Count BYTE 20 dup (?)
DataType BYTE 4 dup (?)
ExeName BYTE 20 dup (?)
MRUInfo ends


each line looks like:
Wordpad?Microsoft\Windows\CurrentVersion\Applets\Wordpad\Recent File List?0???File?1??????
XML NotePad (Files)?Microsoft\XML Notepad\Recent File List?0???File?1??????
XML NotePad (URL)?Microsoft\XML Notepad\Recent URL List?2???URL?1??????
XMLWriter (Files)?Wattle Software\XMLwriter 1.0\Recent File List?0???File?1??????
XMLWriter (Projects)?Wattle Software\XMLwriter 1.0\Recent Project List?0???project?1??????

the last line above is EOF so it has a NULL char at the end of it.

I am using the following to parse this file into a listview, can we speed or shrink this?


LoadListView proc uses esi ebx edi DataFile:DWORD
LOCAL lvi :LVITEM
LOCAL hFileBuf :DWORD
LOCAL BytesRead :DWORD

push 0 ; Open data file for reading
push FILE_ATTRIBUTE_NORMAL or\ ;
FILE_FLAG_SEQUENTIAL_SCAN ;
push OPEN_EXISTING ;
push 0 ;
push 0 ;
push GENERIC_READ ;
push DataFile ;
call CreateFile ;
test eax, eax ; do we have a handle?
js Finished ; nope

mov esi, eax ; Save handle

push 0 ; Get file size for buffer
push eax ; file handle
call GetFileSize ;
inc eax ;
mov ebx, eax ; save file size
cmp eax, 1 ; is it an empty file?
jne GoodFile ; no, parse it

push esi ; empty file, close it
call CloseHandle ;
jmp Finished ; done here

GoodFile:
; Allocate a temporary buffer for file
push ebx ; file size
push HEAP_ZERO_MEMORY ;
push hHeap ;
call HeapAlloc ;
mov hFileBuf, eax ; save pointer to allocated memory block

; Read whole file into buffer then close file
invoke ReadFile, esi, hFileBuf, ebx, addr BytesRead, NULL

push esi ; File handle
call CloseHandle ; Close it

mov ecx, 0 ; LVITEM index
mov esi, hFileBuf

; Parse file in memory and add info to LVITEM
DisplayName:
push ecx ; save our counter to current LVITEM

push sizeof MRUInfo ; Allocate memory block for LVITEM info
push HEAP_ZERO_MEMORY ;
push hHeap ;
call HeapAlloc ;
mov ebx, eax ; save pointer to memory block
lea edi, [ebx].MRUInfo.DisplayName

pop ecx ; restore our counter
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je MRUPath
mov byte ptr [edi], al
inc edi
jmp @B

MRUPath:
lea edi, [ebx].MRUInfo.MRUPath
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je ParseType
mov byte ptr [edi], al
inc edi
jmp @B

ParseType:
lea edi, [ebx].MRUInfo.ParseType
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je SectionName
mov byte ptr [edi], al
inc edi
jmp @B

SectionName:
lea edi, [ebx].MRUInfo.SectionName
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je ValueName
mov byte ptr [edi], al
inc edi
jmp @B

ValueName:
lea edi, [ebx].MRUInfo.ValueName
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je ValueBase
mov byte ptr [edi], al
inc edi
jmp @B

ValueBase:
lea edi, [ebx].MRUInfo.ValueBase
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je Count
mov byte ptr [edi], al
inc edi
jmp @B

Count:
lea edi, [ebx].MRUInfo.Count
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je DataType
mov byte ptr [edi], al
inc edi
jmp @B

DataType:
lea edi, [ebx].MRUInfo.DataType
@@:
mov al, byte ptr [esi]
inc esi
cmp al, '?'
je ExeName
mov byte ptr [edi], al
inc edi
jmp @B

ExeName:
lea edi, [ebx].MRUInfo.ExeName
@@:
mov al, byte ptr [esi]
inc esi
cmp al, 0DH ; do we have a carrage return?
je NewLine ; yes, add to listview
test al, al ; do we have a null?
jz Done ; yes, we are at last line in file, add to listview and leave
mov byte ptr [edi], al
inc edi
jmp @B

NewLine:
mov lvi.imask, LVIF_PARAM or LVIF_TEXT
mov lvi.iItem, ecx
mov lvi.iSubItem, 0
lea eax, [ebx].MRUInfo.DisplayName
mov lvi.pszText, eax
mov lvi.lParam, ebx

push ecx
invoke SendMessage, hListView2, LVM_INSERTITEM, 0, addr lvi
pop ecx
inc ecx
inc esi
jmp DisplayName

Done:
mov lvi.imask, LVIF_PARAM or LVIF_TEXT
mov lvi.iItem, ecx
mov lvi.iSubItem, 0
lea eax, [ebx].MRUInfo.DisplayName
mov lvi.pszText, eax
mov lvi.lParam, ebx
invoke SendMessage, hListView2, LVM_INSERTITEM, 0, addr lvi

push hFileBuf ; free memory block of file buffer
push 0 ;
push hHeap ;
call HeapFree ;

push LVSCW_AUTOSIZE ; Autosize listview headers
push 0 ;
push LVM_SETCOLUMNWIDTH ;
push hListView2 ;
call SendMessage ;

Finished:
ret
LoadListView endp


Please explain any changes so I am learn from it! :grin:
Posted on 2003-01-09 18:15:27 by Gunner
So you want some optimization? well im defintly not the best optimizer
around(esp. since i still consider myself a newbie). Anyhow, I have tried my
best to optimize it. I removed alot of redundant code and tried to make
it faster. Im not shure its faster? but atleast it's smaller. I hope someone
will tell me if the optimizations I tried to implement were wrong or?

I have tried my best to optimize and make comments. So chew on it and
lettme know if its faster/slower/buggy etc.(all the good things) ( ;) )

I might have forgotten to comment on somethings. Maybe even made
bad comments. ( :tongue: ) Just ask me when youre confuzed ok? :alright:
[color=sienna]...

...
call GetFileSize
; inc eax ;any specific reason for increasing it?
; mov ebx, eax ;moved to "GoodFile:" only needed when file is not empty
; cmp eax, 1 ;this is slightly bigger then TEST
test eax,eax ; is it an empty file?
jne GoodFile ; no, parse it

push esi ; empty file, close it
call CloseHandle ;
jmp Finished ; done here

GoodFile: ; Allocate a temporary buffer for file
mov ebx, eax ; save file size(<--HERE)
push ebx ; file size
push HEAP_ZERO_MEMORY ;
push hHeap ;
call HeapAlloc ;
mov hFileBuf, eax ; save pointer to allocated memory block
; Read whole file into buffer then close file
invoke ReadFile, esi, hFileBuf, ebx, addr BytesRead, NULL
push esi ; File handle
call CloseHandle ; Close it

; mov ecx, 0 ; LVITEM index
xor ecx,ecx ; smaller/faster(+/-)
mov esi, hFileBuf

;I don think that the structure gets changed while looping.
;so instead of defining it each time you loop, we define it
;once here instead.
mov lvi.imask, LVIF_PARAM or LVIF_TEXT
mov lvi.iSubItem, ecx ;ECX = 0 saves a few bytes

DisplayName: ; Parse file in memory and add info to LVITEM
push ecx ; save our counter to current LVITEM

push sizeof MRUInfo ; Allocate memory block for LVITEM info
push HEAP_ZERO_MEMORY ;
push hHeap ;
call HeapAlloc ;

pop ecx ; restore our counter
mov ebx, eax ; save pointer to memory block

;What is this little toy? this is just something I
;cooked up. Dont know if its the best solution,
;but it saves alot of code. This is a compare table
;(if we need to name it). We save all of the pointers
;on stack! so that we can use them later when we parse the
;lines from the file. The "-1" is used to determine when we
;have reached the end of the table.
lea edi, [ebx].MRUInfo.ExeName
push edi
push -1
sub edi,4h ;lea edi, [ebx].MRUInfo.DataType
push edi
sub edi,14h ;lea edi, [ebx].MRUInfo.Count
push edi
sub edi,5h ;lea edi, [ebx].MRUInfo.ValueBase
push edi
sub edi,14h ;lea edi, [ebx].MRUInfo.ValueName
push edi
sub edi,14h ;lea edi, [ebx].MRUInfo.SectionName
push edi
sub edi,4h ;lea edi, [ebx].MRUInfo.ParseType
push edi
sub edi,104h;lea edi, [ebx].MRUInfo.MRUPath
push edi
sub edi,32h ;lea edi, [ebx].MRUInfo.DisplayName
push edi

_:pop edi ;restore pointer
inc edi ;check for -1
je ExeName ;end of table
dec edi ;restore edi
@@:lodsb ;lodsb is smaller/faster then mov/inc esi
cmp al, '?'
je short _
stosb ;stosb is smaller/faster then mov/inc edi
jmp short @B

ExeName:
pop edi
@@: lodsb
cmp al, 0dh ; do we have a carrage return?
je NewLine ; yes, add to listview
test al, al ; do we have a null?
jz NewLine ; yes, we are at last line in file, add to listview and leave
stosb
jmp short @B

NewLine:
push eax
lea eax, [ebx].MRUInfo.DisplayName
mov lvi.pszText, eax
mov lvi.iItem, ecx
mov lvi.lParam, ebx

push ecx
invoke SendMessage, hListView2, LVM_INSERTITEM, 0, addr lvi
pop ecx
pop eax
inc ecx
inc esi
test al,al
jne short DisplayName

Done:
push hFileBuf ; free memory block of file buffer
push 0 ;
push hHeap ;
call HeapFree ;
...
...[/color]
Posted on 2003-01-10 08:36:36 by natas
Hmmm, thanks natas.... I will look this over and try this out.
Thanks!
Posted on 2003-01-10 16:51:08 by Gunner
Since I got bored with my current project. I decided to really go through
the code. I removed some unneded code and did some rethinkinking here
and there( ;) ).

I tested this code with the original code and the results was pretty
much the same. However, this is much smaller in code size. You wont
see alot of comments from me in this source tho. I usually dont comment
that much. Especially since I changed alot it wouldnt do any good using
comments anyway.

But just point out the code you dont understand and ill try my best to
explain. :alright:
[color=sienna]LoadListView proc uses esi ebx edi DataFile:DWORD

LOCAL lvi :LVITEM
LOCAL hFileBuf :DWORD
LOCAL BytesRead :DWORD
[color=green];The register ebx is preserved all the way. So its much better
;to use it for our counting purposes. EQU's are just good for readability.[/color]
xor ebx,ebx ; LVITEM index
ZERO$ equ ebx

push ZERO$ ; Open data file for reading
push FILE_ATTRIBUTE_NORMAL or\ ;
FILE_FLAG_SEQUENTIAL_SCAN
push OPEN_EXISTING ;
push ZERO$ ;
push ZERO$ ;
push GENERIC_READ ;
push DataFile ;
call CreateFile ;
test eax, eax ; do we have a handle?
js Finished ; nope

mov esi, eax ; Save handle

push ZERO$ ; Get file size for buffer
push eax ; file handle
call GetFileSize ;
test eax,eax ; is it an empty file?
jne GoodFile ; no, parse it

push esi ; empty file, close it
call CloseHandle ;
jmp Finished ; done here

GoodFile: ; Allocate a temporary buffer for file
mov edi, eax ; save file size(<--HERE)
push edi ; file size
push HEAP_ZERO_MEMORY ;
push hHeap ;
call HeapAlloc ;
mov hFileBuf, eax ; save pointer to allocated memory block
; Read whole file into buffer then close file
invoke ReadFile, esi, hFileBuf, edi, addr BytesRead, NULL
push esi ; File handle
call CloseHandle ; Close it

mov esi, hFileBuf

mov lvi.imask, LVIF_PARAM or LVIF_TEXT
mov lvi.iSubItem, ZERO$

DisplayName:
CMPTABLE$ equ edx
LVINDEX$ equ ebx
MEMBUF$ equ ecx
FILEBUF$ equ esi
; Parse file in memory and add info to LVITEM
push sizeof MRUInfo ; Allocate memory block for LVITEM info
push HEAP_ZERO_MEMORY ;
push hHeap ;
call HeapAlloc ;
mov MEMBUF$, eax ; save pointer to memory block

;[color=green]This is just a little comparison table. Maybe you think I made some
;calculations because of the numbers? There was no calculation whatsoever.
;These values are taken from the structure were dealing with.
;DisplayName BYTE 50 = 32h
;MRUPath BYTE MAX_PATH = 104h
;ParseType BYTE 4 =4h
;SectionName BYTE 20 =14h
;ValueName BYTE 20 = 14h
;ValueBase BYTE 5 =5h
;Count BYTE 20 =14h
;DataType BYTE 4 = 4h
;ExeName BYTE 20 =14h
;This table is used to increase the pointer starting from "DisplayName".
;So that we fill each item in the structure correct. When you define a variable
;and call a label like below. The variable gets pushed onto the stack.
;Thats why we pop it in EDX right after.[/color]
call _cmp_table
dd 0,32h,104h,4h,14h,14h,5h,14h,-1
_cmp_table:pop edx

lea edi, [MEMBUF$].MRUInfo.DisplayName
push MEMBUF$

;[color=green] This is the place we get our values from CS:[CMPTABLE$].
;We are checking for -1 wich defines the end of the variable above.
;The ADD CMPTABLE$,4 increases the table by 4(DWORD). The other
;stuff should be pretty basic. If you wonder why I dont use stosb, its
;because I cant increase the EDI! otherwise the table wont work.[/color]
_:cmp dword ptr cs:[CMPTABLE$],-1
je ExeName
add edi,cs:[CMPTABLE$]
add CMPTABLE$,4
xor ecx,ecx
@@: lodsb
cmp al,'?'
je short _
mov byte ptr [edi+ecx], al
inc ecx
jmp short @B

ExeName:
pop ecx
add edi,4h ; MRUInfo.ExeName
@@: lodsb
cmp al, 0Dh ; do we have a carrage return?
je NewLine ; yes, add to listview
test al, al ; do we have a null?
jz NewLine ; yes, we are at last line in file, add to listview and leave
stosb
jmp short @B

NewLine:
lea edx, [MEMBUF$].MRUInfo.DisplayName
mov lvi.pszText, edx
mov lvi.iItem, LVINDEX$
mov lvi.lParam, MEMBUF$
push eax
invoke SendMessage, hListView2, LVM_INSERTITEM, 0, addr lvi
pop eax
inc LVINDEX$
inc FILEBUF$
test al,al
jne DisplayName

Done:
push hFileBuf ; free memory block of file buffer
push 0 ;
push hHeap ;
call HeapFree ;

push LVSCW_AUTOSIZE ; Autosize listview headers
push 0 ;
push LVM_SETCOLUMNWIDTH ;
push hListView2 ;
call SendMessage ;

Finished:
ret
LoadListView endp[/color]


EDIT: Added some comments! Is there still something you dont
understand? Then dont hesitate to pop the question! :alright:
Posted on 2003-01-11 00:53:35 by natas