| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# winf64.htm
Class
FILE64
Encoding
FileStatusEnc
Macros
FileAppend
FileAssign
FileClose
FileCreate
FileDelete
FileEach
FileEnclose
FileEnclose$
FileEncloseLn
FileExists?
FileLoad
FileMapCreate
FileMapOpen
FileMkDir
FileMove
FileNameParse
FileOpen
FileRead
FileReset
FileStore
FileStreamAppend
FileStreamCreate
FileStreamOpen
FileStreamRead
FileStreamReadByte
FileStreamReadLn
FileStreamWrite
FileStreamWriteByte
FileStreamWriteWord
FileStreamWriteDword
FileStreamWrite$
FileStreamWriteLn
FileWrite
FileWrite$
FileWriteLn

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:

[.bss] InpFile DS FILE64 OutFile DS FILE64 Record: DB 512 * BYTE [.text] FileAssign InpFile, ="Input.dat" FileAssign OutFile, ="Output.dat" FileOpen InpFile JC .InpErr: FileCreate OutFile JC .OutErr: .Next: FileRead InpFile, Record, SIZE# Record JC .InpErr: JZ .EOF: CALL ModifyRecord FileWrite OutFile, Record, SIZE# Record JC .OutErr: JMP .Next: .InpErr: StdOutput ="Error reading ",InpFile.Name JMP .EOF: .OutErr: StdOutput ="Error writing ",OutFile.Name .EOF: FileClose OutFile, InpFile TerminateProgram

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:

FileAssign InpFile, ="Input.txt" FileAssign OutFile, ="Output.txt" FileStreamOpen InpFile JC .Error: FileStreamCreate OutFile JC .Error: .Next: FileStreamReadLn InpFile JC .Error: JZ .EOF: MOV RCX,RAX ; line size MOV RDI,aLine REP MOVSB CALL ModifyLine FileStreamWrite OutFile, aLine, RAX JC .Error: JMP .Next: .EOF: FileClose OutFile, InpFile

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
  structure keeps information about the file status. Variable with FILE64 structure should be defined for each file used in program, either statically (in .data segment) or cleared when defined on stack or .bss. Pointer to a FILE64 structured variable is passed as the first parameter to all macros in this library.

    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

FileStatusEnc
  Definition of flags which describe `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.

FileNameParse FileNamePtr, Size= -1, Unicode=%^UNICODE
  FileNameParse will analyze string with complete FileName, which may contain path, name, extension, and return pointers to the name without path and to the file extension.
  Name starts behind the last slash `/`, backslash `\` or colon`:`. If no such characters exists, the whole input string is a name.
  File extension starts at the last point `.` in the name. If there is no point in name, extension is empty.
Input
  FileNamePtr is pointer to a string of ANSII or WIDE characters.
  Size=-1 is the size of input string in bytes. By default it is unlimited and the string must be zero terminated in this case.
  Unicode=%^UNICODE specifies whether the FileNamePtr string is ANSI or WIDE. By default it copies the value of system variable `%^UNICODE` at macro invocation but you may want to set this parameter to 0 even if %UNICODE is enabled and vice versa.
Output
  RAX is pointer to the start of name without path.
  RCX is pointer to the start of extension.
  RDX points behind the last FileName character.
  Path starts at %FileNamePtr, size=RAX - OFFSET#FileNamePtr
  Name starts at RAX, size=RCX - RAX
  Extension starts at RCX, size=RDX - RCX
Error
  -
Examples
  %FileNamePtr │ │ │ │ "D:\path.ext\nam.part1.txt" "\plain" "./.profile" "name" │ │ │ │ │ │ │ │ │ RAX │ │ RAX │ RAX │ RAX │ RCX │ RCX RCX │ RCX RDX RDX RDX RDX

    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

FileAssign theFile, Name$1, Name$2,,,Size=-1, Unicode=%^UNICODE
  Macro FileAssign associates file name with the FILE64 data object. Name of the file is copied to `theFile.Name` member.
  The file must be assigned with file name before it is created or opened. FileAssign can concatenate the filename from several input strings, e.g. path, name, extension.
Input
  theFile is pointer to a FILE64 structured memory variable.
  Name$* is pointer to a zero terminated string with the file name or its part. It needs not be zero terminated when Size= is expicitly specified. Filename will be concatenated when more than one string is provided.
  Name$1 may also be 0 or pointer to an empty string. The file is then assigned to standard input or output.
  Device name, such as COM1, LPT1, NULL, may be assigned instead of a disk file.
  Size= applies to all input strings. Size is unlimited by default and the strings must be zero terminated in this case.
  Unicode=%^UNICODE This boolean parameter specifies whether the Name$ strings are ANSI or WIDE. By default it copies the current status of `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.
Output
  Members of theFile `.Name, .NameOffs, .ExtOffs, .Status:fi64StUnicode` of `theFile` are set.
Error
  CF=1 if the concatenated name length exceeds `SIZE# FILE64.Name`, i.e. MAX_PATH_SIZE=260 characters.
Depends on
  FileNameParse
Examples
  File1 DS FILE64 Path$ DB "C:\Text\",0 Name$ DB "Some",0 Ext$ DB ".txt",0 [.text] FileAssign File1,Path$,Name$,Ext$ FileAssign File1,=U"\\Server\Share\File.txt",Unicode=1 FileAssign File1,0 ; Standard output, by default redirected to console. FileAssign File1,="CON" ; Output to system console, not redirectable.

    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

FileExists? theFile
  will test if the given file with assigned name exists on disk. File may be opened or closed. Wildcard characters `* ?` are allowed in the file name.
  This macro can test the presence of a directory, too.
Input
  theFile is pointer to FILE64 object with assigned name.
Output
  CF=1 if the file|directory does not exist.
  CF=0 ZF=1 if the file exists
  CF=0 ZF=0 if the directory exists
Example
  FileExists? =".\Config.ini" JC ErrorIniNotFound

    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 theFile
  will parse the file name and create all directories in its path if they didn't exist.
  The last portion of assigned name is treated as directory only if it is terminated with backslash.
Input
  theFile is pointer to FILE64 object with assigned name.
Output
  CF=0
  RAX=0 if the directory was created or if it existed before.
Error
  CF=1
  RAX=last error if CreateDirectory failed.
Example
  FileAssign SomeFile, ="C:\D1\D2\file.txt" FileMkDir SomeFile ; will create folders C:\D1 and C:\D1\D2 FileAssign SomeFile, ="C:\D1\D2\file.txt\" FileMkDir SomeFile ; will create folders C:\D1, C:\D1\D2 and C:\D1\D2\file.txt\

    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 theFile
  is a service macro used internally in FileClose, FileStreamWrite* to write the contents of file buffer on disk. There is no reason to invoke this macro explicitly by the programmer.
Output
  CF=0
  EAX=0.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.

    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 theFile1, theFile2,,,
  Macro FileClose will flush and deallocate the buffer, close file mapping, close the file, clear pointers in the FILE64 structure.
  FileClose does not clear the name assignment, so the closed file may be reopen with the same name without invoking FileAssign again.
Input
  theFile is pointer to a FILE64 object. More than one file may be specified simultaneously.
Output
  -
Error
  -

    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 SourceFile, DestinationFile
  FileMove renames directory on the same volume or moves the source file to the destination. Files will be closed first, if necessarry. The destination file will be erased if it existed before.
  Directories in the destination file name will be maked, if necessarry. Both files must have been assigned with either WIDE or ANSI name.
Input
  SourceFile and DestinationFile are pointers to assigned FILE64 objects.
Output
  CF=0
  RAX=0
Error
  CF=1
  RAX= error as returned from GetLastError.
Depends on
  FileMkDir 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 theFile1, theFile2,,,
  will close and erase the disk file(s).
  FileDelete does not clear the name assignment, so the deleted file may be reopen with the same name without invoking FileAssign again.
Input
  theFile is pointer to a FILE64object. More than one file may be specified simultaneously.
Output
  CF=0,
  RAX=0 if the last file was succesfully deleted.
Error
  CF=1
  RAX= error as returned from GetLastError.
Depends on
  FileClose

    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

FileEach theFile, CallbackProc
  Macro FileEach expects the file object assigned with file name which can contain wildcard characters `*` and `?`. FileEach will resolve the mask and performs callback procedure with each such filename. If no file matches the mask, CallbackProc is never called.
Input
  theFile is a pointer to FILE64 object which must have assigned the requested file path and file name mask.
  CallbackProc is the address of callback procedure.
Output
  RAX=content of RAX at the last CallbackProc exit, or 0 if the CallbackProc was never called.
CallbackProc
  is called with register calling convention. CallbackProc should return CF=0 to let FileEach continue with the next file otherwise FileEach stops searching.
  CallbackProc input registers:
    RBX=pointer to %theFile where the mask in `FILE64.Name` is replaced with the file found in directory. The file is not open.
    RDX=Find handle, as returned from WinABI function FindFirstFile().
    If CallbackProc aborts the program instead of returning to FileEach, it should also close this FindHandle using `WinABI FindClose,RDX` before terminating.
    RSI=pointer to the file name without path inside RBX+FILE64.Name. The string is zero-terminated ANSI or WIDE, depending on what mask was assigned to %theFile.
    RDI=pointer to WIN32_FIND_DATA structure which contains attributes of the found file.
    RBP=RBP at FileEach macro entry. This allows to address local stack variables of the procedure which invoked FileEach.
    Other registers are undefined at CallbackProc entry.
  CallbackProc output registers:
    RAX is passed through. FileEach returns RAX value from the last called CallbackProc, or 0 if it was never called.
    CF=0 to continue with the next file
    CF=1 to break further searching. FileEach discards the WIN32_FIND_DATA structure pointed to with EDI and exits but the actual file name without wildcards assigned to %theFile remains intact.
    CallbackProc may destroy any GP register.
Depends on
  FileNameParse
Example
  MyFile DS FILE64 FileAssign MyFile,="D:\Dir\*.* FileEach MyFile, ListFile TerminateProgram ListFile PROC StdOutput RSI, Eol=Yes CLC RET ENDP ListFile

    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 theFile
  will allocate memory buffer on Windows heap, open the file, read entire file content to memory and then close the file.
  Although the file handle is closed immediately, you should always use FileClose to free allocated buffer when the file contents is no longer needed.
Input
  theFile is pointer to FILE64 assigned with filename.
Output
  CF=0
  RAX= file size,
  RSI= pointer to the file contents in dynamically allocated memory.
Error
  CF=1
  RAX= errorCode as returned from GetLastError,
  RSI= is undefined.

    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 theFile, DataPtr, DataSize
  Macro FileStore will open the file, write data and close the file.
Input
  theFile is pointer to an assigned unopened FILE64 object,
  DataPtr is pointer to the data to be written,
  DataSize is size of the data in bytes, i.e. the future file size.
Output
  CF=0
  RAX= is the data size of written data.
Error
  CF=1
  RAX= is error code returned by GetLastError.
Example
  FileAssign File1,="C:\Temp\MyFile1.txt" FileStore File1, MyDataPtr, MyDataEnd-MyDataPtr File1 DS FILE64

    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 theFile
  opens the assigned file for reading.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  RAX= file size.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.

    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 theFile, Position
  Macro FileReset will reset internal file pointers to a new Position in the file.
Input
  theFile is pointer to a FILE64 object, which must have been opened with FileOpen, FileMapOpen or FileStreamOpen.
  Position specifies the number of bytes from the beginning of theFile. Zero is used if omitted.
Output
  CF=0
  RAX=Position
Error
  CF=1
  RAX= error code if SetFilePointer failed.

    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 theFile, DataPtr, DataSize
  reads from an opened file to the memory provided by caller.
Input
  theFile is pointer to a FILE64 object opened for reading.
  DataPtr is pointer where the data will be read,
  DataSize is requested number of bytes.
Output
  CF=0
  ZF=0
  RAX= the actually read size (may be less than DataSize if the file is not large enough).
End of file
  CF=0
  ZF=1
  RAX=0 if all data have been read from the file (EOF).
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Example
  FileRead InpFile,aLine,80 JC .ErrorReadingFile JZ .EOF

    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 theFile
  creates a new file or rewrites an existing file for writing.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  RAX=0 (size of just rewritten file).
Error
  CF=1
  EAX=errorCode as returned from GetLastError.

    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 theFile
  Macro FileAppend creates a new file or opens an existing file for writing and sets file pointer to its end.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  RAX= file size.
Error
  CF=1
  RAX=errorCode as returned from GetLastError.
Depends on
  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
  is a runtime defining macro used internally by FileWrite, FileWriteLn, FileWrite$.
  Returns RAX=total written size.

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data to the file previously opened for writing with FileCreate or FileAppend.
  Multiple data may be written in one macro invocation.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr* points to the data to be written,
  DataSize* is the size of data in bytes.
Output
  CF=0
  RAX=total written size in bytes.
Error
  CF=1
  RAX=errorCode as returned from GetLastError.
Depends on
  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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  Macro FileWriteLn writes data to the file previously opened for writing with FileCreate or FileAppend.
  Multiple data may be written in one macro invocation. End of line CR+LF characters are written in the end.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr* points to the data to be written,
  DataSize* is size of data in bytes.
Output
  CF=0
  RAX= is the total written size including CR+LF.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileWriteRT

    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$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes zero terminated ANSI string(s) to the file previously opened for writing with FileCreate or FileAppend.
  Multiple strings may be written in one macro invocation. The terminating zeros are not written to the file.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr$* are pointers to zero terminated strings to be written.
Output
  CF=0
  RAX= total written size in bytes.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileWriteRT

    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
  is a runtime defining macro used internally by FileEnclose, FileEncloseLn, FileEnclose$.
Depends on
  FileCreate, FileClose

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data at the end of existing file or creates a new one and then closes the file.
  Multiple data can be appended with one invocation.
  The file should be assigned but not open.
Input
  theFile is pointer to FILE64 object with assigned name,
  DataPtr* is pointer to the data to be written,
  DataSize* is size of the data in bytes.
Output
  CF=0
  RAX= it total written size in bytes.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileEncloseRT
Example
  FileEnclose LogFile,Datum,SIZE#Datum

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data at the end of existing file or creates a new one and then closes the file.
  Multiple data can be appended with one invocation.
  When all data have been written, it appends end-of-line characters CR+LF to the file.
  The file should be assigned but not open.
Input
  theFile is pointer to FILE64 object with assigned name,
  DataPtr* is pointer to the data to be written,
  DataSize* is size of the data in bytes.
Output
  CF=0
  RAX= it total written size in bytes, including CR+LF.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileEncloseRT

    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$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes one or more zero-terminated data strings at the end of existing file or it creates a new one, and then closes the file.
  The file should be assigned but not open.
  Multiple strings can be appended with one invocation. The terminating NULL is not written.
Input
  theFile is pointer to FILE64 object with assigned name,
  DataPtr$* are pointers to zero-terminated ANSI strings. Terminating zeroes are not written to the file.
Output
  CF=0
  RAX= total written size.
Error
  CF=1
  RAX= is errorCode as returned by GetLastError.
Depends on
  FileEncloseRT
Example
  FileEnclose$ LogFile, Time$, =B" Job started"

    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 theFile
  opens an existing file for reading and creates file mapping to memory.
  Content of the file will be available for reading and pointed to with RSI.
  The file must not be assigned with device or empty name.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  RAX= file size,
  RSI= pointer to the memory mapped file contents.
Error
  CF=1
  RSI=0
  RAX= errorCode as returned from GetLastError.

    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 theFile, FileSize
  Macro FileMapCreate will create or rewrite an existing file for writing and create file mapping. Size of the file being created must be specified with FileSize.
  File content may be copied to the mapped memory returned in RDI but not more than FileSize bytes.
  The file must not be assigned with device or empty name.
Input
  theFile is pointer to a FILE64 object.
  FileSize is the size of memory mapped file. It may be omitted when FileMapCreate opens an existing file.
Output
  CF=0
  RAX=FileSize
  RDI= is pointer to the memory mapped file content.
Error
  CF=1
  RDI=0
  RAX= errorCode as returned from GetLastError.

    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 theFile, BufSize=16K
  This macro opens an existing file for reading and allocates memory buffer from OS heap. Buffer will be read from file on the FileStreamRead* request.
Input
  theFile is pointer to a FILE64 object.
  BuffSize= specifies the buffer size.
Output
  CF=0
  RAX= file size.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileOpen

    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 theFile, DataPtr, DataSize
  reads data from the file opened with FileStreamOpen.
Input
  theFile is pointer to a FILE64 object.
  DataPtr points to a memory area allocated by the caller,
  DataSize is amount of bytes to read.
Output
  CF=0
  ZF=0
  RAX= how many bytes was read (may be less the DataSize).
End of file
  CF=0
  ZF=1
  RAX= 0 when there are no more bytes in the file (EOF).
error
  CF=1
  RAX= errorCode as returned from GetLastError.

    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 theFile
  reads one physical line from the file opened with FileStreamOpen.
  Line is always terminated with LF character (except for the last line in the file).
  Size of any line in file should not exceed the size of buffer allocated with FileStreamOpen. Longer lines will be read per partes.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  ZF=0
  RAX= line size (never bigger than the FILE64.BufSize)
  RSI= pointer to the line in buffer.
End of file
  CF=0
  ZF=1
  RAX=0 when there are no more data in file (EOF).
error
  CF=1
  RAX= errorCode as returned from GetLastError.

    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 theFile
  reads one byte from the file opened with FileStreamOpen.
Input
  theFile is pointer to a FILE64 object.
Output
  CF=0
  ZF=0
  AL= the byte read from file. Upper 7 bytes in RAX are preserved.
End of file
  CF=0
  ZF=1
  AL=0 when there are no more bytes in the file (EOF).
Error
  CF=1
  RAX= errorCode as returned from GetLastError.

    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 theFile, BufSize=16K
  This macro creates a new file or rewrites an existing file for writing and allocates memory buffer from OS heap. The buffer will be automatically written to file every time it is completely filled with FileStreamWrite*.
Input
  theFile is pointer to a FILE64 object,
  BuffSize= specifies the buffer size.
Output
  CF=0
  RAX=0 (size of just rewritten file).
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileCreate

    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 theFile, BufSize=16K
  This macro creates a new file or rewrites an existing file for writing at its end and allocates memory buffer from heap. Buffer will be written to file every time it is completely filled with FileStreamWrite*.
Input
  theFile is pointer to a FILE64 object,
  BuffSize= specifies the buffer size.
Output
  CF=0
  RAX= is the old file size.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  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 theFile
  This macro writes one byte from AL to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE64 object,
  AL contains the data byte to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  EAX= errorCode as returned from GetLastError.
Depends on
  FileFlush

    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 theFile
  This macro writes one word from AX to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE64 object,
  AX contains the data word to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileFlush

    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 theFile
  This macro writes one doubleword from EAX to the file opened with FileStreamCreate or FileStreamAppend.
Input
  theFile is pointer to a FILE64 object,
  EAX contains the data word to write.
Output
  CF=0, registers unchanged.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileFlush

    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
  is a runtime defining macro used internally by FileStreamWrite*.
  Macro returns CF=0, RAX=total written size, or CF=error
Depends on
  FileFlush

    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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple data portions may be written in one macro invocation.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr* is pointer to the data to be written,
  DataSize* is the size of the data in bytes to be written. It may be bigger than the buffer size specified at opening the file.
Output
  CF=0
  RAX= Total written size in bytes.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  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 theFile, DataPtr1, DataSize1, DataPtr2, DataSize2,,,
  This macro writes data to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple data portions may be written in one macro invocation. End of line CR+LF characters are written in the end.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr* is pointer to the data to be written,
  DataSize* is the size of the data to be written, including the CR+LF. It may be bigger than the buffer size specified on opening the file.
Output
  CF=0
  RAX= total written size including CR+LF.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileStreamWriteRT

    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$ theFile, DataPtr$1, DataPtr$2,,,
  This macro writes zero terminated ANSI string(s) to the file previously opened with FileStreamCreate or FileStreamAppend.
  Multiple ASCIIZ strings may be written in one macro invocation. The terminating zeros are not written to the file.
Input
  theFile is pointer to an open FILE64 object,
  DataPtr$* are pointers to the zero terminated strings to be written.
Output
  CF=0
  RAX= total written size.
Error
  CF=1
  RAX= errorCode as returned from GetLastError.
Depends on
  FileStreamWriteRT

    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

▲Back to the top▲