/// <summary> /// Get an output stream for the specified <see cref="HfsEntry"/> /// </summary> /// <param name="entry">The entry to get an output stream for.</param> /// <returns>The output stream obtained for the entry.</returns> Stream GetOutputStream(HfsEntry entry) { Stream result = baseStream_; long start = result.Position; switch (entry.CompressionMethod) { case CompressionMethod.Stored: { Stream base_result = result; if (entry.Name.Substring(entry.Name.Length - 5) == ".comp") { start += 8; } result = new HFSXorStream(result, start, HfsXorCipher.XorTruths, false); // post process instead //if (obfuscationkey_ > 0) //{ // result = new HFSXorStream(result, start, bytekey_, true); //} if (entry.Name.Substring(entry.Name.Length - 5) == ".comp") { using (MemoryStream ms = new MemoryStream()) using (BinaryWriter writer = new BinaryWriter(ms)) { writer.Write((UInt32)HfsConstants.CompSignature); writer.Write((UInt32)entry.Size); ms.Seek(0, SeekOrigin.Begin); byte[] buff = new byte[ms.Length]; ms.Read(buff, 0, buff.Length); HfsXorCipher.XorBlockWithKey(buff, HfsXorCipher.XorTruths, (int)start - 8); //if (obfuscationkey_ > 0) //{ // HfsXorCipher.XorBlockWithKey(buff, bytekey_, (int)start - 8); //} start += buff.Length; base_result.Write(buff, 0, buff.Length); } DeflaterOutputStream dos = new DeflaterOutputStream(result, new Deflater(9, false)); result = dos; dos.IsStreamOwner = false; } } break; default: throw new HfsException("Unknown compression method " + entry.CompressionMethod); } return result; }
/// <summary> /// Creates an input stream reading a Hfs entry /// </summary> /// <param name="entryIndex">The index of the entry to obtain an input stream for.</param> /// <returns> /// An input <see cref="Stream"/> containing data for this <paramref name="entryIndex"/> /// </returns> /// <exception cref="ObjectDisposedException"> /// The HfsFile has already been closed /// </exception> /// <exception cref="ICSharpCode.SharpZipLib.Hfs.HfsException"> /// The compression method for the entry is unknown /// </exception> /// <exception cref="IndexOutOfRangeException"> /// The entry is not found in the HfsFile /// </exception> public Stream GetInputStream(long entryIndex) { if (isDisposed_) { throw new ObjectDisposedException("HfsFile"); } HfsEntry entry = entries_[entryIndex]; long start = LocateEntry(entry); CompressionMethod method = entries_[entryIndex].CompressionMethod; Stream result = new PartialInputStream(this, start, entries_[entryIndex].CompressedSize); switch (method) { case CompressionMethod.Stored: { Stream base_result = result = new HFSXorStream(result, start, HfsXorCipher.XorTruths, true); if (obfuscationkey_ > 0) { result = new HFSXorStream(result, start, bytekey_, true); } if (entry.Name.Substring(entry.Name.Length - 5) == ".comp") { UInt32 decomp; // technically we don't decompress this, but we will to make it easier (.comp is transparently handled in this lib) byte[] compHeader = new byte[8]; result.Read(compHeader, 0, compHeader.Length); if (!HfsXorCipher.ValidateCompSig(compHeader, out decomp)) { if (obfuscationkey_ == 0) { throw new Exception("No obfs key, bad signature"); } base_result.Seek(-8, SeekOrigin.Current); base_result.Read(compHeader, 0, compHeader.Length); key = HfsXorCipher.BruteforceInnerKey(compHeader, (int)start); HfsXorCipher.XorBlockWithKey(compHeader, key, (int)start); if (!HfsXorCipher.ValidateCompSig(compHeader, out decomp)) { throw new Exception("Bad compression signature"); } Console.WriteLine("Had to brute-force inner XOR key"); bytekey_ = key; obfuscationkey_ = BitConverter.ToUInt32(bytekey_, 0); result = new HFSXorStream(base_result, start, key, true); } entry.Size = decomp; // to ease copying the stream straight to the zip we wrap it with the correct length result = new WrapperStream(new InflaterInputStream(result), entry.Size); } } break; default: throw new HfsException("Unsupported compression method " + method); } return result; }