using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using ProtoBuf; using SteamKit2; namespace DepotDownloader.Core { [ProtoContract()] public class ProtoManifest { // Proto ctor private ProtoManifest() { Files = new List(); } public ProtoManifest(DepotManifest sourceManifest, ulong id) : this() { sourceManifest.Files.ForEach(f => Files.Add(new FileData(f))); ID = id; CreationTime = sourceManifest.CreationTime; } [ProtoContract()] public class FileData { // Proto ctor private FileData() { Chunks = new List(); } public FileData(DepotManifest.FileData sourceData) : this() { FileName = sourceData.FileName; sourceData.Chunks.ForEach(c => Chunks.Add(new ChunkData(c))); Flags = sourceData.Flags; TotalSize = sourceData.TotalSize; FileHash = sourceData.FileHash; } [ProtoMember(1)] public string FileName { get; internal set; } /// /// Gets the chunks that this file is composed of. /// [ProtoMember(2)] public List Chunks { get; private set; } /// /// Gets the file flags /// [ProtoMember(3)] public EDepotFileFlag Flags { get; private set; } /// /// Gets the total size of this file. /// [ProtoMember(4)] public ulong TotalSize { get; private set; } /// /// Gets the hash of this file. /// [ProtoMember(5)] public byte[] FileHash { get; private set; } } [ProtoContract(SkipConstructor = true)] public class ChunkData { public ChunkData(DepotManifest.ChunkData sourceChunk) { ChunkID = sourceChunk.ChunkID; Checksum = sourceChunk.Checksum; Offset = sourceChunk.Offset; CompressedLength = sourceChunk.CompressedLength; UncompressedLength = sourceChunk.UncompressedLength; } /// /// Gets the SHA-1 hash chunk id. /// [ProtoMember(1)] public byte[] ChunkID { get; private set; } /// /// Gets the expected Adler32 checksum of this chunk. /// [ProtoMember(2)] public byte[] Checksum { get; private set; } /// /// Gets the chunk offset. /// [ProtoMember(3)] public ulong Offset { get; private set; } /// /// Gets the compressed length of this chunk. /// [ProtoMember(4)] public uint CompressedLength { get; private set; } /// /// Gets the decompressed length of this chunk. /// [ProtoMember(5)] public uint UncompressedLength { get; private set; } } [ProtoMember(1)] public List Files { get; private set; } [ProtoMember(2)] public ulong ID { get; private set; } [ProtoMember(3)] public DateTime CreationTime { get; private set; } public static ProtoManifest LoadFromFile(string filename, out byte[] checksum) { if (!File.Exists(filename)) { checksum = null; return null; } using (MemoryStream ms = new MemoryStream()) { using (FileStream fs = File.Open(filename, FileMode.Open)) using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress)) ds.CopyTo(ms); checksum = Util.SHAHash(ms.ToArray()); ms.Seek(0, SeekOrigin.Begin); return ProtoBuf.Serializer.Deserialize(ms); } } public void SaveToFile(string filename, out byte[] checksum) { using (MemoryStream ms = new MemoryStream()) { ProtoBuf.Serializer.Serialize(ms, this); checksum = Util.SHAHash(ms.ToArray()); ms.Seek(0, SeekOrigin.Begin); using (FileStream fs = File.Open(filename, FileMode.Create)) using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress)) ms.CopyTo(ds); } } } }