This macrolibrary implements file access which encapsulates WinAPI calls for most typical file operations in 32bit Windows.
File Access method | Open | Data transfer | Close |
---|---|---|---|
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 |
read file at once | - | FileLoad | FileClose |
write file at once | - | FileStore | - |
append to file | - | FileEnclose, FileEncloseLn, FileEnclose$ | - |
special functions | FileReset | FileNameParse, FileAssign, FileMove, FileExists?, FileMkDir, FileEach | FileDelete |
Macros return the results in registers, usually EAX. 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. When CF=1, EAX returns the error code as obtained from GetLastError().
Association of the FILE 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 after the data. Macro names suffixed with ~$ write NULL character after the data.
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.
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 WinAPI functions ReadFile/WriteFile and they can process files of any size. Example:
Memory mapped file access allocates memory and the entire file contents is virtually loaded to memory. File shouldn't be bigger than the available virtual memory (physical memory plus swap size). Memory mapped files are shared globally in OS and they can be used for interprocess communication.
Buffered (streamed) 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:
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.
winfile HEAD INCLUDEHEAD1 winsfile.htm, winapi.htm, status32.htm, cpuext.htm
FILE STRUC .Ptr DD 0 ; Pointer to the file content in memory-mapped|buffered data. .Top DD 0 ; Pointer to the end of the memory-mapped|buffered data. .BufPtr DD 0 ; Pointer to the memory-map|allocated buffer. .BufSize DD 0 ; Size of memory map|buffer. .Pos DD 0 ; Zero based offset of the file position. .Size DD 0 ; File size in bytes. .Handle DD -1 ; Handle to open file. .MapHandle DD -1 ; Handle to file mapping. .Status DD 0 ; File status flags, see FileStatusEnc. .NameOffs DD 0 ; Offset of the filename without path inside the .Name. Zero if no path in .Name. .ExtOffs DD 0 ; Offset of the file extension inside the .Name. .Name D MAX_PATH_SIZE * U ; Zero terminated WIDE|ANSI file name. ENDSTRUC FILE
FILE.Status
.fileFound EQU 0x00000010 ; File was once succesfully opened. fileStAppend EQU 0x00100000 ; Created file should move its pointer to the end. fileStStdIO EQU 0x00200000 ; FILE.Handle is standard input|output. fileStAllocated EQU 0x00400000 ; FILE.BufPtr is pointer to the allocated memory. fileStUnicode EQU 0x00800000 ; FILE.Name is in WIDE characters. fileStMapCreated EQU 0x01000000 ; FILE.MapHandle is valid for writing. fileStMapOpened EQU 0x02000000 ; FILE.MapHandle is valid for reading. fileStMapped EQU 0x04000000 ; FILE.Ptr is pointer to the mapped memory. fileStCreated EQU 0x10000000 ; FILE.Handle is valid for writing. fileStOpened EQU 0x20000000 ; FILE.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 PUSHD %Size,%FileNamePtr %IF %Unicode CALL FileNameParseW@RT:: FileNameParseW@RT:: PROC1 PUSHAD MOV EBP,ESP MOV ESI,[%Param1] ; %FileNamePtr. MOV EDX,[%Param2] ; %Size. SUB ECX,ECX TEST EDX JS .UnlimitedSize: ADD EDX,ESI ; End of input string. .UnlimitedSize: MOV [%ReturnEAX],ECX MOV [%ReturnECX],ECX MOV [%ReturnEDX],ECX .NextChar: CMP ESI,EDX JNB .E0: LODSW Dispatch AX,58,92,47,46,0 ; colon, backslash, slash, dot, NULL ; Ordinary character. LEA EAX,[ESI-2] CMP [%ReturnEAX],ECX JNZ .NextChar: MOV [%ReturnEAX],EAX JMP .NextChar: .46: ; dot . LEA EAX,[ESI-2] MOV [%ReturnECX],EAX CMP [%ReturnEAX],ECX JNE .NextChar: MOV [%ReturnEAX],EAX JMP .NextChar: .47: ; Colon, slash, backslash. .58: .92: MOV [%ReturnEAX],ESI MOV [%ReturnECX],ECX JMP .NextChar: .0: DEC ESI ; Unichar NULL. DEC ESI .E0:MOV [%ReturnEDX],ESI CMP [%ReturnECX],ECX JNE .E1: MOV [%ReturnECX],ESI .E1:CMP [%ReturnEAX],ECX JNE .E2: MOV EAX,[%ReturnECX] MOV [%ReturnEAX],EAX .E2:POPAD RET 8 ENDPROC1 FileNameParseW@RT:: %ELSE ; ANSI variant. CALL FileNameParseA@RT:: FileNameParseA@RT:: PROC1 PUSHAD MOV EBP,ESP MOV ESI,[%Param1] ; %FileNamePtr. MOV EDX,[%Param2] ; %Size. SUB ECX,ECX TEST EDX JS .UnlimitedSize: ADD EDX,ESI ; End of input string. .UnlimitedSize: MOV [%ReturnEAX],ECX MOV [%ReturnECX],ECX MOV [%ReturnEDX],ECX .NextChar: CMP ESI,EDX JNB .E0: LODSB Dispatch AL,58,92,47,46,0 ; colon, backslash, slash, dot, NULL. ; Ordinary character LEA EAX,[ESI-1] CMP [%ReturnEAX],ECX JNZ .NextChar: MOV [%ReturnEAX],EAX JMP .NextChar: .46: ; dot . LEA EAX,[ESI-1] MOV [%ReturnECX],EAX CMP [%ReturnEAX],ECX JNE .NextChar: MOV [%ReturnEAX],EAX JMP .NextChar: .47: ; colon, slash, backslash .58: .92: MOV [%ReturnEAX],ESI MOV [%ReturnECX],ECX JMP .NextChar: .0: DEC ESI ; Byte NULL. .E0:MOV [%ReturnEDX],ESI CMP [%ReturnECX],ECX JNE .E1: MOV [%ReturnECX],ESI .E1:CMP [%ReturnEAX],ECX JNE .E2: MOV EAX,[%ReturnECX] MOV [%ReturnEAX],EAX .E2:POPAD RET 8 ENDPROC1 FileNameParseA@RT:: %ENDIF ; %Unicode %ENDMACRO FileNameParse
theFile.Name
member.
EUROASM UNICODE=
option at macro invocation,
but you may want to set this parameter to 0 even if UNICODE is globally enabled, and vice versa..Name, .NameOffs, .ExtOffs, .Status:fileStUnicode
of theFile
are set.SIZE# FILE.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 PUSHD 0 ; Mark the end of arguments. ArgNr %FOR %#..2,STEP=-1 PUSHD %*{%ArgNr} %ENDFOR ArgNr PUSHD %Size, %theFile, ESP ADDD [ESP],4*(%#+2) %IF %Unicode CALL FileAssignW@RT:: FileAssignW@RT:: PROC1 ; Wide variant. PUSHAD MOV EBX,[ESP+40] ; %theFile LEA EBP,[ESP+48] ; %Name$1 LEA EDI,[EBX+FILE.Name] SetSt [EBX+FILE.Status],fileStUnicode LEA EDX,[EDI+MAX_PATH_SIZE-2] .10:XCHG EBP,ESI LODSD ; Offset of source string. MOV EBP,EAX XCHG ESI,EBP TEST EAX ; No more macro arguments (zero marker)? JZ .50: MOV ECX,[ESP+44] ; %Size. SAR ECX,1 ; Size in unichars. .20:LODSW CMP AX,0 JE .10: CMP EDI,EDX JNB .40: STOSW LOOP .20: JMP .10: .40:SUB EAX,EAX STC ; Overflow. .50:MOV ECX,EDI STOSW LEA EDX,[EBX+FILE.Name] PUSHFD SUB ECX,EDX FileNameParse EDX,Size=ECX,Unicode=1 LEA EDX,[EBX+FILE.Name] SUB EAX,EDX SUB ECX,EDX MOV [EBX+FILE.NameOffs],EAX MOV [EBX+FILE.ExtOffs],ECX POPFD POPAD RET ENDPROC1 FileAssignW@RT:: %ELSE ; ANSI. CALL FileAssignA@RT:: FileAssignA@RT:: PROC1 ; ANSI variant. PUSHAD MOV EBX,[ESP+40] ; %theFile LEA EBP,[ESP+48] ; %Name$1 LEA EDI,[EBX+FILE.Name] RstSt [EBX+FILE.Status],fileStUnicode LEA EDX,[EDI+MAX_PATH_SIZE] .10:XCHG EBP,ESI LODSD ; Offset of source string. MOV EBP,EAX XCHG ESI,EBP TEST EAX JZ .50: MOV ECX,[ESP+44] ; %Size. .20:LODSB CMP AL,0 JE .10: CMP EDI,EDX JNB .40: STOSB LOOP .20: JMP .10: .40:SUB EAX,EAX STC ; Overflow. .50:MOV ECX,EDI STOSB LEA EDX,[EBX+FILE.Name] PUSHFD SUB ECX,EDX FileNameParse EDX,Size=ECX,Unicode=0 LEA EDX,[EBX+FILE.Name] SUB EAX,EDX SUB ECX,EDX MOV [EBX+FILE.NameOffs],EAX MOV [EBX+FILE.ExtOffs],ECX POPFD POPAD RET ENDPROC1 FileAssignA@RT:: %ENDIF POP ESP %ENDMACRO FileAssign
* ?
are allowed in the file name.
FileExists? %MACRO theFile PUSHD %theFile CALL FileExists?@RT:: FileExists?@RT:: PROC1 IMPORT FindFirstFileA,FindFirstFileW PUSHAD MOV EBP,ESP MOV EBX,[EBP+36] ; theFile LEA ESI,[EBX+FILE.Name] SUB ESP,SIZE# WIN32_FIND_DATAW MOV EDI,ESP MOV EAX,FindFirstFileW:: ; WinAPI function thunk. JSt [EBX+FILE.Status],fileStUnicode,.20 MOV EAX,FindFirstFileA:: ; WinAPI function thunk. .20:WinAPI EAX,ESI,EDI ; FindFirstFile. .30:CMP EAX,INVALID_HANDLE_VALUE STC JE .90 WinAPI FindClose,EAX TEST [EDI+WIN32_FIND_DATAW.FileAttributes],FILE_ATTRIBUTE_DIRECTORY .90:MOV ESP,EBP POPAD RET 4 ENDPROC1 FileExists?@RT:: %ENDMACRO FileExists?
FileMkDir %MACRO theFile PUSHD %theFile CALL FileMkDir@RT:: FileMkDir@RT:: PROC1 PUSHAD MOV EBP,ESP SUB ESP,SIZE#WIN32_FIND_DATAW + 4 %FileMkDirEntry %SET EBP-4 MOV [%FileMkDirEntry],ESP,DATA=DWORD SUB ESP,2*MAX_PATH_SIZE MOV EBX,[EBP+36] ; %theFile MOV EDI,ESP ; directory name copy LEA ESI,[EBX+FILE.Name] MOV CX,'\' MOVW [ESI+SIZE#FILE.Name-2],0 JSt [EBX+FILE.Status],fileStUnicode,.50: ; ANSI variant. LODSB CMP AL,0 JE .95: CMP AL,CL JNE .30: CMP [ESI],CL JNE .30: STOSB ; \\server\share\dir\file LODSB .10:STOSB LODSB CMP AL,0 JE .95: CMP AL,CL JNE .10: .20:STOSB LODSB CMP AL,0 JE .95: CMP AL,CL JNE .20: .30:STOSB LODSB CMP AL,0 JE .95: CMP AL,CL JNE .30: CMPB [EDI-1],':' ; D:\dir\file JE .30: SUB EAX,EAX STOSB ; Temporary terminate folder name. MOV EAX,ESP WinAPI FindFirstFileA,EAX,[%FileMkDirEntry] CMP EAX,INVALID_HANDLE_VALUE JE .35: WinAPI FindClose,EAX MOV EDX,[%FileMkDirEntry] JSt [EDX+WIN32_FIND_DATAW.FileAttributes],FILE_ATTRIBUTE_DIRECTORY,.40: .35:MOV EAX,ESP WinAPI CreateDirectoryA,EAX,0 TEST EAX JNZ .40: WinAPI GetLastError STC JMP .99: .40:DEC EDI ; Remove temporary zero-termination. MOV AL,'\' MOV ECX,EAX JMP .30: .50: ; WIDE variant. LODSW CMP AX,0 JE .95: CMP AX,CX JNE .80: CMP [ESI],CX JNE .80: STOSW ; \\server\share\dir\file LODSW .60:STOSW LODSW CMP AX,0 JE .95: CMP AX,CX JNE .60: .70:STOSW LODSW CMP AX,0 JE .95: CMP AX,CX JNE .70: .80:STOSW LODSW CMP AX,0 JE .95: CMP AX,CX JNE .80: CMPW [EDI-2],':' ; D:\dir\file JE .80: SUB EAX,EAX STOSW ; Temporary terminate folder name. MOV EAX,ESP WinAPI FindFirstFileW,EAX,[%FileMkDirEntry] CMP EAX,INVALID_HANDLE_VALUE JE .85: WinAPI FindClose,EAX MOV EDX,[%FileMkDirEntry] JSt [EDX+WIN32_FIND_DATAW.FileAttributes],FILE_ATTRIBUTE_DIRECTORY,.90: .85:MOV EAX,ESP WinAPI CreateDirectoryW,EAX,0 TEST EAX JNZ .90: WinAPI GetLastError STC JMP .99: .90:DEC EDI ; Remove temporary zero-termination. DEC EDI MOV AX,'\' MOV ECX,EAX JMP .80: .95:SUB EAX,EAX .99:MOV [%ReturnEAX],EAX MOV ESP,EBP POPAD RET 4 ENDPROC1 FileMkDir@RT:: %ENDMACRO FileMkDir
FILE.Name
is replaced
with the file found in directory. The file is not open.
WinAPI FindClose,EDX
before terminating.
FileEach %MACRO theFile, CallbackProc PUSHD %CallbackProc, %theFile CALL FileEach@RT:: FileEach@RT: PROC1 IMPORT FindFirstFileA,FindFirstFileW,FindNextFileA,FindNextFileW PUSHAD MOV EBP,ESP SUB ESP,SIZE#WIN32_FIND_DATAW + 8 %FileEachSearchRec %SET EBP-SIZE#WIN32_FIND_DATAW %FileEachFindHandle %SET EBP-SIZE#WIN32_FIND_DATAW-4 %FileEachNamePtr %SET EBP-SIZE#WIN32_FIND_DATAW-8 MOV EBX,[%Param1] MOVD [%ReturnEAX],0 LEA ESI,[%FileEachSearchRec] LEA ECX,[EBX+FILE.Name] MOV EAX,FindFirstFileW:: JSt [EBX+FILE.Status],fileStUnicode,.20: MOV EAX,FindFirstFileA:: .20: WinAPI EAX,ECX,ESI ; FindFirstFile. MOV [%FileEachFindHandle],EAX CMP EAX,INVALID_HANDLE_VALUE JE .90: .30: LEA EDI,[EBX+FILE.Name] LEA ESI,[EDI+MAX_PATH_SIZE] JSt [EBX+FILE.Status],fileStUnicode,.50: FileNameParse EDI,Size=MAX_PATH_SIZE,Unicode=0 SUB ESI,EAX MOV ECX,ESI JNA .70: MOV EDI,EAX LEA ESI,[%FileEachSearchRec] MOV [%FileEachNamePtr],EAX LEA ESI,[ESI+WIN32_FIND_DATAA.FileName] .40: LODSB STOSB CMP AL,0 LOOPNE .40: LEA EDI,[EBX+FILE.Name] FileNameParse EDI,Size=MAX_PATH_SIZE,Unicode=0 SUB EAX,EDI MOV [EBX+FILE.NameOffs],EAX SUB ECX,EDI MOV [EBX+FILE.ExtOffs],ECX JMP .70: .50: LEA ESI,[EDI+2*MAX_PATH_SIZE] FileNameParse EDI,Size=2*MAX_PATH_SIZE,Unicode=1 SUB ESI,EAX MOV ECX,ESI JNA .70: MOV EDI,EAX LEA ESI,[%FileEachSearchRec] MOV [%FileEachNamePtr],EAX LEA ESI,[ESI+WIN32_FIND_DATAW.FileName] .60: LODSW STOSW CMP AX,0 LOOPNE .60: LEA EDI,[EBX+FILE.Name] FileNameParse EDI,Size=2*MAX_PATH_SIZE,Unicode=1 SUB EAX,EDI MOV [EBX+FILE.NameOffs],EAX SUB ECX,EDI MOV [EBX+FILE.ExtOffs],ECX .70: LEA EDI,[%FileEachSearchRec] MOV ESI,[%FileEachNamePtr] MOV EDX,[%FileEachFindHandle] MOV EBX,[%Param1] MOV EAX,[%Param2] PUSH EBP MOV EBP,[%ReturnEBP] CALL EAX ; CallbackProc POP EBP MOV [%ReturnEAX],EAX MOV EDI,[%FileEachFindHandle] JC .90: ; CF from CallbackProc MOV EBX,[%Param1] MOV EAX,FindNextFileW:: JSt [EBX+FILE.Status],fileStUnicode,.80: MOV EAX,FindNextFileA:: .80: LEA ESI,[%FileEachSearchRec] WinAPI EAX,EDI,ESI ; FindNextFile TEST EAX JNZ .30: .90: WinAPI FindClose,[%FileEachFindHandle] MOV ESP,EBP POPAD RET 8 ENDPROC1 FileEach@RT: %ENDMACRO FileEach
FileLoad %MACRO theFile PUSHD %theFile CALL FileLoad@RT:: FileLoad@RT:: PROC1 IMPORT CreateFileA,CreateFileW PUSHAD MOV EBP,ESP MOV EBX,[%Param1] LEA EDX,[EBX+FILE.Name] SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI MOV [EBX+FILE.BufPtr],ESI MOV [EBX+FILE.BufSize],ESI MOV [EBX+FILE.Pos],ESI MOV [EBX+FILE.Size],ESI MOV EAX,CreateFileW:: JSt [EBX+FILE.Status],fileStUnicode,.10: MOV EAX,CreateFileA:: .10:WinAPI EAX,EDX,GENERIC_READ,FILE_SHARE_READ,ESI, \ OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,ESI MOV [EBX+FILE.Handle],EAX CMP EAX,EDI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStOpened WinAPI GetFileSize,EAX,ESI CMP EAX,EDI JE .EndWithLastError: MOV [EBX+FILE.Size],EAX MOV [EBX+FILE.Top],EAX MOV [EBX+FILE.BufSize],EAX MOV [%ReturnEAX],EAX WinAPI GlobalAlloc,GMEM_FIXED,EAX MOV [EBX+FILE.Ptr],EAX ADD [EBX+FILE.Top],EAX MOV [EBX+FILE.BufPtr],EAX CMP EAX,ESI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStAllocated MOV [%ReturnESI],EAX PUSH ECX MOV ECX,ESP WinAPI ReadFile,[EBX+FILE.Handle],EAX,[EBX+FILE.Size],ECX,ESI POP ECX ADD [EBX+FILE.Pos],ECX TEST EAX JZ .EndWithLastError: MOV EAX,[EBX+FILE.Size] CMP EAX,ECX JE .EndWithEAX MOV EAX,0xE0070026 JMP .ErrorEAX .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC .EndWithEAX: MOV [%ReturnEAX],EAX PUSHFD JNSt [EBX+FILE.Status],fileStOpened,.90: WinAPI CloseHandle,[EBX+FILE.Handle] .90: RstSt [EBX+FILE.Status],fileStOpened MOV [EBX+FILE.Handle],EDI POPFD POPAD RET 4 ENDPROC1 FileLoad@RT:: %ENDMACRO FileLoad
FileStore %MACRO theFile,DataPtr,DataSize PUSHD %DataSize,%DataPtr,%theFile CALL FileStore@RT:: FileStore@RT:: PROC1 IMPORT CreateFileA,CreateFileW PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV EAX,[%Param2] MOV ECX,[%Param3] MOV [EBX+FILE.Ptr],EAX MOV [EBX+FILE.Top],EAX MOV [EBX+FILE.Size],ECX ADD [EBX+FILE.Top],ECX MOV [%ReturnEAX],ECX SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE MOV [EBX+FILE.Pos],ESI LEA EDX,[EBX+FILE.Name] MOV EAX,CreateFileW:: JSt [EBX+FILE.Status],fileStUnicode,.10: MOV EAX,CreateFileA:: .10:WinAPI EAX,EDX,GENERIC_WRITE,FILE_SHARE_READ,ESI, \ CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,ESI MOV [EBX+FILE.Handle],EAX CMP EAX,EDI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStCreated PUSH ECX MOV ECX,ESP WinAPI WriteFile,EAX,[EBX+FILE.Ptr],[EBX+FILE.Size],ECX,ESI POP ECX ADD [EBX+FILE.Pos],ECX TEST EAX JZ .EndWithLastError: MOV EAX,[EBX+FILE.Size] CMP EAX,ECX JE .EndWithEAX MOV EAX,0xE0070000 + 39 ; "The disk is full." JMP .ErrorEAX .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC .EndWithEAX: MOV [%ReturnEAX],EAX PUSHFD JNSt [EBX+FILE.Status],fileStCreated,.90: WinAPI CloseHandle,[EBX+FILE.Handle] .90: RstSt [EBX+FILE.Status],fileStCreated MOV [EBX+FILE.Handle],EDI POPFD POPAD RET 12 ENDPROC1 FileStore@RT:: %ENDMACRO FileStore
FileEncloseRT %MACRO ; Common RT procedure declaration for macros FileEnclose* FileEnclose@RT: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[ESP+40] ; theFile SetSt [EBX+FILE.Status],fileStAppend FileCreate EBX JC .ErrorEAX: LEA ESI,[ESP+44] ; Pointer to 1st string pointer. SUB EDI,EDI MOV [ESP+28],EDI ; %ReturnEAX. .10: LODSD ; DataPtr. MOV EDX,EAX TEST EAX JZ .90 ; End of data. LODSD ; DataSize. MOV ECX,EAX PUSH EBP PUSH EBP ; Make room for written size. MOV EBP,ESP WinAPI WriteFile,[EBX+FILE.Handle],EDX,ECX,EBP,EDI POP EBP ; Written size. ADD [ESP+32],EBP ; %ReturnEAX. ADD [EBX+FILE.Pos],EBP ADD [EBX+FILE.Size],EBP POP EBP ; Restore frame. TEST EAX ; WriteFile result. JNZ .10: ; If OK, write the next Data. WinAPI GetLastError .ErrorEAX: STC MOV [ESP+28],EAX ; %ReturnEAX. .90: PUSHFD FileClose EBX POPFD POPAD RET FileEnclose$size@RT: ; Subprocedure for zero-terminated strings. PUSH EAX,ECX,EDI SUB ECX,ECX SUB EAX,EAX DEC ECX MOV EDI,[ESP+16] ; DataPtr. REPNE SCASB SUB EAX,ECX SUB EAX,2 MOV [ESP+20],EAX ; DataSize. POP EDI,ECX,EAX RET ENDPROC1 FileEnclose@RT: %ENDMACRO FileEncloseRT
FileEnclose %MACRO theFile,DataPtr,DataSize,,,, %IF %# & 1 = 0 %ERROR ID=5942, 'Macro "FileEnclose" expects odd number of arguments.' %EXITMACRO FileEnclose %ENDIF PUSHD 0 ; Mark the end of arguments. ArgNr %FOR %#..2,STEP=-2 PUSHD %*{%ArgNr}, %*{%ArgNr-1} %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],4*(%#+1) CALL FileEnclose@RT POP ESP 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 PUSHD 0x00000A0D ; CR+LF PUSHD 0 ; Mark the end of arguments. PUSHD 2 ; Size of CR+LF. PUSHD ESP ADDD [ESP],8 ; Pointer to CR+LF. ArgNr %FOR %#..2,STEP=-2 PUSHD %*{%ArgNr}, %*{%ArgNr-1} %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],4*(%#+4) CALL FileEnclose@RT POP ESP FileEncloseRT ; Invoke the common runtime macro. %ENDMACRO FileEncloseLn
FileEnclose$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,, PUSHD 0 ; Mark the end of arguments. ArgNr %FOR %#..2,STEP=-1 PUSHD EAX,%*{%ArgNr} CALL FileEnclose$size@RT ; Using subprocedure in FileEncloseRT get datasize to EAX. %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],8 * %# CALL FileEnclose@RT POP ESP FileEncloseRT ; Invoke the common runtime macro. %ENDMACRO FileEnclose$
FileOpen %MACRO theFile PUSHD %theFile CALL FileOpen@RT:: FileOpen@RT:: PROC1 IMPORT CreateFileA,CreateFileW PUSHAD MOV EBP,ESP MOV EBX,[%Param1] LEA EDX,[EBX+FILE.Name] SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE MOV [EBX+FILE.Size],ESI MOV [EBX+FILE.Pos],ESI MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI RstSt [EBX+FILE.Status],fileStStdIO MOV EAX,CreateFileW:: JSt [EBX+FILE.Status],fileStUnicode,.30: MOV EAX,CreateFileA:: CMPB [EDX],0 JNE .40: .20:SetSt [EBX+FILE.Status],fileStStdIO WinAPI GetStdHandle,STD_INPUT_HANDLE JMP .50: .30:CMPW [EDX],0 JE .20: .40:WinAPI EAX,EDX,GENERIC_READ,FILE_SHARE_READ,ESI, \ OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,ESI .50:MOV [EBX+FILE.Handle],EAX CMP EAX,EDI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStOpened+fileFound MOV ECX,EAX SUB EAX,EAX JSt [EBX+FILE.Status],fileStStdIO,.EndWithEAX: WinAPI GetFileSize,ECX,ESI CMP EAX,EDI JE .EndWithLastError: MOV [EBX+FILE.Size],EAX CLC JMP .EndWithEAX .EndWithLastError: WinAPI GetLastError STC .EndWithEAX: MOV [%ReturnEAX],EAX POPAD RET 4 ENDPROC1 FileOpen@RT:: %ENDMACRO FileOpen
FileReset %MACRO theFile, Position %IF "%Position" === "" PUSHD 0 %ELSE PUSHD %Position %ENDIF PUSHD %theFile CALL FileReset@RT:: FileReset@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV EDI,[%Param2] MOV EAX,0xE0070004 ; File is not opened. MOV [%ReturnEAX],EDI JNSt [EBX+FILE.Status],fileStOpened,.ErrorEAX: WinAPI SetFilePointer,[EBX+FILE.Handle],EDI,0,FILE_BEGIN INC EAX JZ .EndWithLastError: MOV [EBX+FILE.Pos],EDI MOV EAX,[EBX+FILE.BufPtr] MOV [EBX+FILE.Ptr],EAX JSt [EBX+FILE.Status],fileStMapOpened,.30: MOV [EBX+FILE.Top],EAX JMPS .90: .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC MOV [%ReturnEAX],EAX JMPS .90: .30: ADD [EBX+FILE.Ptr],EDI .90:POPAD RET 8 ENDPROC1 FileReset@RT:: %ENDMACRO FileReset
FileRead %MACRO theFile,DataPtr,DataSize PUSHD %DataSize,%DataPtr,%theFile CALL FileRead@RT:: FileRead@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV EAX,0xE0070004 ; File is not open. JNSt [EBX+FILE.Status],fileStOpened,.ErrorEAX: PUSH ECX MOV ECX,ESP WinAPI ReadFile,[EBX+FILE.Handle],[%Param2],[%Param3],ECX,0 POP ECX TEST EAX JZ .EndWithLastError: MOV EAX,ECX ADD [EBX+FILE.Pos],EAX TEST EAX JMP .EndWithEAX .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC .EndWithEAX: MOV [%ReturnEAX],EAX POPAD RET 12 ENDPROC1 FileRead@RT:: %ENDMACRO FileRead
FileCreate %MACRO theFile PUSHD %theFile CALL FileCreate@RT:: FileCreate@RT:: PROC1 IMPORT CreateFileA,CreateFileW PUSHAD MOV EBP,ESP MOV EBX,[%Param1] LEA EDX,[EBX+FILE.Name] SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE MOV [EBX+FILE.Size],ESI MOV [EBX+FILE.Pos],ESI MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI RstSt [EBX+FILE.Status],fileStStdIO MOV EAX,CreateFileW:: JSt [EBX+FILE.Status],fileStUnicode,.30: MOV EAX,CreateFileA:: CMPB [EDX],0 JNE .40: .20:SetSt [EBX+FILE.Status],fileStStdIO WinAPI GetStdHandle,STD_OUTPUT_HANDLE JMP .60: .30:CMPW [EDX],0 JE .20: .40:MOV ECX,OPEN_ALWAYS JSt [EBX+FILE.Status],fileStAppend,.50: MOV ECX,CREATE_ALWAYS MOV ESI,FILE_ATTRIBUTE_NORMAL .50:WinAPI EAX,EDX,GENERIC_WRITE,FILE_SHARE_READ,0,ECX,ESI,0 .60:MOV [EBX+FILE.Handle],EAX CMP EAX,EDI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStCreated MOV ECX,EAX SUB EAX,EAX JSt [EBX+FILE.Status],fileStStdIO,.EndWithEAX: XOR ESI,ESI WinAPI GetFileSize,ECX,ESI CMP EAX,EDI JE .EndWithLastError: MOV [EBX+FILE.Size],EAX JNSt [EBX+FILE.Status],fileStAppend,.EndWithEAX: MOV [EBX+FILE.Pos],EAX WinAPI SetFilePointer,[EBX+FILE.Handle],ESI,ESI,FILE_END CMP EDI,EAX JA .EndWithEAX: .EndWithLastError: WinAPI GetLastError STC .EndWithEAX: MOV [%ReturnEAX],EAX POPAD RET 4 ENDPROC1 FileCreate@RT:: %ENDMACRO FileCreate
FileAppend %MACRO theFile PUSHD %theFile CALL FileAppend@RT:: FileAppend@RT:: PROC1 PUSH EBX MOV EBX,[ESP+8] ; theFile SetSt [EBX+FILE.Status],fileStAppend FileCreate EBX POP EBX RET 4 ENDPROC1 FileAppend@RT:: %ENDMACRO FileAppend
FileWriteRT %MACRO ; Common runtime procedure declaration for macros FileWrite* FileWrite@RT: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[ESP+40] ; theFile LEA ESI,[ESP+44] ; 1st string ptr. MOV EAX,0xE0070004 ; File is not opened. JNSt [EBX+FILE.Status],fileStCreated, .ErrorEAX: SUB EDI,EDI MOV [ESP+28],EDI ; %Return EAX. .10: LODSD ; DataPtr MOV EDX,EAX TEST EAX JZ .90 ; End of data. LODSD ; DataSize. MOV ECX,EAX PUSH EBP,EBP MOV EBP,ESP WinAPI WriteFile,[EBX+FILE.Handle],EDX,ECX,EBP,EDI POP EBP ; written size ADD [ESP+32],EBP ; %ReturnEAX ADD [EBX+FILE.Pos],EBP ADD [EBX+FILE.Size],EBP POP EBP TEST EAX JNZ .10: WinAPI GetLastError .ErrorEAX: STC MOV [%ReturnEAX],EAX .90:POPAD RET FileWrite$size@RT: PUSH ECX,EDI SUB ECX,ECX SUB EAX,EAX DEC ECX MOV EDI,[ESP+12] ; DataPtr REPNE SCASB SUB EAX,ECX SUB EAX,2 MOV [ESP+16],EAX ; DataSize POP EDI,ECX RET ENDPROC1 FileWrite@RT: %ENDMACRO FileWriteRT
FileWrite %MACRO theFile,DataPtr,DataSize,,,, %IF %# & 1 = 0 %ERROR ID=5944, 'Macro "FileWrite" expects odd number of arguments.' %EXITMACRO FileWrite %ENDIF PUSHD 0 ; Mark the end of arguments. ArgNr %FOR %#..2,STEP=-2 PUSHD %*{%ArgNr}, %*{%ArgNr-1} %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],4*(%#+1) CALL FileWrite@RT POP ESP 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 PUSHD 0x00000A0D ; CR+LF. PUSHD 0 ; Mark the end of arguments. PUSHD 2 ; Size of CR+LF. PUSHD ESP ADDD [ESP],8 ; Pointer to CR+LF. ArgNr %FOR %#..2,STEP=-2 PUSHD %*{%ArgNr}, %*{%ArgNr-1} %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],4*(%#+4) CALL FileWrite@RT POP ESP FileWriteRT ; Invoke the common runtime macro. %ENDMACRO FileWriteLn
FileWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,, PUSHD 0 ; Mark the end of arguments ArgNr %FOR %#..2,STEP=-1 PUSHD EAX,%*{%ArgNr} CALL FileWrite$size@RT %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],8*%# CALL FileWrite@RT POP ESP FileWriteRT %ENDMACRO FileWrite$
FileMapOpen %MACRO theFile PUSHD %theFile CALL FileMapOpen@RT:: FileMapOpen@RT:: PROC1 IMPORT CreateFileA,CreateFileW,CreateFileMappingA,CreateFileMappingW PUSHAD MOV EBP,ESP MOV EBX,[%Param1] LEA EDX,[EBX+FILE.Name] SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI MOV [EBX+FILE.BufPtr],ESI MOV [EBX+FILE.BufSize],ESI MOV [EBX+FILE.Size],ESI MOV [EBX+FILE.Pos],ESI MOV [EBX+FILE.Handle],EDI MOV [%ReturnESI],ESI MOV EAX,CreateFileW:: JSt [EBX+FILE.Status],fileStUnicode,.30: MOV EAX,CreateFileA:: CMPB [EDX],0 JNE .40: .20: MOV EAX,0xC0070000+123 ; "The file name is incorrect." JMP .ErrorEAX: .30: CMPW [EDX],0 JE .20: .40: WinAPI EAX,EDX,GENERIC_READ,FILE_SHARE_READ,ESI, \ OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,ESI MOV [EBX+FILE.Handle],EAX CMP EAX,EDI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStOpened+fileFound WinAPI GetFileSize,EAX,ESI CMP EAX,EDI JE .EndWithLastError: MOV [EBX+FILE.Size],EAX MOV [EBX+FILE.BufSize],EAX MOV [EBX+FILE.Top],EAX MOV [%ReturnEAX],EAX MOV EAX,CreateFileMappingW:: JSt [EBX+FILE.Status],fileStUnicode,.50: MOV EAX,CreateFileMappingA:: .50: WinAPI EAX,[EBX+FILE.Handle],ESI,PAGE_READONLY,ESI,ESI,ESI MOV [EBX+FILE.MapHandle],EAX TEST EAX JZ .EndWithLastError: SetSt [EBX+FILE.Status],fileStMapOpened WinAPI MapViewOfFile,EAX,FILE_MAP_READ,ESI,ESI,ESI MOV [EBX+FILE.Ptr],EAX MOV [%ReturnESI],EAX ADD [EBX+FILE.Top],EAX MOV [EBX+FILE.BufPtr],EAX TEST EAX JZ .EndWithLastError: SetSt [EBX+FILE.Status],fileStMapped JMP .End: .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC MOV [%ReturnEAX],EAX .End: POPAD RET 4 ENDPROC1 FileMapOpen@RT:: %ENDMACRO FileMapOpen
FileMapCreate %MACRO theFile,FileSize %IF %# > 1 PUSHD %FileSize %ELSE PUSHD 0 %ENDIF PUSHD %theFile CALL FileMapCreate@RT:: FileMapCreate@RT:: PROC1 IMPORT CreateFileA,CreateFileW,CreateFileMappingA,CreateFileMappingW PUSHAD MOV EBP,ESP MOV EBX,[%Param1] LEA EDX,[EBX+FILE.Name] SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE MOV [%ReturnEDI],ESI RstSt [EBX+FILE.Status],fileStAppend MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI MOV [EBX+FILE.BufPtr],ESI MOV [EBX+FILE.BufSize],ESI MOV [EBX+FILE.Size],ESI MOV [EBX+FILE.Pos],ESI MOV [EBX+FILE.Handle],EDI MOV EAX,CreateFileW:: JSt [EBX+FILE.Status],fileStUnicode,.30: MOV EAX,CreateFileA:: CMPB [EDX],0 JNE .40: .20: MOV EAX,0xC0070000+123 ; "Error: The file name is incorrect." JMP .ErrorEAX: .30: CMPW [EDX],0 JE .20: .40: WinAPI EAX,EDX,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, \ ESI,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,ESI MOV [EBX+FILE.Handle],EAX CMP EAX,EDI JE .EndWithLastError: SetSt [EBX+FILE.Status],fileStCreated MOV ECX,[%Param2] TEST ECX JNZ .45: WinAPI GetFileSize,[EBX+FILE.Handle],ECX MOV ECX,EAX INC EAX JZ .EndWithLastError: .45: MOV [EBX+FILE.Size],ECX MOV [EBX+FILE.BufSize],ECX MOV [EBX+FILE.Top],ECX MOV [%ReturnEAX],ECX MOV EAX,CreateFileMappingW:: JSt [EBX+FILE.Status],fileStUnicode,.50: MOV EAX,CreateFileMappingA:: .50: WinAPI EAX,[EBX+FILE.Handle],ESI,PAGE_READWRITE,ESI,ECX,ESI MOV [EBX+FILE.MapHandle],EAX TEST EAX JZ .EndWithLastError: SetSt [EBX+FILE.Status],fileStMapCreated WinAPI MapViewOfFile,EAX,FILE_MAP_WRITE,ESI,ESI,ESI MOV [EBX+FILE.Ptr],EAX ADD [EBX+FILE.Top],EAX MOV [EBX+FILE.BufPtr],EAX MOV [%ReturnEDI],EAX TEST EAX JZ .EndWithLastError: SetSt [EBX+FILE.Status],fileStMapped JMP .End: .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC MOV [%ReturnEAX],EAX .End: POPAD RET 8 ENDPROC1 FileMapCreate@RT:: %ENDMACRO FileMapCreate
FileStreamOpen %MACRO theFile,BufSize=16K PUSHD %BufSize,%theFile CALL FileStreamOpen@RT:: FileStreamOpen@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV ECX,[%Param2] MOV [EBX+FILE.BufSize],ECX WinAPI GlobalAlloc,GMEM_FIXED,ECX TEST EAX JZ .EndWithLastError: MOV [EBX+FILE.BufPtr],EAX MOV EDI,EAX SetSt [EBX+FILE.Status],fileStAllocated FileOpen EBX MOV [EBX+FILE.Ptr],EDI MOV [EBX+FILE.Top],EDI JNC .EndWithEAX .EndWithLastError: WinAPI GetLastError STC .EndWithEAX: MOV [%ReturnEAX],EAX POPAD RET 8 ENDPROC1 FileStreamOpen@RT:: %ENDMACRO FileStreamOpen
FileStreamReadByte %MACRO theFile PUSHD %theFile CALL FileStreamReadByte@RT:: FileStreamReadByte@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] .10: MOV ESI,[EBX+FILE.Ptr] CMP ESI,[EBX+FILE.Top] JB .50: MOV EAX,0xE0070004 ; not open JNSt [EBX+FILE.Status],fileStOpened,.ErrorEAX: JNSt [EBX+FILE.Status],fileStAllocated,.ErrorEAX: MOV EDI,[EBX+FILE.BufPtr] MOV [EBX+FILE.Ptr],EDI MOV [EBX+FILE.Top],EDI PUSH ECX MOV ECX,ESP WinAPI ReadFile,[EBX+FILE.Handle],EDI,[EBX+FILE.BufSize],ECX,0 POP ECX TEST EAX JZ .EndWithLastError: ADD [EBX+FILE.Top],ECX TEST ECX JNZ .10 MOV EAX,[%ReturnEAX] XOR AL,AL ; ZF=1 JMP .EndWithEAX: .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC JMP .EndWithEAX: .50: MOV EAX,[%ReturnEAX] LODSB MOV [EBX+FILE.Ptr],ESI INCD [EBX+FILE.Pos] CLC .EndWithEAX: MOV [%ReturnEAX],EAX POPAD RET 4 ENDPROC1 FileStreamReadByte@RT:: %ENDMACRO FileStreamReadByte
FileStreamRead %MACRO theFile,DataPtr,DataSize PUSHD %DataSize,%DataPtr,%theFile CALL FileStreamRead@RT:: FileStreamRead@RT:: PROC1 PUSHAD MOV EBP,ESP SUB EDX,EDX MOV EBX,[%Param1] MOV EDI,[%Param2] MOV [%ReturnEAX],EDX .10: MOV ESI,[EBX+FILE.Ptr] .20: MOV ECX,[EBX+FILE.Top] SUB ECX,ESI JNA .50: CMP ECX,[%Param3] JA .30: SUB [%Param3],ECX ADD EDX,ECX REP MOVSB MOV [EBX+FILE.Ptr],ESI JMP .20: .30: MOV ECX,[%Param3] ADD EDX,ECX REP MOVSB MOV [EBX+FILE.Ptr],ESI JMP .70: .50: MOV ESI,[EBX+FILE.BufPtr] MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI PUSH ECX MOV ECX,ESP WinAPI ReadFile,[EBX+FILE.Handle],ESI,[EBX+FILE.BufSize],ECX,0 POP ECX TEST EAX JZ .EndWithLastError: JECXZ .70: ; EOF ADD [EBX+FILE.Top],ECX JMP .20: .70: MOV EAX,EDX ADD [EBX+FILE.Pos],EDX TEST EAX JMP .EndWithEAX ; ZF if EAX=0 .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC .EndWithEAX: MOV [%ReturnEAX],EAX .90: POPAD RET 12 ENDPROC1 FileStreamRead@RT:: %ENDMACRO FileStreamRead
FileStreamReadLn %MACRO theFile PUSHD %theFile CALL FileStreamReadLn@RT:: FileStreamReadLn@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV EAX,0xE0070004 ; not open JNSt [EBX+FILE.Status],fileStOpened,.ErrorEAX: JNSt [EBX+FILE.Status],fileStAllocated,.ErrorEAX: MOV EDI,[EBX+FILE.Ptr] MOV ECX,[EBX+FILE.Top] .10: MOV [%ReturnESI],EDI MOV EDX,EDI SUB ECX,EDI JNA .30: MOV AL,10 ; LineFeed REPNE SCASB JE .50: CMP EDX,[EBX+FILE.BufPtr] JE .50: ; When 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 EDX,EDI WinAPI SetFilePointer,[EBX+FILE.Handle],EDX,0,FILE_CURRENT .30: MOV EDI,[EBX+FILE.BufPtr] MOV [EBX+FILE.Ptr],EDI MOV [EBX+FILE.Top],EDI PUSH ECX MOV ECX,ESP WinAPI ReadFile,[EBX+FILE.Handle],EDI,[EBX+FILE.BufSize],ECX,0 POP ECX TEST EAX JZ .EndWithLastError: JECXZ .70: ; EOF ADD ECX,EDI MOV [EBX+FILE.Top],ECX JMP .10: .50: MOV [EBX+FILE.Ptr],EDI SUB EDI,EDX MOV [%ReturnEAX],EDI ADD [EBX+FILE.Pos],EDI JMP .90: .70: SUB EAX,EAX JMP .EndWithEAX: .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC .EndWithEAX: MOV [%ReturnEAX],EAX .90:POPAD RET 4 ENDPROC1 FileStreamReadLn@RT:: %ENDMACRO FileStreamReadLn
FileStreamCreate %MACRO theFile,BufSize=16K PUSHD %BufSize,%theFile CALL FileStreamCreate@RT:: FileStreamCreate@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV ECX,[%Param2] MOV [EBX+FILE.BufSize],ECX MOV EDI,ECX WinAPI GlobalAlloc,GMEM_FIXED,ECX TEST EAX JZ .EndWithLastError: SetSt [EBX+FILE.Status],fileStAllocated MOV [EBX+FILE.BufPtr],EAX ADD EDI,EAX MOV ESI,EAX FileCreate EBX MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],EDI JNC .EndWithEAX .EndWithLastError: WinAPI GetLastError STC .EndWithEAX: MOV [%ReturnEAX],EAX POPAD RET 8 ENDPROC1 FileStreamCreate@RT:: %ENDMACRO FileStreamCreate
FileStreamAppend %MACRO theFile,BufSize=16K PUSHD %BufSize,%theFile CALL FileStreamAppend@RT:: FileStreamAppend@RT:: PROC1 PUSH EBX,ECX MOV EBX,[ESP+12] ; theFile MOV ECX,[ESP+16] ; BufSize SetSt [EBX+FILE.Status],fileStAppend FileStreamCreate EBX,ECX POP ECX,EBX RET 8 ENDPROC1 FileStreamAppend@RT:: %ENDMACRO FileStreamAppend
FileFlush %MACRO theFile ; OUT: CF=1 EAX=error CF=0 EAX=unchanged PUSHD %theFile CALL FileFlush@RT:: FileFlush@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] MOV EAX,0xE0070004 ; File is not opened. JNSt [EBX+FILE.Status],fileStAllocated,.ErrorEAX: JNSt [EBX+FILE.Status],fileStCreated, .ErrorEAX: MOV EDI,[EBX+FILE.Ptr] MOV ESI,[EBX+FILE.BufPtr] MOV [EBX+FILE.Ptr],ESI SUB EDI,ESI PUSH EDX MOV EDX,ESP WinAPI WriteFile,[EBX+FILE.Handle],ESI,EDI,EDX,0 POP EDX ; written size TEST EAX JZ .EndWithLastError: CMP EDI,EDX JE .90: .EndWithLastError: WinAPI GetLastError .ErrorEAX: STC MOV [%ReturnEAX],EAX .90:POPAD RET 4 ENDPROC1 FileFlush@RT:: %ENDMACRO FileFlush
FileStreamWriteRT %MACRO ; Common runtime procedure for macros FileStreamWrite* FileStreamWrite@RT: PROC1 PUSHAD MOV EBX,[ESP+40] ; theFile LEA ESI,[ESP+44] ; 1st string pointer. MOV EAX,0xE0070004 ; File was not opened. JNSt [EBX+FILE.Status],fileStCreated,.ErrorEAX: JNSt [EBX+FILE.Status],fileStAllocated,.ErrorEAX: SUB EAX,EAX MOV [ESP+28],EAX ; %Return EAX .10: LODSD ; DataPtr MOV EBP,EAX TEST EAX JZ .90 ; end of data LODSD ; DataSize MOV EDX,EAX ADD [ESP+28],EAX ; %ReturnEAX CALL .FileStreamStoreData: JNC .10 .ErrorEAX: STC MOV [ESP+28],EAX .90:POPAD RET .FileStreamStoreData: ; Copy data to FileStream buffer ; INP: EBX=FILE EBP=DataPtr EDX=DataSize ; OUT: CF=error EAX=error EBX,ESI preserved FILE updated PUSH ESI MOV ESI,EBP .S1: TEST EDX JZ .S9 .S2: MOV ECX,[EBX+FILE.Top] MOV EDI,[EBX+FILE.Ptr] SUB ECX,EDI JNZ .S3 FileFlush EBX JNC .S2: JMP .S9: .S3: CMP ECX,EDX JBE .S4: MOV ECX,EDX .S4: SUB EDX,ECX ADD [EBX+FILE.Ptr],ECX ADD [EBX+FILE.Pos],ECX ADD [EBX+FILE.Size],ECX REP MOVSB JMP .S1: .S9:POP ESI RET FileStreamWrite$size@RT: PUSH EAX,ECX,EDI SUB ECX,ECX SUB EAX,EAX DEC ECX MOV EDI,[ESP+16] ; DataPtr REPNE SCASB SUB EAX,ECX SUB EAX,2 MOV [ESP+20],EAX ; DataSize POP EDI,ECX,EAX RET ENDPROC1 FileStreamWrite@RT: %ENDMACRO FileStreamWriteRT
FileStreamWriteByte %MACRO theFile PUSHD %theFile CALL FileStreamWriteByte@RT:: FileStreamWriteByte@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] .10: MOV EDI,[EBX+FILE.Ptr] CMP EDI,[EBX+FILE.Top] JB .50 FileFlush EBX ; If buffer full. JNC .10: MOV [%ReturnEAX],EAX JMP .90: .50: STOSB MOV EAX,[EBX+FILE.Pos] MOV [EBX+FILE.Ptr],EDI ADD EAX,1 MOV [EBX+FILE.Pos],EAX MOV [EBX+FILE.Size],EAX CLC .90:POPAD RET 4 ENDPROC1 FileStreamWriteByte@RT:: %ENDMACRO FileStreamWriteByte
FileStreamWriteWord %MACRO theFile PUSHD %theFile CALL FileStreamWriteWord@RT:: FileStreamWriteWord@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] .10: MOV EDI,[EBX+FILE.Ptr] LEA EDX,[EDI+1] CMP EDX,[EBX+FILE.Top] JB .50 FileFlush EBX ; If buffer full. JNC .10: MOV [%ReturnEAX],EAX JMP .90: .50: STOSW MOV EAX,[EBX+FILE.Pos] MOV [EBX+FILE.Ptr],EDI ADD EAX,2 MOV [EBX+FILE.Pos],EAX MOV [EBX+FILE.Size],EAX CLC .90:POPAD RET 4 ENDPROC1 FileStreamWriteWord@RT:: %ENDMACRO FileStreamWriteWord
FileStreamWriteDword %MACRO theFile PUSHD %theFile CALL FileStreamWriteDword@RT:: FileStreamWriteDword@RT:: PROC1 PUSHAD MOV EBP,ESP MOV EBX,[%Param1] .10: MOV EDI,[EBX+FILE.Ptr] LEA EDX,[EDI+3] CMP EDX,[EBX+FILE.Top] JB .50 FileFlush EBX ; If buffer full. JNC .10: MOV [%ReturnEAX],EAX JMP .90: .50: STOSD MOV EAX,[EBX+FILE.Pos] MOV [EBX+FILE.Ptr],EDI ADD EAX,4 MOV [EBX+FILE.Pos],EAX MOV [EBX+FILE.Size],EAX CLC .90:POPAD RET 4 ENDPROC1 FileStreamWriteDword@RT:: %ENDMACRO FileStreamWriteDword
FileStreamWrite %MACRO theFile,DataPtr,DataSize,DataPtr2,DataSize2,,, %IF %# & 1 = 0 %ERROR ID=5946, 'Macro "FileStreamWrite" expects odd number of arguments.' %EXITMACRO FileStreamWrite %ENDIF PUSHD 0 ; Mark the end of arguments. ArgNr %FOR %#..2,STEP=-2 PUSHD %*{%ArgNr}, %*{%ArgNr-1} %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],4*(%#+1) CALL FileStreamWrite@RT POP ESP 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 PUSHD 0x00000A0D ; CR+LF. PUSHD 0 ; Mark the end of arguments. PUSHD 2 PUSHD ESP ADDD [ESP],8 ; Pointer to CR+LF. ArgNr %FOR %#..2,STEP=-2 PUSHD %*{%ArgNr}, %*{%ArgNr-1} %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],4*(%#+4) CALL FileStreamWrite@RT POP ESP FileStreamWriteRT %ENDMACRO FileStreamWriteLn ; Invoke the common runtime macro.
FileStreamWrite$ %MACRO theFile,DataPtr1,DataPtr2,DataPtr3,,, PUSHD 0 ; mark end of arguments ArgNr %FOR %#..2,STEP=-1 PUSHD EAX,%*{%ArgNr} CALL FileStreamWrite$size@RT %ENDFOR ArgNr PUSHD %theFile PUSH ESP ADDD [ESP],8*%# CALL FileStreamWrite@RT POP ESP FileStreamWriteRT ; Invoke the common runtime macro. %ENDMACRO FileStreamWrite$
FileMove %MACRO SourceFile, DestinationFile PUSHD %DestinationFile, %SourceFile CALL FileMove@RT:: FileMove@RT:: PROC1 IMPORT MoveFileExA,MoveFileExW PUSHAD MOV ESI,[ESP+36] ; SourceFile MOV EDI,[ESP+40] ; DestinationFile MOV EAX,[ESI+FILE.Status] MOV EDX,[EDI+FILE.Status] MOV EBX,fileStUnicode AND EAX,EBX AND EDX,EBX CMP EAX,EDX MOV EAX,0xC008007B ; Error 123: invalid filename. STC JNE .ErrorEAX: ; Error - different width of strings. FileClose ESI,EDI FileMkDir EDI JC .ErrorEAX: LEA ESI,[ESI+FILE.Name] LEA EDI,[EDI+FILE.Name] MOV EAX,MoveFileExW:: JSt EDX,fileStUnicode,.30: MOV EAX,MoveFileExA:: .30: WinAPI EAX,ESI,EDI,MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED TEST EAX MOV EAX,0 JNZ .OK: WinAPI GetLastError .ErrorEAX: STC .OK: MOV [ESP+28],EAX ; ReturnEAX POPAD RET 8 ENDPROC1 FileMove@RT:: %ENDMACRO FileMove
FileClose %MACRO theFile1 ArgNr %FOR 1..%# PUSHD %*{%ArgNr} CALL FileClose@RT:: %ENDFOR ArgNr FileClose@RT:: PROC1 PUSHAD MOV EBX,[ESP+36] ; theFile SUB ESI,ESI MOV EDI,INVALID_HANDLE_VALUE JNSt [EBX+FILE.Status],fileStAllocated,.10: FileFlush EBX WinAPI GlobalFree,[EBX+FILE.BufPtr] RstSt [EBX+FILE.Status],fileStAllocated .10: MOV [EBX+FILE.BufPtr],ESI MOV [EBX+FILE.BufSize],ESI JNSt [EBX+FILE.Status],fileStMapped,.20: WinAPI UnmapViewOfFile,[EBX+FILE.Ptr] RstSt [EBX+FILE.Status],fileStMapped .20: MOV [EBX+FILE.Ptr],ESI MOV [EBX+FILE.Top],ESI JNSt [EBX+FILE.Status],fileStMapOpened|fileStMapCreated,.30: WinAPI CloseHandle,[EBX+FILE.MapHandle] .30: RstSt [EBX+FILE.Status],fileStMapOpened|fileStMapCreated MOV [EBX+FILE.MapHandle],EDI JNSt [EBX+FILE.Status],fileStOpened|fileStCreated,.40: JSt [EBX+FILE.Status],fileStStdIO,.40 WinAPI CloseHandle,[EBX+FILE.Handle] .40: RstSt [EBX+FILE.Status],fileStOpened|fileStCreated|fileStAppend MOV [EBX+FILE.Handle],EDI POPAD RET 4 ENDPROC1 FileClose@RT:: %ENDMACRO FileClose
FileDelete %MACRO theFile1 ArgNr %FOR 1..%# PUSHD %*{%ArgNr} CALL FileDelete@RT:: %ENDFOR ArgNr FileDelete@RT:: PROC1 IMPORT DeleteFileA,DeleteFileW PUSHAD MOV EBX,[ESP+36] ; theFile FileClose EBX LEA ESI,[EBX+FILE.Name] MOV EAX,DeleteFileW:: JSt [EBX+FILE.Status],fileStUnicode,.30: MOV EAX,DeleteFileA:: .30: WinAPI EAX,ESI TEST EAX MOV EAX,0 JNZ .OK: WinAPI GetLastError .ErrorEAX: STC .OK: MOV [ESP+28],EAX ; ReturnEAX POPAD RET 4 ENDPROC1 FileDelete@RT:: %ENDMACRO FileDelete
ENDHEAD winfile