mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-21 21:59:47 +00:00
Enable StormLib for all .NET versions
This commit is contained in:
@@ -9,7 +9,7 @@ Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTo
|
||||
The following non-project libraries (or ports thereof) are used for file handling:
|
||||
|
||||
- [GrindCore.SharpCompress](https://github.com/Nanook/GrindCore.SharpCompress) - Common archive format extraction
|
||||
- [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MoPaQ extraction [Unused in .NET Framework 2.0/3.5/4.0 and non-Windows builds due to Windows-specific libraries]
|
||||
- [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MoPaQ extraction [Unused in non-Windows builds due to Windows-specific libraries]
|
||||
|
||||
The following projects have influenced this library:
|
||||
|
||||
|
||||
@@ -41,14 +41,6 @@
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Exclude all external modules for .NET Framework 2.0 and .NET Framework 3.5 -->
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))">
|
||||
<DefaultItemExcludes>
|
||||
$(DefaultItemExcludes);
|
||||
_EXTERNAL\**
|
||||
</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These are needed for dealing with native Windows DLLs -->
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\**\*">
|
||||
|
||||
@@ -168,11 +168,19 @@ namespace CascLibSharp
|
||||
string build = "fre";
|
||||
#endif
|
||||
|
||||
#if NET20 || NET35
|
||||
string mainPath = Path.Combine(directory, Path.Combine("CascLib", Path.Combine(build, Path.Combine(arch, "CascLib.dll"))));
|
||||
#else
|
||||
string mainPath = Path.Combine(directory, "CascLib", build, arch, "CascLib.dll");
|
||||
#endif
|
||||
if (File.Exists(mainPath))
|
||||
return FromFile(mainPath);
|
||||
|
||||
#if NET20 || NET35
|
||||
string alternatePath = Path.Combine(directory, Path.Combine("CascLib", Path.Combine(arch, "CascLib.dll")));
|
||||
#else
|
||||
string alternatePath = Path.Combine(directory, "CascLib", arch, "CascLib.dll");
|
||||
#endif
|
||||
if (File.Exists(mainPath))
|
||||
return FromFile(alternatePath);
|
||||
|
||||
@@ -183,12 +191,23 @@ namespace CascLibSharp
|
||||
throw new FileNotFoundException(string.Format("Could not locate a copy of CascLib.dll to load. The following paths were tried:\n\t{0}\n\t{1}\n\t{2}\n\nEnsure that an architecture-appropriate copy of CascLib.dll is included in your project.", mainPath, alternatePath, localPath));
|
||||
}
|
||||
|
||||
#if NET20 || NET35
|
||||
private static CascApi? _sharedInstance = null;
|
||||
#else
|
||||
private static Lazy<CascApi> _sharedInstance = new Lazy<CascApi>(Load);
|
||||
#endif
|
||||
public static CascApi Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET20 || NET35
|
||||
if (_sharedInstance == null)
|
||||
_sharedInstance = Load();
|
||||
|
||||
return _sharedInstance;
|
||||
#else
|
||||
return _sharedInstance.Value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,17 @@ namespace CascLibSharp
|
||||
{
|
||||
private CascApi _api;
|
||||
private CascStorageSafeHandle? _handle;
|
||||
#if NET20 || NET35
|
||||
private bool? _hasListfile = null;
|
||||
private CascKnownClient? _clientType = null;
|
||||
private long? _fileCount = null;
|
||||
private int? _gameBuild = null;
|
||||
#else
|
||||
private Lazy<bool> _hasListfile;
|
||||
private Lazy<CascKnownClient> _clientType;
|
||||
private Lazy<long> _fileCount;
|
||||
private Lazy<int> _gameBuild;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CascStorageContext for the specified path.
|
||||
@@ -29,10 +36,12 @@ namespace CascLibSharp
|
||||
throw new CascException();
|
||||
_handle.Api = _api;
|
||||
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
_hasListfile = new Lazy<bool>(CheckHasListfile);
|
||||
_clientType = new Lazy<CascKnownClient>(GetClient);
|
||||
_fileCount = new Lazy<long>(GetFileCount);
|
||||
_gameBuild = new Lazy<int>(GetGameBuild);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,7 +137,11 @@ namespace CascLibSharp
|
||||
if (_handle == null || _handle.IsInvalid)
|
||||
throw new ObjectDisposedException("CascStorageContext");
|
||||
|
||||
#if NET20 || NET35
|
||||
if (this.GameClient == CascKnownClient.WorldOfWarcraft && string.IsNullOrEmpty(listFilePath))
|
||||
#else
|
||||
if (this.GameClient == CascKnownClient.WorldOfWarcraft && string.IsNullOrWhiteSpace(listFilePath))
|
||||
#endif
|
||||
throw new ArgumentNullException("listFilePath");
|
||||
|
||||
CascFindData cfd = new CascFindData();
|
||||
@@ -158,7 +171,11 @@ namespace CascLibSharp
|
||||
throw new CascException();
|
||||
|
||||
CascStorageFeatures features = (CascStorageFeatures)storageInfo;
|
||||
#if NET20 || NET35
|
||||
if ((features & CascStorageFeatures.HasListfile) != 0)
|
||||
#else
|
||||
if (features.HasFlag(CascStorageFeatures.HasListfile))
|
||||
#endif
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -209,6 +226,10 @@ namespace CascLibSharp
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET20 || NET35
|
||||
if (_hasListfile == null)
|
||||
_hasListfile = CheckHasListfile();
|
||||
#endif
|
||||
return _hasListfile.Value;
|
||||
}
|
||||
}
|
||||
@@ -220,6 +241,10 @@ namespace CascLibSharp
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET20 || NET35
|
||||
if (_fileCount == null)
|
||||
_fileCount = GetFileCount();
|
||||
#endif
|
||||
return _fileCount.Value;
|
||||
}
|
||||
}
|
||||
@@ -231,6 +256,10 @@ namespace CascLibSharp
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET20 || NET35
|
||||
if (_gameBuild == null)
|
||||
_gameBuild = GetGameBuild();
|
||||
#endif
|
||||
return _gameBuild.Value;
|
||||
}
|
||||
}
|
||||
@@ -242,6 +271,10 @@ namespace CascLibSharp
|
||||
{
|
||||
get
|
||||
{
|
||||
#if NET20 || NET35
|
||||
if (_clientType == null)
|
||||
_clientType = GetClient();
|
||||
#endif
|
||||
return _clientType.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using StormLibSharp.Native;
|
||||
|
||||
namespace StormLibSharp
|
||||
@@ -30,24 +29,6 @@ namespace StormLibSharp
|
||||
throw new Win32Exception(); // Implicitly calls GetLastError
|
||||
}
|
||||
|
||||
public MpqArchive(MemoryMappedFile file, FileAccess accessType)
|
||||
{
|
||||
_accessType = accessType;
|
||||
string? fileName = Win32Methods.GetFileNameOfMemoryMappedFile(file);
|
||||
if (fileName == null)
|
||||
throw new ArgumentException("Could not retrieve the name of the file to initialize.");
|
||||
|
||||
SFileOpenArchiveFlags flags = SFileOpenArchiveFlags.TypeIsMemoryMapped;
|
||||
if (accessType == FileAccess.Read)
|
||||
flags |= SFileOpenArchiveFlags.AccessReadOnly;
|
||||
else
|
||||
flags |= SFileOpenArchiveFlags.AccessReadWriteShare;
|
||||
|
||||
// constant 2 = SFILE_OPEN_HARD_DISK_FILE
|
||||
if (!NativeMethods.SFileOpenArchive(fileName, 2, flags, out _handle))
|
||||
throw new Win32Exception(); // Implicitly calls GetLastError
|
||||
}
|
||||
|
||||
private MpqArchive(string filePath, MpqArchiveVersion version, MpqFileStreamAttributes listfileAttributes, MpqFileStreamAttributes attributesFileAttributes, int maxFileCount)
|
||||
{
|
||||
if (maxFileCount < 0)
|
||||
|
||||
@@ -1,57 +1,10 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace StormLibSharp.Native
|
||||
{
|
||||
internal static class Win32Methods
|
||||
{
|
||||
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
|
||||
public static extern uint GetMappedFileName(
|
||||
IntPtr hProcess,
|
||||
IntPtr fileHandle,
|
||||
IntPtr lpFilename,
|
||||
uint nSize
|
||||
);
|
||||
|
||||
[DllImport("kernel32", ExactSpelling = false, SetLastError = true)]
|
||||
public static extern uint GetFinalPathNameByHandle(
|
||||
IntPtr hFile,
|
||||
IntPtr lpszFilePath,
|
||||
uint cchFilePath,
|
||||
uint dwFlags
|
||||
);
|
||||
|
||||
[DllImport("kernel32", SetLastError = false, ExactSpelling = false)]
|
||||
public static extern int GetLastError();
|
||||
|
||||
public static string? GetFileNameOfMemoryMappedFile(MemoryMappedFile file)
|
||||
{
|
||||
const uint size = 522;
|
||||
IntPtr path = Marshal.AllocCoTaskMem(unchecked((int)size)); // MAX_PATH + 1 char
|
||||
|
||||
string? result;
|
||||
try
|
||||
{
|
||||
// constant 0x2 = VOLUME_NAME_NT
|
||||
uint test = GetFinalPathNameByHandle(file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size, 0x2);
|
||||
if (test != 0)
|
||||
throw new Win32Exception();
|
||||
|
||||
result = Marshal.PtrToStringAuto(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
uint test = GetMappedFileName(Process.GetCurrentProcess().Handle, file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size);
|
||||
if (test != 0)
|
||||
throw new Win32Exception();
|
||||
|
||||
result = Marshal.PtrToStringAuto(path);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user