**EDIT** Revised SetPointer Method - better error handling and correct 64bit filepointer handling

Here is the most recent version of FStream.
Feel free to remove or comment the DEBUG stuff - in fact, do whatever you like with it.. I don't mind how you use this code module.




;This class provides support for general-purpose file IO.


;FStream_Open will fetch the size of existing file to 'internal size'
;FStream_Put will add the size of file write to 'internal size'
;Killing instance closes the file

class FStream, ,C++ compatible
virtual Open:pName ;Opens a new OR existing file for read/write
virtual Put:pData, dwData ;Writes Data of given Size to file
virtual Get:ppData, dwData ;Reads Data of given Size from file
virtual SetName:pName ;Called by FStream_Open
virtual SetPointer:dwLow, dwHigh
virtual ReadLine:pReturnString
long pName
long hFile
long SizeLow
long SizeHigh
endclass

FStream_ReadLine proc pReturnString
local DidRead
local _done
local dwsize
local hfile
local buf[2]:BYTE

mov _done,FALSE
mov dwsize,0
mov edi,pReturnString
m2m hfile,[ecx].FStream.hFile
.repeat
invoke ReadFile,hfile,addr buf,1,addr DidRead,0
.if buf[0]==0
@@:
mov _done,TRUE
.break
.elseif buf[0]==13
.if dwsize==0
mov byte ptr[edi],255
.else
mov byte ptr[edi],0
.endif
inc edi
inc dwsize
invoke ReadFile,hfile,addr buf[1],1,addr DidRead,0
.if buf[1]!=10
invoke SetFilePointer,hfile,-1, NULL, FILE_CURRENT
.endif
jmp @B
.elseif buf[0]==10
jmp @B
.else
mov al,buf[0]
mov byte ptr[edi],al
inc edi
inc dwsize
.endif

.until _done==TRUE
mov byte ptr[edi],0
return dwsize
FStream_ReadLine endp

FStream_SetPointer proc dwLow,dwHigh
invoke SetFilePointer, [ecx].FStream.hFile, dwLow, addr dwHigh, FILE_BEGIN
.if eax==-1
invoke GetLastError
.if eax!=NO_ERROR
if __DEBUG__
LogDWORD CTEXT("<FStream Failed to Set FilePointer - Error %lu"),eax
endif
return FALSE
.endif
.endif
if __DEBUG__
LogDWORD CTEXT("<FStream Set FilePointer to %lu"),dwHigh
LogDWORD CTEXT(", %lu>",13,10),dwLow
endif
return TRUE
FStream_SetPointer endp

FStream_Put proc pData:DWORD, dwData:DWORD
local DidWrite:DWORD
if __DEBUG__
LogDWORD CTEXT("<FStream Put %lu bytes"),dwData
LogDWORD CTEXT(" to %s>",13,10),[ecx].FStream.pName
endif
WriteMore:
push ecx
invoke WriteFile, [ecx].FStream.hFile, pData,dwData, addr DidWrite,0
pop ecx
.if eax!=0
mov eax,DidWrite
sub dwData,eax
add eax,pData
clc
add [ecx].FStream.SizeLow,eax
jnc @F
inc [ecx].FStream.SizeHigh
.else
invoke GetLastError
$Message "Write Error in FStream - %lu",eax
.endif
@@:
.if dwData!=0
jmp WriteMore
.endif
ret
FStream_Put endp

;=====================================================
FStream_Get proc ppData, dwData
local DidRead
local dwTotalRead

if __DEBUG__
LogDWORD CTEXT("<FStream Get %lu bytes"),dwData
LogDWORD CTEXT(" from %s>",13,10),[ecx].FStream.pName
endif

mov dwTotalRead,0

.while dwData!=0
push ecx
invoke ReadFile, [ecx].FStream.hFile, ppData, dwData, addr DidRead,0
pop ecx
.if eax==FALSE
$Message "Error reading from file %s",[ecx].FStream.pName
invoke GetLastError
.if eax==ERROR_HANDLE_EOF
Message "FStream Get EOF"
if __DEBUG__
Log CTEXT("<FStream Get EOF>",13,10)
endif
.else
$Message "ErrorCode=%lu",eax
.endif
.else
.if DidRead==0
if __DEBUG__
Message "FStream Get EOF"
Log CTEXT("<FStream Get EOF>",13,10)
jmp @F
endif
.else
mov eax,DidRead
add dwTotalRead,eax
sub dwData,eax
add ppData,eax
.endif
.endif
.endw
@@:
if __DEBUG__
LogDWORD CTEXT("<FStream Got %lu bytes>",13,10),dwTotalRead
endif
return dwTotalRead
FStream_Get endp

FStream_SetName proc pName
.if [ecx].FStream.pName!=0
free [ecx].FStream.pName
.endif
invoke AllocString, pName
mov [ecx].FStream.pName, eax
ret
FStream_SetName endp

FStream_Open proc pName
local HighSize
local me
mov me,ecx
icall me, FStream, SetName, pName
invoke CreateFile, pName, GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL, OPEN_ALWAYS, 0,0
.if eax!=INVALID_HANDLE_VALUE
mov ecx,me
mov [ecx].FStream.hFile,eax
invoke GetLastError
.if eax==ERROR_ALREADY_EXISTS
if __DEBUG__
LogDWORD CTEXT("<FStream Opened Existing File '%s'.>",13,10),pName
endif
mov ecx,me
invoke GetFileSize, [ecx].FStream.hFile, addr HighSize
mov ecx,me
mov [ecx].FStream.SizeLow,eax
m2m [ecx].FStream.SizeHigh,HighSize
if __DEBUG__
LogDWORD CTEXT("<FStream Opened Existing File of Size %lu",13,10),[ecx].FStream.SizeHigh
LogDWORD CTEXT(", %lu .>",13,10),[ecx].FStream.SizeLow
endif
.else
if __DEBUG__
LogDWORD CTEXT("<FStream Created New File '%s'>",13,10),pName
endif
mov ecx,me
mov [ecx].FStream.SizeLow,0
mov [ecx].FStream.SizeHigh,0
icall ecx, FStream, SetPointer, 0, 0
.endif
icall me, FStream, SetPointer, 0, 0
return S_OK
.else
if __DEBUG__
LogDWORD CTEXT("<FStream_Open Failed for File '%s'>",13,10),pName
endif
.endif
return E_FAIL
FStream_Open endp

FStream_FStream proc
ret
FStream_FStream endp

FStream_$FStream proc
.if [ecx].FStream.pName!=0
free [ecx].FStream.pName
.endif
.if [ecx].FStream.hFile!=0
invoke CloseHandle,[ecx].FStream.hFile
.endif
ret
FStream_$FStream endp


Posted on 2005-02-02 02:17:32 by Homer