Added pointers and list handling in reader

This commit is contained in:
mm00
2025-03-10 19:09:11 +01:00
parent b6760ab27a
commit 37ebc71cf3
3 changed files with 85 additions and 7 deletions

View File

@@ -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<DNAClassAttribute>()!.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<DNAFieldAttribute>()!.IsPointer).ToList();
// for each pointer field
foreach (var f in list) {
// get the pointer value
var addr = GetBlockFieldDataOffset(obj.Key.Item1, f.GetCustomAttribute<DNAFieldAttribute>()!.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<Object?> 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) {