public void Deserialize(Stream input) { const Endian endian = Endian.Little; var basePosition = input.Position; var magic = input.ReadBytes(7); if (magic.SequenceEqual(_Signature) == false) { throw new FormatException(); } var compressionMode = (ArchiveCompressionMode)input.ReadValueU8(); var indexTableOffset = input.ReadValueU32(endian); var indexTableCount = input.ReadValueU16(endian); this._BasePosition = basePosition; this._Endian = endian; this._CompressionMode = compressionMode; this._Entries.Clear(); if (indexTableCount > 0) { var entries = new ArchiveEntry[indexTableCount]; input.Seek(basePosition + indexTableOffset, SeekOrigin.Begin); for (int i = 0; i < indexTableCount; i++) { var entry = new ArchiveEntry(); entry.NameHashPartA = input.ReadValueU32(endian); entry.NameHashPartB = input.ReadValueU32(endian); entry.Offset = input.ReadValueU32(endian); entry.Length = input.ReadValueU32(endian); entry.Checksum = input.ReadValueU32(endian); entries[i] = entry; } this._Entries.AddRange(entries); } }
public static MemoryStream ReadEntry( Stream input, ArchiveFile.Entry entry, ArchiveCompressionMode mode, Endian endian) { switch (mode) { case ArchiveCompressionMode.Bogocrypt1: { var output = new MemoryStream(); var key = entry.BogocryptKey; long remaining = entry.Length; var block = new byte[1024]; while (remaining > 0) { var blockLength = (int)Math.Min(block.Length, remaining + 3 & ~3); var actualBlockLength = (int)Math.Min(block.Length, remaining); if (blockLength == 0) { throw new InvalidOperationException(); } if (input.Read(block, 0, blockLength) < actualBlockLength) { throw new EndOfStreamException(); } key = ArchiveFile.Bogocrypt1(block, 0, blockLength, key); output.Write(block, 0, actualBlockLength); remaining -= blockLength; } output.Position = 0; return(output); } case ArchiveCompressionMode.LZW: { var output = new MemoryStream(); LZW.Decompress(input, entry.Length, output, endian); output.Position = 0; return(output); } case ArchiveCompressionMode.MiniZ: { ISAAC isaac = null; var outputBytes = new byte[entry.Length]; var outputOffset = 0; var blockBytes = new byte[0x800]; long remaining = entry.Length; bool isCompressed = true; bool isLastBlock; do { var blockFlags = input.ReadValueU32(endian); var blockLength = (int)(blockFlags & ~0x80000000u); isLastBlock = (blockFlags & 0x80000000u) != 0; if (blockLength > blockBytes.Length) { throw new InvalidOperationException(); } if (input.Read(blockBytes, 0, blockLength) != blockLength) { throw new EndOfStreamException(); } if (isCompressed == false || (isLastBlock == false && blockLength == 1024)) { isCompressed = false; if (isaac == null) { isaac = entry.GetISAAC(); } int seed = 0; for (int o = 0; o < blockLength; o++) { if ((o & 3) != 0) { seed >>= 8; } else { seed = isaac.Value(); } blockBytes[o] ^= (byte)seed; } Array.Copy(blockBytes, 0, outputBytes, outputOffset, blockLength); outputOffset += blockLength; remaining -= blockLength; } else { using (var temp = new MemoryStream(blockBytes, false)) { var zlib = new InflaterInputStream(temp, new Inflater(true)); var read = zlib.Read(outputBytes, outputOffset, (int)Math.Min(remaining, 1024)); outputOffset += read; remaining -= read; } } }while (isLastBlock == false); return(new MemoryStream(outputBytes)); } case ArchiveCompressionMode.Bogocrypt2: { var blockBytes = new byte[1024]; var output = new MemoryStream(); long remaining = entry.Length; while (remaining >= 4) { var blockLength = (int)Math.Min(blockBytes.Length, remaining); if (input.Read(blockBytes, 0, blockLength) != blockLength) { throw new EndOfStreamException(); } ArchiveFile.Bogocrypt2(blockBytes, 0, blockLength); output.Write(blockBytes, 0, blockLength); remaining -= blockLength; } if (remaining > 0) { output.WriteFromStream(input, remaining); } output.Position = 0; return(output); } default: { throw new NotSupportedException(); } } }