Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion src/Andre/SoulsFormats/SoulsFormats/Formats/DCX.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.IO.Compression;
using System.IO.MemoryMappedFiles;
using DotNext.IO.MemoryMappedFiles;
using System.Linq;
using ZstdNet;

namespace SoulsFormats
{
Expand Down Expand Up @@ -125,6 +127,10 @@ internal static Memory<byte> Decompress(BinaryReaderEx br, out Type type)
int compressionLevel = br.GetByte(0x30);
type = compressionLevel == 9 ? Type.DCX_KRAK_MAX : Type.DCX_KRAK;
}
else if (format == "ZSTD")
{
type = Type.ZSTD;
}
}
else
{
Expand Down Expand Up @@ -155,6 +161,8 @@ internal static Memory<byte> Decompress(BinaryReaderEx br, out Type type)
return DecompressDCXKRAK(br);
else if (type == Type.DCX_KRAK_MAX)
return DecompressDCXKRAK(br, 9);
else if (type == Type.ZSTD)
return DecompressDCXZSTD(br);
else
throw new FormatException("Unknown DCX format.");
}
Expand Down Expand Up @@ -382,6 +390,42 @@ private static Memory<byte> DecompressDCXKRAK(BinaryReaderEx br, byte compressio

return Oodle.GetOodleCompressor(compressionLevel).Decompress(compressed, uncompressedSize);
}

private static byte[] DecompressDCXZSTD(BinaryReaderEx br)
{
br.AssertASCII("DCX\0");
br.AssertInt32(0x11000);
br.AssertInt32(0x18);
br.AssertInt32(0x24);
br.AssertInt32(0x44);
br.AssertInt32(0x4C);

br.AssertASCII("DCS\0");
int uncompressedSize = br.ReadInt32();
int compressedSize = br.ReadInt32();

br.AssertASCII("DCP\0");
br.AssertASCII("ZSTD");
br.AssertInt32(0x20);
br.AssertByte(0x15);
br.AssertByte(0);
br.AssertByte(0);
br.AssertByte(0);
br.AssertInt32(0x0);
br.AssertByte(0);
br.AssertByte(0);
br.AssertByte(0);
br.AssertByte(0);
br.AssertInt32(0x0);
br.AssertInt32(0x010100);

br.AssertASCII("DCA\0");
br.AssertInt32(8);

byte[] decompressed = SFUtil.ReadZstd(br, compressedSize);

return decompressed;
}

#region Public Compress
/// <summary>
Expand Down Expand Up @@ -427,6 +471,8 @@ internal static void Compress(Span<byte> data, BinaryWriterEx bw, Type type)
CompressDCXKRAK(data, bw);
else if (type == Type.DCX_KRAK_MAX)
CompressDCXKRAK(data, bw, 9);
else if (type == Type.ZSTD)
CompressDCXZSTD(data, bw);
else if (type == Type.Unknown)
throw new ArgumentException("You cannot compress a DCX with an unknown type.");
else
Expand Down Expand Up @@ -642,6 +688,7 @@ private static void CompressDCXKRAK(Span<byte> data, BinaryWriterEx bw, byte com
bw.WriteBytes(compressed);
bw.Pad(0x10);
}


/// <summary>
/// Specific compression format used for a certain file.
Expand Down Expand Up @@ -711,7 +758,12 @@ public enum Type
/// <summary>
/// DCX header, different Oodle compression. Used in Armored Core VI.
/// </summary>
DCX_KRAK_MAX
DCX_KRAK_MAX,

/// <summary>
/// DCX header, new compression format chosen via dart board. Used in Elden Ring: Shadow of the Erdtree.
/// </summary>
ZSTD
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Andre/SoulsFormats/SoulsFormats/SoulsFormats.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
<PackageReference Include="DotNext.Unsafe" Version="4.14.0" />
<PackageReference Include="Microsoft.Toolkit.HighPerformance" Version="7.1.2" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageReference Include="ZstdNet" Version="1.4.5" />
</ItemGroup>
</Project>
19 changes: 19 additions & 0 deletions src/Andre/SoulsFormats/SoulsFormats/Util/SFUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using ZstdNet;

namespace SoulsFormats
{
Expand Down Expand Up @@ -326,6 +327,24 @@ public static byte[] ReadZlib(BinaryReaderEx br, int compressedSize)
return decompressedStream.ToArray();
}
}

/// <summary>
/// Reads a ZSTD compressed file from a BinaryReaderEx and returns the uncompressed data.
/// </summary>
public static byte[] ReadZstd(BinaryReaderEx br, int compressedSize)
{
byte[] compressed = br.ReadBytes(compressedSize);

using (var decompressedStream = new MemoryStream())
{
using (var compressedStream = new MemoryStream(compressed))
using (var deflateStream = new DecompressionStream(compressedStream))
{
deflateStream.CopyTo(decompressedStream);
}
return decompressedStream.ToArray();
}
}

/// <summary>
/// Computes an Adler32 checksum used by Zlib.
Expand Down