use IndexOf in IndexType tag parsing to handle ParameterIndex and GenericParameterIndex properly

This commit is contained in:
LukeFZ
2026-02-28 03:54:02 +01:00
parent 248f15a84f
commit 9ea4108e8a

View File

@@ -1,53 +1,67 @@
using VersionedSerialization;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using VersionedSerialization;
namespace Il2CppInspector.Next.Metadata;
file static class Il2CppMetadataIndex
{
public const int Invalid = -1;
public const char NumberZeroChar = '0';
}
public interface IIndexType<T> where T
: IIndexType<T>, allows ref struct
{
public static abstract string TagPrefix { get; }
private static string TagSize4 => $"{T.TagPrefix}4";
private static string TagSize2 => $"{T.TagPrefix}2";
private static string TagSize1 => $"{T.TagPrefix}1";
private static bool HasCustomSize(in StructVersion version)
=> version.Tag != null
&& (version.Tag.Contains(TagSize2)
|| version.Tag.Contains(TagSize1));
public static int IndexSize(in StructVersion version = default, bool is32Bit = false)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetSizeFromTag(in StructVersion version)
{
if (version.Tag != null && HasCustomSize(version))
// Fallback to the default for unsupported configurations.
if (version < MetadataVersions.V380 || version.Tag == null)
{
if (version.Tag.Contains(TagSize2))
return sizeof(ushort);
if (version.Tag.Contains(TagSize1))
return sizeof(byte);
return sizeof(int);
}
return sizeof(int);
// Get the position of the size tag in the version tag.
// Bail out if not found.
var sizeTagPosition = version.Tag.IndexOf(T.TagPrefix, StringComparison.Ordinal);
if (sizeTagPosition == -1)
{
return sizeof(int);
}
// Get the number that follows immediately after the size tag, and convert it to the actual size.
var numberChar = version.Tag[sizeTagPosition + T.TagPrefix.Length];
return numberChar - Il2CppMetadataIndex.NumberZeroChar;
}
public static int IndexSize(in StructVersion version = default, bool is32Bit = false)
=> GetSizeFromTag(version);
public static int ReadIndex<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
if (version.Tag != null && HasCustomSize(version))
{
if (version.Tag.Contains(TagSize2))
{
var value = reader.ReadPrimitive<ushort>();
return value == ushort.MaxValue ? -1 : value;
}
var size = GetSizeFromTag(in version);
if (version.Tag.Contains(TagSize1))
{
var value = reader.ReadPrimitive<byte>();
return value == byte.MaxValue ? -1 : value;
}
int index;
if (size == sizeof(int))
{
index = reader.ReadPrimitive<int>();
}
else if (size == sizeof(ushort))
{
var value = reader.ReadPrimitive<ushort>();
index = value == ushort.MaxValue ? Il2CppMetadataIndex.Invalid : value;
}
else
{
Debug.Assert(size == sizeof(byte));
var value = reader.ReadPrimitive<byte>();
index = value == byte.MaxValue ? Il2CppMetadataIndex.Invalid : value;
}
return reader.ReadPrimitive<int>();
return index;
}
}