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