Beispiel #1
0
        /// <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;
        }
Beispiel #2
0
        /// <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;
        }