using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
struct CPVSCompressor
{
public static byte[] Decompress(byte[] data, int start, int end)
{
byte[] result = new byte[512];
for (int input = start, output = 0; input < end;)
{
byte size = data[input++];
if (size >= 128) // Copy
{
size -= 127;
for (int j = 0; j < size; ++j)
result[output++] = data[input++];
}
else // Fill
{
byte value = data[input++];
for (int j = 0; j < size; ++j)
result[output++] = value;
}
}
return result;
}
public static int GetFillLength(byte[] data, int index)
{
var result = Array.FindIndex(data, index + 1, x => x != data[index]);
if (result < 0)
{
result = data.Length;
}
result -= index;
return result;
}
public static (int, int) GetNextFill(byte[] data, int index)
{
int length = 0;
while (index < data.Length)
{
length = GetFillLength(data, index);
if (length >= 3)
{
break;
}
index += length;
}
return (index, length);
}
public static void WriteCopy(BinaryWriter writer, byte[] data, int index, int length)
{
const int MAX_COPY = 128;
for (int i = 0; i < length; i += MAX_COPY)
{
var block_length = Math.Min(length - i, MAX_COPY);
writer.Write((byte) (block_length + 127));
writer.Write(data, index + i, block_length);
}
}
public static void WriteFill(BinaryWriter writer, byte value, int length)
{
const int MAX_FILL = 127;
for (int i = 0; i < length; i += MAX_FILL)
{
var block_length = Math.Min(length - i, MAX_FILL);
writer.Write((byte) block_length);
writer.Write(value);
}
}
public static byte[] Compress(byte[] data)
{
var result = new MemoryStream();
var writer = new BinaryWriter(result);
for (int i = 0; i < data.Length;)
{
var (fill_start, fill_length) = GetNextFill(data, i);
var copy_length = fill_start - i;
if (copy_length > 0)
{
WriteCopy(writer, data, i, copy_length);
}
if (fill_length > 0)
{
var value = data[fill_start];
// And remaining data is zeroed
if ((value != 0) || ((fill_start + fill_length) < data.Length))
{
WriteFill(writer, data[fill_start], fill_length);
}
}
i = fill_start + fill_length;
}
return result.ToArray();
}
public static bool[] ExpandCPVSData(byte[] data)
{
var results = new bool[data.Length * 4];
for (int i = 0; i < results.Length; ++i)
{
results[i] = ((data[i / 4] >> ((i % 4) * 2)) & 0x3) != 0;
}
return results;
}
}
struct CPVS
{
static readonly uint PVS0_MAGIC = 0x30535650; /*PVS0*/
public readonly byte[][] Values;
public CPVS(BinaryReader reader)
{
if (reader.ReadUInt32() != PVS0_MAGIC)
{
throw new Exception("Invalid Magic");
}
var indices = new int[reader.ReadUInt32()];
indices[0] = 0;
for (int i = 1; i < indices.Length; ++i)
{
indices[i] = reader.ReadInt32();
}
var data = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
Values = Enumerable.Range(0, indices.Length - 1).Select(x => CPVSCompressor.Decompress(data, indices[x], indices[x + 1])).ToArray();
}
public void Save(BinaryWriter writer)
{
writer.Write(PVS0_MAGIC);
var compresed = Values.Select(x => CPVSCompressor.Compress(x)).ToArray();
writer.Write(compresed.Length + 1);
for (int i = 0, offset = 0; i < compresed.Length; ++i)
{
offset += compresed[i].Length;
writer.Write(offset);
}
foreach (var value in compresed)
{
writer.Write(value);
}
}
}
static CPVS ReadCPVS(string filename)
{
using (var fs = File.OpenRead(filename))
{
var reader = new BinaryReader(fs);
return new CPVS(reader);
}
}
static void WriteCPVS(CPVS cpvs, string filename)
{
using (var fs = File.OpenWrite(filename))
{
var writer = new BinaryWriter(fs);
cpvs.Save(writer);
}
}
static string ByteArrayToHex(byte[] data)
{
return String.Join(String.Empty, Array.ConvertAll(data, x => x.ToString("X2")));
}
static void Main(string[] args)
{
string original_name = "london.cpvs";
string copy_name = "london_copy.cpvs";
var original = ReadCPVS(original_name);
WriteCPVS(original, copy_name);
var copy = ReadCPVS(copy_name);
if (original.Values.Length != copy.Values.Length)
{
Console.WriteLine("Failed Length");
}
for (int i = 0; i < original.Values.Length; ++i)
{
if (!Enumerable.SequenceEqual(original.Values[i], copy.Values[i]))
{
Console.WriteLine("{0} Different", i);
}
}
}
}
}
Comments
0 B
|👍
/👎