Advertisement
Moolah60

SA2 SET Parser

Feb 27th, 2019
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.46 KB | None | 0 0
  1. using System;
  2. using System.Buffers.Binary;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Runtime.InteropServices;
  8.  
  9. namespace SA2SetParser
  10. {
  11.     public enum ByteOrder
  12.     {
  13.         LittleEndian = 0,
  14.         BigEndian = 1
  15.     }
  16.  
  17.     [AttributeUsage(AttributeTargets.Field)]
  18.     public class Endianness : Attribute
  19.     {
  20.         public ByteOrder ByteOrder;
  21.  
  22.         public Endianness(ByteOrder byteOrder)
  23.         {
  24.             ByteOrder = byteOrder;
  25.         }
  26.     }
  27.  
  28.     public static class DataExtensions
  29.     {
  30.         public static unsafe T ToStruct<T>(this IEnumerable<byte> buffer, int offset = 0)
  31.         {
  32.             if (buffer == null) throw new ArgumentNullException($"{nameof(buffer)} cannot be null!");
  33.             if (offset < 0) throw new ArgumentOutOfRangeException($"{nameof(offset)} cannot be less than 0!");
  34.  
  35.             byte[] bufferAsArray;
  36.  
  37.             if (buffer is byte[] localBuffer)
  38.             {
  39.                 bufferAsArray = localBuffer;
  40.             }
  41.             else
  42.             {
  43.                 bufferAsArray = buffer.ToArray();
  44.             }
  45.  
  46.             T structure;
  47.  
  48.             fixed (byte* bufferPointer = bufferAsArray)
  49.             {
  50.                 structure = Marshal.PtrToStructure<T>((IntPtr)bufferPointer + offset);
  51.             }
  52.  
  53.             // Sort endianness
  54.             object boxedStruct = structure;
  55.             foreach (var property in typeof(T).GetFields())
  56.             {
  57.                 if (property.GetCustomAttribute<Endianness>(true)?.ByteOrder != ByteOrder.BigEndian) continue;
  58.  
  59.                 if (property.FieldType == typeof(float))
  60.                 {
  61.                     var propVal = (float)property.GetValue(boxedStruct);
  62.                     var value = BinaryPrimitives.ReverseEndianness(*(uint*)&propVal);
  63.                     property.SetValue(boxedStruct, *(float*)&value);
  64.                 }
  65.                 else
  66.                 {
  67.                     var value = BinaryPrimitives.ReverseEndianness(
  68.                         (dynamic)property.GetValue(boxedStruct));
  69.                     property.SetValue(boxedStruct, value);
  70.                 }
  71.             }
  72.  
  73.             return (T)boxedStruct;
  74.         }
  75.  
  76.         public static unsafe IEnumerable<byte> ToBytes<T>(this T structure)
  77.         {
  78.             if (structure == null) throw new ArgumentNullException($"{nameof(structure)} cannot be null!");
  79.  
  80.             var type = structure.GetType();
  81.             if (!type.IsValueType || type.IsEnum) throw new ArgumentException($"{nameof(structure)} must be a struct!");
  82.  
  83.             var structureClone = structure;
  84.             object boxedStruct = structureClone;
  85.             foreach (var property in typeof(T).GetFields())
  86.             {
  87.                 if (property.GetCustomAttribute<Endianness>(true)?.ByteOrder != ByteOrder.BigEndian) continue;
  88.  
  89.                 if (property.FieldType == typeof(float))
  90.                 {
  91.                     var propVal = (float)property.GetValue(boxedStruct);
  92.                     var value = BinaryPrimitives.ReverseEndianness(*(uint*)&propVal);
  93.                     property.SetValue(boxedStruct, *(float*)&value);
  94.                 }
  95.                 else
  96.                 {
  97.                     var value = BinaryPrimitives.ReverseEndianness(
  98.                     (dynamic)property.GetValue(boxedStruct));
  99.                     property.SetValue(boxedStruct, value);
  100.                 }
  101.             }
  102.  
  103.             var buffer = new byte[Marshal.SizeOf<T>()];
  104.  
  105.             fixed (byte* bufferPointer = buffer)
  106.             {
  107.                 Marshal.StructureToPtr(structureClone, (IntPtr)bufferPointer, false);
  108.             }
  109.  
  110.             return buffer;
  111.         }
  112.     }
  113.  
  114.     public static class SetParser
  115.     {
  116.         //public TextAsset SETFile;
  117.         //public bool SETIsBigEndian = false;
  118.         //public int ChunkSize = 4;
  119.         //public GameObject Placeholder;
  120.         //private byte[] SET;
  121.         //private List<List<byte>> Split;
  122.  
  123.         [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 32)]
  124.         private struct SetHeader
  125.         {
  126.             [Endianness(ByteOrder.BigEndian)]
  127.             public int ObjectCount;
  128.         }
  129.  
  130.         [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 32)]
  131.         public struct Object
  132.         {
  133.             [Endianness(ByteOrder.BigEndian)]
  134.             public ushort ObjectInfo;
  135.             [Endianness(ByteOrder.BigEndian)]
  136.             public ushort RotationX;
  137.             [Endianness(ByteOrder.BigEndian)]
  138.             public ushort RotationY;
  139.             [Endianness(ByteOrder.BigEndian)]
  140.             public ushort RotationZ;
  141.             [Endianness(ByteOrder.BigEndian)]
  142.             public float PositionX;
  143.             [Endianness(ByteOrder.BigEndian)]
  144.             public float PositionY;
  145.             [Endianness(ByteOrder.BigEndian)]
  146.             public float PositionZ;
  147.             [Endianness(ByteOrder.BigEndian)]
  148.             public float PropertyA;
  149.             [Endianness(ByteOrder.BigEndian)]
  150.             public float PropertyB;
  151.             [Endianness(ByteOrder.BigEndian)]
  152.             public float PropertyC;
  153.         }
  154.  
  155.         public unsafe static List<Object> ParseSETFile(string fileLocation)
  156.         {
  157.             if (File.Exists(fileLocation))
  158.             {
  159.                 byte[] fileData;
  160.  
  161.                 try
  162.                 {
  163.                     fileData = File.ReadAllBytes(fileLocation);
  164.                 }
  165.                 catch
  166.                 {
  167.                     Console.WriteLine("Unable to read the SET File! It may be in use by another program.");
  168.                     return new List<Object>();
  169.                 }
  170.  
  171.                 // Get header struct
  172.                 var header = fileData.ToStruct<SetHeader>();
  173.  
  174.                 // Iterate through the subentries and convert each to a struct.
  175.                 var objectList = new List<Object>();
  176.                 try
  177.                 {
  178.                     for (var i = 0; i < header.ObjectCount; i++)
  179.                     {
  180.                         objectList.Add(fileData.ToStruct<Object>(sizeof(SetHeader) + i * sizeof(Object)));
  181.                     }
  182.                 }
  183.                 catch
  184.                 {
  185.                     return objectList; // We hit the end of the file while reading. Return what we have.
  186.                 }
  187.  
  188.                 return objectList;
  189.             }
  190.  
  191.             return new List<Object>();
  192.         }
  193.     }
  194. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement