(DrgFormat): fixed stride calculation and tweaked decoder.

This commit is contained in:
morkt 2015-12-29 09:54:31 +04:00
parent 36ebffb010
commit 6831125278

View File

@ -89,7 +89,7 @@ namespace GameRes.Formats.Ikura
else else
format = PixelFormats.Bgr565; format = PixelFormats.Bgr565;
int stride = (int)info.Width*((info.BPP+7)/8); int stride = ((int)info.Width * info.BPP / 8 + 3) & ~3;
var pixel_data = DecodeStream (file, stride*(int)info.Height); var pixel_data = DecodeStream (file, stride*(int)info.Height);
if (null == pixel_data) if (null == pixel_data)
throw new InvalidFormatException(); throw new InvalidFormatException();
@ -99,81 +99,64 @@ namespace GameRes.Formats.Ikura
byte[] DecodeStream (Stream input, int pixel_count) byte[] DecodeStream (Stream input, int pixel_count)
{ {
byte[] output = new byte[pixel_count]; byte[] output = new byte[pixel_count];
for (int out_pos = 0; pixel_count > 0; ) for (int out_pos = 0; out_pos < output.Length; )
{ {
int opcode = input.ReadByte (); int opcode = input.ReadByte();
if (-1 == opcode) if (-1 == opcode)
break; break;
int count, src_offset; int count, src_offset;
int remaining = output.Length - out_pos;
switch (opcode) switch (opcode)
{ {
case 0: case 0:
count = input.ReadByte (); count = Math.Min (3 * input.ReadByte(), remaining);
src_offset = out_pos - 3; src_offset = out_pos - 3;
if (count < 0 || count * 3 > pixel_count || src_offset < 0) if (count < 0 || src_offset < 0)
return null; return null;
for (int i = 0; i < count; ++i) Binary.CopyOverlapped (output, src_offset, out_pos, count);
{ break;
Buffer.BlockCopy (output, src_offset, output, out_pos, 3); case 1:
out_pos += 3; count = Math.Min (3 * input.ReadByte(), remaining);
} src_offset = out_pos - 3 * input.ReadByte();
pixel_count -= count * 3; if (count < 0 || src_offset < 0 || src_offset == out_pos)
break;
case 1:
count = 3 * input.ReadByte ();
src_offset = out_pos - 3 * input.ReadByte ();
if (count < 0 || count > pixel_count || src_offset < 0 || src_offset == out_pos)
return null; return null;
Binary.CopyOverlapped (output, src_offset, out_pos, count); Binary.CopyOverlapped (output, src_offset, out_pos, count);
out_pos += count;
pixel_count -= count;
break; break;
case 2: case 2:
{ {
count = 3 * input.ReadByte (); count = Math.Min (3 * input.ReadByte(), remaining);
int off_lo = input.ReadByte (); int off_lo = input.ReadByte();
int off_hi = input.ReadByte (); int off_hi = input.ReadByte();
src_offset = out_pos - 3 * (off_hi << 8 | off_lo); src_offset = out_pos - 3 * (off_hi << 8 | off_lo);
if (count < 0 || count > pixel_count || src_offset < 0 || src_offset == out_pos) if (count < 0 || src_offset < 0 || src_offset == out_pos)
return null; return null;
Binary.CopyOverlapped (output, src_offset, out_pos, count); Binary.CopyOverlapped (output, src_offset, out_pos, count);
out_pos += count;
pixel_count -= count;
break; break;
} }
case 3: case 3:
count = 3; count = Math.Min (3, remaining);
src_offset = out_pos - 3 * input.ReadByte (); src_offset = out_pos - 3 * input.ReadByte();
if (count > pixel_count || src_offset < 0 || src_offset == out_pos) if (src_offset < 0 || src_offset == out_pos)
return null; return null;
Buffer.BlockCopy (output, src_offset, output, out_pos, count); Buffer.BlockCopy (output, src_offset, output, out_pos, count);
out_pos += count;
pixel_count -= count;
break; break;
case 4: case 4:
{ {
count = 3; count = Math.Min (3, remaining);
int off_lo = input.ReadByte (); int off_lo = input.ReadByte();
int off_hi = input.ReadByte (); int off_hi = input.ReadByte();
src_offset = out_pos - 3 * (off_hi << 8 | off_lo); src_offset = out_pos - 3 * (off_hi << 8 | off_lo);
if (count > pixel_count || src_offset < 0 || src_offset == out_pos) if (src_offset < 0 || src_offset == out_pos)
return null; return null;
Buffer.BlockCopy (output, src_offset, output, out_pos, count); Buffer.BlockCopy (output, src_offset, output, out_pos, count);
out_pos += count;
pixel_count -= count;
break; break;
} }
default: default:
count = 3*(opcode - 4); count = Math.Min (3*(opcode - 4), remaining);
if (count > pixel_count) input.Read (output, out_pos, count);
return null;
for (int i = 0; i < count; ++i)
{
output[out_pos++] = (byte)input.ReadByte ();
}
pixel_count -= count;
break; break;
} }
out_pos += count;
} }
return output; return output;
} }