migrate core library to new serialization version

This commit is contained in:
LukeFZ
2026-03-13 17:39:36 +01:00
parent 20f90a0926
commit 2d91a4f6da
15 changed files with 136 additions and 121 deletions

View File

@@ -226,7 +226,7 @@ namespace Il2CppInspector
}
public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
var binary = (T) Activator.CreateInstance(typeof(T));
var binary = Activator.CreateInstance<T>();
if (stream.CanSeek)
stream.Position = 0;
stream.CopyTo(binary);
@@ -375,7 +375,7 @@ namespace Il2CppInspector
public ulong ReadMappedUWord(ulong uiAddr)
{
Position = MapVATR(uiAddr);
return ReadNUInt();
return ReadNativeUInt();
}
public ulong[] ReadMappedUWordArray(ulong uiAddr, int count)
@@ -383,7 +383,7 @@ namespace Il2CppInspector
Position = MapVATR(uiAddr);
var arr = new ulong[count];
for (int i = 0; i < count; i++)
arr[i] = ReadNUInt();
arr[i] = ReadNativeUInt();
return arr;
}

View File

@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using VersionedSerialization;
namespace Il2CppInspector
{
@@ -194,7 +195,7 @@ namespace Il2CppInspector
var rels = ReadArray<MachO_relocation_info>(section.ImageRelocOffset, section.NumRelocEntries);
// TODO: Implement Mach-O relocations
if (rels.Any()) {
if (rels.Length > 0) {
AnsiConsole.WriteLine("Mach-O file contains relocations (feature not yet implemented)");
break;
}
@@ -341,7 +342,7 @@ namespace Il2CppInspector
var pointerFormat = (MachODyldChainedPtr)startsInfo.PointerFormat;
var pages = ReadPrimitiveArray<ushort>(
startsBase + startOffset + MachODyldChainedStartsInSegment.Size(), startsInfo.PageCount);
startsBase + startOffset + MachODyldChainedStartsInSegment.StructSize(), startsInfo.PageCount);
for (var i = 0; i < pages.Length; i++)
{

View File

@@ -418,8 +418,8 @@ namespace Il2CppInspector
}
var definitionSize = (ulong)Il2CppTypeDefinition.Size(Image.Version);
var genericParameterSize = (ulong)Il2CppGenericParameter.Size(Image.Version);
var definitionSize = (ulong)Il2CppTypeDefinition.StructSize(Image.Version);
var genericParameterSize = (ulong)Il2CppGenericParameter.StructSize(Image.Version);
var builder = ImmutableArray.CreateBuilder<Il2CppType>(TypeReferences.Length);
for (var i = 0; i < TypeReferences.Length; i++)

View File

@@ -118,6 +118,8 @@ namespace Il2CppInspector
var imageBytes = Image.ReadBytes((int) Image.Length);
var ptrSize = (uint) Image.Bits / 8;
var readerConfig = new ReaderConfig(Image.Bits == 32);
ulong codeRegistration = 0;
IEnumerable<ulong> vas;
@@ -205,10 +207,9 @@ namespace Il2CppInspector
if (codeRegVa == 0)
return (0, 0);
var codeGenEndPtr = codeRegVa + ptrSize;
// pCodeGenModules is the last field in CodeRegistration so we subtract the size of one pointer from the struct size
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.StructSize(Image.Version, readerConfig);
// In v24.3, windowsRuntimeFactoryTable collides with codeGenModules. So far no samples have had windowsRuntimeFactoryCount > 0;
// if this changes we'll have to get smarter about disambiguating these two.
@@ -216,7 +217,7 @@ namespace Il2CppInspector
if (Image.Version == MetadataVersions.V242 && cr.InteropDataCount == 0) {
Image.Version = MetadataVersions.V243;
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.StructSize(Image.Version, readerConfig);
}
if (Image.Version == MetadataVersions.V270 && cr.ReversePInvokeWrapperCount > 0x30000)
@@ -224,7 +225,7 @@ namespace Il2CppInspector
// If reversePInvokeWrapperCount is a pointer, then it's because we're actually on 27.1 and there's a genericAdjustorThunks pointer interfering.
// We need to bump version to 27.1 and back up one more pointer.
Image.Version = MetadataVersions.V271;
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.StructSize(Image.Version, readerConfig);
cr = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
}
@@ -234,7 +235,7 @@ namespace Il2CppInspector
(cr.InvokerPointersCount > 0x50000 || cr.ReversePInvokeWrapperCount > cr.ReversePInvokeWrappers))
{
Image.Version = MetadataVersions.V245;
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.StructSize(Image.Version, readerConfig);
cr = Image.ReadMappedVersionedObject<Il2CppCodeRegistration>(codeRegistration);
}
@@ -242,7 +243,7 @@ namespace Il2CppInspector
cr.GenericMethodPointersCount >= cr.GenericMethodPointers)
{
Image.Version = new StructVersion(Image.Version.Major, 0, MetadataVersions.Tag2022);
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32);
codeRegistration = codeGenEndPtr - (ulong)Il2CppCodeRegistration.StructSize(Image.Version, readerConfig);
}
}
@@ -272,7 +273,7 @@ namespace Il2CppInspector
// Find TypeDefinitionsSizesCount (4th last field) then work back to the start of the struct
// This saves us from guessing where metadataUsagesCount is later
var mrSize = (ulong)Il2CppMetadataRegistration.Size(Image.Version, Image.Bits == 32);
var mrSize = (ulong)Il2CppMetadataRegistration.StructSize(Image.Version, readerConfig);
var typesLength = (ulong) metadata.Types.Length;
vas = FindAllMappedWords(imageBytes, typesLength).Select(a => a - mrSize + ptrSize * 4);

View File

@@ -135,7 +135,7 @@ namespace Il2CppInspector
// thankfully, we can just guess the size based off the three available options and the known total size of
// a type entry that uses TypeIndex.
var actualSize = Header.InterfaceOffsets.SectionSize / Header.InterfaceOffsets.Count;
var maxSize = Il2CppInterfaceOffsetPair.Size(tempVersion);
var maxSize = Il2CppInterfaceOffsetPair.StructSize(tempVersion);
int typeIndexSize;
if (actualSize == maxSize)
@@ -445,7 +445,7 @@ namespace Il2CppInspector
CopyTo(outFile);
}
public int Sizeof<T>() where T : IReadable => T.Size(Version, Is32Bit);
public int Sizeof<T>() where T : IReadable => T.Size(Version, new ReaderConfig(Is32Bit));
}
}

View File

@@ -1,39 +1,32 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using NoisyCowStudios.Bin2Object;
using VersionedSerialization;
using VersionedSerialization.Impl;
namespace Il2CppInspector.Next;
public class BinaryObjectStreamReader : BinaryObjectStream, IReader
public class BinaryObjectStreamReader : BinaryObjectStream, ISeekableReader
{
public new StructVersion Version
{
get => _version;
get;
set
{
_version = value;
base.Version = _version.AsDouble;
field = value;
base.Version = field.AsDouble;
}
}
private StructVersion _version;
public virtual int Bits { get; set; }
public bool Is32Bit => Bits == 32;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static TTo Cast<TFrom, TTo>(in TFrom from) => Unsafe.As<TFrom, TTo>(ref Unsafe.AsRef(in from));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private T ReadInternal<T>() where T : unmanaged
{
var size = Unsafe.SizeOf<T>();
var value = MemoryMarshal.Read<T>(ReadBytes(size));
return value;
}
public T ReadPrimitive<T>() where T : unmanaged
{
if (typeof(T) == typeof(sbyte))
@@ -60,60 +53,80 @@ public class BinaryObjectStreamReader : BinaryObjectStream, IReader
if (typeof(T) == typeof(ulong))
return Cast<ulong, T>(ReadUInt64());
return ReadInternal<T>();
Debug.Assert(false, "Invalid primitive type");
throw new InvalidOperationException();
}
public void ReadPrimitive<T>(scoped Span<T> dest) where T : unmanaged
{
for (int i = 0; i < dest.Length; i++)
{
dest[i] = ReadPrimitive<T>();
}
}
public void Read<T>(scoped Span<T> dest) where T : unmanaged
{
var asBytes = MemoryMarshal.Cast<T, byte>(dest);
Reader.ReadBytes(asBytes.Length).AsSpan().CopyTo(asBytes);
}
public string ReadString(int length = -1, Encoding encoding = null)
{
return length == -1
? ReadNullTerminatedString(encoding)
: ReadFixedLengthString(length, encoding);
}
ReadOnlySpan<byte> IReader.ReadBytes(long length)
{
return ReadBytes(checked((int)length));
}
// Reader-wrapping helper methods
int ISeekableReader.Offset
{
get => checked((int)Position);
set => Position = value;
}
int ISeekableReader.Length => checked((int)Length);
public ulong ReadNativeUInt()
{
return Endianness == Endianness.Little
? new Reader<LittleEndianSeekableReader<BinaryObjectStreamReader>>(
new LittleEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadNativeUInt()
: new Reader<BigEndianSeekableReader<BinaryObjectStreamReader>>(
new BigEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadNativeUInt();
}
public T ReadVersionedObject<T>() where T : IReadable, new()
{
return Endianness == Endianness.Little
? new Reader<LittleEndianSeekableReader<BinaryObjectStreamReader>>(
new LittleEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadVersionedObject<T>(Version)
: new Reader<BigEndianSeekableReader<BinaryObjectStreamReader>>(
new BigEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadVersionedObject<T>(Version);
}
public ImmutableArray<T> ReadVersionedObjectArray<T>(long count) where T : IReadable, new()
{
return Endianness == Endianness.Little
? new Reader<LittleEndianSeekableReader<BinaryObjectStreamReader>>(
new LittleEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadVersionedObjectArray<T>(count, Version)
: new Reader<BigEndianSeekableReader<BinaryObjectStreamReader>>(
new BigEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadVersionedObjectArray<T>(count, Version);
}
public ImmutableArray<T> ReadPrimitiveArray<T>(long count) where T : unmanaged
{
var array = ImmutableArray.CreateBuilder<T>(checked((int)count));
for (long i = 0; i < count; i++)
array.Add(ReadPrimitive<T>());
return array.MoveToImmutable();
}
public T ReadVersionedObject<T>() where T : IReadable, new() => ReadVersionedObject<T>(Version);
public T ReadVersionedObject<T>(in StructVersion version = default) where T : IReadable, new()
{
var obj = new T();
var a = this;
obj.Read(ref a, in version);
return obj;
}
public ImmutableArray<T> ReadVersionedObjectArray<T>(long count) where T : IReadable, new() => ReadVersionedObjectArray<T>(count, Version);
public ImmutableArray<T> ReadVersionedObjectArray<T>(long count, in StructVersion version = default) where T : IReadable, new()
{
var array = ImmutableArray.CreateBuilder<T>(checked((int)count));
for (long i = 0; i < count; i++)
array.Add(ReadVersionedObject<T>(in version));
return array.MoveToImmutable();
}
public long ReadNInt()
=> Is32Bit ? ReadPrimitive<int>() : ReadPrimitive<long>();
public ulong ReadNUInt()
=> Is32Bit ? ReadPrimitive<uint>() : ReadPrimitive<ulong>();
public string ReadString() => ReadNullTerminatedString();
public new ReadOnlySpan<byte> ReadBytes(int length)
{
return base.ReadBytes(length);
}
public void Align(int alignment = 0)
{
if (alignment == 0)
alignment = Is32Bit ? 4 : 8;
var rem = Position % alignment;
if (rem != 0)
Position += alignment - rem;
return Endianness == Endianness.Little
? new Reader<LittleEndianSeekableReader<BinaryObjectStreamReader>>(
new LittleEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadPrimitiveArray<T>(count)
: new Reader<BigEndianSeekableReader<BinaryObjectStreamReader>>(
new BigEndianSeekableReader<BinaryObjectStreamReader>(this), new ReaderConfig(Is32Bit)).ReadPrimitiveArray<T>(count);
}
public TType ReadPrimitive<TType>(long addr) where TType : unmanaged
@@ -131,17 +144,13 @@ public class BinaryObjectStreamReader : BinaryObjectStream, IReader
public TType ReadVersionedObject<TType>(long addr) where TType : IReadable, new()
{
Position = addr;
return ReadVersionedObject<TType>(Version);
return ReadVersionedObject<TType>();
}
public ImmutableArray<TType> ReadVersionedObjectArray<TType>(long addr, long count) where TType : IReadable, new()
public ImmutableArray<TType> ReadVersionedObjectArray<TType>(long addr, long count)
where TType : IReadable, new()
{
Position = addr;
return ReadVersionedObjectArray<TType>(count, Version);
}
public void Skip(int count)
{
Position += count;
return ReadVersionedObjectArray<TType>(count);
}
}

View File

@@ -10,10 +10,10 @@ public struct InterfacesIndex(int value) : IIndexType<InterfacesIndex>, IReadabl
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<InterfacesIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<InterfacesIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<InterfacesIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -10,10 +10,10 @@ public struct MethodIndex(int value) : IIndexType<MethodIndex>, IReadable, IEqua
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<MethodIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<MethodIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<MethodIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -10,10 +10,10 @@ public struct NestedTypeIndex(int value) : IIndexType<NestedTypeIndex>, IReadabl
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<NestedTypeIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<NestedTypeIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<NestedTypeIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -10,10 +10,10 @@ public struct ParameterIndex(int value) : IIndexType<ParameterIndex>, IReadable,
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<ParameterIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<ParameterIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<ParameterIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -10,10 +10,10 @@ public struct PropertyIndex(int value) : IIndexType<PropertyIndex>, IReadable, I
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<PropertyIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<PropertyIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<PropertyIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -10,10 +10,10 @@ public struct TypeDefinitionIndex(int value) : IIndexType<TypeDefinitionIndex>,
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<TypeDefinitionIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<TypeDefinitionIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<TypeDefinitionIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -10,10 +10,10 @@ public struct TypeIndex(int value) : IIndexType<TypeIndex>, IReadable, IEquatabl
private int _value = value;
public static int Size(in StructVersion version = default, bool is32Bit = false)
=> IIndexType<TypeIndex>.IndexSize(version, is32Bit);
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
=> IIndexType<TypeIndex>.IndexSize(version, config);
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
public void Read<TReader>(ref Reader<TReader> reader, in StructVersion version = default) where TReader : IReader, allows ref struct
{
_value = IIndexType<TypeIndex>.ReadIndex(ref reader, in version);
}

View File

@@ -13,23 +13,25 @@ public struct Pointer<T>(ulong value = 0) : IReadable, IEquatable<Pointer<T>> wh
public readonly ulong PointerValue => _value;
public readonly bool Null => _value == 0;
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
void IReadable.Read<TReader>(ref Reader<TReader> reader, in StructVersion version )
{
_value = reader.ReadNUInt();
_value = reader.ReadNativeUInt();
}
public static int Size(in StructVersion version = default, bool is32Bit = false)
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
{
return is32Bit ? 4 : 8;
return config.Is32Bit ? sizeof(uint) : sizeof(ulong);
}
public readonly T Read(ref SpanReader reader, in StructVersion version)
public readonly T Read<TReader>(ref Reader<TReader> reader, in StructVersion version)
where TReader : ISeekableReader, allows ref struct
{
reader.Offset = (int)PointerValue;
return reader.ReadVersionedObject<T>(version);
}
public readonly ImmutableArray<T> ReadArray(ref SpanReader reader, long count, in StructVersion version)
public readonly ImmutableArray<T> ReadArray<TReader>(ref Reader<TReader> reader, long count, in StructVersion version)
where TReader : ISeekableReader, allows ref struct
{
reader.Offset = (int)PointerValue;
return reader.ReadVersionedObjectArray<T>(count, version);

View File

@@ -13,23 +13,25 @@ public struct PrimitivePointer<T>(ulong value = 0) : IReadable, IEquatable<Primi
public readonly ulong PointerValue => _value;
public readonly bool Null => _value == 0;
public void Read<TReader>(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct
void IReadable.Read<TReader>(ref Reader<TReader> reader, in StructVersion version)
{
_value = reader.ReadNUInt();
_value = reader.ReadNativeUInt();
}
public static int Size(in StructVersion version = default, bool is32Bit = false)
public static int Size(in StructVersion version = default, in ReaderConfig config = default)
{
return is32Bit ? 4 : 8;
return config.Is32Bit ? sizeof(uint) : sizeof(ulong);
}
public readonly T Read(ref SpanReader reader)
public readonly T Read<TReader>(ref Reader<TReader> reader)
where TReader : ISeekableReader, allows ref struct
{
reader.Offset = (int)PointerValue;
return reader.ReadPrimitive<T>();
}
public readonly ImmutableArray<T> ReadArray(ref SpanReader reader, long count)
public readonly ImmutableArray<T> ReadArray<TReader>(ref Reader<TReader> reader, long count)
where TReader : ISeekableReader, allows ref struct
{
reader.Offset = (int)PointerValue;
return reader.ReadPrimitiveArray<T>(count);