(WcgFormat.Reader): use BitStream class.

This commit is contained in:
morkt 2016-01-10 02:34:52 +04:00
parent 83f6f469e5
commit 24a9594273

View File

@ -2,7 +2,7 @@
//! \date Sat Jul 19 23:07:32 2014 //! \date Sat Jul 19 23:07:32 2014
//! \brief Liar-soft WCG image format implementation. //! \brief Liar-soft WCG image format implementation.
// //
// Copyright (C) 2014 by morkt // Copyright (C) 2014-2016 by morkt
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
@ -105,6 +105,7 @@ namespace GameRes.Formats.Liar
{ {
private byte[] m_data; private byte[] m_data;
private BinaryReader m_input; private BinaryReader m_input;
private MsbBitStream m_bits;
private uint m_input_size; private uint m_input_size;
private ushort[] m_index; private ushort[] m_index;
@ -112,11 +113,10 @@ namespace GameRes.Formats.Liar
private uint m_next_size; private uint m_next_size;
private uint m_src; private uint m_src;
private uint m_src_size; private uint m_src_size;
private uint m_dst_size; private int m_dst_size;
private uint edi; private int edi;
private uint m_index_length_limit; private int m_index_length_limit;
private uint m_bits;
public byte[] Data { get { return m_data; } } public byte[] Data { get { return m_data; } }
@ -125,6 +125,7 @@ namespace GameRes.Formats.Liar
m_data = new byte[pixel_size*4]; m_data = new byte[pixel_size*4];
m_input_size = (uint)file.Length; m_input_size = (uint)file.Length;
m_input = new BinaryReader (file, Encoding.ASCII, true); m_input = new BinaryReader (file, Encoding.ASCII, true);
m_bits = new MsbBitStream (file, true);
} }
public void Unpack () public void Unpack ()
@ -137,16 +138,16 @@ namespace GameRes.Formats.Liar
m_data[i] = (byte)~m_data[i]; m_data[i] = (byte)~m_data[i];
} }
private bool Unpack (uint offset) private bool Unpack (int offset)
{ {
m_src = m_next_ptr; m_src = m_next_ptr;
m_src_size = m_next_size; m_src_size = m_next_size;
m_dst_size = (uint)(m_data.Length / 4); m_dst_size = (int)(m_data.Length / 4);
if (m_src_size < 12) if (m_src_size < 12)
throw new InvalidFormatException ("Invalid file size"); throw new InvalidFormatException ("Invalid file size");
m_src_size -= 12; m_src_size -= 12;
m_input.BaseStream.Position = m_next_ptr; m_input.BaseStream.Position = m_next_ptr;
uint unpacked_size = m_input.ReadUInt32(); int unpacked_size = m_input.ReadInt32();
uint data_size = m_input.ReadUInt32(); uint data_size = m_input.ReadUInt32();
uint index_size = m_input.ReadUInt16(); // 8 uint index_size = m_input.ReadUInt16(); // 8
@ -180,81 +181,52 @@ namespace GameRes.Formats.Liar
{ {
ReadIndex (index_size); ReadIndex (index_size);
m_input.BaseStream.Position = data_pos; m_input.BaseStream.Position = data_pos;
m_bits.Reset();
bool small_index = index_size < 0x1002; bool small_index = index_size < 0x1002;
m_index_length_limit = small_index ? 0x06u : 0x0eu; m_index_length_limit = small_index ? 6 : 14;
uint index_bit_length = small_index ? 3u : 4u; int index_bit_length = small_index ? 3 : 4;
m_bits = 0;
while (m_dst_size > 0) while (m_dst_size > 0)
{ {
uint dst_count = 1; int dst_count = 1;
uint index_length = GetBits (index_bit_length, 0); int index_length = m_bits.GetBits (index_bit_length);
if (0 == index_length) if (0 == index_length)
{ {
dst_count = GetBits (4, 0) + 2; dst_count = m_bits.GetBits (4) + 2;
index_length = GetBits (index_bit_length, 0); index_length = m_bits.GetBits (index_bit_length);
} }
if (0 == index_length) if (0 == index_length)
return false; // std::cerr << "zero index length\n"; return false;
uint index = GetIndex (index_length); int index = GetIndex (index_length);
if (index >= index_size) if (index >= index_size)
return false; // std::cerr << "invalid index\n"; return false;
if (dst_count > m_dst_size) if (dst_count > m_dst_size)
return false; return false;
m_dst_size -= dst_count; m_dst_size -= dst_count;
ushort word = m_index[index]; ushort word = m_index[index];
do { do {
PutWord (word); // *(uint16_t*)edi = word; LittleEndian.Pack (word, m_data, edi);
edi += 4; edi += 4;
} while (0 != --dst_count); } while (0 != --dst_count);
} }
return true; return true;
} }
void PutWord (ushort word) int GetIndex (int count)
{
m_data[edi ] = (byte)(word & 0xff);
m_data[edi+1] = (byte)(word >> 8);
}
uint GetNextBit ()
{
m_bits <<= 1;
if (0 == (m_bits & 0xff))
{
if (0 == m_src_size--)
throw new InvalidFormatException ("Unexpected end of file");
m_bits = (uint)m_input.ReadByte() << 1;
m_bits |= 1;
}
return (m_bits >> 8) & 1;
}
uint GetIndex (uint count)
{ {
if (0 == --count) if (0 == --count)
return GetNextBit(); return m_bits.GetNextBit();
if (count < m_index_length_limit) if (count < m_index_length_limit)
return GetBits (count, 1); return 1 << count | m_bits.GetBits (count);
while (0 != GetNextBit()) while (0 != m_bits.GetNextBit())
{ {
if (count >= 0x10) if (count >= 0x10)
throw new InvalidFormatException ("Invalid index count"); throw new InvalidFormatException ("Invalid index count");
++count; ++count;
} }
return GetBits (count, 1); return 1 << count | m_bits.GetBits (count);
}
uint GetBits (uint count, uint word)
{
do
{
word = (word << 1) | GetNextBit();
}
while (0 != --count);
return word;
} }
#region IDisposable Members #region IDisposable Members
@ -271,8 +243,10 @@ namespace GameRes.Formats.Liar
if (!disposed) if (!disposed)
{ {
if (disposing) if (disposing)
{
m_input.Dispose(); m_input.Dispose();
m_input = null; m_bits.Dispose();
}
m_data = null; m_data = null;
m_index = null; m_index = null;
disposed = true; disposed = true;