mirror of
https://github.com/lifegpc/GARbro.git
synced 2026-06-06 05:28:49 +08:00
Add ZSTD support
This commit is contained in:
@@ -162,6 +162,7 @@
|
||||
<Compile Include="Unity\ScriptDSM.cs" />
|
||||
<Compile Include="Xuse\ArcNT.cs" />
|
||||
<Compile Include="Xuse\ArcWVB.cs" />
|
||||
<Compile Include="ZstdStream.cs" />
|
||||
<Compile Include="Zyx\ImageXMG.cs" />
|
||||
<Compile Include="AudioAIFF.cs" />
|
||||
<Compile Include="Basil\ArcMIF.cs" />
|
||||
@@ -1266,7 +1267,14 @@
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\arcStrings.ru-RU.resx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Content Include="x64\zstd.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="x86\zstd.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName)
|
||||
|
||||
@@ -248,11 +248,22 @@ namespace GameRes.Formats.Circus
|
||||
}
|
||||
}
|
||||
|
||||
private Stream GetDecompressStream() {
|
||||
long pos = m_input.Position;
|
||||
uint header = m_input.ReadUInt32();
|
||||
m_input.Position = pos;
|
||||
if (header == 0xFD2FB528) {
|
||||
var zstd = ZstdReader.Unpack(m_input.AsStream);
|
||||
return new MemoryStream(zstd);
|
||||
} else
|
||||
return new ZLibStream(m_input.AsStream, CompressionMode.Decompress);
|
||||
}
|
||||
|
||||
private void UnpackV2 ()
|
||||
{
|
||||
int pixel_size = m_bpp / 8;
|
||||
int src_stride = m_width * pixel_size;
|
||||
using (var zlib = new ZLibStream (m_input.AsStream, CompressionMode.Decompress, true))
|
||||
using (var zlib = GetDecompressStream())
|
||||
using (var src = new BinaryReader (zlib))
|
||||
{
|
||||
if (m_bpp >= 24)
|
||||
|
||||
102
ArcFormats/ZstdStream.cs
Normal file
102
ArcFormats/ZstdStream.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace GameRes.Compression
|
||||
{
|
||||
public static class ZstdReader
|
||||
{
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
|
||||
[DllImport("zstd.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr ZSTD_createDStream();
|
||||
|
||||
[DllImport("zstd.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int ZSTD_decompressStream(IntPtr zds, ref ZSTD_outBuffer output, ref ZSTD_inBuffer input);
|
||||
|
||||
[DllImport("zstd.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int ZSTD_freeDStream(IntPtr zds);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct ZSTD_inBuffer
|
||||
{
|
||||
public IntPtr src;
|
||||
public UIntPtr size;
|
||||
public UIntPtr pos;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct ZSTD_outBuffer
|
||||
{
|
||||
public IntPtr dst;
|
||||
public UIntPtr size;
|
||||
public UIntPtr pos;
|
||||
}
|
||||
|
||||
public static byte[] Unpack(Stream compressedStream)
|
||||
{
|
||||
if (compressedStream == null) throw new ArgumentNullException(nameof(compressedStream));
|
||||
|
||||
IntPtr dctx = ZSTD_createDStream();
|
||||
if (dctx == IntPtr.Zero)
|
||||
throw new InvalidOperationException("Failed to create ZSTD_DStream.");
|
||||
|
||||
byte[] inBuf = new byte[BUFFER_SIZE];
|
||||
byte[] outBuf = new byte[BUFFER_SIZE];
|
||||
using (MemoryStream result = new MemoryStream())
|
||||
{
|
||||
try
|
||||
{
|
||||
ZSTD_inBuffer input = new ZSTD_inBuffer();
|
||||
ZSTD_outBuffer output = new ZSTD_outBuffer();
|
||||
|
||||
GCHandle inHandle = default, outHandle = default;
|
||||
try
|
||||
{
|
||||
inHandle = GCHandle.Alloc(inBuf, GCHandleType.Pinned);
|
||||
outHandle = GCHandle.Alloc(outBuf, GCHandleType.Pinned);
|
||||
|
||||
int lastRet;
|
||||
while (true)
|
||||
{
|
||||
int bytesRead = compressedStream.Read(inBuf, 0, inBuf.Length);
|
||||
if (bytesRead == 0) break;
|
||||
|
||||
input.src = inHandle.AddrOfPinnedObject();
|
||||
input.size = (UIntPtr)(uint)bytesRead;
|
||||
input.pos = UIntPtr.Zero;
|
||||
|
||||
while (input.pos.ToUInt64() < input.size.ToUInt64())
|
||||
{
|
||||
output.dst = outHandle.AddrOfPinnedObject();
|
||||
output.size = (UIntPtr)(uint)outBuf.Length;
|
||||
output.pos = UIntPtr.Zero;
|
||||
|
||||
lastRet = ZSTD_decompressStream(dctx, ref output, ref input);
|
||||
if (lastRet < 0)
|
||||
throw new InvalidDataException($"ZSTD_decompressStream error: {lastRet}");
|
||||
|
||||
if (output.pos.ToUInt64() > 0)
|
||||
result.Write(outBuf, 0, (int)output.pos.ToUInt64());
|
||||
|
||||
if (lastRet == 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (inHandle.IsAllocated) inHandle.Free();
|
||||
if (outHandle.IsAllocated) outHandle.Free();
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ZSTD_freeDStream(dctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user