From d6f00029fd7d0362c8d18fa402b9f4cc644ae817 Mon Sep 17 00:00:00 2001 From: morkt Date: Wed, 3 Oct 2018 17:55:33 +0400 Subject: [PATCH] (Unity): decompress LZMA blocks. --- ArcFormats/Unity/BundleStream.cs | 34 ++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/ArcFormats/Unity/BundleStream.cs b/ArcFormats/Unity/BundleStream.cs index 8afaf826..4483d699 100644 --- a/ArcFormats/Unity/BundleStream.cs +++ b/ArcFormats/Unity/BundleStream.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using GameRes.Compression; +using LZMA = SevenZip.Compression.LZMA; namespace GameRes.Formats.Unity { @@ -97,20 +98,45 @@ namespace GameRes.Formats.Unity } } + byte[] PrepareBuffer (uint length) + { + if (null == m_buffer || length > m_buffer.Length) + m_buffer = new byte[length]; + return m_buffer; + } + void ReadCompressedSegment (BundleSegment segment) { m_input.Position = segment.Offset; + int method = segment.Compression & 0x3F; + if (1 == method) + { + m_buffer_len = LzmaDecompressBlock (segment.PackedSize, segment.UnpackedSize); + return; + } if (null == m_packed || segment.PackedSize > m_packed.Length) m_packed = new byte[segment.PackedSize]; int packed_size = m_input.Read (m_packed, 0, (int)segment.PackedSize); - if (null == m_buffer || segment.UnpackedSize > m_buffer.Length) - m_buffer = new byte[segment.UnpackedSize]; - if (3 == segment.Compression) - m_buffer_len = Lz4Compressor.DecompressBlock (m_packed, packed_size, m_buffer, (int)segment.UnpackedSize); + var output = PrepareBuffer (segment.UnpackedSize); + if (3 == method) + m_buffer_len = Lz4Compressor.DecompressBlock (m_packed, packed_size, output, (int)segment.UnpackedSize); else throw new NotImplementedException ("Not supported Unity asset bundle compression."); } + int LzmaDecompressBlock (uint packed_size, uint unpacked_size) + { + var decoder = new LZMA.Decoder(); + var props = m_input.ReadBytes (5); + decoder.SetDecoderProperties (props); + var buffer = PrepareBuffer (unpacked_size); + using (var output = new MemoryStream (buffer)) + { + decoder.Code (m_input, output, packed_size-5, unpacked_size, null); + return (int)output.Length; + } + } + int ReadFromSegment (BundleSegment segment, byte[] buffer, int offset, int count) { Debug.Assert (m_position >= segment.UnpackedOffset && m_position <= segment.UnpackedOffset + segment.UnpackedSize);