//the reader must currently be at the start of the encoded block. the first [segmentOffset] bytes of the block will be discarded.
        internal static byte[] GetResourceData(EndianReader reader, CacheResourceCodec codec, int maxLength, int segmentOffset, int compressedSize, int decompressedSize)
        {
            var segmentLength = Math.Min(maxLength, decompressedSize - segmentOffset);

            if (codec == CacheResourceCodec.Uncompressed || compressedSize == decompressedSize)
            {
                reader.Seek(segmentOffset, SeekOrigin.Current);
                return(reader.ReadBytes(segmentLength));
            }
            else if (codec == CacheResourceCodec.Deflate)
            {
                using (var ds = new DeflateStream(reader.BaseStream, CompressionMode.Decompress))
                    using (var reader2 = new BinaryReader(ds))
                    {
                        reader2.ReadBytes(segmentOffset);
                        return(reader2.ReadBytes(segmentLength));
                    }
            }
            else if (codec == CacheResourceCodec.LZX)
            {
                var compressed   = reader.ReadBytes(compressedSize);
                var decompressed = new byte[decompressedSize];

                int startSize            = compressedSize;
                int endSize              = decompressedSize;
                int decompressionContext = 0;
                XCompress.XMemCreateDecompressionContext(XCompress.XMemCodecType.LZX, 0, 0, ref decompressionContext);
                XCompress.XMemResetDecompressionContext(decompressionContext);
                XCompress.XMemDecompressStream(decompressionContext, decompressed, ref endSize, compressed, ref startSize);
                XCompress.XMemDestroyDecompressionContext(decompressionContext);

                if (decompressed.Length == segmentLength)
                {
                    return(decompressed);
                }

                var result = new byte[segmentLength];
                Array.Copy(decompressed, segmentOffset, result, 0, result.Length);
                return(result);
            }
            else if (codec == CacheResourceCodec.UnknownDeflate) //experimental
            {
                using (var ms = new MemoryStream())
                    using (var mw = new BinaryWriter(ms))
                        using (var ds = new DeflateStream(reader.BaseStream, CompressionMode.Decompress))
                            using (var reader2 = new BinaryReader(ds))
                            {
                                for (int i = 0; i < segmentLength;)
                                {
                                    bool flag;
                                    var  blockSize = ReadSpecialInt(reader2, out flag);
                                    if (flag)
                                    {
                                        reader2.ReadBytes(2);
                                    }
                                    mw.Write(reader2.ReadBytes(blockSize));
                                    i += blockSize;
                                }

                                return(ms.ToArray());
                            }
            }
            else
            {
                throw new NotSupportedException("Unknown Resource Codec");
            }
        }
Beispiel #2
0
        private bool DecryptBaseFile(Stream outBaseFile)
        {
            var tempStream = new MemoryStream();
            var ci         = Get <XexCompressionInfo>();

            // Incase its compressed
            XexCompressedBaseFile compBlock;

            #region Decrypt if encrypted

            if (ci.EncryptionType == XexEncryptionType.Encrypted)
            {
                #region Calculate our key

                var aes = Rijndael.Create();
                aes.Padding = PaddingMode.None;
                var ms         = new MemoryStream(Header.AesKey);
                var decryptKey = new byte[0x10];
                using (var decrypt = new CryptoStream(ms, aes.CreateDecryptor(_retailKey2, new byte[0x10]), CryptoStreamMode.Read))
                {
                    decrypt.Read(decryptKey, 0, 0x10);
                }

                #endregion

                // Now decrypt our data
                aes         = Rijndael.Create();
                aes.Padding = PaddingMode.None;
                var dataStream = Binary.GetStream();
                dataStream.Seek(DataOffset, SeekOrigin.Begin);
                using (var decrypt = new CryptoStream(dataStream, aes.CreateDecryptor(decryptKey, new byte[0x10]), CryptoStreamMode.Read))
                {
                    #region Decrypt non compressed

                    if (ci.CompressionType == XexCompressionType.NotCompressed)
                    {
                        // Loop through each section and decrypt
                        foreach (var block in ci.RawBlocks)
                        {
                            var buffer = new byte[block.DataSize];
                            decrypt.Read(buffer, 0, buffer.Length);
                            outBaseFile.Write(buffer, 0, buffer.Length);
                            outBaseFile.Write(new byte[block.ZeroSize], 0, block.ZeroSize);
                        }

                        // Set our length to image size
                        outBaseFile.Seek(0, SeekOrigin.Begin);
                        outBaseFile.SetLength(Header.ImageSize);

                        // Return true
                        return(true);
                    }

                    #endregion

                    #region Decrypt compressed

                    compBlock = ci.CompressedBaseFile;

                    var index = 0;
                    while (compBlock.DataSize != 0)
                    {
                        var testData = new byte[compBlock.DataSize];
                        dataStream.Read(testData, 0, compBlock.DataSize);
                        dataStream.Seek(compBlock.DataSize * -1, SeekOrigin.Current);

                        // Decrypt our data size
                        var buffer = new byte[compBlock.DataSize];
                        decrypt.Read(buffer, 0, buffer.Length);

                        // Verify our hash
                        var hash = SHA1.Create().ComputeHash(buffer);
                        for (var x = 0; x < 0x14; x++)
                        {
                            if (hash[x] != compBlock.Hash[x])
                            {
                                throw new Exception("Bad hash");
                            }
                        }

                        // Write each block
                        tempStream.Write(buffer, 0, compBlock.DataSize);

                        compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer);
                        index     = index + 1;
                    }

                    tempStream.Seek(0, SeekOrigin.Begin);

                    #endregion
                }
                dataStream.Close();
            }
            else
            {
                #region Write out non compressed

                if (ci.CompressionType == XexCompressionType.NotCompressed)
                {
                    // Loop through each section and decrypt
                    foreach (var block in ci.RawBlocks)
                    {
                        var buffer = Binary.ReadBytes((int)DataOffset, block.DataSize);
                        outBaseFile.Write(buffer, 0, buffer.Length);
                        outBaseFile.Write(new byte[block.ZeroSize], 0, block.ZeroSize);
                    }

                    // Set our length to image size
                    outBaseFile.Seek(0, SeekOrigin.Begin);
                    outBaseFile.SetLength(Header.ImageSize);

                    // Return true
                    return(true);
                }

                #endregion

                // Since we didnt write to the temp stream
                // lets just take it from the file
            }

            #endregion

            // Time to work with compresed
            var sizeLeft = (int)Header.ImageSize;
            compBlock = ci.CompressedBaseFile;

            #region Handle Delta Compresed

            if (ci.CompressionType == XexCompressionType.DeltaCompressed)
            {
                while (compBlock.DataSize != 0)
                {
                    var buffer = new byte[compBlock.DataSize];
                    tempStream.Read(buffer, 0, buffer.Length);
                    outBaseFile.Write(buffer, 0, compBlock.DataSize);

                    compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer);
                }

                // Seek back to start
                outBaseFile.Seek(0, SeekOrigin.Begin);

                // return
                return(true);
            }

            #endregion

            #region Decompress if compressed

            #region Create Decompression Ctx

            int maxSize = 0x8000, ctx = -1, unknown = 0;
            XCompress.LzxDecompress lzx;
            lzx.CpuType    = 1;
            lzx.WindowSize = ci.CompressedBaseFile.CompressionWindow;
            IntPtr allocate = Marshal.AllocHGlobal(0x23200);
            if (XCompress.LDICreateDecompression(ref maxSize, ref lzx,
                                                 0, 0, allocate, ref unknown, ref ctx) != 0)
            {
                throw new Exception("Failed to create decompression");
            }

            #endregion

            while (compBlock.DataSize != 0)
            {
                var buffer = new byte[compBlock.DataSize];
                tempStream.Read(buffer, 0, buffer.Length);

                compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer);
                var offset = compBlock.OffsetTableSize;

                #region Decompress

                while (true)
                {
                    int compressedLen = BitConverter.ToUInt16(buffer, offset);
                    if (compressedLen == 0)
                    {
                        break;
                    }
                    offset += 2;
                    var compressedData = new byte[compressedLen];
                    Buffer.BlockCopy(buffer, offset, compressedData, 0, compressedLen);
                    offset += compressedLen;
                    var decompressedLength = (sizeLeft < 0x8000) ? sizeLeft : 0x8000;
                    var decompressedData   = new byte[decompressedLength];
                    if (XCompress.LDIDecompress(ctx, compressedData,
                                                compressedLen, decompressedData, ref decompressedLength) != 0)
                    {
                        throw new Exception("Failed to decompress");
                    }
                    outBaseFile.Write(decompressedData, 0, decompressedLength);
                    sizeLeft -= decompressedLength;
                }

                #endregion
            }

            #region Destroy ctx

            if (XCompress.LDIDestroyDecompression(ctx) != 0)
            {
                throw new Exception("Failed to destroy decompression");
            }
            Marshal.FreeHGlobal(allocate);

            #endregion

            #endregion

            // Move back to the begining
            outBaseFile.Seek(0, SeekOrigin.Begin);
            outBaseFile.SetLength(Header.ImageSize);

            // All done
            return(true);
        }
Beispiel #3
0
        public override byte[] GetRawFromID(int ID, int DataLength)
        {
            EndianReader er;
            string       fName = "";

            var Entry = zone.RawEntries[ID & ushort.MaxValue];

            if (Entry.SegmentIndex == -1)
            {
                throw new InvalidDataException("Raw data not found.");
            }

            var Loc = play.Segments[Entry.SegmentIndex];

            //if (Loc.SoundRawIndex != -1)
            //    return GetSoundRaw(ID);

            int index     = (Loc.OptionalPageIndex2 != -1) ? Loc.OptionalPageIndex2 : (Loc.OptionalPageIndex != -1) ? Loc.OptionalPageIndex : Loc.RequiredPageIndex;
            int locOffset = (Loc.OptionalPageOffset2 != -1) ? Loc.OptionalPageOffset2 : (Loc.OptionalPageOffset != -1) ? Loc.OptionalPageOffset : Loc.RequiredPageOffset;

            if (index == -1 || locOffset == -1)
            {
                throw new InvalidDataException("Raw data not found.");
            }

            if (play.Pages[index].RawOffset == -1)
            {
                index     = Loc.RequiredPageIndex;
                locOffset = Loc.RequiredPageOffset;
            }

            var Pool = play.Pages[index];

            if (Pool.CacheIndex != -1)
            {
                fName = play.SharedCaches[Pool.CacheIndex].FileName;
                fName = fName.Substring(fName.LastIndexOf('\\'));
                fName = FilePath + fName;

                if (fName == Filename)
                {
                    er = Reader;
                }
                else
                {
                    FileStream fs = new FileStream(fName, FileMode.Open, FileAccess.Read);
                    er = new EndianReader(fs, EndianFormat.Big);
                }
            }
            else
            {
                er = Reader;
            }

            er.SeekTo(int.Parse(versionNode.ChildNodes[0].Attributes["rawTableOffset"].Value));
            int offset = Pool.RawOffset + er.ReadInt32();

            er.SeekTo(offset);
            byte[] compressed   = er.ReadBytes(Pool.CompressedSize);
            byte[] decompressed = new byte[Pool.DecompressedSize];

            if (Version >= DefinitionSet.Halo4Retail)
            {
                int decompressionContext = 0;
                XCompress.XMemCreateDecompressionContext(XCompress.XMemCodecType.LZX, 0, 0, ref decompressionContext);
                XCompress.XMemResetDecompressionContext(decompressionContext);
                XCompress.XMemDecompressStream(decompressionContext, decompressed, ref Pool.DecompressedSize, compressed, ref Pool.CompressedSize);
                XCompress.XMemDestroyDecompressionContext(decompressionContext);
            }
            else
            {
                BinaryReader BR = new BinaryReader(new DeflateStream(new MemoryStream(compressed), CompressionMode.Decompress));
                decompressed = BR.ReadBytes(Pool.DecompressedSize);
                BR.Close();
                BR.Dispose();
            }

            byte[] data   = new byte[(DataLength != -1) ? DataLength : (Pool.DecompressedSize - locOffset)];
            int    length = data.Length;

            if (length > decompressed.Length)
            {
                length = decompressed.Length;
            }
            Array.Copy(decompressed, locOffset, data, 0, length);

            if (er != Reader)
            {
                er.Close();
                er.Dispose();
            }

            return(data);
        }