mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-09-23 07:05:38 +00:00
Add support for LPArray types
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user