Skip to content

Commit a695ef1

Browse files
committedFeb 7, 2025·
Add support for zstd compressed depot chunks
1 parent 39c6a3a commit a695ef1

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed
 

‎SteamKit2/SteamKit2/Steam/CDN/DepotChunk.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static int Process( DepotManifest.ChunkData info, ReadOnlySpan<byte> data
6161

6262
if ( buffer[ 0 ] == 'V' && buffer[ 1 ] == 'S' && buffer[ 2 ] == 'Z' && buffer[ 3 ] == 'a' ) // Zstd
6363
{
64-
throw new NotImplementedException( "Zstd compressed chunks are not yet implemented in SteamKit." );
64+
writtenDecompressed = VZstdUtil.Decompress( buffer.AsSpan( 0, written ), destination );
6565
}
6666
else if ( buffer[ 0 ] == 'V' && buffer[ 1 ] == 'Z' && buffer[ 2 ] == 'a' ) // LZMA
6767
{

‎SteamKit2/SteamKit2/SteamKit2.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
</PackageReference>
5656
<PackageReference Include="protobuf-net" Version="3.2.46" />
5757
<PackageReference Include="System.IO.Hashing" Version="9.0.1" />
58+
<PackageReference Include="ZstdSharp.Port" Version="0.8.4" />
5859
</ItemGroup>
5960

6061
</Project>

‎SteamKit2/SteamKit2/Util/VZstdUtil.cs

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
using System.Buffers;
3+
using System.IO;
4+
using System.Runtime.InteropServices;
5+
6+
namespace SteamKit2
7+
{
8+
static class VZstdUtil
9+
{
10+
private const uint VZstdHeader = 0x56535A61;
11+
12+
public static int Decompress( ReadOnlySpan<byte> buffer, byte[] destination )
13+
{
14+
if ( MemoryMarshal.Read<uint>( buffer ) != VZstdHeader )
15+
{
16+
throw new InvalidDataException( "Expecting VZstdHeader at start of stream" );
17+
}
18+
19+
var sizeCompressed = MemoryMarshal.Read<int>( buffer[ ^15.. ] ); // TODO: I am not convinced this is correct -- maybe its the frame size
20+
var sizeDecompressed = MemoryMarshal.Read<int>( buffer[ ^11.. ] );
21+
22+
if ( buffer[ ^3 ] != 'z' || buffer[ ^2 ] != 's' || buffer[ ^1 ] != 'v' )
23+
{
24+
throw new InvalidDataException( "Expecting VZstdFooter at end of stream" );
25+
}
26+
27+
if ( destination.Length < sizeDecompressed )
28+
{
29+
throw new ArgumentException( "The destination buffer is smaller than the decompressed data size.", nameof( destination ) );
30+
}
31+
32+
using var zstdDecompressor = new ZstdSharp.Decompressor();
33+
34+
var input = buffer[ 4..^12 ];
35+
36+
if ( !zstdDecompressor.TryUnwrap( input, destination, out var sizeWritten ) || sizeDecompressed != sizeWritten )
37+
{
38+
throw new InvalidDataException( $"Failed to decompress Zstd (expected {sizeDecompressed} bytes, got {sizeWritten})." );
39+
}
40+
41+
return sizeDecompressed;
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)
Please sign in to comment.