Replaced Classless.Hasher's Adler32 with a simple, valve-compatible implementation. Added Steam2 file checksum verification to DepotDownloader, so existing files on disk can be used instead of downloading new copies.

pull/8/head
Michael Busby 14 years ago
parent 512e13cc88
commit 24640978b6

@ -655,6 +655,12 @@ namespace DepotDownloader
Console.WriteLine( " Done!" );
Console.Write("Downloading depot checksums...");
Steam2ChecksumData checksums = session.DownloadChecksums();
Console.WriteLine(" Done!");
StringBuilder manifestBuilder = new StringBuilder();
byte[] cryptKey = CDRManager.GetDepotEncryptionKey( depotId, depotVersion );
@ -703,10 +709,16 @@ namespace DepotDownloader
float perc = ( ( float )x / ( float )manifest.Nodes.Count ) * 100.0f;
Console.WriteLine("{0,6:#00.00}%\t{1}", perc, downloadPath);
// TODO: non-checksum validation
FileInfo fi = new FileInfo( downloadPath );
if ( fi.Exists && fi.Length == dirEntry.SizeOrCount )
continue;
if (fi.Exists && fi.Length == dirEntry.SizeOrCount)
{
// Similar file, let's check checksums
if(Util.ValidateFileChecksums(fi, checksums.GetFileChecksums(dirEntry.FileID)))
{
// checksums OK
continue;
}
}
var file = session.DownloadFile( dirEntry, ContentServerClient.StorageSession.DownloadPriority.High, cryptKey );

@ -55,6 +55,10 @@
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="Classless.Hasher, Version=0.9.4179.24334, Culture=neutral, PublicKeyToken=25b6bb7f72693b18, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\SteamKit2\Classless.Hasher.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>

@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using Classless.Hasher;
namespace DepotDownloader
{
@ -75,5 +77,85 @@ namespace DepotDownloader
return password.ToString();
}
// Validate a file against Steam2 Checksums
public static bool ValidateFileChecksums( FileInfo file, int [] checksums )
{
byte[] chunk = new byte[0x8000]; // checksums are for 32KB at a time
FileStream fs = file.OpenRead();
int read, cnt=0;
while ((read = fs.Read(chunk, 0, 0x8000)) > 0)
{
byte[] tempchunk;
if(read < 0x8000)
{
tempchunk = new byte[read];
Array.Copy(chunk, 0, tempchunk, 0, read);
}
else
{
tempchunk = chunk;
}
int adler = BitConverter.ToInt32(AdlerHash(tempchunk), 0);
int crc32 = BitConverter.ToInt32(CRCHash(tempchunk), 0);
if((adler ^ crc32) != checksums[cnt])
{
fs.Close();
return false;
}
++cnt;
}
return (cnt == checksums.Length);
}
// Generate Steam2 Checksums for a file
public static int [] CalculateFileChecksums( FileInfo file )
{
byte[] chunk = new byte[0x8000]; // checksums are for 32KB at a time
int [] checksums = new int[((file.Length-1)/0x8000)+1];
FileStream fs = file.OpenRead();
int read, cnt=0;
while ((read = fs.Read(chunk, 0, 0x8000)) > 0)
{
byte[] tempchunk;
if(read < 0x8000)
{
tempchunk = new byte[read];
Array.Copy(chunk, 0, tempchunk, 0, read);
}
else
{
tempchunk = chunk;
}
int adler = BitConverter.ToInt32(AdlerHash(tempchunk), 0);
int crc32 = BitConverter.ToInt32(CRCHash(tempchunk), 0);
checksums[cnt++] = adler ^ crc32;
}
fs.Close();
return checksums;
}
public static byte[] CRCHash( byte[] input )
{
using ( Crc crc = new Crc( CrcParameters.GetParameters( CrcStandard.Crc32Bit ) ) )
{
byte[] hash = crc.ComputeHash( input );
Array.Reverse( hash );
return hash;
}
}
public static byte[] AdlerHash(byte[] input)
{
uint a = 0, b = 0;
for (int i = 0; i < input.Length; i++)
{
a = (a + input[i]) % 65521;
b = (b + a) % 65521;
}
return BitConverter.GetBytes(a | (b << 16));
}
}
}

Loading…
Cancel
Save