From 18e7d1f849acb57a0fb7dc8af2fcfd3634784c6b Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 21 Aug 2015 02:21:31 +0400 Subject: [PATCH] slightly improved CMP1 decompression performance. --- ArcFormats/RiddleSoft/ImageGCP.cs | 101 +++++++++++------------------- 1 file changed, 37 insertions(+), 64 deletions(-) diff --git a/ArcFormats/RiddleSoft/ImageGCP.cs b/ArcFormats/RiddleSoft/ImageGCP.cs index ec2b87f3..2298b5e3 100644 --- a/ArcFormats/RiddleSoft/ImageGCP.cs +++ b/ArcFormats/RiddleSoft/ImageGCP.cs @@ -45,7 +45,7 @@ namespace GameRes.Formats.Riddle public class GcpFormat : ImageFormat { public override string Tag { get { return "GCP"; } } - public override string Description { get { return "Riddle Soft RGB image format"; } } + public override string Description { get { return "Riddle Soft compressed bitmap"; } } public override uint Signature { get { return 0x31504d43u; } } // 'CMP1' public override void Write (Stream file, ImageData image) @@ -62,24 +62,22 @@ namespace GameRes.Formats.Riddle int pack_size = LittleEndian.ToInt32 (header, 8); if (data_size < 54) return null; - using (var reader = new Reader (stream, pack_size, 0x22)) // BMP header + var reader = new CmpReader (stream, pack_size, 0x22); // BMP header + reader.Unpack(); + var bmp = reader.Data; + if (bmp[0] != 'B' || bmp[1] != 'M') + return null; + int width = LittleEndian.ToInt32 (bmp, 0x12); + int height = LittleEndian.ToInt32 (bmp, 0x16); + int bpp = LittleEndian.ToInt16 (bmp, 0x1c); + return new GcpMetaData { - reader.Unpack(); - var bmp = reader.Data; - if (bmp[0] != 'B' || bmp[1] != 'M') - return null; - int width = LittleEndian.ToInt32 (bmp, 0x12); - int height = LittleEndian.ToInt32 (bmp, 0x16); - int bpp = LittleEndian.ToInt16 (bmp, 0x1c); - return new GcpMetaData - { - Width = (uint)width, - Height = (uint)height, - BPP = bpp, - DataSize = data_size, - PackedSize = pack_size, - }; - } + Width = (uint)width, + Height = (uint)height, + BPP = bpp, + DataSize = data_size, + PackedSize = pack_size, + }; } public override ImageData Read (Stream stream, ImageMetaData info) @@ -89,22 +87,20 @@ namespace GameRes.Formats.Riddle throw new ArgumentException ("GcpFormat.Read should be supplied with GcpMetaData", "info"); stream.Position = 12; - using (var reader = new Reader (stream, meta.PackedSize, meta.DataSize)) + var reader = new CmpReader (stream, meta.PackedSize, meta.DataSize); + reader.Unpack(); + using (var bmp = new MemoryStream (reader.Data, false)) { - reader.Unpack(); - using (var bmp = new MemoryStream (reader.Data, false)) - { - var decoder = new BmpBitmapDecoder (bmp, - BitmapCreateOptions.None, BitmapCacheOption.OnLoad); - BitmapSource frame = decoder.Frames[0]; - frame.Freeze(); - return new ImageData (frame, info); - } + var decoder = new BmpBitmapDecoder (bmp, + BitmapCreateOptions.None, BitmapCacheOption.OnLoad); + BitmapSource frame = decoder.Frames[0]; + frame.Freeze(); + return new ImageData (frame, info); } } } - internal class Reader : IDisposable + internal class CmpReader { Stream m_input; byte[] m_output; @@ -113,7 +109,7 @@ namespace GameRes.Formats.Riddle public byte[] Data { get { return m_output; } } - public Reader (Stream file, int src_size, int dst_size) + public CmpReader (Stream file, int src_size, int dst_size) { m_input = file; m_output = new byte[dst_size]; @@ -129,7 +125,7 @@ namespace GameRes.Formats.Riddle shift[i] = 0x20; while (dst < m_output.Length) { - int bit = GetNextBit(); + int bit = GetBits (1); if (-1 == bit) break; if (1 == bit) @@ -164,46 +160,23 @@ namespace GameRes.Formats.Riddle } int m_bits = 0; + int m_cached_bits = 0; - int GetNextBit () + int GetBits (int count) { - bool bit = 0 != (m_bits & 0x80); - m_bits <<= 1; - if (0 == (m_bits & 0xff)) + while (m_cached_bits < count) { if (m_src_count++ >= m_src_total) return -1; - m_bits = m_input.ReadByte(); - if (-1 == m_bits) - throw new EndOfStreamException ("Invalid compressed stream"); - bit = 0 != (m_bits & 0x80); - m_bits = (m_bits << 1) | 1; - } - return bit ? 1 : 0; - } - - int GetBits (int count, int data = 0) - { - while (count > 0) - { - int bit = GetNextBit(); - if (-1 == bit) + int b = m_input.ReadByte(); + if (-1 == b) return -1; - data = (data << 1) | bit; - --count; + m_bits = (m_bits << 8) | b; + m_cached_bits += 8; } - return data; + int mask = (1 << count) - 1; + m_cached_bits -= count; + return (m_bits >> m_cached_bits) & mask; } - - #region IDisposable Members - public void Dispose () - { - if (null != m_input) - { - m_input = null; - } - GC.SuppressFinalize (this); - } - #endregion } }