diff --git a/Tests/VfsControl.pas b/Tests/VfsControl.pas
index 845a50f..2df74da 100644
--- a/Tests/VfsControl.pas
+++ b/Tests/VfsControl.pas
@@ -8,8 +8,17 @@ unit VfsControl;
uses
Windows, SysUtils,
- Utils, WinUtils,
- VfsBase, VfsUtils, VfsHooks;
+ Utils, WinUtils, TypeWrappers, DataLib,
+ 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 *)
@@ -44,4 +53,87 @@ begin
end; // .with
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.
\ No newline at end of file
diff --git a/Tests/VfsIntegratedTest.pas b/Tests/VfsIntegratedTest.pas
index edb17ff..fa0113b 100644
--- a/Tests/VfsIntegratedTest.pas
+++ b/Tests/VfsIntegratedTest.pas
@@ -61,7 +61,7 @@ end;
procedure TestIntegrated.TearDown;
begin
VfsBase.ResetVfs();
- VfsDebug.SetLoggingProc(nil);
+ //VfsDebug.SetLoggingProc(nil);
end;
procedure TestIntegrated.TestGetFileAttributes;
@@ -88,12 +88,14 @@ var
end; // .function HasValidAttrs
begin
+ VfsDebug.WriteLog('TestGetFileAttributes', 'Started');
RootDir := VfsTestHelper.GetTestsRootDir;
- 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, '\503.html']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{3}');
- Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Hobbots\']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{4}');
- Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Mods']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{5}');
+ 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, '503.html']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{3}');
+ Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Hobbots\']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{4}');
+ Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Mods']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{5}');
+ VfsDebug.WriteLog('TestGetFileAttributes', 'Ended');
end; // .procedure TestIntegrated.TestGetFileAttributes;
procedure TestIntegrated.TestGetFileAttributesEx;
@@ -113,11 +115,13 @@ var
end;
begin
+ VfsDebug.WriteLog('TestGetFileAttributesEx', 'Started');
RootDir := VfsTestHelper.GetTestsRootDir;
- CheckEquals(-1, GetFileSize(VfsUtils.MakePath([RootDir, '\non-existing.non'])), '{1}');
- CheckEquals(42, GetFileSize(VfsUtils.MakePath([RootDir, '\Hobbots\mms.cfg'])), '{2}');
- CheckEquals(22, GetFileSize(VfsUtils.MakePath([RootDir, '\503.html'])), '{3}');
- CheckEquals(318, GetFileSize(VfsUtils.MakePath([RootDir, '\default'])), '{4}');
+ CheckEquals(-1, GetFileSize(VfsUtils.MakePath([RootDir, 'non-existing.non'])), '{1}');
+ CheckEquals(42, GetFileSize(VfsUtils.MakePath([RootDir, 'Hobbots\mms.cfg'])), '{2}');
+ CheckEquals(22, GetFileSize(VfsUtils.MakePath([RootDir, '503.html'])), '{3}');
+ CheckEquals(318, GetFileSize(VfsUtils.MakePath([RootDir, 'default'])), '{4}');
+ VfsDebug.WriteLog('TestGetFileAttributesEx', 'Ended');
end; // .procedure TestIntegrated.TestGetFileAttributesEx;
procedure TestIntegrated.TestFilesOpenClose;
@@ -137,6 +141,7 @@ begin
RootDir := VfsTestHelper.GetTestsRootDir;
try
+ VfsDebug.WriteLog('TestFilesOpenClose', 'Started');
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');
@@ -165,6 +170,8 @@ begin
finally
WinUtils.SetCurrentDirW(CurrDir);
end; // .try
+
+ VfsDebug.WriteLog('TestFilesOpenClose', 'Ended');
end; // .procedure TestIntegrated.TestFilesOpenClose;
procedure TestIntegrated.TestDirectoryListing;
@@ -223,6 +230,7 @@ begin
RootDir := VfsTestHelper.GetTestsRootDir;
try
+ VfsDebug.WriteLog('TestDirectoryListing', 'Started');
FileList := GetDirListing(VfsUtils.MakePath([RootDir, '*']));
DirContents := FileList.ToText(#13#10);
CheckEquals(VALID_ROOT_DIR_LISTING, DirContents);
@@ -242,6 +250,8 @@ begin
SysUtils.FreeAndNil(FileList);
SysUtils.FreeAndNil(DirListing);
end; // .try
+
+ VfsDebug.WriteLog('TestDirectoryListing', 'Ended');
end; // .procedure TestIntegrated.TestDirectoryListing;
begin
diff --git a/VfsBase.pas b/VfsBase.pas
index 8ec0407..16978d9 100644
--- a/VfsBase.pas
+++ b/VfsBase.pas
@@ -331,7 +331,10 @@ end;
function IsVfsActive: boolean;
begin
result := EnterVfs;
- LeaveVfs;
+
+ if result then begin
+ LeaveVfs;
+ end;
end;
(* Returns real path for vfs item by its absolute virtual path or empty string. Optionally returns file info structure *)
diff --git a/VfsHooks.pas b/VfsHooks.pas
index 59c7919..215126f 100644
--- a/VfsHooks.pas
+++ b/VfsHooks.pas
@@ -83,11 +83,12 @@ end; // .function GetFileObjectPath
function Hook_NtQueryAttributesFile (OrigFunc: WinNative.TNtQueryAttributesFile; ObjectAttributes: POBJECT_ATTRIBUTES; FileInformation: PFILE_BASIC_INFORMATION): NTSTATUS; stdcall;
var
- ExpandedPath: WideString;
- RedirectedPath: WideString;
- ReplacedObjAttrs: WinNative.TObjectAttributes;
- FileInfo: TNativeFileInfo;
- HadTrailingDelim: boolean;
+ ExpandedPath: WideString;
+ RedirectedPath: WideString;
+ ReplacedObjAttrs: WinNative.TObjectAttributes;
+ FileInfo: TNativeFileInfo;
+ HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
+ HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin
if VfsDebug.LoggingEnabled then begin
@@ -140,11 +141,12 @@ end; // .function Hook_NtQueryAttributesFile
function Hook_NtQueryFullAttributesFile (OrigFunc: WinNative.TNtQueryFullAttributesFile; ObjectAttributes: POBJECT_ATTRIBUTES; FileInformation: PFILE_NETWORK_OPEN_INFORMATION): NTSTATUS; stdcall;
var
- ExpandedPath: WideString;
- RedirectedPath: WideString;
- ReplacedObjAttrs: WinNative.TObjectAttributes;
- FileInfo: TNativeFileInfo;
- HadTrailingDelim: boolean;
+ ExpandedPath: WideString;
+ RedirectedPath: WideString;
+ ReplacedObjAttrs: WinNative.TObjectAttributes;
+ FileInfo: TNativeFileInfo;
+ HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
+ HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin
if VfsDebug.LoggingEnabled then begin
@@ -211,10 +213,11 @@ end;
function Hook_NtCreateFile (OrigFunc: WinNative.TNtCreateFile; FileHandle: PHANDLE; DesiredAccess: ACCESS_MASK; ObjectAttributes: POBJECT_ATTRIBUTES; IoStatusBlock: PIO_STATUS_BLOCK;
AllocationSize: PLARGE_INTEGER; FileAttributes: ULONG; ShareAccess: ULONG; CreateDisposition: ULONG; CreateOptions: ULONG; EaBuffer: PVOID; EaLength: ULONG): NTSTATUS; stdcall;
var
- ExpandedPath: WideString;
- RedirectedPath: WideString;
- ReplacedObjAttrs: WinNative.TObjectAttributes;
- HadTrailingDelim: boolean;
+ ExpandedPath: WideString;
+ RedirectedPath: WideString;
+ ReplacedObjAttrs: WinNative.TObjectAttributes;
+ HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
+ HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin
if VfsDebug.LoggingEnabled then begin
diff --git a/VfsOpenFiles.pas b/VfsOpenFiles.pas
index 692a84d..586ac73 100644
--- a/VfsOpenFiles.pas
+++ b/VfsOpenFiles.pas
@@ -96,7 +96,7 @@ begin
ExcludedItems := DataLib.NewDict(not Utils.OWNS_ITEMS, DataLib.CASE_SENSITIVE);
if VfsItemFound then begin
- while DirListing.GetNextItem(DirItem) do begin
+ while Self.DirListing.GetNextItem(DirItem) do begin
ExcludedItems[WideStrToCaselessKey(DirItem.Data.FileName)] := Ptr(1);
end;
diff --git a/VfsTest.dproj b/VfsTest.dproj
index d304ba3..33381f2 100644
--- a/VfsTest.dproj
+++ b/VfsTest.dproj
@@ -24,7 +24,6 @@
..\Lib\B2;.\Tests
..\Lib\B2;.\Tests
3
- False
Delphi.Personality
@@ -58,6 +57,14 @@
+
+
+
+
+
+
+
+
diff --git a/_TODO_.txt b/_TODO_.txt
index bf44dfa..f0e80a8 100644
--- a/_TODO_.txt
+++ b/_TODO_.txt
@@ -1 +1,10 @@
-UTF-8 Logging
\ No newline at end of file
+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
\ No newline at end of file