diff --git a/BlendFile/BlendFile.csproj b/BlendFile/BlendFile.csproj index f45969b..df6f659 100644 --- a/BlendFile/BlendFile.csproj +++ b/BlendFile/BlendFile.csproj @@ -14,6 +14,9 @@ BlendFile.cs + + StrExt.cs + diff --git a/BlendFile/Reader.cs b/BlendFile/Reader.cs index 815fd52..0426b27 100644 --- a/BlendFile/Reader.cs +++ b/BlendFile/Reader.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Text; +using CodeGenerator; using Kaitai; using static Kaitai.BlendFile; @@ -102,17 +103,40 @@ public class Reader { blockOffset += t.GetCustomAttribute()!.Size; } } - foreach (var obj in objects) { + foreach (var obj in objects) { // for each converted object + // get the fields of the object FieldInfo[] fieldInfo = obj.Value.GetType().GetFields(); + // get all fields that are pointers var list = fieldInfo.Where(fldInfo => fldInfo.GetCustomAttribute()!.IsPointer).ToList(); + // for each pointer field foreach (var f in list) { + // get the pointer value var addr = GetBlockFieldDataOffset(obj.Key.Item1, f.GetCustomAttribute()!.OriginalIndex, fieldInfo); + // get the object that the pointer is pointing to if we've already converted it var newobj = objects.GetValueOrDefault((addr, f.FieldType)); - if (newobj != null) f.SetValue(obj.Value, newobj); + if (newobj != null) + f.SetValue(obj.Value, newobj); + else // if we haven't converted the object yet, we need to convert it now + { + newobj = ActivateInstance(f.FieldType); + if (newobj != null) + { + FillObject(addr, ref newobj, f.FieldType.GetFields()); + f.SetValue(obj.Value, newobj); + Objects.Add((addr, f.FieldType), newobj); + } // should never happen + else throw new NotSupportedException($"Type \"{f.FieldType}\" is unknown"); + } } } + + foreach(var ptr in pointers) { + var obj = objects.GetValueOrDefault((ptr.Key, typeof(object))); + if (obj == null) continue; + InstantiatedObjects.Add(ptr.Key, obj); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -179,6 +203,15 @@ public class Reader { objects.Add((block.MemAddr.ToPointer() + startOffset, obj!.GetType()), obj!); } + private void FillObject(IntPtr ptr, ref object? obj, FieldInfo[] fieldMetadata) + { + var block = GetBlock(ptr.ToInt64()); + if (block == null) throw new($"Block for pointer {ptr.ToInt64():X} not found"); + + var blockOffset = ptr.ToInt64() - block.MemAddr.ToPointer(); + FillObject(block, ref obj, fieldMetadata, new IntPtr(blockOffset)); + } + private object? ConvertNormalField(FileBlock block, DNAFieldAttribute attrib, IntPtr startOffset) { //Calculate the offset from where the data of the field starts. //Because the order of the fields is not guaranteed we need to compute it each time @@ -219,11 +252,50 @@ public class Reader { throw new NotSupportedException($"Unknown type \"{attrib.OriginalType}\""); } - private object? ConvertListField(FileBlock block, FieldInfo field, DNAListAttribute attrib, IntPtr startOffset) {/* - IntPtr offset = attrib.MemoryOffset + startOffset; - int size = Array.Copy((byte[])block.Body, startOffset+attrib.) - var data = new byte[]*/ - return null; + private object? ConvertListField(FileBlock block, FieldInfo field, DNAListAttribute attrib, IntPtr startOffset) { + IntPtr countOffset = attrib.CountMemoryOffset + startOffset; + IntPtr ptrOffset = attrib.PtrMemoryOffset + startOffset; + + var countLen = attrib.CountFieldName.ParseFSize(); + var countData = new byte[countLen]; + Array.Copy((byte[])block.Body, countOffset, countData, 0, countLen); + var tmpCount = ConvertFieldData(countData, attrib.CountFieldName); + int count; + + switch (tmpCount) + { + case int i: + count = i; + break; + case short s: + count = s; + break; + default: + throw new NotSupportedException($"Unknown type \"{attrib.CountFieldName}\""); + } + + List objList = new(); + + for(IntPtr ptr = ptrOffset; ptr < ptrOffset + count * sizeof(Int64); ptr += sizeof(Int64)) { + var data = new byte[sizeof(Int64)]; + Array.Copy((byte[])block.Body, ptr, data, 0, sizeof(Int64)); + IntPtr memAddr = new IntPtr(BitConverter.ToInt64(data, 0)); + + if (memAddr == IntPtr.Zero) { + objList.Add(null); + continue; + } + + var obj = ActivateInstance(attrib.UnderlyingType); + if (obj == null) throw new NotSupportedException($"Type \"{attrib.UnderlyingType}\" is unknown"); + + var fieldMetadata = obj.GetType().GetFields(); + + FillObject(memAddr, ref obj, fieldMetadata); + objList.Add(obj); + } + + return objList; } private object? ConvertFieldData(byte[] data, string type) { diff --git a/BlenderSharp.sln.DotSettings.user b/BlenderSharp.sln.DotSettings.user index d59bd47..066ce2b 100644 --- a/BlenderSharp.sln.DotSettings.user +++ b/BlenderSharp.sln.DotSettings.user @@ -1,4 +1,5 @@  + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -10,8 +11,10 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded