//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"); } }
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); }
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); }