Add support for LPArray types

This commit is contained in:
Matt Nadareski
2024-04-28 23:47:33 -04:00
parent 0317f751b9
commit 8c19ad712a
7 changed files with 167 additions and 15 deletions

View File

@@ -497,6 +497,10 @@ namespace SabreTools.IO.Test.Extensions
0x00, 0xFF, 0xFF, 0x00,
0xAA, 0x55, 0x55, 0xAA,
0x55, 0xAA, 0xAA, 0x55,
// LPArray
0x04, 0x00,
0x00, 0x01, 0x02, 0x03,
];
var stream = new MemoryStream(structBytes);
@@ -512,6 +516,8 @@ namespace SabreTools.IO.Test.Extensions
new TestStructPoint { X = 0x55AA, Y = 0xAA55 },
new TestStructPoint { X = 0xAA55, Y = 0x55AA },
],
LPByteArrayLength = 0x0004,
LPByteArray = [0x00, 0x01, 0x02, 0x03],
};
var read = br.ReadType<TestStructArrays>();
Assert.NotNull(read.ByteArray);
@@ -520,6 +526,9 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
Assert.NotNull(read.StructArray);
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);
Assert.NotNull(read.LPByteArray);
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
}
}
}

View File

@@ -461,6 +461,10 @@ namespace SabreTools.IO.Test.Extensions
0x00, 0xFF, 0xFF, 0x00,
0xAA, 0x55, 0x55, 0xAA,
0x55, 0xAA, 0xAA, 0x55,
// LPArray
0x04, 0x00,
0x00, 0x01, 0x02, 0x03,
];
int offset = 0;
@@ -475,6 +479,8 @@ namespace SabreTools.IO.Test.Extensions
new TestStructPoint { X = 0x55AA, Y = 0xAA55 },
new TestStructPoint { X = 0xAA55, Y = 0x55AA },
],
LPByteArrayLength = 0x0004,
LPByteArray = [0x00, 0x01, 0x02, 0x03],
};
var read = structBytes.ReadType<TestStructArrays>(ref offset);
Assert.NotNull(read.ByteArray);
@@ -483,6 +489,9 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
Assert.NotNull(read.StructArray);
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);
Assert.NotNull(read.LPByteArray);
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
}
}
}

View File

@@ -455,6 +455,10 @@ namespace SabreTools.IO.Test.Extensions
0x00, 0xFF, 0xFF, 0x00,
0xAA, 0x55, 0x55, 0xAA,
0x55, 0xAA, 0xAA, 0x55,
// LPArray
0x04, 0x00,
0x00, 0x01, 0x02, 0x03,
];
var stream = new MemoryStream(structBytes);
@@ -469,6 +473,8 @@ namespace SabreTools.IO.Test.Extensions
new TestStructPoint { X = 0x55AA, Y = 0xAA55 },
new TestStructPoint { X = 0xAA55, Y = 0x55AA },
],
LPByteArrayLength = 0x0004,
LPByteArray = [0x00, 0x01, 0x02, 0x03],
};
var read = stream.ReadType<TestStructArrays>();
Assert.NotNull(read.ByteArray);
@@ -477,6 +483,9 @@ namespace SabreTools.IO.Test.Extensions
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
Assert.NotNull(read.StructArray);
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);
Assert.NotNull(read.LPByteArray);
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
}
}
}

View File

@@ -22,6 +22,17 @@ namespace SabreTools.IO.Test.Extensions
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public TestStructPoint[]? StructArray;
/// <summary>
/// Length of <see cref="LPByteArray"/>
/// </summary>
public ushort LPByteArrayLength;
/// <summary>
/// 4 entry byte array whose length is defined by <see cref="LPByteArrayLength"/>
/// </summary>
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
public byte[]? LPByteArray;
// /// <summary>
// /// 4 entry nested byte array

View File

@@ -570,7 +570,7 @@ namespace SabreTools.IO.Extensions
}
else if (fi.FieldType.IsArray)
{
var value = ReadArrayType(reader, fi);
var value = ReadArrayType(reader, fields, instance, fi);
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
}
else
@@ -583,15 +583,24 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an array type field for an object
/// </summary>
/// TODO: Handle LPArray + SizeParamIndex
private static Array ReadArrayType(BinaryReader reader, FieldInfo fi)
private static Array ReadArrayType(BinaryReader reader, FieldInfo[] fields, object instance, FieldInfo fi)
{
var marshalAsAttr = fi.GetCustomAttributes(typeof(MarshalAsAttribute), true).FirstOrDefault() as MarshalAsAttribute;
if (marshalAsAttr?.Value != UnmanagedType.ByValArray)
if (marshalAsAttr == null)
return new object[0];
// Get the number of elements expected
int elementCount = marshalAsAttr?.SizeConst ?? -1;
int elementCount = -1;
if (marshalAsAttr.Value == UnmanagedType.ByValArray)
{
elementCount = marshalAsAttr.SizeConst;
}
else if (marshalAsAttr.Value == UnmanagedType.LPArray)
{
elementCount = marshalAsAttr.SizeConst;
if (marshalAsAttr.SizeParamIndex >= 0)
elementCount = GetSizeFromField(marshalAsAttr, fields, instance);
}
// Get the item type for the array
Type elementType = fi.FieldType.GetElementType() ?? typeof(object);
@@ -610,6 +619,35 @@ namespace SabreTools.IO.Extensions
return arr;
}
/// <summary>
/// Get the expected LPArray size
/// </summary>
private static int GetSizeFromField(MarshalAsAttribute marshalAsAttr, FieldInfo[] fields, object instance)
{
// If the index is invalid
if (marshalAsAttr.SizeParamIndex < 0)
return -1;
// Get the size field
var sizeField = fields[marshalAsAttr.SizeParamIndex];
if (sizeField == null)
return -1;
// Cast based on the field type
return sizeField.GetValue(instance) switch
{
sbyte val => val,
byte val => val,
short val => val,
ushort val => val,
int val => val,
uint val => (int)val,
long val => (int)val,
ulong val => (int)val,
_ => -1,
};
}
/// <summary>
/// Read a string type field for an object
/// </summary>

View File

@@ -697,7 +697,7 @@ namespace SabreTools.IO.Extensions
}
else if (fi.FieldType.IsArray)
{
var value = ReadArrayType(content, ref offset, fi);
var value = ReadArrayType(content, ref offset, fields, instance, fi);
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
}
else
@@ -710,15 +710,24 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an array type field for an object
/// </summary>
/// TODO: Handle LPArray + SizeParamIndex
private static Array ReadArrayType(byte[] content, ref int offset, FieldInfo fi)
private static Array ReadArrayType(byte[] content, ref int offset, FieldInfo[] fields, object instance, FieldInfo fi)
{
var marshalAsAttr = fi.GetCustomAttributes(typeof(MarshalAsAttribute), true).FirstOrDefault() as MarshalAsAttribute;
if (marshalAsAttr?.Value != UnmanagedType.ByValArray)
if (marshalAsAttr == null)
return new object[0];
// Get the number of elements expected
int elementCount = marshalAsAttr?.SizeConst ?? -1;
int elementCount = -1;
if (marshalAsAttr.Value == UnmanagedType.ByValArray)
{
elementCount = marshalAsAttr.SizeConst;
}
else if (marshalAsAttr.Value == UnmanagedType.LPArray)
{
elementCount = marshalAsAttr.SizeConst;
if (marshalAsAttr.SizeParamIndex >= 0)
elementCount = GetSizeFromField(marshalAsAttr, fields, instance);
}
// Get the item type for the array
Type elementType = fi.FieldType.GetElementType() ?? typeof(object);
@@ -737,6 +746,35 @@ namespace SabreTools.IO.Extensions
return arr;
}
/// <summary>
/// Get the expected LPArray size
/// </summary>
private static int GetSizeFromField(MarshalAsAttribute marshalAsAttr, FieldInfo[] fields, object instance)
{
// If the index is invalid
if (marshalAsAttr.SizeParamIndex < 0)
return -1;
// Get the size field
var sizeField = fields[marshalAsAttr.SizeParamIndex];
if (sizeField == null)
return -1;
// Cast based on the field type
return sizeField.GetValue(instance) switch
{
sbyte val => val,
byte val => val,
short val => val,
ushort val => val,
int val => val,
uint val => (int)val,
long val => (int)val,
ulong val => (int)val,
_ => -1,
};
}
/// <summary>
/// Read a string type field for an object
/// </summary>

View File

@@ -681,7 +681,7 @@ namespace SabreTools.IO.Extensions
}
else if (fi.FieldType.IsArray)
{
var value = ReadArrayType(stream, fi);
var value = ReadArrayType(stream, fields, instance, fi);
fi.SetValue(instance, Convert.ChangeType(value, fi.FieldType));
}
else
@@ -694,15 +694,24 @@ namespace SabreTools.IO.Extensions
/// <summary>
/// Read an array type field for an object
/// </summary>
/// TODO: Handle LPArray + SizeParamIndex
private static Array ReadArrayType(Stream stream, FieldInfo fi)
private static Array ReadArrayType(Stream stream, FieldInfo[] fields, object instance, FieldInfo fi)
{
var marshalAsAttr = fi.GetCustomAttributes(typeof(MarshalAsAttribute), true).FirstOrDefault() as MarshalAsAttribute;
if (marshalAsAttr?.Value != UnmanagedType.ByValArray)
if (marshalAsAttr == null)
return new object[0];
// Get the number of elements expected
int elementCount = marshalAsAttr?.SizeConst ?? -1;
int elementCount = -1;
if (marshalAsAttr.Value == UnmanagedType.ByValArray)
{
elementCount = marshalAsAttr.SizeConst;
}
else if (marshalAsAttr.Value == UnmanagedType.LPArray)
{
elementCount = marshalAsAttr.SizeConst;
if (marshalAsAttr.SizeParamIndex >= 0)
elementCount = GetSizeFromField(marshalAsAttr, fields, instance);
}
// Get the item type for the array
Type elementType = fi.FieldType.GetElementType() ?? typeof(object);
@@ -721,6 +730,35 @@ namespace SabreTools.IO.Extensions
return arr;
}
/// <summary>
/// Get the expected LPArray size
/// </summary>
private static int GetSizeFromField(MarshalAsAttribute marshalAsAttr, FieldInfo[] fields, object instance)
{
// If the index is invalid
if (marshalAsAttr.SizeParamIndex < 0)
return -1;
// Get the size field
var sizeField = fields[marshalAsAttr.SizeParamIndex];
if (sizeField == null)
return -1;
// Cast based on the field type
return sizeField.GetValue(instance) switch
{
sbyte val => val,
byte val => val,
short val => val,
ushort val => val,
int val => val,
uint val => (int)val,
long val => (int)val,
ulong val => (int)val,
_ => -1,
};
}
/// <summary>
/// Read a string type field for an object
/// </summary>