function WriteFileFromBuffer(const AFileName: string; AFileSize: Cardinal; var AData; AIsAppend: Boolean = False): Boolean;
type
PTQWord = ^TQWord;
TQWord = packed record
case Boolean of
False: (QWORD: Int64);
True: (LODWORD: DWORD; HIDWORD: DWORD);
end;
var
DriveName: string;
MappingName: string;
DiskFreeSize: Int64;
FileHandle: THandle;
MappingHandle: THandle;
IsNewFile, IsMapping: Boolean;
FindData: TWin32FindData;
TheCreationTime: TFileTime;
FileAttrs: DWORD;
OpenMode: DWORD;
ExistsSize, ThisSize: TQWord;
PFileData, P, PSource: Pointer;
Segment: Cardinal;
Offset: Cardinal;
OffsetSize: Cardinal;
CommitSize: Cardinal;
function MoveDataTo(ASource, ADest: Pointer; ASize: Cardinal): Boolean;
begin
Result := False;
try
CriticalSectionLock;
Windows.VirtualAlloc(PFileData, CommitSize, MEM_COMMIT, PAGE_READWRITE);
Windows.VirtualLock(PFileData, CommitSize);
try
System.Move(ASource^, ADest^, ASize);
except
on EAccessViolation do Exit;
end;
finally
Windows.VirtualUnlock(PFileData, CommitSize);
Windows.VirtualFree(PFileData, CommitSize, MEM_DECOMMIT);
CriticalSectionUnlock;
end;
Result := True;
end;
begin
Result := False;
if PPointer(@AData)^ = nil then Exit;
if AFileSize = 0 then Exit;
try
PFileData := nil;
MappingHandle := 0;
FileHandle := INVALID_HANDLE_VALUE;
ThisSize.QWORD := 0;
ExistsSize.QWORD := 0;
DriveName := ExtractFileDrive(AFileName);
if DriveName = '' then DriveName := ExtractFileDrive(ParamStr(0));
DiskFreeSize := DiskFree(Byte(UpCase(DriveName[1])) - $40);
FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData);
if FileHandle = INVALID_HANDLE_VALUE then
begin
if DiskFreeSize < AFileSize then Exit;
OpenMode := CREATE_NEW;
IsNewFile := True;
ThisSize.QWORD := AFileSize;
FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess, Const_FileShare, nil, OpenMode, 0, 0);
if FileHandle = INVALID_HANDLE_VALUE then Exit;
try
CriticalSectionLock;
Windows.SetFilePointer(FileHandle, ThisSize.LODWORD, @ThisSize.HIDWORD, FILE_BEGIN);
Windows.SetEndOfFile(FileHandle);
finally
CriticalSectionUnlock;
end;
Windows.CloseHandle(FileHandle);
FileHandle := Windows.FindFirstFile(PChar(AFileName), FindData);
if FileHandle = INVALID_HANDLE_VALUE then Exit;
end
else
IsNewFile := False;
Windows.FindClose(FileHandle);
TheCreationTime := FindData.ftCreationTime;
MappingName := GetFileNameExcludeExt(AFileName) + Format('_%.8x%.8x', [TheCreationTime.dwHighDateTime, TheCreationTime.dwLowDateTime]);
if AIsAppend then
begin
if not IsNewFile then
begin
ExistsSize.HIDWORD := FindData.nFileSizeHigh;
ExistsSize.LODWORD := FindData.nFileSizeLow;
ThisSize.QWORD := AFileSize + ExistsSize.QWORD;
end
else
ThisSize.QWORD := AFileSize;
if DiskFreeSize < (AFileSize + ExistsSize.QWORD) then Exit;
OpenMode := OPEN_ALWAYS
end
else
begin
if DiskFreeSize < AFileSize then Exit;
OpenMode := TRUNCATE_EXISTING;
ThisSize.QWORD := AFileSize;
end;
FileAttrs := Windows.GetFileAttributes(PChar(AFileName));
if (FileAttrs and FILE_ATTRIBUTE_READONLY) <> 0 then
begin
if not Windows.SetFileAttributes(PChar(AFileName), FileAttrs xor FILE_ATTRIBUTE_READONLY) then Exit;
end;
try
FileHandle := Windows.CreateFile(PChar(AFileName), Const_FileAccess, Const_FileShare, nil, OpenMode, 0, 0);
if FileHandle = INVALID_HANDLE_VALUE then Exit;
MappingHandle := Windows.OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(MappingName));
IsMapping := MappingHandle <> 0;
if not IsMapping then
begin
MappingHandle := Windows.CreateFileMapping(FileHandle, nil, PAGE_READWRITE or SEC_RESERVE, ThisSize.HIDWORD,
((((ThisSize.LODWORD and $FFFF0000) shr 16) + 1) shl 16), PChar(MappingName));
if (MappingHandle = 0) or (Windows.GetLastError <> ERROR_SUCCESS) then Exit;
end;
PSource := PPointer(@AData)^;
PFileData := nil;
Segment := 0;
if AIsAppend then
begin
Offset := ExistsSize.LODWORD and $0000FFFF;
if Offset > 0 then
begin
Segment := ExistsSize.LODWORD and $FFFF0000;
if ((Offset + AFileSize) and $FFFF0000) > 0 then
begin
PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, $00010000);
if PFileData = nil then Exit;
CommitSize := $00010000;
OffsetSize := ((Offset xor $FFFFFFFF) and $0000FFFF) + 1
end
else
begin
OffsetSize := (((Offset + AFileSize) shr 12) + 1) shl 12;
PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, OffsetSize);
if PFileData = nil then Exit;
CommitSize := OffsetSize;
OffsetSize := AFileSize;
end;
P := Pointer(DWORD(PFileData) + Offset);
if not MoveDataTo(PSource, P, OffsetSize) then Exit;
Windows.UnmapViewOfFile(PFileData);
PSource := Pointer(DWORD(PSource) + OffsetSize );
Dec(AFileSize, OffsetSize);
if AFileSize > 0 then Segment := ((Segment shr 16) + 1) shl 16;
end;
end;
while AFileSize <> 0 do
begin
if AFileSize and $FFFF0000 > 0 then
begin
PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, $00010000);
if PFileData = nil then Exit;
CommitSize := $00010000;
if not MoveDataTo(PSource, PFileData, $00010000) then Exit;
Windows.UnmapViewOfFile(PFileData);
PSource := Pointer(DWORD(PSource) + $00010000);
Dec(AFileSize, $00010000);
if AFileSize > 0 then Segment := ((Segment shr 16) + 1) shl 16;
end
else
begin
PFileData := Windows.MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, ExistsSize.HIDWORD, Segment, AFileSize);
if PFileData = nil then Exit;
CommitSize := ((AFileSize shr 12) + 1) shl 12;
if not MoveDataTo(PSource, PFileData, AFileSize) then Exit;
Windows.UnmapViewOfFile(PFileData);
Dec(AFileSize, AFileSize);
end;
end;
PFileData := nil;
Result := True;
finally
if PFileData <> nil then Windows.UnmapViewOfFile(PFileData);
if MappingHandle <> 0 then Windows.CloseHandle(MappingHandle);
if FileHandle <> INVALID_HANDLE_VALUE then
begin
if Result then
begin
try
CriticalSectionLock;
Windows.SetFilePointer(FileHandle, ThisSize.LODWORD, @ThisSize.HIDWORD, FILE_BEGIN);
Windows.SetEndOfFile(FileHandle);
finally
CriticalSectionUnlock;
end;
end;
Windows.CloseHandle(FileHandle);
end;
end;
except
on Exception do
begin
if PFileData <> nil then Windows.UnmapViewOfFile(PFileData);
if MappingHandle <> 0 then Windows.CloseHandle(MappingHandle);
if FileHandle <> INVALID_HANDLE_VALUE then Windows.CloseHandle(FileHandle);
Exit;
end;
end;
end;