This library contains wrapper macros which encapsulate WinAPI calls for most typical file operations in 64bit Windows . See also equivalent homonymous macroinstructions in winf32.htm, linf32.htm, linf64.htm.
| File Access method | Open | Data transfer | Close |
|---|---|---|---|
| read file at once | - | FileLoad | FileClose |
| write file at once | - | FileStore | - |
| standard read | FileOpen | FileRead | FileClose |
| standard write | FileCreate | FileWrite, FileWriteLn, FileWrite$ | FileClose |
| standard write at the end of file | FileAppend | FileWrite, FileWriteLn, FileWrite$ | FileClose |
| memory mapped read | FileMapOpen | - | FileClose |
| memory mapped write | FileMapCreate | - | FileClose |
| buffered read | FileStreamOpen | FileStreamReadByte, FileStreamRead, FileStreamReadLn | FileClose |
| buffered write | FileStreamCreate | FileStreamWriteByte, FileStreamWriteWord, FileStreamWriteDword, FileStreamWrite, FileStreamWriteLn, FileStreamWrite$ | FileClose |
| buffered write at end of file | FileStreamAppend | FileStreamWriteByte, FileStreamWriteWord, FileStreamWriteDword, FileStreamWrite, FileStreamWriteLn, FileStreamWrite$ | FileClose |
| append to file | - | FileEnclose, FileEncloseLn, FileEnclose$ | - |
| special functions | FileReset | FileAssign, FileExists?, FileNameParse, FileMove, FileMkDir, FileEach | FileDelete |
Macros return the results in registers, usually RAX. Other registers do not change. CF is set when error occurs, ZF is set at the end of file, DF must be always reset. Other flags are undefined.
Association of the FILE64 object with the name of file is provided separately, using the macro FileAssign. File must be assigned before opening.
Macro names suffixed with ~Ln write CR+LF characters after the data. Macro names suffixed with ~$ expect NULL-terminated input data.
Acces methods at once, stream, memory-map allocate dynamic virtual memory. It will be freed in FileClose.
| Access method | Virtual memory | |
|---|---|---|
| reserved | comitted | |
| At once load | filesize | filesize |
| At once store | none | none |
| Standard | none | none |
| MemoryMapped | filesize | pagesize |
| Streamed | buffersize | buffersize |
File access method at once loads entire file content into comitted memory, so it is suitable for small files only. The loaded/stored file doesn't need explicit opening nor closing.
This access method is equivalent to PHP functions file_get_contents, file_put_contents.
Access method enclose opens the file at its end for writing, appends the data and closes file in one operation.
Standard read/write methods only encapsulate API functions read/write and they can process files of any size. Example:
Memory mapped file access reserves memory for the entire file contents virtually loaded to memory.
Streamed (buffered) file access method allocates its own memory buffer to accelerate reading/writing of small pieces of data. This method is also suitable for processing text files line by line. Example:
Common limitations: This library cannot be used if special requirements are required, such as overlapped file access, other than normal file attributes, nonstandard share disposition, files bigger than 2 GB, filename longer than 260 characters.
Runtime procedures defined in this library use macros WinABI, Dispatch, status32.htm.
winf64 HEAD INCLUDEHEAD1 winsfile.htm, wins.htm, winabi.htm, winscon.htm, status32.htm, cpuext.htm
FILE64 STRUC .Ptr DQ Q ; Pointer to the file content in memory-mapped|buffered data. .Top DQ Q ; Pointer to the end of the memory-mapped|buffered data. .BufPtr DQ Q ; Pointer to the memory-map|allocated buffer. .BufSize DQ Q ; Size of memory map|buffer. .Pos DQ Q ; Zero based offset of the file position. .Size DQ Q ; File size in bytes. .Handle DQ Q ; Handle to the opened file. .MapHandle DQ Q ; Handle to the file mapping. .Status DD D ; File status flags, see FileStatusEnc. .NameOffs DD D ; Offset of the filename without path inside the .Name. Zero if no path in .Name. .ExtOffs DD D ; Offset of the file extension inside the .Name. .Name D MAX_PATH_SIZE * U ; Zero terminated WIDE|ANSI file name. ENDSTRUC FILE64
FILE64.Status.fi64StFound EQU 0x00000010 ; File was once succesfully opened. fi64StAppend EQU 0x00100000 ; Created file should move its pointer to the end. fi64StStdIO EQU 0x00200000 ; FILE64.Handle is standard input|output. fi64StAllocated EQU 0x00400000 ; FILE64.BufPtr is pointer to the allocated memory. fi64StUnicode EQU 0x00800000 ; FILE64.Name is in WIDE characters. fi64StMapCreated EQU 0x01000000 ; FILE64.MapHandle is valid for writing. fi64StMapOpened EQU 0x02000000 ; FILE64.MapHandle is valid for reading. fi64StMapped EQU 0x04000000 ; FILE64.Ptr is pointer to the mapped memory. fi64StCreated EQU 0x10000000 ; FILE64.Handle is valid for writing. fi64StOpened EQU 0x20000000 ; FILE64.Handle is valid for reading.
%^UNICODE at macro invocation
but you may want to set this parameter to 0 even if %UNICODE is enabled and vice versa.
FileNameParse %MACRO FileNamePtr,Size=-1, Unicode=%^UNICODE
PUSHQ %Size,%FileNamePtr
%IF %Unicode
CALL FileNameParseW64@RT::
FileNameParseW64@RT:: PROC1
PUSH RAX,RCX,RDX,RSI
MOV RSI,[RSP+40] ; %FileNamePtr.
MOV RDX,[RSP+48] ; %Size.
SUB RCX,RCX
TEST RDX
JS .UnlimitedSize:
ADD RDX,RSI ; End of input string.
.UnlimitedSize:
MOV [RSP+24],RCX ; Returned RAX.
MOV [RSP+16],RCX ; Returned RCX.
MOV [RSP+08],RCX ; Returned RDX.
.NextChar:
CMP RSI,RDX
JNB .E0:
LODSW
Dispatch AX,58,92,47,46,0 ; colon, backslash, slash, dot, NULL
; Ordinary character.
LEA RAX,[RSI-2]
CMP [RSP+24],RCX ; ReturnedRAX.
JNZ .NextChar:
MOV [RSP+24],RAX ; ReturnedRAX.
JMP .NextChar:
.46: ; dot .
LEA RAX,[RSI-2]
MOV [RSP+16],RAX ; ReturnedRCX.
CMP [RSP+24],RCX ; ReturnedRAX.
JNE .NextChar:
MOV [RSP+24],RAX ; ReturnedRAX.
JMP .NextChar:
.47: ; Colon, slash, backslash.
.58:
.92: MOV [RSP+24],RSI ; ReturnedRAX.
MOV [RSP+16],RCX ; ReturnedRCX.
JMP .NextChar:
.0: DEC RSI,RSI ; Unichar NULL.
.E0:MOV [RSP+08],RSI ; ReturnedRDX.
CMP [RSP+16],RCX ; ReturnedRCX.
JNE .E1:
MOV [RSP+16],RSI ; ReturnedRCX.
.E1:CMP [RSP+24],RCX ; ReturnedRAX.
JNE .E2:
MOV RAX,[RSP+16] ; ReturnedRCX.
MOV [RSP+24],RAX ; ReturnedRAX.
.E2:POP RSI,RDX,RCX,RAX
RET 2*8
ENDPROC1 FileNameParseW64@RT::
%ELSE ; ANSI variant.
CALL FileNameParseA64@RT::
FileNameParseA64@RT:: PROC1
PUSH RAX,RCX,RDX,RSI
MOV RSI,[RSP+40] ; %FileNamePtr.
MOV RDX,[RSP+48] ; %Size.
SUB RCX,RCX
TEST RDX
JS .UnlimitedSize:
ADD RDX,RSI ; End of input string.
.UnlimitedSize:
MOV [RSP+24],RCX
MOV [RSP+16],RCX
MOV [RSP+08],RCX
.NextChar:
CMP RSI,RDX
JNB .E0:
LODSB
Dispatch AL,58,92,47,46,0 ; colon, backslash, slash, dot, NULL.
; Ordinary character.
LEA RAX,[RSI-1]
CMP [RSP+24],RCX
JNZ .NextChar:
MOV [RSP+24],RAX
JMP .NextChar:
.46: ; dot .
LEA RAX,[RSI-1]
MOV [RSP+16],RAX
CMP [RSP+24],RCX
JNE .NextChar:
MOV [RSP+24],RAX
JMP .NextChar:
.47: ; colon, slash, backslash
.58:
.92: MOV [RSP+24],RSI
MOV [RSP+16],RCX
JMP .NextChar:
.0: DEC RSI ; Byte NULL.
.E0:MOV [RSP+08],RSI
CMP [RSP+16],RCX
JNE .E1:
MOV [RSP+16],RSI
.E1:CMP [RSP+24],RCX
JNE .E2:
MOV RAX,[RSP+16]
MOV [RSP+24],RAX
.E2:POP RSI,RDX,RCX,RAX
RET 2*8
ENDPROC1 FileNameParseA64@RT::
%ENDIF ; %Unicode
%ENDMACRO FileNameParse
theFile.Name member.
EUROASM UNICODE=
option at macro invocation,
but you may want to set this parameter to OFF even if UNICODE is globally enabled, and vice versa..Name, .NameOffs, .ExtOffs, .Status:fi64StUnicode of theFile are set.SIZE# FILE64.Name, i.e. MAX_PATH_SIZE=260 characters.
FileAssign %MACRO theFile,Name$1,Name$2,,, Size=-1, Unicode=%^UNICODE
%IF %#<2 ; >
%ERROR ID=5941, 'File name missing in macro "FileAssign".'
%EXITMACRO FileAssign
%ENDIF
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-1
PUSHQ %*{%ArgNr}
%ENDFOR ArgNr
PUSHQ %Size, %theFile, RSP
ADDQ [RSP],8*(%#+2)
%IF %Unicode
CALL FileAssignW64@RT::
FileAssignW64@RT:: PROC1 ; Wide variant.
PUSH RAX,RCX,RDX,RBX,RBP,RSI,RDI
MOV RBX,[RSP+72] ; %theFile
LEA RBP,[RSP+88] ; %Name$1
LEA RDI,[RBX+FILE64.Name]
SetSt [RBX+FILE64.Status],fi64StUnicode
LEA RDX,[RDI+MAX_PATH_SIZE-2]
.10:XCHG RBP,RSI
LODSQ ; Offset of source string.
MOV RBP,RAX
XCHG RSI,RBP
TEST RAX ; No more macro arguments (zero marker)?
JZ .50:
MOV RCX,[RSP+80] ; %Size.
SAR RCX,1 ; Convert the size from bytes to unichars.
JZ .10:
.20:LODSW
CMP AX,0
JE .10:
CMP RDI,RDX
JNB .40:
STOSW
LOOP .20:
JMP .10:
.40:SUB EAX,EAX
STC ; Overflow.
.50:MOV RCX,RDI
STOSW
LEA RDX,[RBX+FILE64.Name]
PUSHFQ ; Keep the overflow flag.
SUB RCX,RDX
FileNameParse RDX,Size=RCX,Unicode=1
LEA RDX,[RBX+FILE64.Name]
SUB RAX,RDX
SUB RCX,RDX
MOV [RBX+FILE64.NameOffs],EAX
MOV [RBX+FILE64.ExtOffs],ECX
POPFQ
POP RDI,RSI,RBP,RBX,RDX,RCX,RAX
RET
ENDPROC1 FileAssignW64@RT::
%ELSE ; ANSI.
CALL FileAssignA64@RT::
FileAssignA64@RT:: PROC1 ; ANSI variant.
PUSH RAX,RCX,RDX,RBX,RBP,RSI,RDI
MOV RBX,[RSP+72] ; %theFile
LEA RBP,[RSP+88] ; %Name$1
LEA RDI,[RBX+FILE64.Name]
RstSt [RBX+FILE64.Status],fi64StUnicode
LEA RDX,[RDI+MAX_PATH_SIZE]
.10:XCHG RBP,RSI
LODSQ ; Offset of source string.
MOV RBP,RAX
XCHG RSI,RBP
TEST RAX
JZ .50:
MOV RCX,[RSP+80] ; %Size.
JRCXZ .10:
.20:LODSB
CMP AL,0
JE .10:
CMP RDI,RDX
JNB .40:
STOSB
LOOP .20:
JMP .10:
.40:SUB EAX,EAX
STC ; Overflow.
.50:MOV RCX,RDI
STOSB
LEA RDX,[RBX+FILE64.Name]
PUSHFQ
SUB RCX,RDX
FileNameParse RDX,Size=RCX,Unicode=0
LEA RDX,[RBX+FILE64.Name]
SUB RAX,RDX
SUB RCX,RDX
MOV [RBX+FILE64.NameOffs],EAX
MOV [RBX+FILE64.ExtOffs],ECX
POPFQ
POP RDI,RSI,RBP,RBX,RDX,RCX,RAX
RET
ENDPROC1 FileAssignA64@RT::
%ENDIF
POP RSP
%ENDMACRO FileAssign
* ? are allowed in the file name.
FileExists? %MACRO theFile
PUSHQ %theFile
CALL FileExists?64@RT::
FileExists?64@RT:: PROC1
IMPORT FindFirstFileA,FindFirstFileW
PUSH RAX,RBX,RSI,RDI
MOV RBX,[RSP+40] ; theFile
LEA RSI,[RBX+FILE64.Name]
SUB RSP,SIZE# WIN32_FIND_DATAW
MOV RDI,RSP
LEA RAX,[FindFirstFileW::] ; WinABI function thunk.
JSt [RBX+FILE64.Status],fi64StUnicode,.20
LEA RAX,[FindFirstFileA::] ; WinABI function thunk.
.20:WinABI RAX,RSI,RDI, Fastmode=No ; FindFirstFile.
.30:CMP RAX,INVALID_HANDLE_VALUE
STC
JE .90
WinABI FindClose,RAX,Fastmode=No
TEST [RDI+WIN32_FIND_DATAW.FileAttributes],FILE_ATTRIBUTE_DIRECTORY
.90:LEA RSP,[RSP+SIZE# WIN32_FIND_DATAW]
POP RDI,RSI,RBX,RAX
RET 1*8
ENDPROC1 FileExists?64@RT::
%ENDMACRO FileExists?
FileMkDir %MACRO theFile
PUSHQ %theFile
CALL FileMkDir64@RT::
FileMkDir64@RT:: PROC1
PUSH RCX,RDX,RBX,RBP,RSI,RDI
MOV RBP,RSP
MOV RBX,[RBP+56] ; RBX=Pointer to %theFile structure FILE64.
SUB RSP,SIZE#WIN32_FIND_DATAW
MOV RDX,RSP ; RDX=Local FindData structure.
SUB RSP,2* MAX_PATH_SIZE
MOV RDI,RSP ; RSP=LocalVar for the copy of directory name.
LEA RSI,[RBX+FILE64.Name]
MOV CX,'\'
MOVW [RSI+SIZE#FILE64.Name-2],0 ; Zero terminate MAX_PATH_SIZE for safety.
JSt [RBX+FILE64.Status],fi64StUnicode,.50:
; ANSI variant.
LODSB
CMP AL,0
JE .Done:
CMP AL,CL
JNE .30:
CMP [RSI],CL ; Test the case "\\server\share\dir\file".
JNE .30:
STOSB
LODSB
.10:STOSB
LODSB
CMP AL,0
JE .Done:
CMP AL,CL
JNE .10:
.20:STOSB
LODSB
CMP AL,0
JE .Done:
CMP AL,CL
JNE .20:
.30:STOSB
LODSB
CMP AL,0
JE .Done:
CMP AL,CL
JNE .30:
CMPB [RDI-1],':' ; Test the case "D:\dir\file".
JE .30:
SUB EAX,EAX
STOSB ; Temporary terminate folder name.
MOV RAX,RSP ; Local copy of directory name.
WinABI FindFirstFileA,RAX,RDX,Fastmode=No
CMP RAX,INVALID_HANDLE_VALUE
JE .35:
WinABI FindClose,RAX,Fastmode=No
JSt [RDX+WIN32_FIND_DATAA.FileAttributes],FILE_ATTRIBUTE_DIRECTORY,.40:
.35:MOV RAX,RSP ; Local copy of directory name.
WinABI CreateDirectoryA,RAX,0,Fastmode=No
TEST RAX
JZ .Error:
.40:DEC RDI ; Remove temporary zero-terminator.
MOV EAX,ECX
JMP .30:
.50: ; WIDE variant.
LODSW
CMP AX,0
JE .Done:
CMP AX,CX
JNE .80:
CMP [RSI],CX ; Test the case "\\server\share\dir\file".
JNE .80:
STOSW
LODSW
.60:STOSW
LODSW
CMP AX,0
JE .Done:
CMP AX,CX
JNE .60:
.70:STOSW
LODSW
CMP AX,0
JE .Done:
CMP AX,CX
JNE .70:
.80:STOSW
LODSW
CMP AX,0
JE .Done:
CMP AX,CX
JNE .80:
CMPW [EDI-2],':' ; Test the case "D:\dir\file".
JE .80:
SUB EAX,EAX
STOSW ; Temporary terminate folder name.
MOV RAX,RSP ; Local copy of directory name.
WinABI FindFirstFileW,RAX,RDX,Fastmode=No
CMP RAX,INVALID_HANDLE_VALUE
JE .85:
WinABI FindClose,RAX,Fastmode=No
JSt [RDX+WIN32_FIND_DATAW.FileAttributes],FILE_ATTRIBUTE_DIRECTORY,.90:
.85:MOV RAX,RSP ; Local copy of directory name.
WinABI CreateDirectoryW,RAX,0,Fastmode=No
TEST RAX
JNZ .90:
.Error:WinABI GetLastError,Fastmode=No
STC
JMP .Ret:
.90:DEC RDI,RDI ; Remove temporary zero-terminator.
MOV EAX,ECX
JMP .80:
.Done:SUB EAX,EAX
.Ret:MOV RSP,RBP
POP RDI,RSI,RBP,RBX,RDX,RCX
RET 1*8
ENDPROC1 FileMkDir64@RT::
%ENDMACRO FileMkDir
FileFlush %MACRO theFile
; OUT: CF=1 EAX=error CF=0 EAX=unchanged
PUSHQ %theFile
CALL FileFlush64@RT::
FileFlush64@RT:: PROC1
PUSH RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+48] ; theFile.
MOV RAX,0xE0070004 ; File is not opened.
JNSt [RBX+FILE64.Status],fi64StAllocated,.ErrorRAX:
JNSt [RBX+FILE64.Status],fi64StCreated, .ErrorRAX:
MOV RDI,[RBX+FILE64.Ptr]
MOV RSI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RSI
SUB RDI,RSI
PUSH RDX
MOV RDX,RSP
WinABI WriteFile,[RBX+FILE64.Handle],RSI,RDI,RDX,0,Fastmode=No
POP RDX ; Written size.
TEST RAX
JZ .EndWithLastError:
XOR EAX,EAX
CMP RDI,RDX
JE .Ret:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
.Ret:POP RDI,RSI,RBX,RDX,RCX
RET 1*8
ENDPROC1 FileFlush64@RT::
%ENDMACRO FileFlush
FileClose %MACRO theFile1
ArgNr %FOR 1..%#
PUSHQ %*{%ArgNr}
CALL FileClose64@RT::
%ENDFOR ArgNr
FileClose64@RT:: PROC1
PUSH RBX,RSI,RDI
MOV RBX,[ESP+32] ; theFile
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
JNSt [RBX+FILE64.Status],fi64StAllocated,.10:
FileFlush RBX
WinABI GlobalFree,[RBX+FILE64.BufPtr],Fastmode=No
RstSt [RBX+FILE64.Status],fi64StAllocated
.10: MOV [RBX+FILE64.BufPtr],RSI
MOV [RBX+FILE64.BufSize],RSI
JNSt [RBX+FILE64.Status],fi64StMapped,.20:
WinABI UnmapViewOfFile,[RBX+FILE64.Ptr],Fastmode=No
RstSt [RBX+FILE64.Status],fi64StMapped
.20: MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
JNSt [RBX+FILE64.Status],fi64StMapOpened|fi64StMapCreated,.30:
WinABI CloseHandle,[RBX+FILE64.MapHandle],Fastmode=No
.30: RstSt [RBX+FILE64.Status],fi64StMapOpened|fi64StMapCreated
MOV [RBX+FILE64.MapHandle],RDI
JNSt [RBX+FILE64.Status],fi64StOpened|fi64StCreated,.40:
JSt [RBX+FILE64.Status],fi64StStdIO,.40
WinABI CloseHandle,[RBX+FILE64.Handle],Fastmode=No
.40: MOV [RBX+FILE64.Handle],RDI
MOV ESI,fi64StFound+fi64StStdIO+fi64StUnicode
AND ESI,[RBX+FILE64.Status]
MOV [RBX+FILE64.Status],ESI
POP RDI,RSI,RBX
RET 1*8
ENDPROC1 FileClose64@RT::
%ENDMACRO FileClose
FileMove %MACRO SourceFile, DestinationFile
PUSHQ %DestinationFile, %SourceFile
CALL FileMove64@RT::
FileMove64@RT:: PROC1
IMPORT MoveFileExA,MoveFileExW
PUSH RDX,RBX,RSI,RDI
MOV RSI,[RSP+40] ; SourceFile
MOV RDI,[RSP+48] ; DestinationFile
MOV EAX,[RSI+FILE64.Status]
MOV EDX,[RDI+FILE64.Status]
MOV EBX,fi64StUnicode
AND EAX,EBX
AND EDX,EBX
CMP EAX,EDX
MOV RAX,0xC008007B ; Error 123: invalid filename.
JNE .ErrorRAX: ; Different width of strings.
FileClose RSI,RDI
FileMkDir RDI
JC .ErrorRAX:
LEA RSI,[RSI+FILE64.Name]
LEA RDI,[RDI+FILE64.Name]
LEA RAX,[MoveFileExW]
JSt EDX,fi64StUnicode,.30:
LEA RAX,[MoveFileExA]
.30: WinABI RAX,RSI,RDI,MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED,Fastmode=No
TEST RAX
MOV EAX,0
JNZ .Ret:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
.Ret:POP RDI,RSI,RBX,RDX
RET 2*8
ENDPROC1 FileMove64@RT::
%ENDMACRO FileMove
FileDelete %MACRO theFile1
ArgNr %FOR 1..%#
PUSHQ %*{%ArgNr}
CALL FileDelete64@RT::
%ENDFOR ArgNr
FileDelete64@RT:: PROC1
IMPORT DeleteFileA,DeleteFileW
PUSH RBX,RSI
MOV RBX,[RSP+24] ; theFile.
FileClose RBX
LEA RSI,[RBX+FILE64.Name]
LEA RAX,[DeleteFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.30:
LEA RAX,[DeleteFileA]
.30: WinABI RAX,RSI,Fastmode=No
TEST RAX
JNZ .OK:
WinABI GetLastError,Fastmode=No
CMP EAX,2 ; ERROR_FILE_NOT_FOUND
JE .OK:
CMP EAX,3 ; ERROR_PATH_NOT_FOUND
JE .OK:
STC
JMPS .90:
.OK: XOR EAX,EAX
.90: POP RSI,RBX
RET 1*8
ENDPROC1 FileDelete64@RT::
%ENDMACRO FileDelete
FILE64.Name is replaced
with the file found in directory. The file is not open.
WinABI FindClose,RDX before terminating.
FileEach %MACRO theFile, CallbackProc
LEA RAX,[%CallbackProc]
PUSH RAX
LEA RAX,[%theFile]
PUSH RAX
CALL FileEach64@RT::
FileEach64@RT: PROC1
IMPORT FindFirstFileA,FindFirstFileW,FindNextFileA,FindNextFileW
PUSHQ 0,RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+56] ; RBX=theFile.
SUB RSP,SIZE# WIN32_FIND_DATAW
MOV RDI,RSP ; RDI=Local WIN32_FIND_DATA structure.
LEA RSI,[RBX+FILE64.Name]
LEA RAX,[FindFirstFileW]
JSt [RBX+FILE64.Status],fi64StUnicode, .10:
LEA RAX,[FindFirstFileA]
.10: WinABI RAX,RSI,RDI,Fastmode=No
MOV RDX,RAX ; RDX=FindHandle.
CMP RAX,INVALID_HANDLE_VALUE
JE .90:
.20: ; Copy resolved name to theFile.
LEA RSI,[RDI+WIN32_FIND_DATAW.FileName] ; Identical for WIN32_FIND_DATAA.FileName.
LEA RDI,[RBX+FILE64.Name]
MOVZXD RAX,[RBX+FILE64.NameOffs]; Path size.
ADD RDI,RAX ; RDI=^wildcarded mask without path.
LEA RCX,[RBX+FILE64.Name + SIZE# FILE64.Name]
SUB RCX,RDI
REP MOVSB ; Copy resolved name to FILE64.
; Prepare GPRs for CallbackProc.
LEA RSI,[RBX+FILE64.Name]
ADD RSI,RAX ; RSI=^resolved name without path.
MOV RDI,RSP ; RDI=Local WIN32_FIND_DATA structure.
MOV RAX,[RSP+64+SIZE#WIN32_FIND_DATAW] ; RAX=^CallbackProc.
PUSH RDX,RBX
CALL RAX ; Perform the callback with resolved FILE64.
POP RBX,RDX
MOV [RSP+40+SIZE#WIN32_FIND_DATAW],RAX ; Value returned from CallbackProc.
JC .90: ; Abort next files if CallbackProc returned CF.
MOV RDI,RSP
LEA RAX,[FindNextFileW]
JSt [RBX+FILE64.Status],fi64StUnicode, .80:
LEA RAX,[FindNextFileA]
.80: WinABI RAX,RDX,RDI,Fastmode=No
TEST RAX
JNZ .20: ; The next file.
.90: WinABI FindClose,RDX,Fastmode=No
ADD RSP,SIZE# WIN32_FIND_DATAW
POP RDI,RSI,RBX,RDX,RCX,RAX
RET 2*8
ENDPROC1 FileEach64@RT:
%ENDMACRO FileEach
FileLoad %MACRO theFile
PUSHQ %theFile
CALL FileLoad64@RT::
FileLoad64@RT:: PROC1
IMPORT CreateFileA,CreateFileW
PUSH RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+48] ; %theFile.
LEA RDX,[RBX+FILE64.Name]
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
MOV [RBX+FILE64.BufPtr],RSI
MOV [RBX+FILE64.BufSize],RSI
MOV [RBX+FILE64.Pos],RSI
MOV [RBX+FILE64.Size],RSI
LEA RAX,[CreateFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.10:
LEA RAX,[CreateFileA]
.10:WinABI RAX,RDX,GENERIC_READ,FILE_SHARE_READ,RSI, \
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,RSI,Fastmode=No
MOV [RBX+FILE64.Handle],RAX
CMP RAX,RDI
JE .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StOpened
WinABI GetFileSize,RAX,RSI,Fastmode=No
CMP RAX,RDI
JE .EndWithLastError:
MOV [RBX+FILE64.Size],RAX
MOV [RBX+FILE64.Top],RAX
MOV [RBX+FILE64.BufSize],RAX
WinABI GlobalAlloc,GMEM_FIXED,RAX,Fastmode=No
MOV [RBX+FILE64.Ptr],RAX
ADD [RBX+FILE64.Top],RAX
MOV [RBX+FILE64.BufPtr],RAX
TEST RAX
JZ .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StAllocated
MOV [RSP+8],RAX ; ReturnRSI.
PUSH RCX
MOV RCX,RSP
WinABI ReadFile,[RBX+FILE64.Handle],RAX,[RBX+FILE64.Size],RCX,0,Fastmode=No
POP RCX
ADD [RBX+FILE64.Pos],RCX
TEST RAX
JZ .EndWithLastError:
MOV RAX,[RBX+FILE64.Size]
CMP RAX,RCX
JE .EndWithRAX
MOV EAX,0xE0070026
JMP .ErrorEAX
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorEAX: STC
.EndWithRAX:
PUSH RAX
PUSHFD
JNSt [RBX+FILE64.Status],fi64StOpened,.90:
WinABI CloseHandle,[RBX+FILE64.Handle],Fastmode=No
.90: RstSt [RBX+FILE64.Status],fi64StOpened
MOV [RBX+FILE64.Handle],RDI
POPFD
POP RAX
POP RDI,RSI,RBX,RDX,RCX
RET 1*8
ENDPROC1 FileLoad64@RT::
%ENDMACRO FileLoad
FileStore %MACRO theFile,DataPtr,DataSize
PUSHQ %DataSize,%DataPtr,%theFile
CALL FileStore64@RT::
FileStore64@RT:: PROC1
IMPORT CreateFileA,CreateFileW
PUSH RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+48] ; theFile.
MOV RAX,[RSP+56] ; DataPtr.
MOV RCX,[RSP+64] ; DataSize.
MOV [RBX+FILE64.Ptr],RAX
MOV [RBX+FILE64.Top],RAX
MOV [RBX+FILE64.Size],RCX
ADD [RBX+FILE64.Top],RCX
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
MOV [RBX+FILE64.Pos],RSI
LEA RDX,[RBX+FILE64.Name]
LEA RAX,[CreateFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.10:
LEA RAX,[CreateFileA]
.10:WinABI RAX,RDX,GENERIC_WRITE,FILE_SHARE_READ,RSI, \
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,RSI,Fastmode=No
MOV [RBX+FILE64.Handle],RAX
CMP RAX,RDI
JE .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StCreated
PUSH RCX
MOV RCX,RSP
WinABI WriteFile,RAX,[RBX+FILE64.Ptr],[RBX+FILE64.Size],RCX,RSI,Fastmode=No
POP RCX
ADD [RBX+FILE64.Pos],RCX
TEST RAX
JZ .EndWithLastError:
MOV RAX,[RBX+FILE64.Size]
CMP RAX,RCX
JE .EndWithRAX
MOV EAX,0xE0070000 + 39 ; "The disk is full."
JMP .ErrorEAX
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorEAX: STC
.EndWithRAX:
PUSHFD
JNSt [RBX+FILE64.Status],fi64StCreated,.90:
WinABI CloseHandle,[RBX+FILE64.Handle],Fastmode=No
.90: RstSt [RBX+FILE64.Status],fi64StCreated
MOV [RBX+FILE64.Handle],RDI
POPFD
POP RDI,RSI,RBX,RDX,RCX
RET 3*8
ENDPROC1 FileStore64@RT::
%ENDMACRO FileStore
FileOpen %MACRO theFile
PUSHQ %theFile
CALL FileOpen64@RT::
FileOpen64@RT:: PROC1
IMPORT CreateFileA,CreateFileW
PUSHQ RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+48] ; theFile.
LEA RDX,[RBX+FILE64.Name]
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
MOV [RBX+FILE64.Size],RSI
MOV [RBX+FILE64.Pos],RSI
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
RstSt [RBX+FILE64.Status],fi64StStdIO
LEA RAX,[CreateFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.30:
LEA RAX,[CreateFileA]
CMPB [RDX],0
JNE .40:
.20:SetSt [RBX+FILE64.Status],fi64StStdIO
WinABI GetStdHandle,STD_INPUT_HANDLE,Fastmode=No
JMP .50:
.30:CMPW [RDX],0
JE .20:
.40:WinABI RAX,RDX,GENERIC_READ,FILE_SHARE_READ,RSI, \
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,RSI,Fastmode=No
.50:MOV [RBX+FILE64.Handle],RAX
CMP RAX,RDI
JE .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StOpened + fi64StFound
MOV RCX,RAX
SUB EAX,EAX
JSt [RBX+FILE64.Status],fi64StStdIO,.EndWithRAX:
WinABI GetFileSize,RCX,RSI,Fastmode=No
CMP RAX,RDI
JE .EndWithLastError:
MOV [RBX+FILE64.Size],RAX
CLC
JMP .EndWithRAX
.EndWithLastError:
WinABI GetLastError,Fastmode=No
STC
.EndWithRAX:
POP RDI,RSI,RBX,RDX,RCX
RET 1*8
ENDPROC1 FileOpen64@RT::
%ENDMACRO FileOpen
FileReset %MACRO theFile, Position
%IF "%Position" === ""
PUSHQ 0
%ELSE
PUSHQ %Position
%ENDIF
PUSHQ %theFile
CALL FileReset64@RT::
FileReset64@RT:: PROC1
PUSH RDX,RBX
MOV RBX,[RSP+24] ; theFile.
MOV RDI,[RSP+32] ; Position.
MOV RAX,0xE0070004 ; Error: File is not opened.
JNSt [RBX+FILE64.Status],fi64StOpened, .ErrorRAX:
WinABI SetFilePointer,[RBX+FILE64.Handle],RDI,0,FILE_BEGIN,Fastmode=No
INC EAX
JZ .EndWithLastError:
MOV [RBX+FILE64.Pos],EDI
MOV RAX,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RAX
JSt [RBX+FILE64.Status],fi64StMapOpened,.80:
MOV [RBX+FILE64.Top],RAX
JMPS .90:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX: STC
JMPS .90:
.80: ADD [RBX+FILE64.Ptr],RDI
.90:POP RBX,RDI
RET 2*8
ENDPROC1 FileReset64@RT::
%ENDMACRO FileReset
FileRead %MACRO theFile,DataPtr,DataSize
PUSHQ %DataSize,%DataPtr,%theFile
CALL FileRead64@RT::
FileRead64@RT:: PROC1
PUSH RCX,RBX,RSI
MOV RBX,[RSP+32] ; theFile.
MOV RSI,[RSP+40] ; DataPtr.
MOV RCX,[RSP+48] ; DataSize.
MOV RAX,0xE0070004 ; File is not open.
JNSt [RBX+FILE64.Status],fi64StOpened, .ErrorRAX:
PUSH RAX
MOV RAX,RSP
WinABI ReadFile,[RBX+FILE64.Handle],RSI,RCX,RAX,0,Fastmode=No
TEST EAX
POP RAX
JZ .EndWithLastError:
ADD [RBX+FILE64.Pos],RAX
TEST RAX
JMP .EndWithRAX
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
.EndWithRAX:
POP RSI,RBX,RCX
RET 3*8
ENDPROC1 FileRead64@RT::
%ENDMACRO FileRead
FileCreate %MACRO theFile
PUSHQ %theFile
CALL FileCreate64@RT::
FileCreate64@RT:: PROC1
IMPORT CreateFileA,CreateFileW
PUSH RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+48] ; theFile.
LEA RDX,[RBX+FILE64.Name]
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
MOV [RBX+FILE64.Size],RSI
MOV [RBX+FILE64.Pos],RSI
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
RstSt [RBX+FILE64.Status],fi64StStdIO
LEA RAX,[CreateFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.30:
LEA RAX,[CreateFileA] ; ANSI version.
CMPB [RDX],0
JNE .40:
.20:SetSt [RBX+FILE64.Status],fi64StStdIO
WinABI GetStdHandle,STD_OUTPUT_HANDLE,Fastmode=No
JMP .60:
.30:CMPW [RDX],0 ; WIDE version.
JE .20:
.40:MOV RCX,OPEN_ALWAYS
JSt [RBX+FILE64.Status],fi64StAppend,.50:
MOV RCX,CREATE_ALWAYS
MOV RSI,FILE_ATTRIBUTE_NORMAL
.50:WinABI RAX,RDX,GENERIC_WRITE,FILE_SHARE_READ,0,RCX,RSI,0,Fastmode=No
.60:MOV [RBX+FILE64.Handle],RAX
CMP RAX,RDI
JE .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StCreated
MOV RCX,RAX
SUB EAX,EAX
JSt [RBX+FILE64.Status],fi64StStdIO, .EndWithRAX:
SUB ESI,ESI
WinABI GetFileSize,RCX,RSI,Fastmode=No
CMP RAX,RDI
JE .EndWithLastError:
MOV [RBX+FILE64.Size],RAX
JNSt [RBX+FILE64.Status],fi64StAppend,.EndWithRAX:
MOV [RBX+FILE64.Pos],RAX
WinABI SetFilePointer,[RBX+FILE64.Handle],RSI,RSI,FILE_END,Fastmode=No
CMP RDI,RAX
JA .EndWithRAX:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
STC
.EndWithRAX:
POP RDI,RSI,RBX,RDX,RCX
RET 1*8
ENDPROC1 FileCreate64@RT::
%ENDMACRO FileCreate
FileAppend %MACRO theFile
PUSHQ %theFile
CALL FileAppend64@RT::
FileAppend64@RT:: PROC1
PUSH RBX
MOV RBX,[RSP+16] ; theFile.
SetSt [RBX+FILE64.Status],fi64StAppend
FileCreate RBX
POP RBX
RET 1*8
ENDPROC1 FileAppend64@RT::
%ENDMACRO FileAppend
FileWriteRT %MACRO ; Common runtime procedure declaration for macros FileWrite*
FileWrite64@RT: PROC1
PUSHQ 0,RCX,RDX,RBX,RSI
MOV RBX,[RSP+56] ; theFile.
LEA RSI,[RSP+64] ; Address of 1st string ptr.
MOV RAX,0xE0070004 ; File is not opened.
JNSt [RBX+FILE64.Status],fi64StCreated, .ErrorRAX:
.Next:LODSQ ; DataPtr.
MOV RDX,RAX
TEST RAX
JZ .Ret: ; End of data. CF=0, ZF=1.
LODSQ ; DataSize.
MOV RCX,RAX
PUSH RAX
MOV RAX,RSP
WinABI WriteFile,[RBX+FILE64.Handle],RDX,RCX,RAX,0,Fastmode=No
TEST RAX
POP RAX ; Written size.
JZ .GetLastError:
ADD [RSP+32],RAX ; %ReturnRAX.
ADD [RBX+FILE64.Pos],RAX
ADD [RBX+FILE64.Size],RAX
JMP .Next:
.GetLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
MOV [RSP+32],RAX
.Ret:POP RSI,RBX,RDX,RCX,RAX
RET
FileWrite$size64@RT:
PUSH RCX,RDI
SUB ECX,ECX
SUB EAX,EAX
DEC RCX
MOV RDI,[RSP+24] ; DataPtr
REPNE SCASB
SUB RAX,RCX
SUB RAX,2
MOV [RSP+32],RAX ; DataSize
POP RDI,RCX
RET
ENDPROC1 FileWrite64@RT:
%ENDMACRO FileWriteRT
FileWrite %MACRO theFile,DataPtr,DataSize,,,,
%IF %# & 1 = 0
%ERROR ID=5944, 'Macro "FileWrite" expects odd number of arguments.'
%EXITMACRO FileWrite
%ENDIF
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],(%#+1)*8
CALL FileWrite64@RT
POP RSP
FileWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileWrite
FileWriteLn %MACRO theFile,DataPtr,DataSize,,,
%IF %# & 1 = 0
%ERROR ID=5945, 'Macro "FileWriteLn" expects odd number of arguments.'
%EXITMACRO FileWriteLn
%ENDIF
PUSHQ 0x00000A0D ; CR+LF.
PUSHQ 0 ; Mark the end of arguments.
PUSHQ 2 ; Size of CR+LF.
PUSH RSP
ADDQ [RSP],2*8 ; Pointer to CR+LF.
ArgNr %FOR %#..2, STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],(%#+4)*8
CALL FileWrite64@RT
POP RSP
FileWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileWriteLn
FileWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
PUSHQ 0 ; Mark the end of arguments
ArgNr %FOR %#..2,STEP=-1
PUSHQ RAX,%*{%ArgNr}
CALL FileWrite$size64@RT
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],2 * %# * 8
CALL FileWrite64@RT
POP RSP
FileWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileWrite$
FileEncloseRT %MACRO ; Common RT procedure declaration for macros FileEnclose*
FileEnclose64@RT:: PROC1
PUSHQ 0,RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+64] ; theFile.
SetSt [RBX+FILE64.Status],fi64StAppend
FileCreate RBX
JC .ErrorRAX:
LEA RSI,[RSP+72] ; Pointer to the 1st string pointer.
.10: LODSQ ; DataPtr.
MOV RDX,RAX
TEST RAX
JZ .90: ; End of data.
LODSQ ; DataSize.
MOV RCX,RAX
PUSH RDI ; Make room for written size.
MOV RDI,RSP
WinABI WriteFile,[RBX+FILE64.Handle],RDX,RCX,RDI,0,Fastmode=No
POP RDI ; Written size.
ADD [RSP+40],RDI ; %ReturnEAX.
ADD [RBX+FILE64.Pos],RDI
ADD [RBX+FILE64.Size],RDI
TEST RAX ; WriteFile result.
JNZ .10: ; If OK, write the next Data.
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
MOV [RSP+28],RAX ; %ReturnEAX.
.90: PUSHFQ
FileClose RBX
POPFQ
POP RDI,RSI,RBX,RDX,RCX,RAX
RET
FileEnclose$size64@RT:: ; Subprocedure for zero-terminated strings.
PUSH RAX,RCX,RDI
SUB ECX,ECX
SUB EAX,EAX
DEC RCX
MOV RDI,[RSP+32] ; DataPtr.
REPNE SCASB
SUB RAX,RCX
SUB RAX,2
MOV [RSP+40],RAX ; DataSize.
POP RDI,RCX,RAX
RET
ENDPROC1 FileEnclose64@RT::
%ENDMACRO FileEncloseRT
FileEnclose %MACRO theFile,DataPtr,DataSize,,,,
%IF %# & 1 = 0
%ERROR ID=5942, 'Macro "FileEnclose" expects odd number of arguments.'
%EXITMACRO FileEnclose
%ENDIF
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],(%#+1)*8
CALL FileEnclose64@RT
POP RSP
FileEncloseRT ; Invoke the common runtime macro.
%ENDMACRO FileEnclose
FileEncloseLn %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,,
%IF %# & 1 = 0
%ERROR ID=5943, 'Macro "FileEncloseLn" expects odd number of arguments.'
%EXITMACRO FileEncloseLn
%ENDIF
PUSHQ 0x00000A0D ; CR+LF
PUSHQ 0 ; Mark the end of arguments.
PUSHQ 2 ; Size of CR+LF.
PUSH RSP
ADDQ [RSP],2*8 ; Pointer to CR+LF.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],8*(%#+4)
CALL FileEnclose64@RT
POP RSP
FileEncloseRT ; Invoke the common runtime macro.
%ENDMACRO FileEncloseLn
FileEnclose$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-1
PUSHQ RAX,%*{%ArgNr}
CALL FileEnclose$size64@RT ; Get length of string and write it to the stack.
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],2 * %# * 8
CALL FileEnclose64@RT
POP RSP
FileEncloseRT ; Invoke the common runtime macro.
%ENDMACRO FileEnclose$
FileMapOpen %MACRO theFile
PUSHQ %theFile
CALL FileMapOpen64@RT::
FileMapOpen64@RT:: PROC1
IMPORT CreateFileA,CreateFileW,CreateFileMappingA,CreateFileMappingW
PUSH RAX,RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+56] ; theFile.
LEA RDX,[RBX+FILE64.Name]
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
MOV [RBX+FILE64.BufPtr],RSI
MOV [RBX+FILE64.BufSize],RSI
MOV [RBX+FILE64.Size],RSI
MOV [RBX+FILE64.Pos],RSI
MOV [RBX+FILE64.Handle],RDI
MOV [RSP+08],RSI ; ReturnRSI.
LEA RAX,[CreateFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.30:
LEA RAX,[CreateFileA] ; ANSI variant.
CMPB [RDX],0
JNE .40:
.20: MOV RAX,0xC0070000+123 ; "The file name is incorrect."
JMP .ErrorRAX:
.30: CMPW [RDX],0 ; WIDE variant.
JE .20:
.40: WinABI RAX,RDX,GENERIC_READ,FILE_SHARE_READ,RSI, \
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,RSI,Fastmode=No
MOV [RBX+FILE64.Handle],RAX
CMP RAX,RDI
JE .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StOpened + fi64StFound
WinABI GetFileSize,RAX,RSI,Fastmode=No
CMP RAX,RDI
JE .EndWithLastError:
MOV [RBX+FILE64.Size],RAX
MOV [RBX+FILE64.BufSize],RAX
MOV [RBX+FILE64.Top],RAX
MOV [RSP+40],RAX ; ReturnRAX.
TEST RAX
JZ .Ret:
LEA RAX,[CreateFileMappingW]
JSt [RBX+FILE64.Status],fi64StUnicode,.50:
LEA RAX,[CreateFileMappingA]
.50: WinABI RAX,[RBX+FILE64.Handle],RSI,PAGE_READONLY,RSI,RSI,RSI,Fastmode=No
MOV [RBX+FILE64.MapHandle],RAX
TEST RAX
JZ .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StMapOpened
WinABI MapViewOfFile,RAX,FILE_MAP_READ,RSI,RSI,RSI
MOV [RBX+FILE64.Ptr],RAX
MOV [RSP+08],RAX ; ReturnRSI.
ADD [RBX+FILE64.Top],RAX
MOV [RBX+FILE64.BufPtr],RAX
TEST RAX
JZ .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StMapped
JMP .Ret:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
MOV [RSP+40],EAX ; ReturnRAX.
.Ret:POP RDI,RSI,RBX,RDX,RCX,RAX
RET 1*8
ENDPROC1 FileMapOpen64@RT::
%ENDMACRO FileMapOpen
FileMapCreate %MACRO theFile,FileSize
%IF %# > 1
PUSHQ %FileSize
%ELSE
PUSHQ 0
%ENDIF
PUSHQ %theFile
CALL FileMapCreate64@RT::
FileMapCreate64@RT:: PROC1
IMPORT CreateFileA,CreateFileW,CreateFileMappingA,CreateFileMappingW
PUSH RCX,RDX,RBX,RSI,0
MOV RBX,[RSP+48] ; theFile.
LEA RDX,[RBX+FILE64.Name]
SUB ESI,ESI
MOV RDI,INVALID_HANDLE_VALUE
RstSt [RBX+FILE64.Status],fi64StAppend
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
MOV [RBX+FILE64.BufPtr],RSI
MOV [RBX+FILE64.BufSize],RSI
MOV [RBX+FILE64.Size],RSI
MOV [RBX+FILE64.Pos],RSI
MOV [RBX+FILE64.Handle],RDI
LEA RAX,[CreateFileW]
JSt [RBX+FILE64.Status],fi64StUnicode,.30:
LEA RAX,[CreateFileA]
CMPB [RDX],0
JNE .40:
.20: MOV RAX,0xC0070000+123 ; "Error: The file name is incorrect."
JMP .ErrorRAX:
.30: CMPW [RDX],0
JE .20:
.40: WinABI RAX,RDX,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, \
RSI,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,RSI,Fastmode=No
MOV [RBX+FILE64.Handle],RAX
CMP RAX,RDI
JE .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StCreated
MOV RCX,[RSP+56] ; FileSize.
TEST RCX
JNZ .45:
WinABI GetFileSize,[RBX+FILE64.Handle],RCX,Fastmode=No
MOV RCX,RAX
INC RAX
JZ .EndWithLastError:
.45: MOV [RBX+FILE64.Size],RCX
MOV [RBX+FILE64.BufSize],RCX
MOV [RBX+FILE64.Top],RCX
LEA RAX,[CreateFileMappingW]
JSt [RBX+FILE64.Status],fi64StUnicode,.50:
LEA RAX,[CreateFileMappingA]
.50: WinABI RAX,[RBX+FILE64.Handle],RSI,PAGE_READWRITE,RSI,RCX,RSI,Fastmode=No
MOV [RBX+FILE64.MapHandle],RAX
TEST RAX
JZ .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StMapCreated
WinABI MapViewOfFile,RAX,FILE_MAP_WRITE,RSI,RSI,RSI,Fastmode=No
MOV [RBX+FILE64.Ptr],RAX
ADD [RBX+FILE64.Top],RAX
MOV [RBX+FILE64.BufPtr],RAX
MOV [RSP+00],RAX ; ReturnRDI.
TEST RAX
JZ .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StMapped
MOV RAX,RCX
JMP .Ret:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
.Ret:POP RDI,RSI,RBX,RDX,RCX
RET 2*8
ENDPROC1 FileMapCreate64@RT::
%ENDMACRO FileMapCreate
FileStreamOpen %MACRO theFile,BufSize=16K
PUSH %BufSize,%theFile
CALL FileStreamOpen64@RT::
FileStreamOpen64@RT:: PROC1
PUSH RCX,RBX
MOV RBX,[RSP+3*8] ; theFile.
MOV RCX,[RSP+4*8] ; BufSize.
MOV [RBX+FILE64.BufSize],RCX
WinABI GlobalAlloc,GMEM_FIXED,RCX,Fastmode=No
TEST RAX
JZ .EndWithLastError:
MOV [RBX+FILE64.BufPtr],RAX
PUSH RDI
MOV RDI,RAX
SetSt [RBX+FILE64.Status],fi64StAllocated
FileOpen RBX
MOV [RBX+FILE64.Ptr],RDI
MOV [RBX+FILE64.Top],RDI
POP RDI
JNC .EndWithRAX
.EndWithLastError:
WinABI GetLastError,Fastmode=No
STC
.EndWithRAX:
POP RBX,RCX
RET 2*8
ENDPROC1 FileStreamOpen64@RT::
%ENDMACRO FileStreamOpen
FileStreamRead %MACRO theFile,DataPtr,DataSize
PUSHQ %DataSize,%DataPtr,%theFile
CALL FileStreamRead64@RT::
FileStreamRead64@RT:: PROC1
PUSH RCX,RDX,RBX,RSI,RDI
SUB EDX,EDX
MOV RBX,[RSP+48] ; theFile.
MOV RDI,[RSP+56] ; DataPtr.
.10: MOV RSI,[RBX+FILE64.Ptr]
.20: MOV RCX,[RBX+FILE64.Top]
SUB RCX,RSI
JNA .50:
CMP RCX,[RSP+64] ; DataSize.
JA .30:
SUB [RSP+64],RCX ; DataSize.
ADD RDX,RCX
REP MOVSB
MOV [RBX+FILE64.Ptr],RSI
JMP .20:
.30: MOV RCX,[RSP+64] ; DataSize.
ADD RDX,RCX
REP MOVSB
MOV [RBX+FILE64.Ptr],RSI
JMP .70:
.50: MOV RSI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RSI
PUSH RCX
MOV RCX,RSP
WinABI ReadFile,[RBX+FILE64.Handle],RSI,[RBX+FILE64.BufSize],RCX,0,Fastmode=No
POP RCX
TEST RAX
JZ .EndWithLastError:
JRCXZ .70: ; EOF
ADD [RBX+FILE64.Top],RCX
JMP .20:
.70: MOV RAX,RDX
ADD [RBX+FILE64.Pos],RDX
TEST RAX
JMP .EndWithRAX ; ZF if RAX=0.
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
.EndWithRAX:
.90: POP RDI,RSI,RBX,RDX,RCX
RET 3*8
ENDPROC1 FileStreamRead64@RT::
%ENDMACRO FileStreamRead
FileStreamReadLn %MACRO theFile
PUSHQ %theFile
CALL FileStreamReadLn64@RT::
FileStreamReadLn64@RT:: PROC1
PUSH 0,RCX,RDX,RBX,RSI,RDI
MOV RBX,[RSP+56] ; theFile.
MOV RAX,0xE0070004 ; File is not open.
JNSt [RBX+FILE64.Status],fi64StOpened,.ErrorRAX:
JNSt [RBX+FILE64.Status],fi64StAllocated,.ErrorRAX:
MOV RDI,[RBX+FILE64.Ptr]
MOV RCX,[RBX+FILE64.Top]
.10: MOV [RSP+08],RDI ; ReturnRSI.
MOV RDX,RDI
SUB RCX,RDI
JNA .30:
MOV AL,10 ; LineFeed
REPNE SCASB
JE .50:
CMP RDX,[RBX+FILE64.BufPtr]
JE .50:
; When the end of line is out of buffer and start of line is not
; at buffer's beginning, the buffer will be reloaded with the current line.
SUB RDX,RDI
WinABI SetFilePointer,[RBX+FILE64.Handle],RDX,0,FILE_CURRENT,Fastmode=No
.30: MOV RDI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],RDI
MOV [RBX+FILE64.Top],RDI
PUSH RCX
MOV RCX,RSP
WinABI ReadFile,[RBX+FILE64.Handle],RDI,[RBX+FILE64.BufSize],RCX,0,Fastmode=No
POP RCX
TEST RAX
JZ .EndWithLastError:
JRCXZ .70: ; EOF
ADD RCX,RDI
MOV [RBX+FILE64.Top],RCX
JMP .10:
.50: MOV [RBX+FILE64.Ptr],RDI
SUB RDI,RDX
MOV [RSP+40],RDI ; ReturnRAX.
ADD [RBX+FILE64.Pos],RDI
JMP .90:
.70: SUB EAX,EAX
JMP .EndWithRAX:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
.EndWithRAX:
MOV [RSP+40],RAX ; ReturnRAX.
.90:POP RDI,RSI,RBX,RDX,RCX,RAX
RET 1*8
ENDPROC1 FileStreamReadLn64@RT::
%ENDMACRO FileStreamReadLn
FileStreamReadByte %MACRO theFile
PUSHQ %theFile
CALL FileStreamReadByte64@RT::
FileStreamReadByte64@RT:: PROC1
PUSH RAX,RCX,RBX,RSI,RDI
MOV RBX,[RSP+48]
.10: MOV RSI,[RBX+FILE64.Ptr]
CMP RSI,[RBX+FILE64.Top]
JB .50: ; Buffer is not empty.
MOV RAX,0xE0070004 ; File is not open.
JNSt [RBX+FILE64.Status],fi64StOpened,.ErrorRAX:
JNSt [RBX+FILE64.Status],fi64StAllocated,.ErrorRAX:
MOV RDI,[RBX+FILE64.BufPtr]
MOV [RBX+FILE64.Ptr],EDI
MOV [RBX+FILE64.Top],EDI
PUSH RCX
MOV RCX,RSP
WinABI ReadFile,[RBX+FILE64.Handle],RDI,[RBX+FILE64.BufSize],RCX,0,Fastmode=No
POP RCX
TEST RAX
JZ .EndWithLastError:
ADD [RBX+FILE64.Top],RCX
TEST RCX
JNZ .10
MOV RAX,[RSP+32] ; ReturnRAX.
XOR AL,AL ; Set ZF=1.
JMP .EndWithRAX:
.EndWithLastError:
WinABI GetLastError,Fastmode=No
.ErrorRAX:
STC
JMP .EndWithRAX:
.50: MOV RAX,[RSP+32] ; ReturnRAX.
LODSB
MOV [RBX+FILE64.Ptr],RSI
INCQ [RBX+FILE64.Pos]
CLC
.EndWithRAX:
MOV [RSP+32],RAX
POP RDI,RSI,RBX,RCX,RAX
RET 1*8
ENDPROC1 FileStreamReadByte64@RT::
%ENDMACRO FileStreamReadByte
FileStreamCreate %MACRO theFile,BufSize=16K
PUSHQ %BufSize,%theFile
CALL FileStreamCreate64@RT::
FileStreamCreate64@RT:: PROC1
PUSH RCX,RBX,RSI,RDI
MOV RBX,[RSP+40] ; theFile.
MOV RCX,[RSP+48] ; BufSize.
MOV [RBX+FILE64.BufSize],RCX
MOV RDI,RCX
WinABI GlobalAlloc,GMEM_FIXED,RCX,Fastmode=No
TEST RAX
JZ .EndWithLastError:
SetSt [RBX+FILE64.Status],fi64StAllocated
MOV [RBX+FILE64.BufPtr],RAX
ADD RDI,RAX
MOV RSI,RAX
FileCreate RBX
MOV [RBX+FILE64.Ptr],RSI
MOV [RBX+FILE64.Top],RDI
JNC .EndWithRAX
.EndWithLastError:
WinABI GetLastError,Fastmode=No
STC
.EndWithRAX:
POP RDI,RSI,RBX,RCX
RET 2*8
ENDPROC1 FileStreamCreate64@RT::
%ENDMACRO FileStreamCreate
FileStreamAppend %MACRO theFile,BufSize=16K
PUSHQ %BufSize,%theFile
CALL FileStreamAppend64@RT::
FileStreamAppend64@RT:: PROC1
PUSH RBX,RCX
MOV RBX,[RSP+24] ; theFile.
MOV RCX,[RSP+32] ; BufSize.
SetSt [RBX+FILE64.Status],fi64StAppend
FileStreamCreate RBX,RCX
POP RCX,RBX
RET 2*8
ENDPROC1 FileStreamAppend64@RT::
%ENDMACRO FileStreamAppend
FileStreamWriteByte %MACRO theFile
PUSHQ %theFile
CALL FileStreamWriteByte64@RT::
FileStreamWriteByte64@RT:: PROC1
PUSH RAX,RCX,RDX,RBX,RDI
MOV RBX,[RSP+48] ; theFile.
.10: MOV RDI,[RBX+FILE64.Ptr]
CMP RDI,[RBX+FILE64.Top]
JB .50:
MOV EDX,EAX
FileFlush RBX ; If buffer is full.
JC .40:
MOV EAX,EDX
JMP .10:
.40: MOV [RSP+32],RAX ; ReturnRAX.
JMP .90:
.50: STOSB
MOV RAX,[RBX+FILE64.Pos]
MOV [RBX+FILE64.Ptr],RDI
ADD RAX,1
MOV [RBX+FILE64.Pos],RAX
MOV [RBX+FILE64.Size],RAX
CLC
.90:POP RDI,RBX,RDX,RCX,RAX
RET 1*8
ENDPROC1 FileStreamWriteByte64@RT::
%ENDMACRO FileStreamWriteByte
FileStreamWriteWord %MACRO theFile
PUSHQ %theFile
CALL FileStreamWriteWord64@RT::
FileStreamWriteWord64@RT:: PROC1
PUSH RAX,RCX,RDX,RBX,RDI
MOV RBX,[RSP+48] ; theFile.
.10: MOV RDI,[RBX+FILE64.Ptr]
LEA RDX,[RDI+1]
CMP RDX,[RBX+FILE64.Top]
JB .50
MOV EDX,EAX
FileFlush RBX ; If the buffer is full.
JC .40: ; On error.
MOV EAX,EDX
JMP .10:
.40: MOV [RSP+32],RAX ; ReturnRAX.
JMP .90:
.50: STOSW
MOV RAX,[RBX+FILE64.Pos]
MOV [RBX+FILE64.Ptr],RDI
ADD RAX,2
MOV [RBX+FILE64.Pos],RAX
MOV [RBX+FILE64.Size],RAX
CLC
.90:POP RDI,RBX,RDX,RCX,RAX
RET 1*8
ENDPROC1 FileStreamWriteWord64@RT::
%ENDMACRO FileStreamWriteWord
FileStreamWriteDword %MACRO theFile
PUSHQ %theFile
CALL FileStreamWriteDword64@RT::
FileStreamWriteDword64@RT:: PROC1
PUSH RAX,RCX,RDX,RBX,RDI
MOV RBX,[RSP+48] ; theFile.
.10: MOV RDI,[RBX+FILE64.Ptr]
LEA RDX,[RDI+3]
CMP RDX,[RBX+FILE64.Top]
JB .50
MOV EDX,EAX
FileFlush RBX ; If buffer full.
JC .40:
MOV EAX,EDX
JMP .10:
.40: MOV [RSP+32],RAX ; ReturnRAX.
JMP .90:
.50: STOSD
MOV RAX,[RBX+FILE64.Pos]
MOV [RBX+FILE64.Ptr],RDI
ADD RAX,4
MOV [RBX+FILE64.Pos],RAX
MOV [RBX+FILE64.Size],RAX
CLC
.90:POP RDI,RBX,RDX,RCX,RAX
RET 1*8
ENDPROC1 FileStreamWriteDword64@RT::
%ENDMACRO FileStreamWriteDword
FileStreamWriteRT %MACRO ; Common runtime procedure for macros FileStreamWrite*
FileStreamWrite64@RT: PROC1
PUSHQ 0,RCX,RDX,RBX,RBP,RSI,RDI
MOV RBX,[RSP+72] ; theFile.
LEA RSI,[RSP+80] ; Pointer to Data1Ptr.
MOV RAX,0xE0070004 ; File was not opened.
JNSt [RBX+FILE64.Status],fi64StCreated,.ErrorRAX:
JNSt [RBX+FILE64.Status],fi64StAllocated,.ErrorRAX:
SUB EAX,EAX
MOV [RSP+48],EAX ; ReturnRAX
.Next:LODSQ ; DataPtr.
MOV RBP,RAX
TEST RAX
JZ .Ret: ; End of data.
LODSQ ; DataSize.
MOV RDX,RAX
ADD [RSP+48],RAX ; ReturnRAX
CALL .FileStreamStoreData:
JNC .Next:
.ErrorRAX:
STC
MOV [RSP+48],RAX ; ReturnRAX
.Ret:POP RDI,RSI,RBP,RBX,RDX,RCX,RAX
RET
.FileStreamStoreData: ; Copy data to FileStream buffer
; INP: RBX=^FILE64, RBP=DataPtr, RDX=DataSize.
; OUT: CF=error, RAX=error, EBX,ESI preserved, FILE64 updated.
PUSH RSI
MOV RSI,RBP
.S1: TEST RDX
JZ .S9
.S2: MOV RCX,[RBX+FILE64.Top]
MOV RDI,[RBX+FILE64.Ptr]
SUB RCX,RDI
JNZ .S3
FileFlush RBX
JNC .S2:
JMP .S9:
.S3: CMP RCX,RDX
JBE .S4:
MOV RCX,RDX
.S4: SUB RDX,RCX
ADD [RBX+FILE64.Ptr],RCX
ADD [RBX+FILE64.Pos],RCX
ADD [RBX+FILE64.Size],RCX
REP MOVSB
JMP .S1:
.S9:POP RSI
RET
FileStreamWrite$size64@RT::
PUSH RAX,RCX,RDI
SUB ECX,ECX
SUB EAX,EAX
DEC RCX
MOV RDI,[RSP+32] ; DataPtr
REPNE SCASB
SUB RAX,RCX
SUB RAX,2
MOV [RSP+40],RAX ; DataSize
POP RDI,RCX,RAX
RET
ENDPROC1 FileStreamWrite64@RT:
%ENDMACRO FileStreamWriteRT
FileStreamWrite %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,,
%IF %# & 1 = 0
%ERROR ID=5946, 'Macro "FileStreamWrite" expects odd number of arguments.'
%EXITMACRO FileStreamWrite
%ENDIF
PUSHQ 0 ; Mark the end of arguments.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],(%#+1)*8
CALL FileStreamWrite64@RT
POP RSP
FileStreamWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileStreamWrite
FileStreamWriteLn %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,,
%IF %# & 1 = 0
%ERROR ID=5947, 'Macro "FileStreamWriteLn" expects odd number of arguments.'
%EXITMACRO FileStreamWriteLn
%ENDIF
PUSHQ 0x00000A0D ; CR+LF.
PUSHQ 0 ; Mark the end of arguments.
PUSHQ 2 ; Size of CR+LF.
PUSH RSP
ADDD [RSP],2*8 ; Pointer to CR+LF.
ArgNr %FOR %#..2,STEP=-2
PUSHQ %*{%ArgNr}, %*{%ArgNr-1}
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],(%#+4)*8
CALL FileStreamWrite64@RT
POP RSP
FileStreamWriteRT
%ENDMACRO FileStreamWriteLn ; Invoke the common runtime macro.
FileStreamWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,,
PUSHQ 0 ; mark end of arguments
ArgNr %FOR %#..2,STEP=-1
PUSHQ RAX,%*{%ArgNr}
CALL FileStreamWrite$size64@RT::
%ENDFOR ArgNr
PUSHQ %theFile
PUSH RSP
ADDQ [RSP],2 * %# * 8
CALL FileStreamWrite64@RT
POP RSP
FileStreamWriteRT ; Invoke the common runtime macro.
%ENDMACRO FileStreamWrite$
ENDHEAD winf64