From 29bd97fca9bf92fc7e0dd8f4b0ab3c66f689773e Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 12 Jun 2015 01:47:00 +0400 Subject: [PATCH] (StreamRange): new wrapper around IO.Stream. (LzssReader): allow compressed format customization. --- ArcFormats/ArcCommon.cs | 120 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 6 deletions(-) diff --git a/ArcFormats/ArcCommon.cs b/ArcFormats/ArcCommon.cs index c4f0e17f..e1f23f65 100644 --- a/ArcFormats/ArcCommon.cs +++ b/ArcFormats/ArcCommon.cs @@ -187,26 +187,134 @@ namespace GameRes.Formats } } + /// + /// Represents a region within existing stream. + /// Underlying stream should allow seeking (CanSeek == true). + /// + public class StreamRegion : Stream + { + private Stream m_stream; + private long m_begin; + private long m_end; + + public StreamRegion (Stream main, long offset, long length) + { + m_stream = main; + m_begin = offset; + m_end = Math.Min (offset + length, m_stream.Length); + m_stream.Position = m_begin; + } + + public StreamRegion (Stream main, long offset) : this (main, offset, main.Length-offset) + { + } + + public override bool CanRead { get { return m_stream.CanRead; } } + public override bool CanSeek { get { return true; } } + public override bool CanWrite { get { return false; } } + public override long Length { get { return m_end - m_begin; } } + public override long Position + { + get { return m_stream.Position - m_begin; } + set { m_stream.Position = Math.Max (m_begin + value, m_begin); } + } + + public override void Flush() + { + m_stream.Flush(); + } + + public override long Seek (long offset, SeekOrigin origin) + { + if (SeekOrigin.Begin == origin) + offset += m_begin; + else if (SeekOrigin.Current == origin) + offset += m_stream.Position; + else + offset += m_end; + offset = Math.Max (offset, m_begin); + m_stream.Position = offset; + return offset - m_begin; + } + + public override int Read (byte[] buffer, int offset, int count) + { + int read = 0; + long available = m_end - m_stream.Position; + if (available > 0) + { + read = m_stream.Read (buffer, offset, (int)Math.Min (count, available)); + } + return read; + } + + public override int ReadByte () + { + if (m_stream.Position < m_end) + return m_stream.ReadByte(); + else + return -1; + } + + public override void SetLength (long length) + { + throw new NotSupportedException ("StreamRegion.SetLength method is not supported"); + } + + public override void Write (byte[] buffer, int offset, int count) + { + throw new NotSupportedException ("StreamRegion.Write method is not supported"); + } + + public override void WriteByte (byte value) + { + throw new NotSupportedException ("StreamRegion.WriteByte method is not supported"); + } + + bool m_disposed = false; + protected override void Dispose (bool disposing) + { + if (!m_disposed) + { + m_stream.Dispose(); + m_disposed = true; + base.Dispose (disposing); + } + } + } + public class LzssReader : IDisposable { BinaryReader m_input; byte[] m_output; int m_size; - public byte[] Data { get { return m_output; } } + public BinaryReader Input { get { return m_input; } } + public byte[] Data { get { return m_output; } } + public int FrameSize { get; set; } + public byte FrameFill { get; set; } + public int FrameInitPos { get; set; } public LzssReader (Stream input, int input_length, int output_length) { m_input = new BinaryReader (input, Encoding.ASCII, true); m_output = new byte[output_length]; m_size = input_length; + + FrameSize = 0x1000; + FrameFill = 0; + FrameInitPos = 0xfee; } public void Unpack () { int dst = 0; - var frame = new byte[0x1000]; - int frame_pos = 0xfee; + var frame = new byte[FrameSize]; + if (FrameFill != 0) + for (int i = 0; i < frame.Length; ++i) + frame[i] = FrameFill; + int frame_pos = FrameInitPos; + int frame_mask = FrameSize-1; int remaining = (int)m_size; while (remaining > 0) { @@ -221,7 +329,7 @@ namespace GameRes.Formats byte b = m_input.ReadByte(); --remaining; frame[frame_pos++] = b; - frame_pos &= 0xfff; + frame_pos &= frame_mask; m_output[dst++] = b; } else @@ -237,9 +345,9 @@ namespace GameRes.Formats if (dst >= m_output.Length) break; byte v = frame[offset++]; - offset &= 0xfff; + offset &= frame_mask; frame[frame_pos++] = v; - frame_pos &= 0xfff; + frame_pos &= frame_mask; m_output[dst++] = v; } }