Started working on high-level exported mod API. Fixed Delphi bug with wrong stack variables alignment. Fixed bug in IsVfsOn (leave crit section without entering). Now XP normally passes all tests

This commit is contained in:
Berserker 2019-05-11 13:27:17 +03:00
parent c4698834c2
commit ff8192c149
7 changed files with 154 additions and 30 deletions

View File

@ -8,8 +8,17 @@ unit VfsControl;
uses uses
Windows, SysUtils, Windows, SysUtils,
Utils, WinUtils, Utils, WinUtils, TypeWrappers, DataLib,
VfsBase, VfsUtils, VfsHooks; Files, StrLib,
VfsBase, VfsUtils, VfsHooks, DlgMes;
type
(* Import *)
TWideString = TypeWrappers.TWideString;
const
(* Flag forces to skip directory names, starting with '#' *)
SKIP_HASHTAGGED_MODS = 1;
(* Runs all VFS subsystems, unless VFS is already running *) (* Runs all VFS subsystems, unless VFS is already running *)
@ -44,4 +53,87 @@ begin
end; // .with end; // .with
end; // function RunVfs end; // function RunVfs
function ValidateModName (const ModName: WideString): boolean;
const
DISALLOWED_CHARS = ['<', '>', '"', '?', '*', '\', '/', '|', ':', #0];
var
StrLen: integer;
i: integer;
begin
StrLen := Length(ModName);
i := 1;
while (i <= StrLen) and ((ord(ModName[i]) > 255) or not (AnsiChar(ModName[i]) in DISALLOWED_CHARS)) do begin
Inc(i);
end;
result := (i > StrLen) and (ModName <> '') and (ModName <> '.') and (ModName <> '..');
end;
function LoadModList (const ModListFilePath: WideString): {O} DataLib.TList {of (O) TWideString};
var
AbsFilePath: WideString;
FileContents: string;
Lines: Utils.TArrayOfStr;
ModNameUtf8: string;
ModName: WideString;
i: integer;
begin
result := DataLib.NewList(Utils.OWNS_ITEMS);
// * * * * * //
AbsFilePath := VfsUtils.NormalizePath(ModListFilePath);
if (AbsFilePath <> '') and (Files.ReadFileContents(AbsFilePath, FileContents)) then begin
Lines := StrLib.Explode(FileContents, #10);
for i := 0 to High(Lines) do begin
ModNameUtf8 := Lines[i];
ModName := StrLib.Utf8ToWide(ModNameUtf8);
if ValidateModName(ModName) then begin
result.Add(TWideString.Create(ModName));
end;
end;
end;
end; // .function LoadModList
// function MapModsDir (const RootDir, ModsDir: WideString; Flags: integer = 0);
// var
// AbsRootDir: WideString;
// AbsModsDir: WideString;
// FileInfo: VfsUtils.TNativeFileInfo;
// ModName: WideString;
// begin
// AbsRootDir := VfsUtils.NormalizePath(RootDir);
// AbsModsDir := VfsUtils.NormalizePath(ModsDir);
// result := (AbsRootDir <> '') and (AbsModsDir <> '') and VfsUtils.GetFileInfo(AbsRootDir, FileInfo);
// result := result and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes);
// result := result and VfsUtils.GetFileInfo(AbsModsDir, FileInfo);
// result := result and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes);
// if result then begin
// with VfsUtils.SysScanDir(AbsModsDir, '*') do begin
// while IterNext(ModName, @FileInfo.Base) do begin
// if (ModName <> '.') and (ModName <> '..') and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes) then begin
// end;
// end;
// end;
// end;
// end;
var
L: TList;
i: integer;
begin
// L := LoadModList('D:\Heroes 3\Mods\list.txt');
// for i := 0 to L.Count- 1 do begin
// VarDump([TWideString(L[i]).Value]);
// end;
end. end.

View File

@ -61,7 +61,7 @@ end;
procedure TestIntegrated.TearDown; procedure TestIntegrated.TearDown;
begin begin
VfsBase.ResetVfs(); VfsBase.ResetVfs();
VfsDebug.SetLoggingProc(nil); //VfsDebug.SetLoggingProc(nil);
end; end;
procedure TestIntegrated.TestGetFileAttributes; procedure TestIntegrated.TestGetFileAttributes;
@ -88,12 +88,14 @@ var
end; // .function HasValidAttrs end; // .function HasValidAttrs
begin begin
VfsDebug.WriteLog('TestGetFileAttributes', 'Started');
RootDir := VfsTestHelper.GetTestsRootDir; RootDir := VfsTestHelper.GetTestsRootDir;
Check(not HasValidAttrs(VfsUtils.MakePath([RootDir, '\non-existing.non'])), '{1}'); Check(not HasValidAttrs(VfsUtils.MakePath([RootDir, 'non-existing.non'])), '{1}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Hobbots\mms.cfg']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{2}'); Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Hobbots\mms.cfg']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{2}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\503.html']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{3}'); Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '503.html']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{3}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Hobbots\']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{4}'); Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Hobbots\']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{4}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Mods']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{5}'); Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Mods']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{5}');
VfsDebug.WriteLog('TestGetFileAttributes', 'Ended');
end; // .procedure TestIntegrated.TestGetFileAttributes; end; // .procedure TestIntegrated.TestGetFileAttributes;
procedure TestIntegrated.TestGetFileAttributesEx; procedure TestIntegrated.TestGetFileAttributesEx;
@ -113,11 +115,13 @@ var
end; end;
begin begin
VfsDebug.WriteLog('TestGetFileAttributesEx', 'Started');
RootDir := VfsTestHelper.GetTestsRootDir; RootDir := VfsTestHelper.GetTestsRootDir;
CheckEquals(-1, GetFileSize(VfsUtils.MakePath([RootDir, '\non-existing.non'])), '{1}'); CheckEquals(-1, GetFileSize(VfsUtils.MakePath([RootDir, 'non-existing.non'])), '{1}');
CheckEquals(42, GetFileSize(VfsUtils.MakePath([RootDir, '\Hobbots\mms.cfg'])), '{2}'); CheckEquals(42, GetFileSize(VfsUtils.MakePath([RootDir, 'Hobbots\mms.cfg'])), '{2}');
CheckEquals(22, GetFileSize(VfsUtils.MakePath([RootDir, '\503.html'])), '{3}'); CheckEquals(22, GetFileSize(VfsUtils.MakePath([RootDir, '503.html'])), '{3}');
CheckEquals(318, GetFileSize(VfsUtils.MakePath([RootDir, '\default'])), '{4}'); CheckEquals(318, GetFileSize(VfsUtils.MakePath([RootDir, 'default'])), '{4}');
VfsDebug.WriteLog('TestGetFileAttributesEx', 'Ended');
end; // .procedure TestIntegrated.TestGetFileAttributesEx; end; // .procedure TestIntegrated.TestGetFileAttributesEx;
procedure TestIntegrated.TestFilesOpenClose; procedure TestIntegrated.TestFilesOpenClose;
@ -137,6 +141,7 @@ begin
RootDir := VfsTestHelper.GetTestsRootDir; RootDir := VfsTestHelper.GetTestsRootDir;
try try
VfsDebug.WriteLog('TestFilesOpenClose', 'Started');
Check(WinUtils.SetCurrentDirW(RootDir), 'Setting current directory to real path must succeed. Path: ' + RootDir); Check(WinUtils.SetCurrentDirW(RootDir), 'Setting current directory to real path must succeed. Path: ' + RootDir);
Check(OpenFile(VfsUtils.MakePath([RootDir, 'non-existing.non'])) <= 0, 'Opening non-existing file must fail'); Check(OpenFile(VfsUtils.MakePath([RootDir, 'non-existing.non'])) <= 0, 'Opening non-existing file must fail');
@ -165,6 +170,8 @@ begin
finally finally
WinUtils.SetCurrentDirW(CurrDir); WinUtils.SetCurrentDirW(CurrDir);
end; // .try end; // .try
VfsDebug.WriteLog('TestFilesOpenClose', 'Ended');
end; // .procedure TestIntegrated.TestFilesOpenClose; end; // .procedure TestIntegrated.TestFilesOpenClose;
procedure TestIntegrated.TestDirectoryListing; procedure TestIntegrated.TestDirectoryListing;
@ -223,6 +230,7 @@ begin
RootDir := VfsTestHelper.GetTestsRootDir; RootDir := VfsTestHelper.GetTestsRootDir;
try try
VfsDebug.WriteLog('TestDirectoryListing', 'Started');
FileList := GetDirListing(VfsUtils.MakePath([RootDir, '*'])); FileList := GetDirListing(VfsUtils.MakePath([RootDir, '*']));
DirContents := FileList.ToText(#13#10); DirContents := FileList.ToText(#13#10);
CheckEquals(VALID_ROOT_DIR_LISTING, DirContents); CheckEquals(VALID_ROOT_DIR_LISTING, DirContents);
@ -242,6 +250,8 @@ begin
SysUtils.FreeAndNil(FileList); SysUtils.FreeAndNil(FileList);
SysUtils.FreeAndNil(DirListing); SysUtils.FreeAndNil(DirListing);
end; // .try end; // .try
VfsDebug.WriteLog('TestDirectoryListing', 'Ended');
end; // .procedure TestIntegrated.TestDirectoryListing; end; // .procedure TestIntegrated.TestDirectoryListing;
begin begin

View File

@ -331,7 +331,10 @@ end;
function IsVfsActive: boolean; function IsVfsActive: boolean;
begin begin
result := EnterVfs; result := EnterVfs;
if result then begin
LeaveVfs; LeaveVfs;
end;
end; end;
(* Returns real path for vfs item by its absolute virtual path or empty string. Optionally returns file info structure *) (* Returns real path for vfs item by its absolute virtual path or empty string. Optionally returns file info structure *)

View File

@ -87,7 +87,8 @@ var
RedirectedPath: WideString; RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes; ReplacedObjAttrs: WinNative.TObjectAttributes;
FileInfo: TNativeFileInfo; FileInfo: TNativeFileInfo;
HadTrailingDelim: boolean; HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin begin
if VfsDebug.LoggingEnabled then begin if VfsDebug.LoggingEnabled then begin
@ -144,7 +145,8 @@ var
RedirectedPath: WideString; RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes; ReplacedObjAttrs: WinNative.TObjectAttributes;
FileInfo: TNativeFileInfo; FileInfo: TNativeFileInfo;
HadTrailingDelim: boolean; HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin begin
if VfsDebug.LoggingEnabled then begin if VfsDebug.LoggingEnabled then begin
@ -214,7 +216,8 @@ var
ExpandedPath: WideString; ExpandedPath: WideString;
RedirectedPath: WideString; RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes; ReplacedObjAttrs: WinNative.TObjectAttributes;
HadTrailingDelim: boolean; HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin begin
if VfsDebug.LoggingEnabled then begin if VfsDebug.LoggingEnabled then begin

View File

@ -96,7 +96,7 @@ begin
ExcludedItems := DataLib.NewDict(not Utils.OWNS_ITEMS, DataLib.CASE_SENSITIVE); ExcludedItems := DataLib.NewDict(not Utils.OWNS_ITEMS, DataLib.CASE_SENSITIVE);
if VfsItemFound then begin if VfsItemFound then begin
while DirListing.GetNextItem(DirItem) do begin while Self.DirListing.GetNextItem(DirItem) do begin
ExcludedItems[WideStrToCaselessKey(DirItem.Data.FileName)] := Ptr(1); ExcludedItems[WideStrToCaselessKey(DirItem.Data.FileName)] := Ptr(1);
end; end;

View File

@ -24,7 +24,6 @@
<DCC_ObjPath>..\Lib\B2;.\Tests</DCC_ObjPath> <DCC_ObjPath>..\Lib\B2;.\Tests</DCC_ObjPath>
<DCC_IncludePath>..\Lib\B2;.\Tests</DCC_IncludePath> <DCC_IncludePath>..\Lib\B2;.\Tests</DCC_IncludePath>
<DCC_MapFile>3</DCC_MapFile> <DCC_MapFile>3</DCC_MapFile>
<DCC_Optimize>False</DCC_Optimize>
</PropertyGroup> </PropertyGroup>
<ProjectExtensions> <ProjectExtensions>
<Borland.Personality>Delphi.Personality</Borland.Personality> <Borland.Personality>Delphi.Personality</Borland.Personality>
@ -58,6 +57,14 @@

View File

@ -1 +1,10 @@
UTF-8 Logging UTF-8 Logging
Editor/Development mode:
Separate thread with FindFirstChangeNotificationA/FindNextChangeNotification on mods root dir + WaitForSingleObject
+ ResetVfs + BlockVfs + MapDir for each cached mapped directory + RunVfs.
We will need some API like RefreshVfs.
Add ANSI versions of exported API.
Write VfsImport.pas nad vfs_import.c