using System.Reflection; using System.Text; using Kaitai; namespace BlendFile; public class Reader { readonly string _path; private readonly Dictionary dnaTypes = new(); private List objects = new(); public List Objects => objects; public Reader(string path) { _path = path; var types = Assembly.GetExecutingAssembly().DefinedTypes; foreach (var type in types) { var attrib = type.GetCustomAttribute(); if (attrib ==null) continue; dnaTypes.Add(attrib.OriginalIndex, type); } } public void Read() { var file = new KaitaiStream(_path); var blend = new Kaitai.BlendFile(file); foreach (var block in blend.Blocks) { if (block.Code != "DATA") continue; if(!dnaTypes.ContainsKey((int)block.SdnaIndex)) continue; Type t = dnaTypes[(int)block.SdnaIndex]; var obj = Activator.CreateInstance(t); if(obj == null) continue; objects.Add(obj); var fields = t.GetFields(); foreach (var field in fields) { var attrib = field.GetCustomAttribute(); if (attrib == null) continue; var offset = fields.Where(f => f.GetCustomAttribute()!.OriginalIndex < attrib.OriginalIndex) .Sum(f => f.GetCustomAttribute()!.Size); var size = attrib.Size; byte[] data = new byte[size]; Array.Copy((byte[])block.Body, offset, data, 0, size); var value = ConvertFieldData(data, attrib.OriginalType); if(value == null) continue; field.SetValue(obj, value); } } } /* * "char" => typeof(char).AssemblyQualifiedName, "short" => typeof(short).AssemblyQualifiedName, "int" => typeof(int).AssemblyQualifiedName, "float" => typeof(float).AssemblyQualifiedName, "double" => typeof(double).AssemblyQualifiedName, "string" => typeof(string).AssemblyQualifiedName, "void" => typeof(object).AssemblyQualifiedName, "ushort" => typeof(ushort).AssemblyQualifiedName, "uchar" => typeof(byte).AssemblyQualifiedName, "int64_t" => typeof(long).AssemblyQualifiedName, "int8_t" => typeof(sbyte).AssemblyQualifiedName, "uint64_t" => typeof(ulong).AssemblyQualifiedName, */ private object? ConvertFieldData(byte[] data, string type) { return type switch { "char" => (char)data[0], "short" => BitConverter.ToInt16(data, 0), "int" => BitConverter.ToInt32(data, 0), "float" => BitConverter.ToSingle(data, 0), "double" => BitConverter.ToDouble(data, 0), "string" => Encoding.UTF8.GetString(data), // utf8? "void" => null, // object? "ushort" => BitConverter.ToUInt16(data, 0), "uchar" => data[0], "int64_t" => BitConverter.ToInt64(data, 0), "int8_t" => (sbyte)data[0], "uint64_t" => BitConverter.ToUInt64(data, 0), _ => null }; }}