Compare commits

..

3 Commits

Author SHA1 Message Date
Samuele Lorefice
91b74a24dd Created a builder for attributes in code generator 2025-02-25 16:32:38 +01:00
Samuele Lorefice
23cec0bd0f Replaced longs with built in IntPtr type. 2025-02-25 16:32:08 +01:00
Samuele Lorefice
315cd6eb44 Added ToPointer ByteArray extension method 2025-02-25 16:31:28 +01:00
5 changed files with 146 additions and 265 deletions

View File

@@ -3,4 +3,7 @@ namespace BlendFile;
public static class ByteArrayExt{ public static class ByteArrayExt{
public static long ToMemAddr(this Byte[] bytes, bool isLittleEndian = true) => public static long ToMemAddr(this Byte[] bytes, bool isLittleEndian = true) =>
BitConverter.ToInt64(isLittleEndian == BitConverter.IsLittleEndian ? bytes : bytes.Reverse().ToArray(), 0); BitConverter.ToInt64(isLittleEndian == BitConverter.IsLittleEndian ? bytes : bytes.Reverse().ToArray(), 0);
public static IntPtr ToPointer(this Byte[] bytes, bool isLittleEndian = true) =>
new (BitConverter.ToInt64(isLittleEndian == BitConverter.IsLittleEndian ? bytes : bytes.Reverse().ToArray(), 0));
} }

View File

@@ -11,8 +11,8 @@ public class Reader {
private readonly Dictionary<int, Type> dnaTypes = new(); private readonly Dictionary<int, Type> dnaTypes = new();
private readonly Dictionary<string, Type> dnaTypesDb = new(); private readonly Dictionary<string, Type> dnaTypesDb = new();
private Dictionary<(long, Type), object> objects = new(); private Dictionary<(IntPtr, Type), object> objects = new();
public Dictionary<(long, Type), object> Objects => objects; public Dictionary<(IntPtr, Type), object> Objects => objects;
/// <summary> /// <summary>
/// A dictionary that contains pointers to pointers /// A dictionary that contains pointers to pointers
@@ -21,7 +21,7 @@ public class Reader {
/// Key: Memory address of the pointer /// Key: Memory address of the pointer
/// Value: Memory address of the object we are pointing to /// Value: Memory address of the object we are pointing to
/// </remarks> /// </remarks>
private Dictionary<long, long> pointers = new(); private Dictionary<IntPtr, IntPtr> pointers = new();
public List<object> GetObjects() => objects.Values.ToList(); public List<object> GetObjects() => objects.Values.ToList();
public List<T> GetObjects<T>() => objects.Values.OfType<T>().ToList(); public List<T> GetObjects<T>() => objects.Values.OfType<T>().ToList();
@@ -66,6 +66,8 @@ public class Reader {
var file = new KaitaiStream(_path); var file = new KaitaiStream(_path);
var blend = new Kaitai.BlendFile(file); var blend = new Kaitai.BlendFile(file);
Console.WriteLine($"Start offset: 0x{blend.Blocks[0].MemAddr.ToPointer():X}");
bool isLe = blend.Hdr.Endian == Kaitai.BlendFile.Endian.Le; bool isLe = blend.Hdr.Endian == Kaitai.BlendFile.Endian.Le;
//TODO: two blocks somehow have the same mem address... this sounds wrong. //TODO: two blocks somehow have the same mem address... this sounds wrong.
blend.Blocks.ForEach(block => memBlocks.TryAdd(block.MemAddr.ToMemAddr(isLe), block)); blend.Blocks.ForEach(block => memBlocks.TryAdd(block.MemAddr.ToMemAddr(isLe), block));
@@ -112,6 +114,10 @@ public class Reader {
private long GetBlockFieldDataOffset(long blockAddress, int fieldIndex, FieldInfo[] fieldMetadata) => private long GetBlockFieldDataOffset(long blockAddress, int fieldIndex, FieldInfo[] fieldMetadata) =>
blockAddress + GetFieldDataOffset(fieldIndex, fieldMetadata); blockAddress + GetFieldDataOffset(fieldIndex, fieldMetadata);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private IntPtr GetBlockFieldDataOffset(IntPtr blockAddress, int fieldIndex, FieldInfo[] fieldMetadata) =>
new(blockAddress + GetFieldDataOffset(fieldIndex, fieldMetadata));
/// <summary> /// <summary>
/// Gets the offset of the data of a field in a block /// Gets the offset of the data of a field in a block
/// </summary> /// </summary>
@@ -138,7 +144,7 @@ public class Reader {
/// <param name="obj">object of same struct type as the one that is being decoded</param> /// <param name="obj">object of same struct type as the one that is being decoded</param>
/// <param name="fieldMetadata">Array of <see cref="FieldInfo"/>s containing <see cref="DNAFieldAttribute"/> attributes</param> /// <param name="fieldMetadata">Array of <see cref="FieldInfo"/>s containing <see cref="DNAFieldAttribute"/> attributes</param>
/// <param name="startOffset">offset in bytes from where structure starts in the block</param> /// <param name="startOffset">offset in bytes from where structure starts in the block</param>
private void FillObject(Kaitai.BlendFile.FileBlock block, ref object? obj, FieldInfo[] fieldMetadata, long startOffset = 0) { private void FillObject(Kaitai.BlendFile.FileBlock block, ref object? obj, FieldInfo[] fieldMetadata, IntPtr startOffset = 0) {
if(block.Code == "ENDB") return;// ENDB is a special block that does not contain any data if(block.Code == "ENDB") return;// ENDB is a special block that does not contain any data
foreach (var field in fieldMetadata) { foreach (var field in fieldMetadata) {
//Get the DNAFieldAttribute of the current field //Get the DNAFieldAttribute of the current field
@@ -147,7 +153,7 @@ public class Reader {
//Calculate the offset from where the data of the field starts. //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 //Because the order of the fields is not guaranteed we need to compute it each time
long offset = attrib.MemoryOffset; IntPtr offset = attrib.MemoryOffset;
int size = attrib.Size; int size = attrib.Size;
var data = new byte[size]; var data = new byte[size];
@@ -168,7 +174,7 @@ public class Reader {
//If the field is not a pointer, we need to dereference it //If the field is not a pointer, we need to dereference it
if (!attrib.IsPointer) { if (!attrib.IsPointer) {
long relAddr = block.MemAddr.ToMemAddr() + offset; IntPtr relAddr = block.MemAddr.ToPointer() + offset;
if (objects.TryGetValue((relAddr, newObj.GetType()), out object? o)) { if (objects.TryGetValue((relAddr, newObj.GetType()), out object? o)) {
//If the object is already created, we can just assign it //If the object is already created, we can just assign it
field.SetValue(obj, o); field.SetValue(obj, o);
@@ -177,9 +183,9 @@ public class Reader {
//Fill the object with the data from the block (this is recursive) //Fill the object with the data from the block (this is recursive)
FillObject(block, ref newObj, fieldInfo, offset); FillObject(block, ref newObj, fieldInfo, offset);
} else { // if is a pointer, make a pointer to the pointer } else { // if is a pointer, make a pointer to the pointer
long memAddr = data.ToMemAddr(); IntPtr memAddr = data.ToPointer();
if (memAddr == 0) continue; //nullPointer, no need to store the reference if (memAddr == 0) continue; //nullPointer, no need to store the reference
pointers.TryAdd(block.MemAddr.ToMemAddr() + offset, data.ToMemAddr()); pointers.TryAdd(block.MemAddr.ToPointer() + offset, data.ToPointer());
} }
} }
continue; //should never happen, but means the data could not be converted continue; //should never happen, but means the data could not be converted
@@ -187,7 +193,7 @@ public class Reader {
//Additionally... some fields might not be nullable so it's better to not assign the value and leave the default one. //Additionally... some fields might not be nullable so it's better to not assign the value and leave the default one.
field.SetValue(obj, value); field.SetValue(obj, value);
} }
objects.Add((block.MemAddr.ToMemAddr() + startOffset, obj!.GetType()), obj!); objects.Add((block.MemAddr.ToPointer() + startOffset, obj!.GetType()), obj!);
} }
private object? ConvertFieldData(byte[] data, string type) private object? ConvertFieldData(byte[] data, string type)

View File

@@ -5,6 +5,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACodeDomProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4333c036d67eaa64623a27221cb821b663bc08410ac68797b1c10376d8379fe_003FCodeDomProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACodeDomProvider_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4333c036d67eaa64623a27221cb821b663bc08410ac68797b1c10376d8379fe_003FCodeDomProvider_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACSharpCodeGenerator_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4aa9136c27fa69d6c91e9d8679c1a1d4b7aabee06e20d4405ee3d91ee05048f0_003FCSharpCodeGenerator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACSharpCodeGenerator_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4aa9136c27fa69d6c91e9d8679c1a1d4b7aabee06e20d4405ee3d91ee05048f0_003FCSharpCodeGenerator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACSharpCodeGenerator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4aa9136c27fa69d6c91e9d8679c1a1d4b7aabee06e20d4405ee3d91ee05048f0_003FCSharpCodeGenerator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACSharpCodeGenerator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F4aa9136c27fa69d6c91e9d8679c1a1d4b7aabee06e20d4405ee3d91ee05048f0_003FCSharpCodeGenerator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fb7208b3f72528d22781d25fde9a55271bdf2b5aade4f03b1324579a25493cd8_003FList_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0beb96d31db641cf82014cb1a758a330b2dc00_003F5b_003F039af867_003FRuntimeType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0beb96d31db641cf82014cb1a758a330b2dc00_003F5b_003F039af867_003FRuntimeType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASortedDictionary_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Febdb3cec3b3875204585daa9fc42159a24cae33b2087ff4dc114d0e6a5a3e9_003FSortedDictionary_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASortedDictionary_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Febdb3cec3b3875204585daa9fc42159a24cae33b2087ff4dc114d0e6a5a3e9_003FSortedDictionary_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F2c8e7ca976f350cba9836d5565dac56b11e0b56656fa786460eb1395857a6fa_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003AC_0021_003FUsers_003Fairon_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F2c8e7ca976f350cba9836d5565dac56b11e0b56656fa786460eb1395857a6fa_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

View File

@@ -0,0 +1,106 @@
using System;
using System.CodeDom;
using System.Collections.Generic;
namespace CodeGenerator {
public class AttributeBuilder {
private static AttributeBuilder _instance;
public static AttributeBuilder Instance => _instance ??= new();
private CodeTypeDeclaration _attrDecl = new();
private List<(Type, string)> _fields = new();
private List<(Type, string, string)> _properties = new();
public AttributeBuilder New() {
_attrDecl.IsClass = true;
_attrDecl.Attributes = MemberAttributes.Public;
_attrDecl.BaseTypes.Add(typeof(Attribute));
return this;
}
public AttributeBuilder New(string name) {
New();
_attrDecl.Name = name;
return this;
}
public AttributeBuilder SetAttributeUsage(CodeAttributeArgument usageArgs) {
var attrUsage = new CodeAttributeDeclaration() {
Name = nameof(AttributeUsageAttribute),
Arguments = { usageArgs }
};
_attrDecl.CustomAttributes.Add(attrUsage);
return this;
}
// ReSharper disable always BitwiseOperatorOnEnumWithoutFlags
public AttributeBuilder AddField<T>(string name,
MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) =>
AddField(typeof(T), name, attributes);
public AttributeBuilder AddField(string type, string name,
MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) =>
AddField(Type.GetType(type), name, attributes);
public AttributeBuilder AddField(Type type, string name,
MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) {
var field = new CodeMemberField(type, name);
field.Attributes = attributes;
_attrDecl.Members.Add(field);
_fields.Add((type, name));
return this;
}
public AttributeBuilder AddAutoProperty(Type type, string name, MemberAttributes attributes = MemberAttributes.Public, bool get = true, bool set = true) {
AddField(type, $"_{name}", MemberAttributes.Private);
return AddProperty(type, name, $"_{name}", attributes, get, set);
}
public AttributeBuilder AddProperty(Type type, string name, string backingPropertyName,
MemberAttributes attributes = MemberAttributes.Public, bool get = true, bool set = true) {
var prop = new CodeMemberProperty {
Name = name,
Type = new (type),
Attributes = attributes,
HasGet = get,
HasSet = set
};
if (get) {
prop.GetStatements.Add(
new CodeMethodReturnStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), backingPropertyName)));
}
if (set) {
prop.SetStatements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), backingPropertyName),
new CodePropertySetValueReferenceExpression()));
}
_properties.Add((type, name, backingPropertyName));
_attrDecl.Members.Add(prop);
return this;
}
public AttributeBuilder AddPropertiesConstructor() {
var ctor = new CodeConstructor { Attributes = MemberAttributes.Public };
_attrDecl.Members.Add(ctor);
_properties.ForEach(property => {
ctor.Parameters.Add(new (property.Item1, property.Item2));
ctor.Statements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), property.Item3), new CodeVariableReferenceExpression(property.Item2)));
});
return this;
}
public CodeTypeDeclaration Build() => _attrDecl;
}
}

View File

@@ -4,7 +4,6 @@ using System.CodeDom.Compiler;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Text; using System.Text;
using Kaitai; using Kaitai;
using Microsoft.CSharp; using Microsoft.CSharp;
@@ -139,265 +138,31 @@ namespace CodeGenerator {
} }
private static CodeTypeDeclaration GenerateDNAFieldAttributeType() { private static CodeTypeDeclaration GenerateDNAFieldAttributeType() {
var ctd = new CodeTypeDeclaration("DNAFieldAttribute") { var attributeBuilder = AttributeBuilder.Instance;
IsClass = true,
Attributes = MemberAttributes.Public
};
ctd.BaseTypes.Add(new CodeTypeReference(typeof(Attribute)));
ctd.CustomAttributes.Add(new("AttributeUsage",
new CodeAttributeArgument(new CodeSnippetExpression("AttributeTargets.Field"))));
var cmf = new CodeMemberField(typeof(int), "_size") { return attributeBuilder.New("DNAFieldAttribute")
Attributes = MemberAttributes.Private .SetAttributeUsage(new (new CodeSnippetExpression("AttributeTargets.Field")))
}; .AddAutoProperty(typeof(int), "Size")
ctd.Members.Add(cmf); .AddAutoProperty(typeof(string), "OriginalType")
.AddAutoProperty(typeof(string), "OriginalName")
var cmp = new CodeMemberProperty() { .AddAutoProperty(typeof(int), "OriginalIndex")
Name = "Size", .AddAutoProperty(typeof(string), "UnderlyingType")
Type = new CodeTypeReference(typeof(int)), .AddAutoProperty(typeof(bool), "IsPointer")
Attributes = MemberAttributes.Public, .AddAutoProperty(typeof(int), "MemoryOffset")
HasSet = true, .AddPropertiesConstructor()
SetStatements = { .Build();
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_size"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_size"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(string), "_originalType") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalType",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(string), "_originalName") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalName",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(
new CFieldRefExp(new CThisRefExp(), "_originalName"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(int), "_originalIndex") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalIndex",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"))
}
};
ctd.Members.Add(cmp);
cmp = new CodeMemberProperty() {
Name = "UnderlyingType",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("_originalType"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(bool), "_isPointer") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "IsPointer",
Type = new CodeTypeReference(typeof(bool)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("_isPointer"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_isPointer"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(int), "_memoryOffset") {
Attributes = MemberAttributes.Private
};
cmp = new CodeMemberProperty() {
Name = "MemoryOffset",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("0"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_memoryOffset"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
var cc = new CodeConstructor() { Attributes = MemberAttributes.Public };
cc.Parameters.AddRange(new CParamDeclExp[] {
new(typeof(int), "originalIndex"),
new(typeof(string), "originalType"),
new(typeof(string), "originalName"),
new(typeof(string), "underlyingType"),
new(typeof(int), "size"),
new(typeof(bool), "isPointer"),
new(typeof(int), "memoryOffset")
});
cc.Statements.AddRange(new CodeAssignStatement[] {
new(new CFieldRefExp(new CThisRefExp(), "OriginalIndex"), new CArgRefExp("originalIndex")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalType"), new CArgRefExp("originalType")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalName"), new CArgRefExp("originalName")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalType"), new CArgRefExp("underlyingType")),
new(new CFieldRefExp(new CThisRefExp(), "Size"), new CArgRefExp("size")),
new(new CFieldRefExp(new CThisRefExp(), "IsPointer"), new CArgRefExp("isPointer")),
new(new CFieldRefExp(new CThisRefExp(), "MemoryOffset"), new CArgRefExp("memoryOffset"))
});
ctd.Members.Add(cc);
return ctd;
} }
private static CodeTypeDeclaration GenerateDNAClassAttributeType() { private static CodeTypeDeclaration GenerateDNAClassAttributeType() {
var ctd = new CodeTypeDeclaration("DNAClassAttribute") { var attributeBuilder = AttributeBuilder.Instance;
IsClass = true,
Attributes = MemberAttributes.Public
};
ctd.BaseTypes.Add(new CodeTypeReference(typeof(Attribute)));
ctd.CustomAttributes.Add(new("AttributeUsage",
new CodeAttributeArgument(new CodeSnippetExpression("AttributeTargets.Class | AttributeTargets.Struct"))));
return attributeBuilder.New("DNAClassAttribute")
var cmf = new CodeMemberField(typeof(int), "_originalIndex") { .SetAttributeUsage(new (new CodeSnippetExpression("AttributeTargets.Class | AttributeTargets.Struct")))
Attributes = MemberAttributes.Private .AddAutoProperty(typeof(int), "OriginalIndex")
}; .AddAutoProperty(typeof(string), "OriginalName")
ctd.Members.Add(cmf); .AddAutoProperty(typeof(int), "Size")
.AddPropertiesConstructor()
var cmp = new CodeMemberProperty() { .Build();
Name = "OriginalIndex",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(string), "_originalName") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalName",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(int), "_size") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "Size",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("_size"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_size"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
var cc = new CodeConstructor() { Attributes = MemberAttributes.Public };
cc.Parameters.AddRange(new CParamDeclExp[] {
new(typeof(int), "originalIndex"),
new(typeof(string), "originalName"),
new(typeof(int), "size")
});
cc.Statements.AddRange(new CodeAssignStatement[] {
new(new CFieldRefExp(new CThisRefExp(), "OriginalIndex"), new CArgRefExp("originalIndex")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalName"), new CArgRefExp("originalName")),
new(new CFieldRefExp(new CThisRefExp(), "Size"), new CArgRefExp("size"))
});
ctd.Members.Add(cc);
return ctd;
} }
private static CodeAttributeDeclaration GenerateDNAFieldAttribute(int index, BlendFile.DnaField field, private static CodeAttributeDeclaration GenerateDNAFieldAttribute(int index, BlendFile.DnaField field,