Merge pull request #5781 from pavlos256/format80-write-rle

Implement Format80 RLE compression
This commit is contained in:
Paul Chote
2014-07-04 10:34:01 +12:00

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -126,26 +126,78 @@ namespace OpenRA.FileFormats
} }
} }
static int CountSame(byte[] src, int offset, int maxCount)
{
maxCount = Math.Min(src.Length - offset, maxCount);
if (maxCount <= 0)
return 0;
var first = src[offset++];
var count = 1;
while (count < maxCount && src[offset++] == first)
count++;
return count;
}
static void WriteCopyBlocks(byte[] src, int offset, int count, MemoryStream output)
{
while (count > 0)
{
var writeNow = Math.Min(count, 0x3F);
output.WriteByte((byte)(0x80 | writeNow));
output.Write(src, offset, writeNow);
count -= writeNow;
offset += writeNow;
}
}
// Quick and dirty Format80 encoder version 2
// Uses raw copy and RLE compression
public static byte[] Encode(byte[] src) public static byte[] Encode(byte[] src)
{ {
/* quick & dirty format80 encoder -- only uses raw copy operator, terminated with a zero-run. */ using (var ms = new MemoryStream())
/* this does not produce good compression, but it's valid format80 */
var ctx = new FastByteReader(src);
var ms = new MemoryStream();
do
{ {
var len = Math.Min(ctx.Remaining(), 0x3F); var offset = 0;
ms.WriteByte((byte)(0x80 | len)); var left = src.Length;
while (len-- > 0) var blockStart = 0;
ms.WriteByte(ctx.ReadByte());
while (offset < left)
{
var repeatCount = CountSame(src, offset, 0xFFFF);
if (repeatCount >= 4)
{
// Write what we haven't written up to now
WriteCopyBlocks(src, blockStart, offset - blockStart, ms);
// Command 4: Repeat byte n times
ms.WriteByte(0xFE);
// Low byte
ms.WriteByte((byte)(repeatCount & 0xFF));
// High byte
ms.WriteByte((byte)(repeatCount >> 8));
// Value to repeat
ms.WriteByte(src[offset]);
offset += repeatCount;
blockStart = offset;
}
else
{
offset++;
}
}
// Write what we haven't written up to now
WriteCopyBlocks(src, blockStart, offset - blockStart, ms);
// Write terminator
ms.WriteByte(0x80);
return ms.ToArray();
} }
while (!ctx.Done());
ms.WriteByte(0x80); // terminator -- 0-length run.
return ms.ToArray();
} }
} }
} }