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); } } } } }