mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-02-04 05:36:05 +00:00
Add "correct order" inheritence serialization
This commit is contained in:
@@ -530,5 +530,57 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.NotNull(read.LPByteArray);
|
||||
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeInheritanceTest()
|
||||
{
|
||||
byte[] structBytes1 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, 0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, 0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
var stream1 = new MemoryStream(structBytes1);
|
||||
var br1 = new BinaryReader(stream1);
|
||||
var expected1 = new TestStructInheritanceChild1
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA55AA,
|
||||
FieldB = 0xAA55AA55,
|
||||
};
|
||||
var read1 = br1.ReadType<TestStructInheritanceChild1>();
|
||||
Assert.NotNull(read1?.Signature);
|
||||
Assert.Equal(expected1.Signature, read1.Signature);
|
||||
Assert.Equal(expected1.IdentifierType, read1.IdentifierType);
|
||||
Assert.Equal(expected1.FieldA, read1.FieldA);
|
||||
Assert.Equal(expected1.FieldB, read1.FieldB);
|
||||
|
||||
byte[] structBytes2 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
var stream2 = new MemoryStream(structBytes2);
|
||||
var br2 = new BinaryReader(stream2);
|
||||
var expected2 = new TestStructInheritanceChild2
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA,
|
||||
FieldB = 0xAA55,
|
||||
};
|
||||
var read2 = br2.ReadType<TestStructInheritanceChild2>();
|
||||
Assert.NotNull(read2?.Signature);
|
||||
Assert.Equal(expected2.Signature, read2.Signature);
|
||||
Assert.Equal(expected2.IdentifierType, read2.IdentifierType);
|
||||
Assert.Equal(expected2.FieldA, read2.FieldA);
|
||||
Assert.Equal(expected2.FieldB, read2.FieldB);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,7 +441,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected.LPStr, read.LPStr);
|
||||
Assert.Equal(expected.LPWStr, read.LPWStr);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeArraysTest()
|
||||
{
|
||||
@@ -493,5 +493,55 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.NotNull(read.LPByteArray);
|
||||
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeInheritanceTest()
|
||||
{
|
||||
byte[] structBytes1 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, 0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, 0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
int offset1 = 0;
|
||||
var expected1 = new TestStructInheritanceChild1
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA55AA,
|
||||
FieldB = 0xAA55AA55,
|
||||
};
|
||||
var read1 = structBytes1.ReadType<TestStructInheritanceChild1>(ref offset1);
|
||||
Assert.NotNull(read1?.Signature);
|
||||
Assert.Equal(expected1.Signature, read1.Signature);
|
||||
Assert.Equal(expected1.IdentifierType, read1.IdentifierType);
|
||||
Assert.Equal(expected1.FieldA, read1.FieldA);
|
||||
Assert.Equal(expected1.FieldB, read1.FieldB);
|
||||
|
||||
byte[] structBytes2 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
int offset2 = 0;
|
||||
var expected2 = new TestStructInheritanceChild2
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA,
|
||||
FieldB = 0xAA55,
|
||||
};
|
||||
var read2 = structBytes2.ReadType<TestStructInheritanceChild2>(ref offset2);
|
||||
Assert.NotNull(read2?.Signature);
|
||||
Assert.Equal(expected2.Signature, read2.Signature);
|
||||
Assert.Equal(expected2.IdentifierType, read2.IdentifierType);
|
||||
Assert.Equal(expected2.FieldA, read2.FieldA);
|
||||
Assert.Equal(expected2.FieldB, read2.FieldB);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,7 +435,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(expected.LPStr, read.LPStr);
|
||||
Assert.Equal(expected.LPWStr, read.LPWStr);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeArraysTest()
|
||||
{
|
||||
@@ -487,5 +487,55 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.NotNull(read.LPByteArray);
|
||||
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeInheritanceTest()
|
||||
{
|
||||
byte[] structBytes1 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, 0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, 0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
var stream1 = new MemoryStream(structBytes1);
|
||||
var expected1 = new TestStructInheritanceChild1
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA55AA,
|
||||
FieldB = 0xAA55AA55,
|
||||
};
|
||||
var read1 = stream1.ReadType<TestStructInheritanceChild1>();
|
||||
Assert.NotNull(read1?.Signature);
|
||||
Assert.Equal(expected1.Signature, read1.Signature);
|
||||
Assert.Equal(expected1.IdentifierType, read1.IdentifierType);
|
||||
Assert.Equal(expected1.FieldA, read1.FieldA);
|
||||
Assert.Equal(expected1.FieldB, read1.FieldB);
|
||||
|
||||
byte[] structBytes2 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
var stream2 = new MemoryStream(structBytes2);
|
||||
var expected2 = new TestStructInheritanceChild2
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA,
|
||||
FieldB = 0xAA55,
|
||||
};
|
||||
var read2 = stream2.ReadType<TestStructInheritanceChild2>();
|
||||
Assert.NotNull(read2?.Signature);
|
||||
Assert.Equal(expected2.Signature, read2.Signature);
|
||||
Assert.Equal(expected2.IdentifierType, read2.IdentifierType);
|
||||
Assert.Equal(expected2.FieldA, read2.FieldA);
|
||||
Assert.Equal(expected2.FieldB, read2.FieldB);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
SabreTools.IO.Test/Extensions/TestStructInheritance.cs
Normal file
29
SabreTools.IO.Test/Extensions/TestStructInheritance.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceParent
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[]? Signature;
|
||||
|
||||
public uint IdentifierType;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceChild1 : TestStructInheritanceParent
|
||||
{
|
||||
public uint FieldA;
|
||||
|
||||
public uint FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceChild2 : TestStructInheritanceParent
|
||||
{
|
||||
public ushort FieldA;
|
||||
|
||||
public ushort FieldB;
|
||||
}
|
||||
}
|
||||
@@ -536,8 +536,30 @@ namespace SabreTools.IO.Extensions
|
||||
// Cache the current offset
|
||||
long currentOffset = reader.BaseStream.Position;
|
||||
|
||||
// Get the type hierarchy for ensuring serialization order
|
||||
var lineage = new List<Type>();
|
||||
Type currentType = type;
|
||||
while (currentType != typeof(object) && currentType != typeof(ValueType))
|
||||
{
|
||||
lineage.Add(currentType);
|
||||
currentType = currentType.BaseType ?? typeof(object);
|
||||
}
|
||||
|
||||
// Generate the fields by parent first
|
||||
lineage.Reverse();
|
||||
var fieldsList = new List<FieldInfo>();
|
||||
foreach (var nextType in lineage)
|
||||
{
|
||||
var nextFields = nextType.GetFields();
|
||||
foreach (var field in nextFields)
|
||||
{
|
||||
if (!fieldsList.Any(f => f.Name == field.Name && f.FieldType == field.FieldType))
|
||||
fieldsList.Add(field);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through the fields and set them
|
||||
var fields = type.GetFields();
|
||||
var fields = fieldsList.ToArray();
|
||||
foreach (var fi in fields)
|
||||
{
|
||||
// If we have an explicit layout, move accordingly
|
||||
|
||||
@@ -663,8 +663,30 @@ namespace SabreTools.IO.Extensions
|
||||
// Cache the current offset
|
||||
int currentOffset = offset;
|
||||
|
||||
// Get the type hierarchy for ensuring serialization order
|
||||
var lineage = new List<Type>();
|
||||
Type currentType = type;
|
||||
while (currentType != typeof(object) && currentType != typeof(ValueType))
|
||||
{
|
||||
lineage.Add(currentType);
|
||||
currentType = currentType.BaseType ?? typeof(object);
|
||||
}
|
||||
|
||||
// Generate the fields by parent first
|
||||
lineage.Reverse();
|
||||
var fieldsList = new List<FieldInfo>();
|
||||
foreach (var nextType in lineage)
|
||||
{
|
||||
var nextFields = nextType.GetFields();
|
||||
foreach (var field in nextFields)
|
||||
{
|
||||
if (!fieldsList.Any(f => f.Name == field.Name && f.FieldType == field.FieldType))
|
||||
fieldsList.Add(field);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through the fields and set them
|
||||
var fields = type.GetFields();
|
||||
var fields = fieldsList.ToArray();
|
||||
foreach (var fi in fields)
|
||||
{
|
||||
// If we have an explicit layout, move accordingly
|
||||
|
||||
@@ -647,8 +647,30 @@ namespace SabreTools.IO.Extensions
|
||||
// Cache the current offset
|
||||
long currentOffset = stream.Position;
|
||||
|
||||
// Get the type hierarchy for ensuring serialization order
|
||||
var lineage = new List<Type>();
|
||||
Type currentType = type;
|
||||
while (currentType != typeof(object) && currentType != typeof(ValueType))
|
||||
{
|
||||
lineage.Add(currentType);
|
||||
currentType = currentType.BaseType ?? typeof(object);
|
||||
}
|
||||
|
||||
// Generate the fields by parent first
|
||||
lineage.Reverse();
|
||||
var fieldsList = new List<FieldInfo>();
|
||||
foreach (var nextType in lineage)
|
||||
{
|
||||
var nextFields = nextType.GetFields();
|
||||
foreach (var field in nextFields)
|
||||
{
|
||||
if (!fieldsList.Any(f => f.Name == field.Name && f.FieldType == field.FieldType))
|
||||
fieldsList.Add(field);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through the fields and set them
|
||||
var fields = type.GetFields();
|
||||
var fields = fieldsList.ToArray();
|
||||
foreach (var fi in fields)
|
||||
{
|
||||
// If we have an explicit layout, move accordingly
|
||||
|
||||
Reference in New Issue
Block a user