diff --git a/.gitignore b/.gitignore
index 808dddb..21ac699 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.dcu
*.exe
+*.dll
*.ini
*.identcache
*.map
diff --git a/Tests/VfsControl.pas b/Tests/VfsControl.pas
deleted file mode 100644
index c715ddf..0000000
--- a/Tests/VfsControl.pas
+++ /dev/null
@@ -1,156 +0,0 @@
-unit VfsControl;
-(*
- Facade unit for high-level VFS API.
-*)
-
-
-(***) interface (***)
-
-uses
- Windows, SysUtils,
- Utils, WinUtils, TypeWrappers, DataLib,
- Files, StrLib,
- VfsBase, VfsUtils, VfsHooks, DlgMes {FIXME DELETEME};
-
-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 *)
-function RunVfs (DirListingOrder: VfsBase.TDirListingSortType): boolean; stdcall;
-
-
-(***) implementation (***)
-
-
-function RunVfs (DirListingOrder: VfsBase.TDirListingSortType): boolean; stdcall;
-var
- CurrDir: WideString;
-
-begin
- with VfsBase.VfsCritSection do begin
- Enter;
-
- result := VfsBase.RunVfs(DirListingOrder);
-
- if result then begin
- VfsHooks.InstallHooks;
-
- // Try to ensure, that current directory handle is tracked by VfsOpenFiles
- CurrDir := WinUtils.GetCurrentDirW;
-
- if CurrDir <> '' then begin
- WinUtils.SetCurrentDirW(CurrDir);
- end;
- end;
-
- Leave;
- 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} var {out} ModList: DataLib.TList {of (O) TWideString}): boolean;
-// var
-// AbsFilePath: WideString;
-// FileHandle: integer;
-// FileContents: string;
-// Lines: Utils.TArrayOfStr;
-// ModNameUtf8: string;
-// ModName: WideString;
-// i: integer;
-
-// // FIXME ModList is not result
-
-// begin
-// result := DataLib.NewList(Utils.OWNS_ITEMS);
-// // * * * * * //
-// AbsFilePath := VfsUtils.NormalizePath(ModListFilePath);
-// FileHandle := Windows.CreateFileW(PWideChar(AbsFilePath), Windows.GENERIC_READ, Windows.FILE_SHARE_READ, nil, Windows.OPEN_EXISTING, 0, nil);
-// // Make available UNICODE path
-// // Make UTF8 BOM support EF BB BF
-
-// 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.TrimW(StrLib.Utf8ToWide(ModNameUtf8, StrLib.FAIL_ON_ERROR));
-
-// if ValidateModName(ModName) then begin
-// result.Add(TWideString.Create(ModName));
-// end;
-// end;
-// end;
-// end; // .function LoadModList
-
-function MapModsFromList_ (const RootDir, ModsDir: WideString; ModList: TList {of (O) TWideString}; Flags: integer = 0): boolean;
-var
- AbsRootDir: WideString;
- AbsModsDir: WideString;
- FileInfo: VfsUtils.TNativeFileInfo;
- ModName: WideString;
- ModPathPrefix: WideString;
- NumFailedMappings: integer;
- i: integer;
-
-begin
- {!} Assert(ModList <> nil);
- // * * * * * //
- 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
- ModPathPrefix := VfsUtils.AddBackslash(AbsModsDir);
- NumFailedMappings := 0;
-
- for i := ModList.Count - 1 downto 0 do begin
- ModName := TWideString(ModList[i]).Value;
-
- if not VfsBase.MapDir(AbsRootDir, ModPathPrefix + ModName, not VfsBase.OVERWRITE_EXISTING, Flags) then begin
- Inc(NumFailedMappings);
- end;
- end;
-
- result := (NumFailedMappings = 0) or (NumFailedMappings < ModList.Count);
- end; // .if
-end; // .function MapModsFromList
-
-function MapModsFromList (const RootDir, ModsDir, ModListFile: WideString; Flags: integer = 0): boolean;
-begin
-
-end;
-
-var
-L: TList;
-i: integer;
-
-begin
-
-end.
\ No newline at end of file
diff --git a/Vfs.dpr b/Vfs.dpr
index a899785..f4b154a 100644
--- a/Vfs.dpr
+++ b/Vfs.dpr
@@ -3,7 +3,7 @@ library Vfs;
Author: Alexander Shostak aka Berserker aka EtherniDee.
*)
-uses Windows;
+uses VfsExport;
begin
System.IsMultiThread := true;
diff --git a/Vfs.dproj b/Vfs.dproj
index 1d40729..4b22525 100644
--- a/Vfs.dproj
+++ b/Vfs.dproj
@@ -16,14 +16,12 @@
7.0
- DEBUG
False
True
- False
- ..\Lib\B2;.\Png
- ..\Lib\B2;.\Png
- ..\Lib\B2;.\Png
- ..\Lib\B2;.\Png
+ ..\Lib\B2
+ ..\Lib\B2
+ ..\Lib\B2
+ ..\Lib\B2
3
@@ -33,6 +31,10 @@
FalseTrueFalseFalseFalse1000FalseFalseFalseFalseFalse104912511.0.0.01.0.0.0Vfs.dpr
+
+
+
+
Microsoft Office 2000 Sample Automation Server Wrapper Components
Microsoft Office XP Sample Automation Server Wrapper Components
diff --git a/Vfs.drc b/Vfs.drc
index 4293adf..6b43930 100644
--- a/Vfs.drc
+++ b/Vfs.drc
@@ -8,3 +8,216 @@
resources were bound to the produced executable.
*/
+#define RTLConsts_SInvalidPropertyValue 65424
+#define RTLConsts_SListCapacityError 65425
+#define RTLConsts_SListCountError 65426
+#define RTLConsts_SListIndexError 65427
+#define RTLConsts_SReadError 65428
+#define RTLConsts_SSeekNotImplemented 65429
+#define RTLConsts_SSortedListError 65430
+#define RTLConsts_SWriteError 65431
+#define SysConst_SShortDayNameTue 65440
+#define SysConst_SShortDayNameWed 65441
+#define SysConst_SShortDayNameThu 65442
+#define SysConst_SShortDayNameFri 65443
+#define SysConst_SShortDayNameSat 65444
+#define SysConst_SLongDayNameSun 65445
+#define SysConst_SLongDayNameMon 65446
+#define SysConst_SLongDayNameTue 65447
+#define SysConst_SLongDayNameWed 65448
+#define SysConst_SLongDayNameThu 65449
+#define SysConst_SLongDayNameFri 65450
+#define SysConst_SLongDayNameSat 65451
+#define RTLConsts_SAssignError 65452
+#define RTLConsts_SDuplicateString 65453
+#define RTLConsts_SFCreateErrorEx 65454
+#define RTLConsts_SFOpenErrorEx 65455
+#define SysConst_SShortMonthNameNov 65456
+#define SysConst_SShortMonthNameDec 65457
+#define SysConst_SLongMonthNameJan 65458
+#define SysConst_SLongMonthNameFeb 65459
+#define SysConst_SLongMonthNameMar 65460
+#define SysConst_SLongMonthNameApr 65461
+#define SysConst_SLongMonthNameMay 65462
+#define SysConst_SLongMonthNameJun 65463
+#define SysConst_SLongMonthNameJul 65464
+#define SysConst_SLongMonthNameAug 65465
+#define SysConst_SLongMonthNameSep 65466
+#define SysConst_SLongMonthNameOct 65467
+#define SysConst_SLongMonthNameNov 65468
+#define SysConst_SLongMonthNameDec 65469
+#define SysConst_SShortDayNameSun 65470
+#define SysConst_SShortDayNameMon 65471
+#define SysConst_SSafecallException 65472
+#define SysConst_SAssertError 65473
+#define SysConst_SAbstractError 65474
+#define SysConst_SModuleAccessViolation 65475
+#define SysConst_SOSError 65476
+#define SysConst_SUnkOSError 65477
+#define SysConst_SShortMonthNameJan 65478
+#define SysConst_SShortMonthNameFeb 65479
+#define SysConst_SShortMonthNameMar 65480
+#define SysConst_SShortMonthNameApr 65481
+#define SysConst_SShortMonthNameMay 65482
+#define SysConst_SShortMonthNameJun 65483
+#define SysConst_SShortMonthNameJul 65484
+#define SysConst_SShortMonthNameAug 65485
+#define SysConst_SShortMonthNameSep 65486
+#define SysConst_SShortMonthNameOct 65487
+#define SysConst_SVarArrayCreate 65488
+#define SysConst_SVarArrayBounds 65489
+#define SysConst_SVarArrayLocked 65490
+#define SysConst_SInvalidVarCast 65491
+#define SysConst_SInvalidVarOp 65492
+#define SysConst_SInvalidVarOpWithHResultWithPrefix 65493
+#define SysConst_SVarTypeCouldNotConvert 65494
+#define SysConst_SVarTypeConvertOverflow 65495
+#define SysConst_SVarOverflow 65496
+#define SysConst_SVarInvalid 65497
+#define SysConst_SVarBadType 65498
+#define SysConst_SVarNotImplemented 65499
+#define SysConst_SVarUnexpected 65500
+#define SysConst_SExternalException 65501
+#define SysConst_SAssertionFailed 65502
+#define SysConst_SIntfCastError 65503
+#define SysConst_SOverflow 65504
+#define SysConst_SUnderflow 65505
+#define SysConst_SInvalidPointer 65506
+#define SysConst_SInvalidCast 65507
+#define SysConst_SAccessViolationArg3 65508
+#define SysConst_SAccessViolationNoArg 65509
+#define SysConst_SStackOverflow 65510
+#define SysConst_SControlC 65511
+#define SysConst_SPrivilege 65512
+#define SysConst_SException 65513
+#define SysConst_SExceptTitle 65514
+#define SysConst_SInvalidFormat 65515
+#define SysConst_SArgumentMissing 65516
+#define SysConst_SDispatchError 65517
+#define SysConst_SReadAccess 65518
+#define SysConst_SWriteAccess 65519
+#define SysConst_STimeEncodeError 65520
+#define SysConst_SDateEncodeError 65521
+#define SysConst_SOutOfMemory 65522
+#define SysConst_SInOutError 65523
+#define SysConst_SFileNotFound 65524
+#define SysConst_SInvalidFilename 65525
+#define SysConst_STooManyOpenFiles 65526
+#define SysConst_SAccessDenied 65527
+#define SysConst_SEndOfFile 65528
+#define SysConst_SDiskFull 65529
+#define SysConst_SInvalidInput 65530
+#define SysConst_SDivByZero 65531
+#define SysConst_SRangeError 65532
+#define SysConst_SIntOverflow 65533
+#define SysConst_SInvalidOp 65534
+#define SysConst_SZeroDivide 65535
+STRINGTABLE
+BEGIN
+ RTLConsts_SInvalidPropertyValue, "Invalid property value"
+ RTLConsts_SListCapacityError, "List capacity out of bounds (%d)"
+ RTLConsts_SListCountError, "List count out of bounds (%d)"
+ RTLConsts_SListIndexError, "List index out of bounds (%d)"
+ RTLConsts_SReadError, "Stream read error"
+ RTLConsts_SSeekNotImplemented, "%s.Seek not implemented"
+ RTLConsts_SSortedListError, "Operation not allowed on sorted list"
+ RTLConsts_SWriteError, "Stream write error"
+ SysConst_SShortDayNameTue, "Tue"
+ SysConst_SShortDayNameWed, "Wed"
+ SysConst_SShortDayNameThu, "Thu"
+ SysConst_SShortDayNameFri, "Fri"
+ SysConst_SShortDayNameSat, "Sat"
+ SysConst_SLongDayNameSun, "Sunday"
+ SysConst_SLongDayNameMon, "Monday"
+ SysConst_SLongDayNameTue, "Tuesday"
+ SysConst_SLongDayNameWed, "Wednesday"
+ SysConst_SLongDayNameThu, "Thursday"
+ SysConst_SLongDayNameFri, "Friday"
+ SysConst_SLongDayNameSat, "Saturday"
+ RTLConsts_SAssignError, "Cannot assign a %s to a %s"
+ RTLConsts_SDuplicateString, "String list does not allow duplicates"
+ RTLConsts_SFCreateErrorEx, "Cannot create file \"%s\". %s"
+ RTLConsts_SFOpenErrorEx, "Cannot open file \"%s\". %s"
+ SysConst_SShortMonthNameNov, "Nov"
+ SysConst_SShortMonthNameDec, "Dec"
+ SysConst_SLongMonthNameJan, "January"
+ SysConst_SLongMonthNameFeb, "February"
+ SysConst_SLongMonthNameMar, "March"
+ SysConst_SLongMonthNameApr, "April"
+ SysConst_SLongMonthNameMay, "May"
+ SysConst_SLongMonthNameJun, "June"
+ SysConst_SLongMonthNameJul, "July"
+ SysConst_SLongMonthNameAug, "August"
+ SysConst_SLongMonthNameSep, "September"
+ SysConst_SLongMonthNameOct, "October"
+ SysConst_SLongMonthNameNov, "November"
+ SysConst_SLongMonthNameDec, "December"
+ SysConst_SShortDayNameSun, "Sun"
+ SysConst_SShortDayNameMon, "Mon"
+ SysConst_SSafecallException, "Exception in safecall method"
+ SysConst_SAssertError, "%s (%s, line %d)"
+ SysConst_SAbstractError, "Abstract Error"
+ SysConst_SModuleAccessViolation, "Access violation at address %p in module '%s'. %s of address %p"
+ SysConst_SOSError, "System Error. Code: %d.\r\n%s"
+ SysConst_SUnkOSError, "A call to an OS function failed"
+ SysConst_SShortMonthNameJan, "Jan"
+ SysConst_SShortMonthNameFeb, "Feb"
+ SysConst_SShortMonthNameMar, "Mar"
+ SysConst_SShortMonthNameApr, "Apr"
+ SysConst_SShortMonthNameMay, "May"
+ SysConst_SShortMonthNameJun, "Jun"
+ SysConst_SShortMonthNameJul, "Jul"
+ SysConst_SShortMonthNameAug, "Aug"
+ SysConst_SShortMonthNameSep, "Sep"
+ SysConst_SShortMonthNameOct, "Oct"
+ SysConst_SVarArrayCreate, "Error creating variant or safe array"
+ SysConst_SVarArrayBounds, "Variant or safe array index out of bounds"
+ SysConst_SVarArrayLocked, "Variant or safe array is locked"
+ SysConst_SInvalidVarCast, "Invalid variant type conversion"
+ SysConst_SInvalidVarOp, "Invalid variant operation"
+ SysConst_SInvalidVarOpWithHResultWithPrefix, "Invalid variant operation (%s%.8x)\n%s"
+ SysConst_SVarTypeCouldNotConvert, "Could not convert variant of type (%s) into type (%s)"
+ SysConst_SVarTypeConvertOverflow, "Overflow while converting variant of type (%s) into type (%s)"
+ SysConst_SVarOverflow, "Variant overflow"
+ SysConst_SVarInvalid, "Invalid argument"
+ SysConst_SVarBadType, "Invalid variant type"
+ SysConst_SVarNotImplemented, "Operation not supported"
+ SysConst_SVarUnexpected, "Unexpected variant error"
+ SysConst_SExternalException, "External exception %x"
+ SysConst_SAssertionFailed, "Assertion failed"
+ SysConst_SIntfCastError, "Interface not supported"
+ SysConst_SOverflow, "Floating point overflow"
+ SysConst_SUnderflow, "Floating point underflow"
+ SysConst_SInvalidPointer, "Invalid pointer operation"
+ SysConst_SInvalidCast, "Invalid class typecast"
+ SysConst_SAccessViolationArg3, "Access violation at address %p. %s of address %p"
+ SysConst_SAccessViolationNoArg, "Access violation"
+ SysConst_SStackOverflow, "Stack overflow"
+ SysConst_SControlC, "Control-C hit"
+ SysConst_SPrivilege, "Privileged instruction"
+ SysConst_SException, "Exception %s in module %s at %p.\r\n%s%s\r\n"
+ SysConst_SExceptTitle, "Application Error"
+ SysConst_SInvalidFormat, "Format '%s' invalid or incompatible with argument"
+ SysConst_SArgumentMissing, "No argument for format '%s'"
+ SysConst_SDispatchError, "Variant method calls not supported"
+ SysConst_SReadAccess, "Read"
+ SysConst_SWriteAccess, "Write"
+ SysConst_STimeEncodeError, "Invalid argument to time encode"
+ SysConst_SDateEncodeError, "Invalid argument to date encode"
+ SysConst_SOutOfMemory, "Out of memory"
+ SysConst_SInOutError, "I/O error %d"
+ SysConst_SFileNotFound, "File not found"
+ SysConst_SInvalidFilename, "Invalid filename"
+ SysConst_STooManyOpenFiles, "Too many open files"
+ SysConst_SAccessDenied, "File access denied"
+ SysConst_SEndOfFile, "Read beyond end of file"
+ SysConst_SDiskFull, "Disk full"
+ SysConst_SInvalidInput, "Invalid numeric input"
+ SysConst_SDivByZero, "Division by zero"
+ SysConst_SRangeError, "Range check error"
+ SysConst_SIntOverflow, "Integer overflow"
+ SysConst_SInvalidOp, "Invalid floating point operation"
+ SysConst_SZeroDivide, "Floating point division by zero"
+END
+
+/* D:\Soft\Programming\Delphi\source\SRC\Vfs\Vfs.drf */
diff --git a/VfsBase.pas b/VfsBase.pas
index d62cd3d..95f25f4 100644
--- a/VfsBase.pas
+++ b/VfsBase.pas
@@ -93,14 +93,19 @@ function GetThreadVfsDisabler: TThreadVfsDisabler;
function RunVfs (DirListingOrder: TDirListingSortType): boolean;
(* Temporarily pauses VFS, but does not reset existing mappings *)
-function PauseVfs: boolean; stdcall;
+function PauseVfs: LONGBOOL; stdcall;
(* Stops VFS and clears all mappings *)
-function ResetVfs: boolean; stdcall;
+function ResetVfs: LONGBOOL; stdcall;
(* Returns true if VFS is active globally and for current thread *)
function IsVfsActive: boolean;
+function EnterVfs: boolean;
+procedure LeaveVfs;
+function EnterVfsConfig: boolean;
+procedure LeaveVfsConfig;
+
(* Returns real path for VFS item by its absolute virtual path or empty string. Optionally returns file info structure *)
function GetVfsItemRealPath (const AbsVirtPath: WideString; {n} FileInfo: PNativeFileInfo = nil): WideString;
@@ -315,7 +320,7 @@ begin
end; // .if
end; // .function RunVfs
-function PauseVfs: boolean; stdcall;
+function PauseVfs: LONGBOOL; stdcall;
begin
result := not DisableVfsForThisThread;
@@ -328,7 +333,7 @@ begin
end;
end;
-function ResetVfs: boolean; stdcall;
+function ResetVfs: LONGBOOL; stdcall;
begin
result := not DisableVfsForThisThread;
diff --git a/VfsControl.pas b/VfsControl.pas
new file mode 100644
index 0000000..c6ef99d
--- /dev/null
+++ b/VfsControl.pas
@@ -0,0 +1,184 @@
+unit VfsControl;
+(*
+ Facade unit for high-level VFS API.
+*)
+
+
+(***) interface (***)
+
+uses
+ Windows, SysUtils,
+ Utils, WinUtils, TypeWrappers, DataLib,
+ Files, StrLib,
+ VfsBase, VfsUtils, VfsHooks, DlgMes {FIXME DELETEME};
+
+type
+ (* Import *)
+ TWideString = TypeWrappers.TWideString;
+
+
+(* Runs all VFS subsystems, unless VFS is already running *)
+function RunVfs (DirListingOrder: VfsBase.TDirListingSortType): LONGBOOL; stdcall;
+
+(* Loads mod list from file and maps each mod directory to specified root directory.
+ File with mod list is treated as (BOM or BOM-less) UTF-8 plain text file, where each mod name is separated
+ from another one via Line Feed (#10) character. Each mod named is trimmed, converted to UCS16 and validated before
+ adding to list. Invalid or empty mods will be skipped.
+ Returns true if root and mods directory existed and file with mod list was loaded successfully *)
+function MapModsFromList (const RootDir, ModsDir, ModListFile: WideString; Flags: integer = 0): boolean;
+
+(***) implementation (***)
+
+
+type
+ TModList = DataLib.TList {of (O) TWideString};
+
+
+function RunVfs (DirListingOrder: VfsBase.TDirListingSortType): LONGBOOL; stdcall;
+var
+ CurrDir: WideString;
+
+begin
+ with VfsBase.VfsCritSection do begin
+ Enter;
+
+ result := VfsBase.RunVfs(DirListingOrder);
+
+ if result then begin
+ VfsHooks.InstallHooks;
+
+ // Try to ensure, that current directory handle is tracked by VfsOpenFiles
+ CurrDir := WinUtils.GetCurrentDirW;
+
+ if CurrDir <> '' then begin
+ WinUtils.SetCurrentDirW(CurrDir);
+ end;
+ end;
+
+ Leave;
+ 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} var {out} ModList: TModList): boolean;
+const
+ UTF8_BOM = #$EF#$BB#$BF;
+
+var
+{O} OpenedFile: Files.TFile;
+ AbsFilePath: WideString;
+ FileHandle: integer;
+ FileContents: string;
+ Lines: Utils.TArrayOfStr;
+ ModNameUtf8: string;
+ ModName: WideString;
+ i: integer;
+
+begin
+ OpenedFile := Files.TFile.Create;
+ // * * * * * //
+ AbsFilePath := VfsUtils.NormalizePath(ModListFilePath);
+ FileHandle := integer(Windows.INVALID_HANDLE_VALUE);
+ result := AbsFilePath <> '';
+
+ if result then begin
+ FileHandle := Windows.CreateFileW(PWideChar(AbsFilePath), Windows.GENERIC_READ, Windows.FILE_SHARE_READ, nil, Windows.OPEN_EXISTING, 0, 0);
+ result := FileHandle <> integer(Windows.INVALID_HANDLE_VALUE);
+ end;
+
+ if result then begin
+ result := Files.ReadFileContents(FileHandle, FileContents);
+
+ if result then begin
+ SysUtils.FreeAndNil(ModList);
+ ModList := DataLib.NewList(Utils.OWNS_ITEMS);
+
+ if (Length(FileContents) >= 3) and (FileContents[1] = UTF8_BOM[1]) and (FileContents[2] = UTF8_BOM[2]) and (FileContents[3] = UTF8_BOM[3]) then begin
+ FileContents := Copy(FileContents, Length(UTF8_BOM) + 1);
+ end;
+
+ Lines := StrLib.Explode(FileContents, #10);
+
+ for i := 0 to High(Lines) do begin
+ ModNameUtf8 := Lines[i];
+ ModName := StrLib.TrimW(StrLib.Utf8ToWide(ModNameUtf8, StrLib.FAIL_ON_ERROR));
+
+ if ValidateModName(ModName) then begin
+ ModList.Add(TWideString.Create(ModName));
+ end;
+ end;
+ end;
+
+ Windows.CloseHandle(FileHandle);
+ end; // .if
+ // * * * * * //
+ SysUtils.FreeAndNil(OpenedFile);
+end; // .function LoadModList
+
+function MapModsFromList_ (const RootDir, ModsDir: WideString; ModList: TModList; Flags: integer = 0): boolean;
+var
+ AbsRootDir: WideString;
+ AbsModsDir: WideString;
+ FileInfo: VfsUtils.TNativeFileInfo;
+ ModName: WideString;
+ ModPathPrefix: WideString;
+ i: integer;
+
+begin
+ {!} Assert(ModList <> nil);
+ // * * * * * //
+ AbsRootDir := VfsUtils.NormalizePath(RootDir);
+ AbsModsDir := VfsUtils.NormalizePath(ModsDir);
+ result := (AbsRootDir <> '') and (AbsModsDir <> '') and
+ VfsUtils.GetFileInfo(AbsRootDir, FileInfo) and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes) and
+ VfsUtils.GetFileInfo(AbsModsDir, FileInfo) and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes);
+
+ if result then begin
+ ModPathPrefix := VfsUtils.AddBackslash(AbsModsDir);
+
+ for i := ModList.Count - 1 downto 0 do begin
+ ModName := TWideString(ModList[i]).Value;
+ VfsBase.MapDir(AbsRootDir, ModPathPrefix + ModName, not VfsBase.OVERWRITE_EXISTING, Flags);
+ end;
+ end; // .if
+end; // .function MapModsFromList
+
+function MapModsFromList (const RootDir, ModsDir, ModListFile: WideString; Flags: integer = 0): boolean;
+var
+{O} ModList: TModList;
+
+begin
+ ModList := nil;
+ // * * * * * //
+ result := VfsBase.EnterVfsConfig;
+
+ if result then begin
+ try
+ result := LoadModList(ModListFile, ModList) and MapModsFromList_(RootDir, ModsDir, ModList, Flags);
+ finally
+ VfsBase.LeaveVfsConfig;
+ end;
+ end;
+ // * * * * * //
+ SysUtils.FreeAndNil(ModList);
+end; // .function MapModsFromList
+
+end.
\ No newline at end of file
diff --git a/VfsExport.pas b/VfsExport.pas
index b367c86..79e1586 100644
--- a/VfsExport.pas
+++ b/VfsExport.pas
@@ -7,7 +7,8 @@ unit VfsExport;
(***) interface (***)
uses
- VfsDebug, VfsBase, VfsControl;
+ Windows,
+ VfsDebug, VfsBase, VfsControl, DlgMes, Files, FilesEx;
exports
VfsDebug.SetLoggingProc,
@@ -21,12 +22,36 @@ exports
(***) implementation (***)
-function MapDir (const VirtPath, RealPath: PWideChar; OverwriteExisting: boolean; Flags: integer = 0): boolean; stdcall;
+function MapDir (const VirtPath, RealPath: PWideChar; OverwriteExisting: boolean; Flags: integer = 0): LONGBOOL; stdcall;
begin
result := VfsBase.MapDir(WideString(VirtPath), WideString(RealPath), OverwriteExisting, Flags);
end;
-exports
- MapDir;
+function MapDirA (const VirtPath, RealPath: PAnsiChar; OverwriteExisting: boolean; Flags: integer = 0): LONGBOOL; stdcall;
+begin
+ result := VfsBase.MapDir(WideString(VirtPath), WideString(RealPath), OverwriteExisting, Flags);
+end;
+function MapModsFromList (const RootDir, ModsDir, ModListFile: PWideChar; Flags: integer = 0): LONGBOOL; stdcall;
+begin
+ result := VfsControl.MapModsFromList(WideString(RootDir), WideString(ModsDir), WideString(ModListFile), Flags);
+end;
+
+function MapModsFromListA (const RootDir, ModsDir, ModListFile: PAnsiChar; Flags: integer = 0): LONGBOOL; stdcall;
+begin
+ result := VfsControl.MapModsFromList(WideString(RootDir), WideString(ModsDir), WideString(ModListFile), Flags);
+end;
+
+exports
+ MapDir,
+ MapDirA,
+ MapModsFromList,
+ MapModsFromListA;
+
+// var s: string;
+// begin
+// assert(MapModsFromListA('D:\Heroes 3', 'D:\Heroes 3\Mods', 'D:\Heroes 3\Mods\list.txt'));
+// VfsControl.RunVfs(SORT_FIFO);
+// ReadFileContents('D:\Heroes 3\Data\s\pHoenix.erm', s);
+// VarDump([GetFileList('D:\Heroes 3\Data\s\*', FILES_AND_DIRS).ToText(#13#10)]);
end.
diff --git a/VfsHooks.pas b/VfsHooks.pas
index 0faa0e7..4710858 100644
--- a/VfsHooks.pas
+++ b/VfsHooks.pas
@@ -633,6 +633,7 @@ begin
end;
initialization
+ System.IsMultiThread := true;
HooksCritSection.Init;
finalization
with VfsBase.VfsCritSection do begin