Advertisement
Brick

MM2 CPVS 2

Jan 17th, 2018
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.09 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace ConsoleApp2
  9. {
  10.     class Program
  11.     {
  12.         struct CPVSCompressor
  13.         {
  14.             public static byte[] Decompress(byte[] data, int start, int end)
  15.             {
  16.                 byte[] result = new byte[512];
  17.  
  18.                 for (int input = start, output = 0; input < end;)
  19.                 {
  20.                     byte size = data[input++];
  21.  
  22.                     if (size >= 128) // Copy
  23.                     {
  24.                         size -= 127;
  25.  
  26.                         for (int j = 0; j < size; ++j)
  27.                             result[output++] = data[input++];
  28.                     }
  29.                     else // Fill
  30.                     {
  31.                         byte value = data[input++];
  32.  
  33.                         for (int j = 0; j < size; ++j)
  34.                             result[output++] = value;
  35.                     }
  36.                 }
  37.  
  38.                 return result;
  39.             }
  40.  
  41.             public static int GetFillLength(byte[] data, int index)
  42.             {
  43.                 var result = Array.FindIndex(data, index + 1, x => x != data[index]);
  44.  
  45.                 if (result < 0)
  46.                 {
  47.                     result = data.Length;
  48.                 }
  49.  
  50.                 result -= index;
  51.  
  52.                 return result;
  53.             }
  54.  
  55.             public static (int, int) GetNextFill(byte[] data, int index)
  56.             {
  57.                 int length = 0;
  58.  
  59.                 while (index < data.Length)
  60.                 {
  61.                     length = GetFillLength(data, index);
  62.  
  63.                     if (length >= 3)
  64.                     {
  65.                         break;
  66.                     }
  67.  
  68.                     index += length;
  69.                 }
  70.  
  71.                 return (index, length);
  72.             }
  73.  
  74.             public static void WriteCopy(BinaryWriter writer, byte[] data, int index, int length)
  75.             {
  76.                 const int MAX_COPY = 128;
  77.  
  78.                 for (int i = 0; i < length; i += MAX_COPY)
  79.                 {
  80.                     var block_length = Math.Min(length - i, MAX_COPY);
  81.  
  82.                     writer.Write((byte) (block_length + 127));
  83.                     writer.Write(data, index + i, block_length);
  84.                 }
  85.             }
  86.  
  87.             public static void WriteFill(BinaryWriter writer, byte value, int length)
  88.             {
  89.                 const int MAX_FILL = 127;
  90.  
  91.                 for (int i = 0; i < length; i += MAX_FILL)
  92.                 {
  93.                     var block_length = Math.Min(length - i, MAX_FILL);
  94.  
  95.                     writer.Write((byte) block_length);
  96.                     writer.Write(value);
  97.                 }
  98.             }
  99.  
  100.             public static byte[] Compress(byte[] data)
  101.             {
  102.                 var result = new MemoryStream();
  103.                 var writer = new BinaryWriter(result);
  104.  
  105.                 for (int i = 0; i < data.Length;)
  106.                 {
  107.                     var (fill_start, fill_length) = GetNextFill(data, i);
  108.  
  109.                     var copy_length = fill_start - i;
  110.                     if (copy_length > 0)
  111.                     {
  112.                         WriteCopy(writer, data, i, copy_length);
  113.                     }
  114.  
  115.                     if (fill_length > 0)
  116.                     {
  117.                         var value = data[fill_start];
  118.  
  119.                         // And remaining data is zeroed
  120.                         if ((value != 0) || ((fill_start + fill_length) < data.Length))
  121.                         {
  122.                             WriteFill(writer, data[fill_start], fill_length);
  123.                         }
  124.                     }
  125.  
  126.                     i = fill_start + fill_length;
  127.                 }
  128.  
  129.                 return result.ToArray();
  130.             }
  131.  
  132.             public static bool[] ExpandCPVSData(byte[] data)
  133.             {
  134.                 var results = new bool[data.Length * 4];
  135.  
  136.                 for (int i = 0; i < results.Length; ++i)
  137.                 {
  138.                     results[i] = ((data[i / 4] >> ((i % 4) * 2)) & 0x3) != 0;
  139.                 }
  140.  
  141.                 return results;
  142.             }
  143.         }
  144.  
  145.         struct CPVS
  146.         {
  147.             static readonly uint PVS0_MAGIC = 0x30535650; /*PVS0*/
  148.  
  149.             public readonly byte[][] Values;
  150.  
  151.             public CPVS(BinaryReader reader)
  152.             {
  153.                 if (reader.ReadUInt32() != PVS0_MAGIC)
  154.                 {
  155.                     throw new Exception("Invalid Magic");
  156.                 }
  157.  
  158.                 var indices = new int[reader.ReadUInt32()];
  159.                 indices[0] = 0;
  160.  
  161.                 for (int i = 1; i < indices.Length; ++i)
  162.                 {
  163.                     indices[i] = reader.ReadInt32();
  164.                 }
  165.  
  166.                 var data = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
  167.  
  168.                 Values = Enumerable.Range(0, indices.Length - 1).Select(x => CPVSCompressor.Decompress(data, indices[x], indices[x + 1])).ToArray();
  169.             }
  170.  
  171.             public void Save(BinaryWriter writer)
  172.             {
  173.                 writer.Write(PVS0_MAGIC);
  174.  
  175.                 var compresed = Values.Select(x => CPVSCompressor.Compress(x)).ToArray();
  176.  
  177.                 writer.Write(compresed.Length + 1);
  178.  
  179.                 for (int i = 0, offset = 0; i < compresed.Length; ++i)
  180.                 {
  181.                     offset += compresed[i].Length;
  182.  
  183.                     writer.Write(offset);
  184.                 }
  185.  
  186.                 foreach (var value in compresed)
  187.                 {
  188.                     writer.Write(value);
  189.                 }
  190.             }
  191.         }
  192.  
  193.         static CPVS ReadCPVS(string filename)
  194.         {
  195.             using (var fs = File.OpenRead(filename))
  196.             {
  197.                 var reader = new BinaryReader(fs);
  198.  
  199.                 return new CPVS(reader);
  200.             }
  201.         }
  202.  
  203.         static void WriteCPVS(CPVS cpvs, string filename)
  204.         {
  205.             using (var fs = File.OpenWrite(filename))
  206.             {
  207.                 var writer = new BinaryWriter(fs);
  208.  
  209.                 cpvs.Save(writer);
  210.             }
  211.         }
  212.  
  213.         static string ByteArrayToHex(byte[] data)
  214.         {
  215.             return String.Join(String.Empty, Array.ConvertAll(data, x => x.ToString("X2")));
  216.         }
  217.  
  218.         static void Main(string[] args)
  219.         {
  220.             string original_name = "london.cpvs";
  221.             string copy_name = "london_copy.cpvs";
  222.  
  223.             var original = ReadCPVS(original_name);
  224.  
  225.             WriteCPVS(original, copy_name);
  226.  
  227.             var copy = ReadCPVS(copy_name);
  228.  
  229.             if (original.Values.Length != copy.Values.Length)
  230.             {
  231.                 Console.WriteLine("Failed Length");
  232.             }
  233.  
  234.             for (int i = 0; i < original.Values.Length; ++i)
  235.             {
  236.                 if (!Enumerable.SequenceEqual(original.Values[i], copy.Values[i]))
  237.                 {
  238.                     Console.WriteLine("{0} Different", i);
  239.                 }
  240.             }
  241.         }
  242.     }
  243. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement