private Stream ReadData(Stream input) { input.Position = DataOffset; int dataSize = (int)CompressedSize; Stream stream = new Decrypt1Stream(input, (int)Version, dataSize, DataHash, hashLow: (uint)(Hash & 0xFFFFFFFF), streamMode: StreamMode.Read); if (Encryption == Cryptography.Magic1 || Encryption == Cryptography.Magic2) { int headerSize = Cryptography.GetHeaderSize(Encryption); stream.Read(new byte[headerSize], 0, headerSize); dataSize -= headerSize; stream = new Decrypt2Stream(stream, dataSize, Key, StreamMode.Read); } if (Compressed) { stream = Compression.UncompressStream(stream); } return(stream); }
public void Write(Stream output, IDirectory inputDirectory) { using (Stream inputStream = inputDirectory.ReadFileStream(Hashing.NormalizeFilePath(FilePath))) using (Md5Stream md5OutputStream = new Md5Stream(output)) { long headerPosition = output.Position; const int entryHeaderSize = 32; long dataStartPosition = headerPosition + entryHeaderSize; output.Position = dataStartPosition; uint uncompressedSize = (uint)inputStream.Length; Stream outputDataStream = md5OutputStream; Stream outputDataStreamCompressed = null; if (Compressed) { outputDataStreamCompressed = Compression.CompressStream(outputDataStream); outputDataStream = outputDataStreamCompressed; } if (Encryption != 0) { int encryptionHeaderSize = Cryptography.GetHeaderSize(Encryption); if (encryptionHeaderSize >= 8) { byte[] header = new byte[encryptionHeaderSize]; Buffer.BlockCopy(BitConverter.GetBytes(Encryption), 0, header, 0, sizeof(uint)); Buffer.BlockCopy(BitConverter.GetBytes(Key), 0, header, 4, sizeof(uint)); if (encryptionHeaderSize == 16) { Buffer.BlockCopy(BitConverter.GetBytes(uncompressedSize), 0, header, 8, sizeof(uint)); Buffer.BlockCopy(BitConverter.GetBytes(uncompressedSize), 0, header, 12, sizeof(uint)); } using (var headerStream = new MemoryStream(header)) { headerStream.CopyTo(outputDataStream); } } outputDataStream = new Decrypt2Stream(outputDataStream, (int)uncompressedSize, Key, StreamMode.Write); } inputStream.CopyTo(outputDataStream); outputDataStreamCompressed?.Close(); // TODO: HACK to support repacked files if (DataHash == null) { md5OutputStream.Flush(); DataHash = md5OutputStream.Hash; } long dataEndPosition = output.Position; uint compressedSize = (uint)(dataEndPosition - dataStartPosition); uncompressedSize = Compressed ? uncompressedSize : compressedSize; using (var decrypt1Stream = new Decrypt1Stream(output, (int)Version, (int)compressedSize, DataHash, hashLow: (uint)(Hash & 0xFFFFFFFF), streamMode: StreamMode.Write)) { CopyTo(output, decrypt1Stream, dataStartPosition, dataEndPosition); } output.Position = headerPosition; const ulong xorMask1Long = 0x4144104341441043; const uint xorMask1 = 0x41441043; const uint xorMask2 = 0x11C22050; const uint xorMask3 = 0xD05608C3; const uint xorMask4 = 0x532C7319; BinaryWriter writer = new BinaryWriter(output, Encoding.ASCII, true); writer.Write(Hash ^ xorMask1Long); writer.Write((Version != 2 ? uncompressedSize : compressedSize) ^ xorMask2); writer.Write((Version != 2 ? compressedSize : uncompressedSize) ^ xorMask3); writer.Write(BitConverter.ToUInt32(DataHash, 0) ^ xorMask4); writer.Write(BitConverter.ToUInt32(DataHash, 4) ^ xorMask1); writer.Write(BitConverter.ToUInt32(DataHash, 8) ^ xorMask1); writer.Write(BitConverter.ToUInt32(DataHash, 12) ^ xorMask2); output.Position = dataEndPosition; } }