diff --git a/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs b/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs index dab3cfb..f7db93f 100644 --- a/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs +++ b/Il2CppInspector.Common/FileFormatStreams/FileFormatStream.cs @@ -94,6 +94,9 @@ namespace Il2CppInspector long[] ReadMappedWordArray(ulong uiAddr, int count); List ReadMappedObjectPointerArray(ulong uiAddr, int count) where U : new(); + ulong ReadMappedUWord(ulong uiAddr); + ulong[] ReadMappedUWordArray(ulong uiAddr, int count); + void WriteEndianBytes(byte[] bytes); void Write(long int64); void Write(ulong uint64); @@ -144,6 +147,9 @@ namespace Il2CppInspector public ImmutableArray ReadVersionedObjectArray(long count) where TType : IReadable, new(); + + public ImmutableArray ReadMappedVersionedObjectPointerArray(ulong addr, int count) + where TType : IReadable, new(); } public class FileFormatStream @@ -356,5 +362,32 @@ namespace Il2CppInspector public ImmutableArray ReadMappedVersionedObjectArray(ulong addr, long count) where TType : IReadable, new() => ReadVersionedObjectArray(MapVATR(addr), count); + + public ImmutableArray ReadMappedVersionedObjectPointerArray(ulong addr, int count) + where TType : IReadable, new() + { + var pointers = ReadMappedUWordArray(addr, count); + var builder = ImmutableArray.CreateBuilder((int)count); + for (long i = 0; i < count; i++) + builder.Add(ReadMappedVersionedObject(pointers[i])); + + return builder.MoveToImmutable(); + } + + public ulong ReadMappedUWord(ulong uiAddr) + { + Position = MapVATR(uiAddr); + return ReadNUInt(); + } + + public ulong[] ReadMappedUWordArray(ulong uiAddr, int count) + { + Position = MapVATR(uiAddr); + var arr = new ulong[count]; + for (int i = 0; i < count; i++) + arr[i] = ReadNUInt(); + + return arr; + } } } \ No newline at end of file diff --git a/Il2CppInspector.Common/IL2CPP/CustomAttributeDataReader.cs b/Il2CppInspector.Common/IL2CPP/CustomAttributeDataReader.cs index 423646a..136f0aa 100644 --- a/Il2CppInspector.Common/IL2CPP/CustomAttributeDataReader.cs +++ b/Il2CppInspector.Common/IL2CPP/CustomAttributeDataReader.cs @@ -4,11 +4,11 @@ using System.Diagnostics; using System.IO; using System.Linq; using dnlib.DotNet; +using Il2CppInspector.Next; using Il2CppInspector.Next.BinaryMetadata; using Il2CppInspector.Next.Metadata; using Il2CppInspector.Reflection; using Il2CppInspector.Utils; -using NoisyCowStudios.Bin2Object; namespace Il2CppInspector { @@ -16,7 +16,7 @@ namespace Il2CppInspector { private readonly Il2CppInspector _inspector; private readonly Assembly _assembly; - private readonly BinaryObjectStream _data; + private readonly BinaryObjectStreamReader _data; private readonly uint _start; private readonly uint _end; @@ -26,7 +26,7 @@ namespace Il2CppInspector public uint Count { get; } - public CustomAttributeDataReader(Il2CppInspector inspector, Assembly assembly, BinaryObjectStream data, uint startOffset, uint endOffset) + public CustomAttributeDataReader(Il2CppInspector inspector, Assembly assembly, BinaryObjectStreamReader data, uint startOffset, uint endOffset) { _inspector = inspector; _assembly = assembly; @@ -146,8 +146,8 @@ namespace Il2CppInspector private TypeInfo ConvertTypeDef(Il2CppTypeDefinition typeDef, Il2CppTypeEnum type) => typeDef.IsValid - ? _assembly.Model.GetTypeDefinitionFromTypeEnum(type) - : _assembly.Model.TypesByDefinitionIndex[Array.IndexOf(_inspector.TypeDefinitions, typeDef)]; + ? _assembly.Model.TypesByDefinitionIndex[_inspector.TypeDefinitions.IndexOf(typeDef)] + : _assembly.Model.GetTypeDefinitionFromTypeEnum(type); private (TypeInfo, int) ReadCustomAttributeNamedArgumentClassAndIndex(TypeInfo attrInfo) { diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs index 16fd620..ab7c7aa 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs @@ -8,6 +8,7 @@ using Il2CppInspector.Next; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; @@ -37,16 +38,16 @@ namespace Il2CppInspector public ulong CodeRegistrationPointer { get; private set; } public ulong MetadataRegistrationPointer { get; private set; } public ulong RegistrationFunctionPointer { get; private set; } - public Dictionary CodeGenModulePointers { get; } = new Dictionary(); + public Dictionary CodeGenModulePointers { get; } = new(); // Only for <=v24.1 public ulong[] GlobalMethodPointers { get; set; } // Only for >=v24.2 - public Dictionary ModuleMethodPointers { get; set; } = new Dictionary(); + public Dictionary ModuleMethodPointers { get; set; } = new(); // Only for >=v24.2. In earlier versions, invoker indices are stored in Il2CppMethodDefinition in the metadata file - public Dictionary MethodInvokerIndices { get; set; } = new Dictionary(); + public Dictionary> MethodInvokerIndices { get; set; } = new(); // NOTE: In versions <21 and earlier releases of v21, use FieldOffsets: // global field index => field offset @@ -54,7 +55,7 @@ namespace Il2CppInspector // type index => RVA in image where the list of field offsets for the type start (4 bytes per field) // Negative field offsets from start of each function - public uint[] FieldOffsets { get; private set; } + public ImmutableArray FieldOffsets { get; private set; } // Pointers to field offsets public long[] FieldOffsetPointers { get; private set; } @@ -68,13 +69,13 @@ namespace Il2CppInspector public ulong[] MethodInvokePointers { get; private set; } // Version 16 and below: method references for vtable - public uint[] VTableMethodReferences { get; private set; } + public ImmutableArray VTableMethodReferences { get; private set; } // Generic method specs for vtables - public Il2CppMethodSpec[] MethodSpecs { get; private set; } + public ImmutableArray MethodSpecs { get; private set; } // List of run-time concrete generic class and method signatures - public List GenericInstances { get; private set; } + public ImmutableArray GenericInstances { get; private set; } // List of constructed generic method function pointers corresponding to each possible method instantiation public Dictionary GenericMethodPointers { get; } = new Dictionary(); @@ -83,7 +84,7 @@ namespace Il2CppInspector public Dictionary GenericMethodInvokerIndices { get; } = new Dictionary(); // Every type reference (TypeRef) sorted by index - public List TypeReferences { get; private set; } + public ImmutableArray TypeReferences { get; private set; } // Every type reference index sorted by virtual address public Dictionary TypeReferenceIndicesByAddress { get; private set; } @@ -92,7 +93,7 @@ namespace Il2CppInspector // One assembly may contain multiple modules public Dictionary Modules { get; private set; } - public List TypeDefinitionSizes { get; private set; } + public ImmutableArray TypeDefinitionSizes { get; private set; } // Status update callback private EventHandler OnStatusUpdate { get; set; } @@ -280,30 +281,8 @@ namespace Il2CppInspector Console.WriteLine("MetadataRegistration struct found at 0x{0:X16} (file offset 0x{1:X8})", Image.Bits == 32 ? metadataRegistration & 0xffff_ffff : metadataRegistration, Image.MapVATR(metadataRegistration)); // Root structures from which we find everything else - CodeRegistration = Image.ReadMappedObject(codeRegistration); - MetadataRegistration = Image.ReadMappedObject(metadataRegistration); - - // genericAdjustorThunks was inserted before invokerPointersCount in 24.5 and 27.1 - // pointer expected if we need to bump version - if (Image.Version == MetadataVersions.V244 && CodeRegistration.InvokerPointersCount > 0x50000) - { - Image.Version = MetadataVersions.V245; - CodeRegistration = Image.ReadMappedObject(codeRegistration); - } - - if (Image.Version == MetadataVersions.V244 && CodeRegistration.ReversePInvokeWrapperCount > 0x50000) { - Image.Version = MetadataVersions.V245; - codeRegistration -= 1 * pointerSize; - CodeRegistration = Image.ReadMappedObject(codeRegistration); - } - - if ((Image.Version == MetadataVersions.V290 || Image.Version == MetadataVersions.V310) && - (long)CodeRegistration.GenericMethodPointersCount - MetadataRegistration.GenericMethodTableCount > 0x10000) - { - Image.Version = new StructVersion(Image.Version.Major, 1, Image.Version.Tag); - codeRegistration -= 2 * pointerSize; - CodeRegistration = Image.ReadMappedObject(codeRegistration); - } + CodeRegistration = Image.ReadMappedVersionedObject(codeRegistration); + MetadataRegistration = Image.ReadMappedVersionedObject(metadataRegistration); // Plugin hook to pre-process binary isModified |= PluginHooks.PreProcessBinary(this).IsStreamModified; @@ -326,7 +305,7 @@ namespace Il2CppInspector // The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule if (Image.Version <= MetadataVersions.V241) - GlobalMethodPointers = Image.ReadMappedArray(CodeRegistration.MethodPointers, (int) CodeRegistration.MethodPointersCount); + GlobalMethodPointers = Image.ReadMappedUWordArray(CodeRegistration.MethodPointers, (int) CodeRegistration.MethodPointersCount); // After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules if (Image.Version >= MetadataVersions.V242) { @@ -336,12 +315,12 @@ namespace Il2CppInspector // if this changes we'll have to get smarter about disambiguating these two. if (CodeRegistration.CodeGenModulesCount == 0) { Image.Version = MetadataVersions.V243; - CodeRegistration = Image.ReadMappedObject(codeRegistration); + CodeRegistration = Image.ReadMappedVersionedObject(codeRegistration); } // Array of pointers to Il2CppCodeGenModule - var codeGenModulePointers = Image.ReadMappedArray(CodeRegistration.CodeGenModules, (int) CodeRegistration.CodeGenModulesCount); - var modules = Image.ReadMappedObjectPointerArray(CodeRegistration.CodeGenModules, (int) CodeRegistration.CodeGenModulesCount); + var codeGenModulePointers = Image.ReadMappedUWordArray(CodeRegistration.CodeGenModules, (int) CodeRegistration.CodeGenModulesCount); + var modules = Image.ReadMappedVersionedObjectPointerArray(CodeRegistration.CodeGenModules, (int) CodeRegistration.CodeGenModulesCount); foreach (var mp in modules.Zip(codeGenModulePointers, (m, p) => new { Module = m, Pointer = p })) { var module = mp.Module; @@ -355,13 +334,13 @@ namespace Il2CppInspector // the entire method pointer array will be NULL values, causing the methodPointer to be mapped to .bss // and therefore out of scope of the binary image try { - ModuleMethodPointers.Add(module, Image.ReadMappedArray(module.MethodPointers, (int) module.MethodPointerCount)); + ModuleMethodPointers.Add(module, Image.ReadMappedUWordArray(module.MethodPointers, (int) module.MethodPointerCount)); } catch (InvalidOperationException) { ModuleMethodPointers.Add(module, new ulong[module.MethodPointerCount]); } // Read method invoker pointer indices - one per method - MethodInvokerIndices.Add(module, Image.ReadMappedArray(module.InvokerIndices, (int) module.MethodPointerCount)); + MethodInvokerIndices.Add(module, Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int) module.MethodPointerCount)); } } @@ -381,24 +360,24 @@ namespace Il2CppInspector // All older versions use values directly in the array if (!fieldOffsetsArePointers) - FieldOffsets = Image.ReadMappedArray(MetadataRegistration.FieldOffsets, (int)MetadataRegistration.FieldOffsetsCount); + FieldOffsets = Image.ReadMappedPrimitiveArray(MetadataRegistration.FieldOffsets, (int)MetadataRegistration.FieldOffsetsCount); else FieldOffsetPointers = Image.ReadMappedWordArray(MetadataRegistration.FieldOffsets, (int)MetadataRegistration.FieldOffsetsCount); // Type references (pointer array) - var typeRefPointers = Image.ReadMappedArray(MetadataRegistration.Types, (int) MetadataRegistration.TypesCount); + var typeRefPointers = Image.ReadMappedUWordArray(MetadataRegistration.Types, (int) MetadataRegistration.TypesCount); TypeReferenceIndicesByAddress = typeRefPointers.Zip(Enumerable.Range(0, typeRefPointers.Length), (a, i) => new { a, i }).ToDictionary(x => x.a, x => x.i); - TypeReferences = Image.ReadMappedObjectPointerArray(MetadataRegistration.Types, (int)MetadataRegistration.TypesCount); + TypeReferences = Image.ReadMappedVersionedObjectPointerArray(MetadataRegistration.Types, (int)MetadataRegistration.TypesCount); // Custom attribute constructors (function pointers) // This is managed in Il2CppInspector for metadata >= 27 if (Image.Version < MetadataVersions.V270) { - CustomAttributeGenerators = Image.ReadMappedArray(CodeRegistration.CustomAttributeGenerators, (int) CodeRegistration.CustomAttributeCount); + CustomAttributeGenerators = Image.ReadMappedUWordArray(CodeRegistration.CustomAttributeGenerators, (int) CodeRegistration.CustomAttributeCount); } // Method.Invoke function pointers - MethodInvokePointers = Image.ReadMappedArray(CodeRegistration.InvokerPointers, (int) CodeRegistration.InvokerPointersCount); + MethodInvokePointers = Image.ReadMappedUWordArray(CodeRegistration.InvokerPointers, (int) CodeRegistration.InvokerPointersCount); // TODO: Function pointers as shown below // reversePInvokeWrappers @@ -408,24 +387,24 @@ namespace Il2CppInspector // >=23: interopData if (Image.Version < MetadataVersions.V190) { - VTableMethodReferences = Image.ReadMappedArray(MetadataRegistration.MethodReferences, (int)MetadataRegistration.MethodReferencesCount); + VTableMethodReferences = Image.ReadMappedPrimitiveArray(MetadataRegistration.MethodReferences, (int)MetadataRegistration.MethodReferencesCount); } // Generic type and method specs (open and closed constructed types) - MethodSpecs = Image.ReadMappedArray(MetadataRegistration.MethodSpecs, (int) MetadataRegistration.MethodSpecsCount); + MethodSpecs = Image.ReadMappedVersionedObjectArray(MetadataRegistration.MethodSpecs, (int) MetadataRegistration.MethodSpecsCount); // Concrete generic class and method signatures - GenericInstances = Image.ReadMappedObjectPointerArray(MetadataRegistration.GenericInsts, (int) MetadataRegistration.GenericInstsCount); + GenericInstances = Image.ReadMappedVersionedObjectPointerArray(MetadataRegistration.GenericInsts, (int) MetadataRegistration.GenericInstsCount); // Concrete generic method pointers - var genericMethodPointers = Image.ReadMappedArray(CodeRegistration.GenericMethodPointers, (int) CodeRegistration.GenericMethodPointersCount); - var genericMethodTable = Image.ReadMappedArray(MetadataRegistration.GenericMethodTable, (int) MetadataRegistration.GenericMethodTableCount); + var genericMethodPointers = Image.ReadMappedUWordArray(CodeRegistration.GenericMethodPointers, (int) CodeRegistration.GenericMethodPointersCount); + var genericMethodTable = Image.ReadMappedVersionedObjectArray(MetadataRegistration.GenericMethodTable, (int) MetadataRegistration.GenericMethodTableCount); foreach (var tableEntry in genericMethodTable) { GenericMethodPointers.Add(MethodSpecs[tableEntry.GenericMethodIndex], genericMethodPointers[tableEntry.Indices.MethodIndex]); GenericMethodInvokerIndices.Add(MethodSpecs[tableEntry.GenericMethodIndex], tableEntry.Indices.InvokerIndex); } - TypeDefinitionSizes = Image.ReadMappedObjectPointerArray( + TypeDefinitionSizes = Image.ReadMappedVersionedObjectPointerArray( MetadataRegistration.TypeDefinitionsSizes, (int) MetadataRegistration.TypeDefinitionsSizesCount); // Plugin hook to pre-process binary diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs index 8eb5570..b0ed401 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppInspector.cs @@ -9,6 +9,7 @@ using Il2CppInspector.Utils; using NoisyCowStudios.Bin2Object; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.IO.Compression; using System.Linq; @@ -41,38 +42,38 @@ namespace Il2CppInspector public Dictionary Strings => Metadata.Strings; public string[] StringLiterals => Metadata.StringLiterals; - public Il2CppTypeDefinition[] TypeDefinitions => Metadata.Types; - public Il2CppAssemblyDefinition[] Assemblies => Metadata.Assemblies; - public Il2CppImageDefinition[] Images => Metadata.Images; - public Il2CppMethodDefinition[] Methods => Metadata.Methods; - public Il2CppParameterDefinition[] Params => Metadata.Params; - public Il2CppFieldDefinition[] Fields => Metadata.Fields; - public Il2CppPropertyDefinition[] Properties => Metadata.Properties; - public Il2CppEventDefinition[] Events => Metadata.Events; - public Il2CppGenericContainer[] GenericContainers => Metadata.GenericContainers; - public Il2CppGenericParameter[] GenericParameters => Metadata.GenericParameters; - public int[] GenericConstraintIndices => Metadata.GenericConstraintIndices; - public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges => Metadata.AttributeTypeRanges; - public Il2CppCustomAttributeDataRange[] AttributeDataRanges => Metadata.AttributeDataRanges; - public Il2CppInterfaceOffsetPair[] InterfaceOffsets => Metadata.InterfaceOffsets; - public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices; - public int[] NestedTypeIndices => Metadata.NestedTypeIndices; - public int[] AttributeTypeIndices => Metadata.AttributeTypeIndices; - public uint[] VTableMethodIndices => Metadata.VTableMethodIndices; - public Il2CppFieldRef[] FieldRefs => Metadata.FieldRefs; + public ImmutableArray TypeDefinitions => Metadata.Types; + public ImmutableArray Assemblies => Metadata.Assemblies; + public ImmutableArray Images => Metadata.Images; + public ImmutableArray Methods => Metadata.Methods; + public ImmutableArray Params => Metadata.Params; + public ImmutableArray Fields => Metadata.Fields; + public ImmutableArray Properties => Metadata.Properties; + public ImmutableArray Events => Metadata.Events; + public ImmutableArray GenericContainers => Metadata.GenericContainers; + public ImmutableArray GenericParameters => Metadata.GenericParameters; + public ImmutableArray GenericConstraintIndices => Metadata.GenericConstraintIndices; + public ImmutableArray AttributeTypeRanges => Metadata.AttributeTypeRanges; + public ImmutableArray AttributeDataRanges => Metadata.AttributeDataRanges; + public ImmutableArray InterfaceOffsets => Metadata.InterfaceOffsets; + public ImmutableArray InterfaceUsageIndices => Metadata.InterfaceUsageIndices; + public ImmutableArray NestedTypeIndices => Metadata.NestedTypeIndices; + public ImmutableArray AttributeTypeIndices => Metadata.AttributeTypeIndices; + public ImmutableArray VTableMethodIndices => Metadata.VTableMethodIndices; + public ImmutableArray FieldRefs => Metadata.FieldRefs; public Dictionary FieldDefaultValue { get; } = new Dictionary(); public Dictionary ParameterDefaultValue { get; } = new Dictionary(); public List FieldOffsets { get; } - public List TypeReferences => Binary.TypeReferences; + public ImmutableArray TypeReferences => Binary.TypeReferences; public Dictionary TypeReferenceIndicesByAddress => Binary.TypeReferenceIndicesByAddress; - public List GenericInstances => Binary.GenericInstances; + public ImmutableArray GenericInstances => Binary.GenericInstances; public Dictionary Modules => Binary.Modules; public ulong[] CustomAttributeGenerators { get; } public ulong[] MethodInvokePointers { get; } - public Il2CppMethodSpec[] MethodSpecs => Binary.MethodSpecs; + public ImmutableArray MethodSpecs => Binary.MethodSpecs; public Dictionary GenericMethodPointers { get; } public Dictionary GenericMethodInvokerIndices => Binary.GenericMethodInvokerIndices; - public List TypeDefinitionSizes => Binary.TypeDefinitionSizes; + public ImmutableArray TypeDefinitionSizes => Binary.TypeDefinitionSizes; // TODO: Finish all file access in the constructor and eliminate the need for this public IFileFormatStream BinaryImage => Binary.Image; @@ -121,7 +122,7 @@ namespace Il2CppInspector // Unfortunately the value supplied in MetadataRegistration.matadataUsagesCount seems to be incorrect, // so we have to calculate the correct number of usages above before reading the usage address list from the binary var count = usages.Keys.Max() + 1; - var addresses = Binary.Image.ReadMappedArray(Binary.MetadataRegistration.MetadataUsages, (int) count); + var addresses = Binary.Image.ReadMappedUWordArray(Binary.MetadataRegistration.MetadataUsages, (int) count); foreach (var usage in usages) usage.Value.SetAddress(addresses[usage.Key]); @@ -161,7 +162,7 @@ namespace Il2CppInspector { return usage.Type switch { - MetadataUsageType.TypeInfo or MetadataUsageType.Type => TypeReferences.Count > usage.SourceIndex, + MetadataUsageType.TypeInfo or MetadataUsageType.Type => TypeReferences.Length > usage.SourceIndex, MetadataUsageType.MethodDef => Methods.Length > usage.SourceIndex, MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => FieldRefs.Length > usage.SourceIndex, MetadataUsageType.StringLiteral => StringLiterals.Length > usage.SourceIndex, @@ -347,7 +348,7 @@ namespace Il2CppInspector // Version >= 24.2 var methodInModule = (methodDef.Token & 0xffffff); - return Binary.MethodInvokerIndices[module][methodInModule - 1]; + return Binary.MethodInvokerIndices[module][(int)methodInModule - 1]; } public MetadataUsage[] GetVTable(Il2CppTypeDefinition definition) { diff --git a/Il2CppInspector.Common/IL2CPP/ImageScan.cs b/Il2CppInspector.Common/IL2CPP/ImageScan.cs index 869abf3..637ae7b 100644 --- a/Il2CppInspector.Common/IL2CPP/ImageScan.cs +++ b/Il2CppInspector.Common/IL2CPP/ImageScan.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Text; using Il2CppInspector.Next; using Il2CppInspector.Next.BinaryMetadata; +using VersionedSerialization; namespace Il2CppInspector { @@ -147,7 +148,7 @@ namespace Il2CppInspector potentialCodeGenModules - (ulong) i * ptrSize, 1)) { var expectedImageCountPtr = potentialCodeRegistrationPtr - ptrSize; - var expectedImageCount = ptrSize == 4 ? Image.ReadMappedInt32(expectedImageCountPtr) : Image.ReadMappedInt64(expectedImageCountPtr); + var expectedImageCount = Image.ReadMappedWord(expectedImageCountPtr); if (expectedImageCount == imagesCount) return potentialCodeRegistrationPtr; } @@ -206,11 +207,12 @@ namespace Il2CppInspector // pCodeGenModules is the last field in CodeRegistration so we subtract the size of one pointer from the struct size - codeRegistration = codeRegVa - ((ulong) metadata.Sizeof(typeof(Il2CppCodeRegistration), Image.Version, Image.Bits / 8) - ptrSize); + var codeRegSize = (ulong)Il2CppCodeRegistration.Size(Image.Version, Image.Bits == 32); + codeRegistration = codeRegVa - codeRegSize - ptrSize; // 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. - var cr = Image.ReadMappedObject(codeRegistration); + var cr = Image.ReadMappedVersionedObject(codeRegistration); if (Image.Version == MetadataVersions.V242 && cr.InteropDataCount == 0) { Image.Version = MetadataVersions.V243; @@ -224,6 +226,22 @@ namespace Il2CppInspector Image.Version = MetadataVersions.V271; codeRegistration -= ptrSize; } + + // genericAdjustorThunks was inserted before invokerPointersCount in 24.5 and 27.1 + // pointer expected if we need to bump version + if (Image.Version == MetadataVersions.V244 && cr.InvokerPointersCount > 0x50000) + { + Image.Version = MetadataVersions.V245; + codeRegistration += 1 * ptrSize; + cr = Image.ReadMappedVersionedObject(codeRegistration); + } + + if ((Image.Version == MetadataVersions.V290 || Image.Version == MetadataVersions.V310) && + cr.InteropData + cr.InteropDataCount >= (ulong)Image.Length) + { + Image.Version = new StructVersion(Image.Version.Major, 1, Image.Version.Tag); + cr = Image.ReadMappedVersionedObject(codeRegistration); + } } // Find CodeRegistration @@ -239,7 +257,7 @@ namespace Il2CppInspector // the count of custom attribute generators; the distance between them // depends on the il2cpp version so we just use ReadMappedObject to simplify the math foreach (var va in vas) { - var cr = Image.ReadMappedObject(va); + var cr = Image.ReadMappedVersionedObject(va); if (cr.CustomAttributeCount == metadata.AttributeTypeRanges.Length) codeRegistration = va; @@ -255,15 +273,16 @@ 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) metadata.Sizeof(typeof(Il2CppMetadataRegistration), Image.Version, Image.Bits / 8); + var mrSize = (ulong)Il2CppMetadataRegistration.Size(Image.Version, Image.Bits == 32); var typesLength = (ulong) metadata.Types.Length; vas = FindAllMappedWords(imageBytes, typesLength).Select(a => a - mrSize + ptrSize * 4); // >= 19 && < 27 if (Image.Version < MetadataVersions.V270) - foreach (var va in vas) { - var mr = Image.ReadMappedObject(va); + foreach (var va in vas) + { + var mr = Image.ReadMappedVersionedObject(va); if (mr.MetadataUsagesCount == (ulong) metadata.MetadataUsageLists.Length) metadataRegistration = va; } @@ -273,22 +292,17 @@ namespace Il2CppInspector // Synonyms: copying, piracy, theft, strealing, infringement of copyright // >= 27 - else { - // We're going to just sanity check all of the fields - // All counts should be under a certain threshold - // All pointers should be mappable to the binary - - var mrFieldCount = mrSize / (ulong) (Image.Bits / 8); - foreach (var va in vas) { - var mrWords = Image.ReadMappedWordArray(va, (int) mrFieldCount); - - // Even field indices are counts, odd field indices are pointers - bool ok = true; - for (var i = 0; i < mrWords.Length && ok; i++) { - ok = i % 2 == 0 || Image.TryMapVATR((ulong) mrWords[i], out _); - } - if (ok) + else + { + foreach (var va in vas) + { + var mr = Image.ReadMappedVersionedObject(va); + if (mr.TypeDefinitionsSizesCount == metadata.Types.Length + && mr.FieldOffsetsCount == metadata.Types.Length) + { metadataRegistration = va; + break; + } } } if (metadataRegistration == 0) diff --git a/Il2CppInspector.Common/IL2CPP/Metadata.cs b/Il2CppInspector.Common/IL2CPP/Metadata.cs index 7040ff7..17c9ee6 100644 --- a/Il2CppInspector.Common/IL2CPP/Metadata.cs +++ b/Il2CppInspector.Common/IL2CPP/Metadata.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reflection; @@ -21,30 +22,30 @@ namespace Il2CppInspector { public Il2CppGlobalMetadataHeader Header { get; set; } - public Il2CppAssemblyDefinition[] Assemblies { get; set; } - public Il2CppImageDefinition[] Images { get; set; } - public Il2CppTypeDefinition[] Types { get; set; } - public Il2CppMethodDefinition[] Methods { get; set; } - public Il2CppParameterDefinition[] Params { get; set; } - public Il2CppFieldDefinition[] Fields { get; set; } - public Il2CppFieldDefaultValue[] FieldDefaultValues { get; set; } - public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; set; } - public Il2CppPropertyDefinition[] Properties { get; set; } - public Il2CppEventDefinition[] Events { get; set; } - public Il2CppGenericContainer[] GenericContainers { get; set; } - public Il2CppGenericParameter[] GenericParameters { get; set; } - public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges { get; set; } - public Il2CppCustomAttributeDataRange[] AttributeDataRanges { get; set; } - public Il2CppInterfaceOffsetPair[] InterfaceOffsets { get; set; } - public Il2CppMetadataUsageList[] MetadataUsageLists { get; set; } - public Il2CppMetadataUsagePair[] MetadataUsagePairs { get; set; } - public Il2CppFieldRef[] FieldRefs { get; set; } + public ImmutableArray Assemblies { get; set; } + public ImmutableArray Images { get; set; } + public ImmutableArray Types { get; set; } + public ImmutableArray Methods { get; set; } + public ImmutableArray Params { get; set; } + public ImmutableArray Fields { get; set; } + public ImmutableArray FieldDefaultValues { get; set; } + public ImmutableArray ParameterDefaultValues { get; set; } + public ImmutableArray Properties { get; set; } + public ImmutableArray Events { get; set; } + public ImmutableArray GenericContainers { get; set; } + public ImmutableArray GenericParameters { get; set; } + public ImmutableArray AttributeTypeRanges { get; set; } + public ImmutableArray AttributeDataRanges { get; set; } + public ImmutableArray InterfaceOffsets { get; set; } + public ImmutableArray MetadataUsageLists { get; set; } + public ImmutableArray MetadataUsagePairs { get; set; } + public ImmutableArray FieldRefs { get; set; } - public int[] InterfaceUsageIndices { get; set; } - public int[] NestedTypeIndices { get; set; } - public int[] AttributeTypeIndices { get; set; } - public int[] GenericConstraintIndices { get; set; } - public uint[] VTableMethodIndices { get; set; } + public ImmutableArray InterfaceUsageIndices { get; set; } + public ImmutableArray NestedTypeIndices { get; set; } + public ImmutableArray AttributeTypeIndices { get; set; } + public ImmutableArray GenericConstraintIndices { get; set; } + public ImmutableArray VTableMethodIndices { get; set; } public string[] StringLiterals { get; set; } public Dictionary Strings { get; private set; } = new Dictionary(); @@ -81,7 +82,7 @@ namespace Il2CppInspector StatusUpdate("Processing metadata"); // Read metadata header - Header = ReadObject(0); + Header = ReadVersionedObject(0); // Check for correct magic bytes if (!Header.SanityValid) { @@ -96,7 +97,7 @@ namespace Il2CppInspector } // Rewind and read metadata header with the correct version settings - Header = ReadObject(0); + Header = ReadVersionedObject(0); // Sanity checking // Unity.IL2CPP.MetadataCacheWriter.WriteLibIl2CppMetadata always writes the metadata information in the same order it appears in the header, @@ -110,21 +111,21 @@ namespace Il2CppInspector if (!pluginResult.SkipValidation) { var realHeaderLength = Header.StringLiteralOffset; - if (realHeaderLength != Sizeof(typeof(Il2CppGlobalMetadataHeader))) { + if (realHeaderLength != Sizeof()) { if (Version == MetadataVersions.V240) { Version = MetadataVersions.V242; - Header = ReadObject(0); + Header = ReadVersionedObject(0); } } - if (realHeaderLength != Sizeof(typeof(Il2CppGlobalMetadataHeader))) { + if (realHeaderLength != Sizeof()) { throw new InvalidOperationException("Could not verify the integrity of the metadata file or accurately identify the metadata sub-version"); } } // Load all the relevant metadata using offsets provided in the header if (Version >= MetadataVersions.V160) - Images = ReadArray(Header.ImagesOffset, Header.ImagesSize / Sizeof(typeof(Il2CppImageDefinition))); + Images = ReadVersionedObjectArray(Header.ImagesOffset, Header.ImagesSize / Sizeof()); // As an additional sanity check, all images in the metadata should have Mono.Cecil.MetadataToken == 1 // In metadata v24.1, two extra fields were added which will cause the below test to fail. @@ -135,32 +136,32 @@ namespace Il2CppInspector Version = MetadataVersions.V241; // No need to re-read the header, it's the same for both sub-versions - Images = ReadArray(Header.ImagesOffset, Header.ImagesSize / Sizeof(typeof(Il2CppImageDefinition))); + Images = ReadVersionedObjectArray(Header.ImagesOffset, Header.ImagesSize / Sizeof()); if (Images.Any(x => x.Token != 1)) throw new InvalidOperationException("Could not verify the integrity of the metadata file image list"); } - Types = ReadArray(Header.TypeDefinitionsOffset, Header.TypeDefinitionsSize / Sizeof(typeof(Il2CppTypeDefinition))); - Methods = ReadArray(Header.MethodsOffset, Header.MethodsSize / Sizeof(typeof(Il2CppMethodDefinition))); - Params = ReadArray(Header.ParametersOffset, Header.ParametersSize / Sizeof(typeof(Il2CppParameterDefinition))); - Fields = ReadArray(Header.FieldsOffset, Header.FieldsSize / Sizeof(typeof(Il2CppFieldDefinition))); - FieldDefaultValues = ReadArray(Header.FieldDefaultValuesOffset, Header.FieldDefaultValuesSize / Sizeof(typeof(Il2CppFieldDefaultValue))); - Properties = ReadArray(Header.PropertiesOffset, Header.PropertiesSize / Sizeof(typeof(Il2CppPropertyDefinition))); - Events = ReadArray(Header.EventsOffset, Header.EventsSize / Sizeof(typeof(Il2CppEventDefinition))); - InterfaceUsageIndices = ReadArray(Header.InterfacesOffset, Header.InterfacesSize / sizeof(int)); - NestedTypeIndices = ReadArray(Header.NestedTypesOffset, Header.NestedTypesSize / sizeof(int)); - GenericContainers = ReadArray(Header.GenericContainersOffset, Header.GenericContainersSize / Sizeof(typeof(Il2CppGenericContainer))); - GenericParameters = ReadArray(Header.GenericParametersOffset, Header.GenericParametersSize / Sizeof(typeof(Il2CppGenericParameter))); - GenericConstraintIndices = ReadArray(Header.GenericParameterConstraintsOffset, Header.GenericParameterConstraintsSize / sizeof(int)); - InterfaceOffsets = ReadArray(Header.InterfaceOffsetsOffset, Header.InterfaceOffsetsSize / Sizeof(typeof(Il2CppInterfaceOffsetPair))); - VTableMethodIndices = ReadArray(Header.VTableMethodsOffset, Header.VTableMethodsSize / sizeof(uint)); + Types = ReadVersionedObjectArray(Header.TypeDefinitionsOffset, Header.TypeDefinitionsSize / Sizeof()); + Methods = ReadVersionedObjectArray(Header.MethodsOffset, Header.MethodsSize / Sizeof()); + Params = ReadVersionedObjectArray(Header.ParametersOffset, Header.ParametersSize / Sizeof()); + Fields = ReadVersionedObjectArray(Header.FieldsOffset, Header.FieldsSize / Sizeof()); + FieldDefaultValues = ReadVersionedObjectArray(Header.FieldDefaultValuesOffset, Header.FieldDefaultValuesSize / Sizeof()); + Properties = ReadVersionedObjectArray(Header.PropertiesOffset, Header.PropertiesSize / Sizeof()); + Events = ReadVersionedObjectArray(Header.EventsOffset, Header.EventsSize / Sizeof()); + InterfaceUsageIndices = ReadPrimitiveArray(Header.InterfacesOffset, Header.InterfacesSize / sizeof(int)); + NestedTypeIndices = ReadPrimitiveArray(Header.NestedTypesOffset, Header.NestedTypesSize / sizeof(int)); + GenericContainers = ReadVersionedObjectArray(Header.GenericContainersOffset, Header.GenericContainersSize / Sizeof()); + GenericParameters = ReadVersionedObjectArray(Header.GenericParametersOffset, Header.GenericParametersSize / Sizeof()); + GenericConstraintIndices = ReadPrimitiveArray(Header.GenericParameterConstraintsOffset, Header.GenericParameterConstraintsSize / sizeof(int)); + InterfaceOffsets = ReadVersionedObjectArray(Header.InterfaceOffsetsOffset, Header.InterfaceOffsetsSize / Sizeof()); + VTableMethodIndices = ReadPrimitiveArray(Header.VTableMethodsOffset, Header.VTableMethodsSize / sizeof(uint)); if (Version >= MetadataVersions.V160) { // In v24.4 hashValueIndex was removed from Il2CppAssemblyNameDefinition, which is a field in Il2CppAssemblyDefinition // The number of images and assemblies should be the same. If they are not, we deduce that we are using v24.4 // Note the version comparison matches both 24.2 and 24.3 here since 24.3 is tested for during binary loading - var assemblyCount = Header.AssembliesSize / Sizeof(typeof(Il2CppAssemblyDefinition)); + var assemblyCount = Header.AssembliesSize / Sizeof(); var changedAssemblyDefStruct = false; if ((Version == MetadataVersions.V241 || Version == MetadataVersions.V242 || Version == MetadataVersions.V243) && assemblyCount < Images.Length) { @@ -169,29 +170,29 @@ namespace Il2CppInspector Version = MetadataVersions.V244; } - Assemblies = ReadArray(Header.AssembliesOffset, Images.Length); + Assemblies = ReadVersionedObjectArray(Header.AssembliesOffset, Images.Length); if (changedAssemblyDefStruct) Version = MetadataVersions.V241; - ParameterDefaultValues = ReadArray(Header.ParameterDefaultValuesOffset, Header.ParameterDefaultValuesSize / Sizeof(typeof(Il2CppParameterDefaultValue))); + ParameterDefaultValues = ReadVersionedObjectArray(Header.ParameterDefaultValuesOffset, Header.ParameterDefaultValuesSize / Sizeof()); } if (Version >= MetadataVersions.V190 && Version < MetadataVersions.V270) { - MetadataUsageLists = ReadArray(Header.MetadataUsageListsOffset, Header.MetadataUsageListsCount / Sizeof(typeof(Il2CppMetadataUsageList))); - MetadataUsagePairs = ReadArray(Header.MetadataUsagePairsOffset, Header.MetadataUsagePairsCount / Sizeof(typeof(Il2CppMetadataUsagePair))); + MetadataUsageLists = ReadVersionedObjectArray(Header.MetadataUsageListsOffset, Header.MetadataUsageListsCount / Sizeof()); + MetadataUsagePairs = ReadVersionedObjectArray(Header.MetadataUsagePairsOffset, Header.MetadataUsagePairsCount / Sizeof()); } if (Version >= MetadataVersions.V190) { - FieldRefs = ReadArray(Header.FieldRefsOffset, Header.FieldRefsSize / Sizeof(typeof(Il2CppFieldRef))); + FieldRefs = ReadVersionedObjectArray(Header.FieldRefsOffset, Header.FieldRefsSize / Sizeof()); } if (Version >= MetadataVersions.V210 && Version < MetadataVersions.V290) { - AttributeTypeIndices = ReadArray(Header.AttributesTypesOffset, Header.AttributesTypesCount / sizeof(int)); - AttributeTypeRanges = ReadArray(Header.AttributesInfoOffset, Header.AttributesInfoCount / Sizeof(typeof(Il2CppCustomAttributeTypeRange))); + AttributeTypeIndices = ReadPrimitiveArray(Header.AttributesTypesOffset, Header.AttributesTypesCount / sizeof(int)); + AttributeTypeRanges = ReadVersionedObjectArray(Header.AttributesInfoOffset, Header.AttributesInfoCount / Sizeof()); } if (Version >= MetadataVersions.V290) { - AttributeDataRanges = ReadArray(Header.AttributeDataRangeOffset, - Header.AttributeDataRangeSize / Sizeof(typeof(Il2CppCustomAttributeDataRange))); + AttributeDataRanges = ReadVersionedObjectArray(Header.AttributeDataRangeOffset, + Header.AttributeDataRangeSize / Sizeof()); } if (Version == MetadataVersions.V290 || Version == MetadataVersions.V310) @@ -207,8 +208,8 @@ namespace Il2CppInspector { Version = new StructVersion(Version.Major, 1, Version.Tag); - Methods = ReadArray(Header.MethodsOffset, - Header.MethodsSize / Sizeof(typeof(Il2CppMethodDefinition))); + Methods = ReadVersionedObjectArray(Header.MethodsOffset, + Header.MethodsSize / Sizeof()); } } } @@ -231,7 +232,7 @@ namespace Il2CppInspector StringLiterals = pluginGetStringLiteralsResult.StringLiterals.ToArray(); else { - var stringLiteralList = ReadArray(Header.StringLiteralOffset, Header.StringLiteralSize / Sizeof(typeof(Il2CppStringLiteral))); + var stringLiteralList = ReadVersionedObjectArray(Header.StringLiteralOffset, Header.StringLiteralSize / Sizeof()); StringLiterals = new string[stringLiteralList.Length]; for (var i = 0; i < stringLiteralList.Length; i++) @@ -249,42 +250,6 @@ namespace Il2CppInspector CopyTo(outFile); } - public int Sizeof(Type type) => Sizeof(type, Version); - - public int Sizeof(Type type, StructVersion metadataVersion, int longSizeBytes = 8) - { - var doubleRepresentation = metadataVersion.AsDouble; - - if (Reader.ObjectMappings.TryGetValue(type, out var streamType)) - type = streamType; - - int size = 0; - foreach (var i in type.GetTypeInfo().GetFields()) - { - // Only process fields for our selected object versioning (always process if none supplied) - var versions = i.GetCustomAttributes(false).Select(v => (v.Min, v.Max)).ToList(); - if (versions.Any() && !versions.Any(v => (v.Min <= doubleRepresentation || v.Min == -1) && (v.Max >= doubleRepresentation || v.Max == -1))) - continue; - - if (i.FieldType == typeof(long) || i.FieldType == typeof(ulong)) - size += longSizeBytes; - else if (i.FieldType == typeof(int) || i.FieldType == typeof(uint)) - size += 4; - else if (i.FieldType == typeof(short) || i.FieldType == typeof(ushort)) - size += 2; - - // Fixed-length array - else if (i.FieldType.IsArray) { - var attr = i.GetCustomAttribute(false) ?? - throw new InvalidOperationException("Array field " + i.Name + " must have ArrayLength attribute"); - size += attr.FixedSize; - } - - // Embedded object - else - size += Sizeof(i.FieldType, metadataVersion); - } - return size; - } + public int Sizeof() where T : IReadable => T.Size(Version, Is32Bit); } } diff --git a/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs b/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs index 2c4d765..d05d1b8 100644 --- a/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs +++ b/Il2CppInspector.Common/IL2CPP/MetadataUsage.cs @@ -21,7 +21,7 @@ namespace Il2CppInspector FieldRva = 7 } - public class MetadataUsage + public record struct MetadataUsage { public MetadataUsageType Type { get; } public int SourceIndex { get; } @@ -39,7 +39,7 @@ namespace Il2CppInspector if (package.Version < MetadataVersions.V190) { /* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */ var isGeneric = encodedIndex & 0x80000000; - index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF]; + index = package.Binary.VTableMethodReferences[(int)(encodedIndex & 0x7FFFFFFF)]; usageType = (isGeneric != 0) ? MetadataUsageType.MethodRef : MetadataUsageType.MethodDef; } else { /* These encoded indices appear in metadata usages, and are decoded by GetEncodedIndexType/GetDecodedMethodIndex */ diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppArrayType.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppArrayType.cs index 1296aaa..8ff56be 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppArrayType.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppArrayType.cs @@ -3,16 +3,13 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppArrayType +public partial record struct Il2CppArrayType { public Pointer ElementType; public byte Rank; public byte NumSizes; public byte NumLowerBound; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong Sizes; // int* - - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong LoBounds; // int* + public PrimitivePointer Sizes; + public PrimitivePointer LoBounds; } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeGenModule.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeGenModule.cs index f9f1808..55bd08f 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeGenModule.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeGenModule.cs @@ -3,17 +3,16 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppCodeGenModule +public partial record struct Il2CppCodeGenModule { - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong ModuleName; // const char* + public PrimitivePointer ModuleName; // const char* - [Aligned(0)] + [NativeInteger] public uint MethodPointerCount; public Pointer MethodPointers; - [Aligned(0)] + [NativeInteger] [VersionCondition(EqualTo = "24.5")] [VersionCondition(GreaterThan = "27.1")] public uint AdjustorThunksCount; @@ -22,24 +21,22 @@ public partial struct Il2CppCodeGenModule [VersionCondition(GreaterThan = "27.1")] public Pointer AdjustorThunks; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong InvokerIndices; // int* + public PrimitivePointer InvokerIndices; // int* - [Aligned(0)] + [NativeInteger] public uint ReversePInvokeWrapperCount; public Pointer ReversePInvokeWrapperIndices; - [Aligned(0)] + [NativeInteger] public uint RgctxRangesCount; public Pointer RgctxRanges; - [Aligned(0)] + [NativeInteger] public uint RgctxsCount; public Pointer Rgctxs; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong DebuggerMetadata; // Pointer DebuggerMetadata; + public PrimitivePointer DebuggerMetadata; // Pointer DebuggerMetadata; [VersionCondition(GreaterThan = "27.0", LessThan = "27.2")] public Pointer CustomAttributeCacheGenerator; @@ -48,14 +45,11 @@ public partial struct Il2CppCodeGenModule public Il2CppMethodPointer ModuleInitializer; [VersionCondition(GreaterThan = "27.0")] - [Aligned(0)] - public ulong StaticConstructorTypeIndices; // TypeDefinitionIndex* + public PrimitivePointer StaticConstructorTypeIndices; // TypeDefinitionIndex* [VersionCondition(GreaterThan = "27.0")] - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong MetadataRegistration; // Pointer + public PrimitivePointer MetadataRegistration; // Pointer [VersionCondition(GreaterThan = "27.0")] - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong CodeRegistration; // Pointer + public PrimitivePointer CodeRegistration; // Pointer } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs index 428f044..8350d29 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppCodeRegistration.cs @@ -5,38 +5,42 @@ namespace Il2CppInspector.Next.BinaryMetadata; using InvokerMethod = Il2CppMethodPointer; [VersionedStruct] -public partial struct Il2CppCodeRegistration +public partial record struct Il2CppCodeRegistration { - [VersionCondition(LessThan = "24.1"), Aligned(0)] + [NativeInteger] + [VersionCondition(LessThan = "24.1")] public uint MethodPointersCount; [VersionCondition(LessThan = "24.1")] public Pointer MethodPointers; - [Aligned(0)] + [NativeInteger] public uint ReversePInvokeWrapperCount; public Pointer ReversePInvokeWrappers; - [VersionCondition(LessThan = "22.0"), Aligned(0)] + [NativeInteger] + [VersionCondition(LessThan = "22.0")] public uint DelegateWrappersFromManagedToNativeCount; [VersionCondition(LessThan = "22.0")] public Pointer DelegateWrappersFromManagedToNative; - [VersionCondition(LessThan = "22.0"), Aligned(0)] + [NativeInteger] + [VersionCondition(LessThan = "22.0")] public uint MarshalingFunctionsCount; [VersionCondition(LessThan = "22.0")] public Pointer MarshalingFunctions; - [VersionCondition(GreaterThan = "21.0", LessThan = "22.0"), Aligned(0)] + [NativeInteger] + [VersionCondition(GreaterThan = "21.0", LessThan = "22.0")] public uint CcwMarshalingFunctionsCount; [VersionCondition(GreaterThan = "21.0", LessThan = "22.0")] public Pointer CcwMarshalingFunctions; - [Aligned(0)] + [NativeInteger] public uint GenericMethodPointersCount; public Pointer GenericMethodPointers; @@ -45,29 +49,32 @@ public partial struct Il2CppCodeRegistration [VersionCondition(GreaterThan = "27.1")] public Pointer GenericAdjustorThunks; - [Aligned(0)] + [NativeInteger] public uint InvokerPointersCount; public Pointer InvokerPointers; - [VersionCondition(LessThan = "24.5"), Aligned(0)] + [NativeInteger] + [VersionCondition(LessThan = "24.5")] public int CustomAttributeCount; [VersionCondition(LessThan = "24.5")] public Pointer CustomAttributeGenerators; - [VersionCondition(GreaterThan = "21.0", LessThan = "22.0"), Aligned(0)] + [NativeInteger] + [VersionCondition(GreaterThan = "21.0", LessThan = "22.0")] public int GuidCount; [VersionCondition(GreaterThan = "21.0", LessThan = "22.0")] public Pointer Guids; + [NativeInteger] [VersionCondition(GreaterThan = "22.0", LessThan = "29.0")] public int UnresolvedVirtualCallCount; + [NativeInteger] [VersionCondition(EqualTo = "29.1"), VersionCondition(EqualTo = "31.1")] [VersionCondition(EqualTo = "29.2"), VersionCondition(EqualTo = "31.2")] - [Aligned(0)] public uint UnresolvedIndirectCallCount; // UnresolvedVirtualCallCount pre 29.1 [VersionCondition(GreaterThan = "22.0")] @@ -81,19 +88,22 @@ public partial struct Il2CppCodeRegistration [VersionCondition(EqualTo = "29.2"), VersionCondition(EqualTo = "31.2")] public Pointer UnresolvedStaticCallPointers; - [VersionCondition(GreaterThan = "23.0"), Aligned(0)] + [NativeInteger] + [VersionCondition(GreaterThan = "23.0")] public uint InteropDataCount; [VersionCondition(GreaterThan = "23.0")] public Pointer InteropData; - [VersionCondition(GreaterThan = "24.3"), Aligned(0)] + [NativeInteger] + [VersionCondition(GreaterThan = "24.3")] public uint WindowsRuntimeFactoryCount; [VersionCondition(GreaterThan = "24.3")] public Pointer WindowsRuntimeFactoryTable; - [VersionCondition(GreaterThan = "24.2"), Aligned(0)] + [NativeInteger] + [VersionCondition(GreaterThan = "24.2")] public uint CodeGenModulesCount; [VersionCondition(GreaterThan = "24.2")] diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericClass.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericClass.cs index 9259a0c..e147a8a 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericClass.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericClass.cs @@ -3,9 +3,10 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppGenericClass +public partial record struct Il2CppGenericClass { - [VersionCondition(LessThan = "24.5"), Aligned(0)] + [NativeInteger] + [VersionCondition(LessThan = "24.5")] public int TypeDefinitionIndex; [VersionCondition(GreaterThan = "27.0")] @@ -13,6 +14,5 @@ public partial struct Il2CppGenericClass public Il2CppGenericContext Context; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong CachedClass; // Il2CppClass*, optional + public PrimitivePointer CachedClass; // Il2CppClass*, optional } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericContext.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericContext.cs index 1737bcf..b5f3101 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericContext.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericContext.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppGenericContext +public partial record struct Il2CppGenericContext { public Pointer ClassInst; public Pointer MethodInst; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericInst.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericInst.cs index 0a55c91..e77edc5 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericInst.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericInst.cs @@ -3,11 +3,11 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppGenericInst +public partial record struct Il2CppGenericInst { public readonly bool Valid => TypeArgc > 0; - [Aligned(0)] + [NativeInteger] public uint TypeArgc; public Pointer> TypeArgv; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodFunctionsDefinitions.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodFunctionsDefinitions.cs index 97478ef..8bdbf96 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodFunctionsDefinitions.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodFunctionsDefinitions.cs @@ -5,7 +5,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; using GenericMethodIndex = int; [VersionedStruct] -public partial struct Il2CppGenericMethodFunctionsDefinitions +public partial record struct Il2CppGenericMethodFunctionsDefinitions { public GenericMethodIndex GenericMethodIndex; public Il2CppGenericMethodIndices Indices; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodIndices.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodIndices.cs index e18bf10..78afa4b 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodIndices.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGenericMethodIndices.cs @@ -5,7 +5,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; using MethodIndex = int; [VersionedStruct] -public partial struct Il2CppGenericMethodIndices +public partial record struct Il2CppGenericMethodIndices { public MethodIndex MethodIndex; public MethodIndex InvokerIndex; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGuid.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGuid.cs index 341ab1e..b9b304b 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGuid.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppGuid.cs @@ -2,8 +2,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; - -public struct Il2CppGuid : IReadable +public record struct Il2CppGuid : IReadable { public Guid Value; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppInteropData.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppInteropData.cs index 9305569..52a0367 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppInteropData.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppInteropData.cs @@ -8,7 +8,7 @@ using PInvokeMarshalCleanupFunc = Il2CppMethodPointer; using CreateCCWFunc = Il2CppMethodPointer; [VersionedStruct] -public partial struct Il2CppInteropData +public partial record struct Il2CppInteropData { public Il2CppMethodPointer DelegatePInvokeWrapperFunction; public PInvokeMarshalToNativeFunc PInvokeMarshalToNativeFunction; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMetadataRegistration.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMetadataRegistration.cs index 2df65c9..dbd7b3d 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMetadataRegistration.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMetadataRegistration.cs @@ -7,51 +7,50 @@ using FieldIndex = int; using TypeDefinitionIndex = int; [VersionedStruct] -public partial struct Il2CppMetadataRegistration +public partial record struct Il2CppMetadataRegistration { - [Aligned(0)] + [NativeInteger] public int GenericClassesCount; public Pointer> GenericClasses; - [Aligned(0)] + [NativeInteger] public int GenericInstsCount; public Pointer> GenericInsts; - [Aligned(0)] + [NativeInteger] public int GenericMethodTableCount; public Pointer GenericMethodTable; - [Aligned(0)] + [NativeInteger] public int TypesCount; public Pointer> Types; - [Aligned(0)] + [NativeInteger] public int MethodSpecsCount; public Pointer MethodSpecs; + [NativeInteger] [VersionCondition(LessThan = "16.0")] public int MethodReferencesCount; [VersionCondition(LessThan = "16.0")] - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong MethodReferences; // uint** + public PrimitivePointer> MethodReferences; // uint** - [Aligned(0)] + [NativeInteger] public FieldIndex FieldOffsetsCount; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong FieldOffsets; // int** + public PrimitivePointer> FieldOffsets; // int** - [Aligned(0)] + [NativeInteger] public TypeDefinitionIndex TypeDefinitionsSizesCount; public Pointer> TypeDefinitionsSizes; - [Aligned(0)] + [NativeInteger] [VersionCondition(GreaterThan = "19.0")] public ulong MetadataUsagesCount; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodPointer.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodPointer.cs index a6d1005..14f65aa 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodPointer.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodPointer.cs @@ -3,11 +3,11 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppMethodPointer(ulong addr = 0) +public partial record struct Il2CppMethodPointer(ulong addr = 0) { public static readonly Il2CppMethodPointer Null = new(); - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] + [NativeInteger] public ulong Value { get; set; } = addr; public readonly bool IsNull => Value == 0; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodSpec.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodSpec.cs index 0fa7d04..25ab157 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodSpec.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppMethodSpec.cs @@ -6,7 +6,7 @@ using MethodIndex = int; using GenericInstIndex = int; [VersionedStruct] -public partial struct Il2CppMethodSpec +public partial record struct Il2CppMethodSpec { public MethodIndex MethodDefinitionIndex; public GenericInstIndex ClassIndexIndex; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRange.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRange.cs index 557861e..8e8edf6 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRange.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRange.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppRange +public partial record struct Il2CppRange { public int Start; public int Length; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxConstrainedData.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxConstrainedData.cs index f51ddd3..b93a9e8 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxConstrainedData.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxConstrainedData.cs @@ -6,7 +6,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppRgctxConstrainedData +public partial record struct Il2CppRgctxConstrainedData { public TypeIndex TypeIndex; public Il2CppMetadataUsage EncodedMethodIndex; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinition.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinition.cs index 0fb2efe..4cc7d4d 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinition.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinition.cs @@ -3,14 +3,13 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppRgctxDefinition +public partial record struct Il2CppRgctxDefinition { - [Aligned(0)] + [NativeInteger] public Il2CppRgctxDataType Type; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong Data; // void* + public PrimitivePointer Data; // void* - public readonly Pointer Definition => Data; - public readonly Pointer Constrained => Data; + public readonly Pointer Definition => Data.PointerValue; + public readonly Pointer Constrained => Data.PointerValue; } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinitionData.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinitionData.cs index a6b19a2..4343e87 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinitionData.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppRgctxDefinitionData.cs @@ -6,7 +6,7 @@ using MethodIndex = int; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppRgctxDefinitionData +public partial record struct Il2CppRgctxDefinitionData { public int Value; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenAdjustorThunkPair.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenAdjustorThunkPair.cs index e6ac2c5..974024c 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenAdjustorThunkPair.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenAdjustorThunkPair.cs @@ -3,9 +3,9 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppTokenAdjustorThunkPair +public partial record struct Il2CppTokenAdjustorThunkPair { - [Aligned(0)] + [NativeInteger] public uint Token; public Il2CppMethodPointer AdjustorThunk; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenIndexMethodTuple.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenIndexMethodTuple.cs index 6109901..45c47ed 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenIndexMethodTuple.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenIndexMethodTuple.cs @@ -3,13 +3,12 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppTokenIndexMethodTuple +public partial record struct Il2CppTokenIndexMethodTuple { public uint Token; public int Index; - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] - public ulong Method; // void** + public PrimitivePointer Method; // void** public uint GenericMethodIndex; } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenRangePair.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenRangePair.cs index dfc7836..67d1f6a 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenRangePair.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTokenRangePair.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppTokenRangePair +public partial record struct Il2CppTokenRangePair { public uint Token; public Il2CppRange Range; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTypeDefinitionSizes.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTypeDefinitionSizes.cs index dc46ae4..3041d77 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTypeDefinitionSizes.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppTypeDefinitionSizes.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppTypeDefinitionSizes +public partial record struct Il2CppTypeDefinitionSizes { public uint InstanceSize; public int NativeSize; diff --git a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppWindowsRuntimeFactoryTableEntry.cs b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppWindowsRuntimeFactoryTableEntry.cs index 1c42edc..3a6654f 100644 --- a/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppWindowsRuntimeFactoryTableEntry.cs +++ b/Il2CppInspector.Common/Next/BinaryMetadata/Il2CppWindowsRuntimeFactoryTableEntry.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.BinaryMetadata; [VersionedStruct] -public partial struct Il2CppWindowsRuntimeFactoryTableEntry +public partial record struct Il2CppWindowsRuntimeFactoryTableEntry { public Pointer Type; public Il2CppMethodPointer CreateFactoryFunction; diff --git a/Il2CppInspector.Common/Next/BinaryObjectStreamReader.cs b/Il2CppInspector.Common/Next/BinaryObjectStreamReader.cs index a5fae3e..ac4a21c 100644 --- a/Il2CppInspector.Common/Next/BinaryObjectStreamReader.cs +++ b/Il2CppInspector.Common/Next/BinaryObjectStreamReader.cs @@ -8,6 +8,18 @@ namespace Il2CppInspector.Next; public class BinaryObjectStreamReader : BinaryObjectStream, IReader { + public new StructVersion Version + { + get => _version; + set + { + _version = value; + base.Version = _version.AsDouble; + } + } + + private StructVersion _version; + public virtual int Bits { get; set; } public bool Is32Bit => Bits == 32; @@ -127,4 +139,9 @@ public class BinaryObjectStreamReader : BinaryObjectStream, IReader Position = addr; return ReadVersionedObjectArray(count, Version); } + + public void Skip(int count) + { + Position += count; + } } \ No newline at end of file diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyDefinition.cs index ca62195..40d55ee 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyDefinition.cs @@ -7,7 +7,7 @@ using ImageIndex = int; [VersionedStruct] [StructLayout(LayoutKind.Explicit)] -public partial struct Il2CppAssemblyDefinition +public partial record struct Il2CppAssemblyDefinition { [FieldOffset(20)] [VersionCondition(LessThan = "15.0")] diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyNameDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyNameDefinition.cs index 83068e7..27a0aa0 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyNameDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppAssemblyNameDefinition.cs @@ -17,7 +17,7 @@ public struct PublicKeyToken [VersionedStruct] [StructLayout(LayoutKind.Explicit)] -public partial struct Il2CppAssemblyNameDefinition +public partial record struct Il2CppAssemblyNameDefinition { [FieldOffset(0)] public StringIndex NameIndex; diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeDataRange.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeDataRange.cs index a38db96..b31a87c 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeDataRange.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeDataRange.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.Metadata; [VersionedStruct] -public partial struct Il2CppCustomAttributeDataRange +public partial record struct Il2CppCustomAttributeDataRange { public uint Token { get; private set; } public uint StartOffset { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeTypeRange.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeTypeRange.cs index 4be20de..6ecd6a5 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeTypeRange.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppCustomAttributeTypeRange.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.Metadata; [VersionedStruct] -public partial struct Il2CppCustomAttributeTypeRange +public partial record struct Il2CppCustomAttributeTypeRange { [VersionCondition(GreaterThan = "24.1")] public uint Token { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppEventDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppEventDefinition.cs index 7658f5b..c763cbd 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppEventDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppEventDefinition.cs @@ -6,7 +6,7 @@ using MethodIndex = int; using VersionedSerialization.Attributes; [VersionedStruct] -public partial struct Il2CppEventDefinition +public partial record struct Il2CppEventDefinition { public StringIndex NameIndex { get; private set; } public TypeIndex TypeIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefaultValue.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefaultValue.cs index ed984e2..47c9fef 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefaultValue.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefaultValue.cs @@ -7,7 +7,7 @@ using TypeIndex = int; using DefaultValueDataIndex = int; [VersionedStruct] -public partial struct Il2CppFieldDefaultValue +public partial record struct Il2CppFieldDefaultValue { public FieldIndex FieldIndex { get; private set; } public TypeIndex TypeIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefinition.cs index 84d0ef4..91f81e9 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldDefinition.cs @@ -5,7 +5,7 @@ using StringIndex = int; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppFieldDefinition +public partial record struct Il2CppFieldDefinition { public StringIndex NameIndex { get; private set; } public TypeIndex TypeIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldMarshaledSize.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldMarshaledSize.cs index bc71ad7..0cbb5ed 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldMarshaledSize.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldMarshaledSize.cs @@ -5,7 +5,7 @@ using FieldIndex = int; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppFieldMarshaledSize +public partial record struct Il2CppFieldMarshaledSize { public FieldIndex FieldIndex { get; private set; } public TypeIndex TypeIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldRef.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldRef.cs index d02500d..aba478e 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppFieldRef.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppFieldRef.cs @@ -6,7 +6,7 @@ using FieldIndex = int; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppFieldRef +public partial record struct Il2CppFieldRef { public TypeIndex TypeIndex { get; private set; } public FieldIndex FieldIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppGenericContainer.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppGenericContainer.cs index 43421c3..54d4969 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppGenericContainer.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppGenericContainer.cs @@ -4,7 +4,7 @@ using VersionedSerialization.Attributes; using GenericParameterIndex = int; [VersionedStruct] -public partial struct Il2CppGenericContainer +public partial record struct Il2CppGenericContainer { public int OwnerIndex { get; private set; } public int TypeArgc { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppGenericParameter.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppGenericParameter.cs index beaa94a..b9f5a17 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppGenericParameter.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppGenericParameter.cs @@ -8,7 +8,7 @@ using StringIndex = int; using GenericParameterConstraintIndex = short; [VersionedStruct] -public partial struct Il2CppGenericParameter +public partial record struct Il2CppGenericParameter { public GenericContainerIndex OwnerIndex { get; private set; } public StringIndex NameIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppGlobalMetadataHeader.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppGlobalMetadataHeader.cs index d137be3..1eefde9 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppGlobalMetadataHeader.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppGlobalMetadataHeader.cs @@ -25,7 +25,7 @@ namespace Il2CppInspector.Next.Metadata; // Metadata version is written at the end of Unity.IL2CPP.MetadataCacheWriter.WriteLibIl2CppMetadata or WriteMetadata (Unity.IL2CPP.dll) [VersionedStruct] -public partial struct Il2CppGlobalMetadataHeader +public partial record struct Il2CppGlobalMetadataHeader { public int Sanity { get; private set; } public int Version { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppImageDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppImageDefinition.cs index 56bc753..0f50a2b 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppImageDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppImageDefinition.cs @@ -8,7 +8,7 @@ using CustomAttributeIndex = int; using VersionedSerialization.Attributes; [VersionedStruct] -public partial struct Il2CppImageDefinition +public partial record struct Il2CppImageDefinition { public StringIndex NameIndex { get; private set; } public AssemblyIndex AssemblyIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppInterfaceOffsetPair.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppInterfaceOffsetPair.cs index 93337b2..8ed5d41 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppInterfaceOffsetPair.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppInterfaceOffsetPair.cs @@ -5,7 +5,7 @@ namespace Il2CppInspector.Next.Metadata; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppInterfaceOffsetPair +public partial record struct Il2CppInterfaceOffsetPair { public TypeIndex InterfaceTypeIndex { get; private set; } public int Offset { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataRange.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataRange.cs index 4ab7a24..22d79f4 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataRange.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataRange.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.Metadata; [VersionedStruct] -public partial struct Il2CppMetadataRange +public partial record struct Il2CppMetadataRange { public int Start { get; private set; } public int Length { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsage.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsage.cs index 70855f1..b036e0e 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsage.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsage.cs @@ -7,7 +7,7 @@ using VersionedSerialization.Attributes; using EncodedMethodIndex = uint; [VersionedStruct] -public partial struct Il2CppMetadataUsage +public partial record struct Il2CppMetadataUsage { private const uint TypeMask = 0b111u << 29; private const uint InflatedMask = 0b1; diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsageList.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsageList.cs index 517a05a..81da582 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsageList.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsageList.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.Metadata; [VersionedStruct] -public partial struct Il2CppMetadataUsageList +public partial record struct Il2CppMetadataUsageList { public int Start { get; private set; } public int Count { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsagePair.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsagePair.cs index b5b2359..7874ac8 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsagePair.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppMetadataUsagePair.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.Metadata; [VersionedStruct] -public partial struct Il2CppMetadataUsagePair +public partial record struct Il2CppMetadataUsagePair { public uint DestinationIndex { get; private set; } public uint EncodedSourceIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs index 360f0c5..376016b 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppMethodDefinition.cs @@ -10,7 +10,7 @@ using ParameterIndex = int; using GenericContainerIndex = int; [VersionedStruct] -public partial struct Il2CppMethodDefinition +public partial record struct Il2CppMethodDefinition { public StringIndex NameIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefaultValue.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefaultValue.cs index 1a3e473..8451daa 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefaultValue.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefaultValue.cs @@ -6,7 +6,7 @@ using DefaultValueDataIndex = int; using VersionedSerialization.Attributes; [VersionedStruct] -public partial struct Il2CppParameterDefaultValue +public partial record struct Il2CppParameterDefaultValue { public ParameterIndex ParameterIndex { get; private set; } public TypeIndex TypeIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefinition.cs index a66af4d..2bca465 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppParameterDefinition.cs @@ -5,7 +5,7 @@ using StringIndex = int; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppParameterDefinition +public partial record struct Il2CppParameterDefinition { public StringIndex NameIndex { get; private set; } public uint Token { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppPropertyDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppPropertyDefinition.cs index 6ba2ad8..f74e243 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppPropertyDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppPropertyDefinition.cs @@ -7,7 +7,7 @@ using StringIndex = int; using MethodIndex = int; [VersionedStruct] -public partial struct Il2CppPropertyDefinition +public partial record struct Il2CppPropertyDefinition { public StringIndex NameIndex { get; private set; } public MethodIndex Get { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs index 93f4ac6..b1521fe 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppStringLiteral.cs @@ -4,7 +4,7 @@ using VersionedSerialization.Attributes; using StringLiteralIndex = int; [VersionedStruct] -public partial struct Il2CppStringLiteral +public partial record struct Il2CppStringLiteral { public uint Length { get; private set; } public StringLiteralIndex DataIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs index cb89a97..52efe14 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinition.cs @@ -15,7 +15,7 @@ using InterfacesIndex = int; using VTableIndex = int; [VersionedStruct] -public partial struct Il2CppTypeDefinition +public partial record struct Il2CppTypeDefinition { public const TypeIndex InvalidTypeIndex = -1; diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinitionBitfield.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinitionBitfield.cs index 28875b8..b66dbc9 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinitionBitfield.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppTypeDefinitionBitfield.cs @@ -3,7 +3,7 @@ namespace Il2CppInspector.Next.Metadata; [VersionedStruct] -public partial struct Il2CppTypeDefinitionBitfield +public partial record struct Il2CppTypeDefinitionBitfield { private uint _value; diff --git a/Il2CppInspector.Common/Next/Metadata/Il2CppWindowsRuntimeTypeNamePair.cs b/Il2CppInspector.Common/Next/Metadata/Il2CppWindowsRuntimeTypeNamePair.cs index 217a212..6ac6357 100644 --- a/Il2CppInspector.Common/Next/Metadata/Il2CppWindowsRuntimeTypeNamePair.cs +++ b/Il2CppInspector.Common/Next/Metadata/Il2CppWindowsRuntimeTypeNamePair.cs @@ -5,7 +5,7 @@ using StringIndex = int; using TypeIndex = int; [VersionedStruct] -public partial struct Il2CppWindowsRuntimeTypeNamePair +public partial record struct Il2CppWindowsRuntimeTypeNamePair { public StringIndex NameIndex { get; private set; } public TypeIndex TypeIndex { get; private set; } diff --git a/Il2CppInspector.Common/Next/Pointer.cs b/Il2CppInspector.Common/Next/Pointer.cs index db0de19..f523c49 100644 --- a/Il2CppInspector.Common/Next/Pointer.cs +++ b/Il2CppInspector.Common/Next/Pointer.cs @@ -4,9 +4,9 @@ using VersionedSerialization.Attributes; namespace Il2CppInspector.Next; -public struct Pointer(ulong value = 0) : IReadable, IEquatable> where T : IReadable, new() +public struct Pointer(ulong value = 0) : IReadable, IEquatable> where T : struct, IReadable { - [CustomSerialization("reader.ReadNUInt();", "is32Bit ? 4 : 8")] + [NativeInteger] private ulong _value = value; public readonly ulong PointerValue => _value; diff --git a/Il2CppInspector.Common/Next/PrimitivePointer.cs b/Il2CppInspector.Common/Next/PrimitivePointer.cs new file mode 100644 index 0000000..60d17ff --- /dev/null +++ b/Il2CppInspector.Common/Next/PrimitivePointer.cs @@ -0,0 +1,60 @@ +using System.Collections.Immutable; +using VersionedSerialization; +using VersionedSerialization.Attributes; + +namespace Il2CppInspector.Next; + +public struct PrimitivePointer(ulong value = 0) : IReadable, IEquatable> where T : unmanaged +{ + [NativeInteger] + private ulong _value = value; + + public readonly ulong PointerValue => _value; + public readonly bool Null => _value == 0; + + public void Read(ref TReader reader, in StructVersion version = default) where TReader : IReader, allows ref struct + { + _value = reader.ReadNUInt(); + } + + public static int Size(in StructVersion version = default, bool is32Bit = false) + { + return is32Bit ? 4 : 8; + } + + public readonly T Read(ref SpanReader reader) + { + reader.Offset = (int)PointerValue; + return reader.ReadPrimitive(); + } + + public readonly ImmutableArray ReadArray(ref SpanReader reader, long count) + { + reader.Offset = (int)PointerValue; + return reader.ReadPrimitiveArray(count); + } + + public static implicit operator PrimitivePointer(ulong value) => new(value); + public static implicit operator ulong(PrimitivePointer ptr) => ptr.PointerValue; + + #region Equality operators + ToString + + public static bool operator ==(PrimitivePointer left, PrimitivePointer right) + => left._value == right._value; + + public static bool operator !=(PrimitivePointer left, PrimitivePointer right) + => !(left == right); + + public readonly override bool Equals(object? obj) + => obj is PrimitivePointer other && Equals(other); + + public readonly bool Equals(PrimitivePointer other) + => this == other; + + public readonly override int GetHashCode() + => HashCode.Combine(_value); + + public readonly override string ToString() => $"0x{_value:X} <{typeof(T).Name}>"; + + #endregion +} \ No newline at end of file diff --git a/Il2CppInspector.Common/Reflection/TypeModel.cs b/Il2CppInspector.Common/Reflection/TypeModel.cs index e052d32..2cdfd7f 100644 --- a/Il2CppInspector.Common/Reflection/TypeModel.cs +++ b/Il2CppInspector.Common/Reflection/TypeModel.cs @@ -87,7 +87,7 @@ namespace Il2CppInspector.Reflection public TypeModel(Il2CppInspector package) { Package = package; TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length]; - TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count]; + TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Length]; GenericParameterTypes = new TypeInfo[package.GenericParameters.Length]; MethodsByDefinitionIndex = new MethodBase[package.Methods.Length]; MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length]; @@ -99,7 +99,7 @@ namespace Il2CppInspector.Reflection // Create and reference types from TypeRefs // Note that you can't resolve any TypeRefs until all the TypeDefs have been processed - for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) { + for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Length; typeRefIndex++) { if(TypesByReferenceIndex[typeRefIndex] != null) { /* type already generated - probably by forward reference through GetTypeFromVirtualAddress */ continue; @@ -191,7 +191,7 @@ namespace Il2CppInspector.Reflection public TypeInfo[] ResolveGenericArguments(Il2CppGenericInst inst) { // Get list of pointers to type parameters (both unresolved and concrete) - var genericTypeArguments = Package.BinaryImage.ReadMappedArray(inst.TypeArgv, (int)inst.TypeArgc); + var genericTypeArguments = Package.BinaryImage.ReadMappedUWordArray(inst.TypeArgv, (int)inst.TypeArgc); return genericTypeArguments.Select(a => GetTypeFromVirtualAddress(a)).ToArray(); } @@ -212,7 +212,7 @@ namespace Il2CppInspector.Reflection // Constructed types case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: // TODO: Replace with array load from Il2CppMetadataRegistration.genericClasses - var generic = image.ReadMappedObject(typeRef.Data.GenericClass); // Il2CppGenericClass * + var generic = image.ReadMappedVersionedObject(typeRef.Data.GenericClass); // Il2CppGenericClass * // Get generic type definition TypeInfo genericTypeDef; @@ -230,13 +230,13 @@ namespace Il2CppInspector.Reflection // Get the instantiation // TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts - var genericInstance = image.ReadMappedObject(generic.Context.ClassInst); + var genericInstance = image.ReadMappedVersionedObject(generic.Context.ClassInst); var genericArguments = ResolveGenericArguments(genericInstance); underlyingType = genericTypeDef.MakeGenericType(genericArguments); break; case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: - var descriptor = image.ReadMappedObject(typeRef.Data.ArrayType); + var descriptor = image.ReadMappedVersionedObject(typeRef.Data.ArrayType); var elementType = GetTypeFromVirtualAddress(descriptor.ElementType); underlyingType = elementType.MakeArrayType(descriptor.Rank); break; diff --git a/Il2CppInspector.Common/Utils/BlobReader.cs b/Il2CppInspector.Common/Utils/BlobReader.cs index c031950..89e4940 100644 --- a/Il2CppInspector.Common/Utils/BlobReader.cs +++ b/Il2CppInspector.Common/Utils/BlobReader.cs @@ -1,8 +1,6 @@ using NoisyCowStudios.Bin2Object; using System.Text; -using System; using System.Diagnostics; -using System.IO; using Il2CppInspector.Next; using Il2CppInspector.Next.BinaryMetadata; using Il2CppInspector.Next.Metadata; @@ -11,7 +9,7 @@ namespace Il2CppInspector.Utils; public static class BlobReader { - public static object GetConstantValueFromBlob(Il2CppInspector inspector, Il2CppTypeEnum type, BinaryObjectStream blob) + public static object GetConstantValueFromBlob(Il2CppInspector inspector, Il2CppTypeEnum type, BinaryObjectStreamReader blob) { const byte kArrayTypeWithDifferentElements = 1; @@ -28,7 +26,7 @@ public static class BlobReader break; case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: // UTF-8 character assumed - value = BitConverter.ToChar(blob.ReadBytes(2), 0); + value = (char)blob.ReadPrimitive(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U2: value = blob.ReadUInt16(); @@ -162,7 +160,7 @@ public static class BlobReader if (typeEnum == Il2CppTypeEnum.IL2CPP_TYPE_ENUM) { var typeIndex = blob.ReadCompressedInt32(); - var typeHandle = (uint)inspector.TypeReferences[typeIndex].Data.KlassIndex; + var typeHandle = inspector.TypeReferences[typeIndex].Data.KlassIndex; enumType = inspector.TypeDefinitions[typeHandle]; var elementTypeHandle = inspector.TypeReferences[enumType.ElementTypeIndex].Data.KlassIndex; diff --git a/VersionedSerialization.Generator/Models/ObjectSerializationInfo.cs b/VersionedSerialization.Generator/Models/ObjectSerializationInfo.cs index bb2f002..c2f91e0 100644 --- a/VersionedSerialization.Generator/Models/ObjectSerializationInfo.cs +++ b/VersionedSerialization.Generator/Models/ObjectSerializationInfo.cs @@ -1,4 +1,5 @@ -using VersionedSerialization.Generator.Utils; +using Microsoft.CodeAnalysis.CSharp; +using VersionedSerialization.Generator.Utils; namespace VersionedSerialization.Generator.Models; @@ -6,8 +7,7 @@ public sealed record ObjectSerializationInfo( string Namespace, string Name, bool HasBaseType, - bool IsStruct, - bool ShouldGenerateSizeMethod, + SyntaxKind DefinitionType, bool CanGenerateSizeMethod, ImmutableEquatableArray Properties ); \ No newline at end of file diff --git a/VersionedSerialization.Generator/Models/PropertySerializationInfo.cs b/VersionedSerialization.Generator/Models/PropertySerializationInfo.cs index fb4a961..2c5eb40 100644 --- a/VersionedSerialization.Generator/Models/PropertySerializationInfo.cs +++ b/VersionedSerialization.Generator/Models/PropertySerializationInfo.cs @@ -6,6 +6,6 @@ public sealed record PropertySerializationInfo( string Name, string ReadMethod, string SizeExpression, - int Alignment, + PropertyType Type, ImmutableEquatableArray VersionConditions ); \ No newline at end of file diff --git a/VersionedSerialization.Generator/Models/PropertyType.cs b/VersionedSerialization.Generator/Models/PropertyType.cs index 3e855d0..d2a7f48 100644 --- a/VersionedSerialization.Generator/Models/PropertyType.cs +++ b/VersionedSerialization.Generator/Models/PropertyType.cs @@ -16,6 +16,9 @@ public enum PropertyType Int32, Int64, String, + Custom, + NativeInteger, + UNativeInteger, } public static class PropertyTypeExtensions @@ -35,6 +38,9 @@ public static class PropertyTypeExtensions PropertyType.Int32 => nameof(PropertyType.Int32), PropertyType.Int64 => nameof(PropertyType.Int64), PropertyType.String => nameof(String), + PropertyType.Custom => "", + PropertyType.NativeInteger => "NInt", + PropertyType.UNativeInteger => "NUInt", _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; @@ -43,6 +49,40 @@ public static class PropertyTypeExtensions { PropertyType.Boolean => true, PropertyType.String => true, + PropertyType.Custom => true, + PropertyType.NativeInteger => true, + PropertyType.UNativeInteger => true, + _ => false + }; + + public static int GetTypeSize(this PropertyType type) + => type switch + { + PropertyType.Unsupported => -1, + PropertyType.None => 0, + PropertyType.UInt8 => 1, + PropertyType.Int8 => 1, + PropertyType.Boolean => 1, + PropertyType.UInt16 => 2, + PropertyType.UInt32 => 4, + PropertyType.UInt64 => 8, + PropertyType.Int16 => 2, + PropertyType.Int32 => 4, + PropertyType.Int64 => 8, + PropertyType.String => -1, + PropertyType.Custom => -1, + PropertyType.NativeInteger => -1, + PropertyType.UNativeInteger => -1, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + }; + + public static bool IsUnsignedType(this PropertyType type) + => type switch + { + PropertyType.UInt8 + or PropertyType.UInt16 + or PropertyType.UInt32 + or PropertyType.UInt64 => true, _ => false }; } \ No newline at end of file diff --git a/VersionedSerialization.Generator/ObjectSerializationGenerator.cs b/VersionedSerialization.Generator/ObjectSerializationGenerator.cs index ca37280..2c3043a 100644 --- a/VersionedSerialization.Generator/ObjectSerializationGenerator.cs +++ b/VersionedSerialization.Generator/ObjectSerializationGenerator.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -20,7 +19,7 @@ namespace VersionedSerialization.Generator var valueProvider = context.SyntaxProvider .ForAttributeWithMetadataName(Constants.VersionedStructAttribute, - static (node, _) => node is ClassDeclarationSyntax or StructDeclarationSyntax, + static (node, _) => node is ClassDeclarationSyntax or StructDeclarationSyntax or RecordDeclarationSyntax, static (context, _) => (ContextClass: (TypeDeclarationSyntax)context.TargetNode, context.SemanticModel)) .Combine(context.CompilationProvider) .Select(static (tuple, cancellationToken) => ParseSerializationInfo(tuple.Left.ContextClass, tuple.Left.SemanticModel, tuple.Right, cancellationToken)) @@ -63,7 +62,16 @@ namespace VersionedSerialization.Generator generator.LeaveScope(); } - generator.EnterScope($"public partial {(info.IsStruct ? "struct" : "class")} {info.Name} : IReadable"); + var definitionType = info.DefinitionType switch + { + SyntaxKind.ClassDeclaration => "class", + SyntaxKind.StructDeclaration => "struct", + SyntaxKind.RecordDeclaration => "record", + SyntaxKind.RecordStructDeclaration => "record struct", + _ => throw new IndexOutOfRangeException() + }; + + generator.EnterScope($"public partial {definitionType} {info.Name} : IReadable"); GenerateReadMethod(generator, info); generator.AppendLine(); GenerateSizeMethod(generator, info); @@ -92,12 +100,7 @@ namespace VersionedSerialization.Generator GenerateVersionCondition(property.VersionConditions, generator); generator.EnterScope(); - generator.AppendLine($"size += {property.SizeExpression};"); - - if (property.Alignment != 0) - generator.AppendLine($"size += size % {property.Alignment} == 0 ? 0 : {property.Alignment} - (size % {property.Alignment});"); - generator.LeaveScope(); } @@ -121,10 +124,6 @@ namespace VersionedSerialization.Generator generator.EnterScope(); generator.AppendLine($"this.{property.Name} = {property.ReadMethod}"); - - if (property.Alignment != 0) - generator.AppendLine($"reader.Align({property.Alignment});"); - generator.LeaveScope(); } @@ -176,9 +175,10 @@ namespace VersionedSerialization.Generator { var classSymbol = model.GetDeclaredSymbol(contextClass, cancellationToken) ?? throw new InvalidOperationException(); - var alignedAttribute = compilation.GetTypeByMetadataName(Constants.AlignedAttribute); + //var versionedStructAttribute = compilation.GetTypeByMetadataName(Constants.VersionedStructAttribute); var versionConditionAttribute = compilation.GetTypeByMetadataName(Constants.VersionConditionAttribute); var customSerializationAttribute = compilation.GetTypeByMetadataName(Constants.CustomSerializationAttribute); + var nativeIntegerAttribute = compilation.GetTypeByMetadataName(Constants.NativeIntegerAttribute); var canGenerateSizeMethod = true; @@ -190,7 +190,6 @@ namespace VersionedSerialization.Generator || member is IPropertySymbol { SetMethod: null }) continue; - var alignment = 0; var versionConditions = new List(); ITypeSymbol type; @@ -207,41 +206,12 @@ namespace VersionedSerialization.Generator } var typeInfo = ParseType(type); - - canGenerateSizeMethod &= typeInfo.Type != PropertyType.String; - - string readMethod; - if (typeInfo.Type == PropertyType.None) - { - readMethod = $"reader.ReadVersionedObject<{typeInfo.ComplexTypeName}>(in version);"; - } - else - { - readMethod = typeInfo.Type.IsSeperateMethod() - ? $"reader.Read{typeInfo.Type.GetTypeName()}();" - : $"reader.ReadPrimitive<{typeInfo.Type.GetTypeName()}>();"; - - if (typeInfo.ComplexTypeName != "") - readMethod = $"({typeInfo.ComplexTypeName}){readMethod}"; - } - - string sizeExpression; - if (typeInfo.Type == PropertyType.None) - { - sizeExpression = $"{typeInfo.ComplexTypeName}.Size(in version, is32Bit)"; - } - else - { - sizeExpression = $"sizeof({typeInfo.Type.GetTypeName()})"; - } + string? readMethod = null; + string? sizeExpression = null; foreach (var attribute in member.GetAttributes()) { - if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, alignedAttribute)) - { - alignment = (int)attribute.ConstructorArguments[0].Value!; - } - else if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, versionConditionAttribute)) + if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, versionConditionAttribute)) { StructVersion? lessThan = null, moreThan = null, @@ -278,16 +248,54 @@ namespace VersionedSerialization.Generator } else if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, customSerializationAttribute)) { + typeInfo = (PropertyType.Custom, "", typeInfo.IsArray); readMethod = (string)attribute.ConstructorArguments[0].Value!; sizeExpression = (string)attribute.ConstructorArguments[1].Value!; } + else if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, nativeIntegerAttribute)) + { + typeInfo = (typeInfo.Type.IsUnsignedType() + ? PropertyType.UNativeInteger + : PropertyType.NativeInteger, + typeInfo.ComplexTypeName == "" + ? typeInfo.Type.GetTypeName() + : typeInfo.ComplexTypeName, + typeInfo.IsArray); + } } + canGenerateSizeMethod &= typeInfo.Type != PropertyType.String; + + if (readMethod == null) + { + if (typeInfo.Type == PropertyType.None) + { + readMethod = $"reader.ReadVersionedObject<{typeInfo.ComplexTypeName}>(in version);"; + } + else + { + readMethod = typeInfo.Type.IsSeperateMethod() + ? $"reader.Read{typeInfo.Type.GetTypeName()}();" + : $"reader.ReadPrimitive<{typeInfo.Type.GetTypeName()}>();"; + + if (typeInfo.ComplexTypeName != "") + readMethod = $"({typeInfo.ComplexTypeName}){readMethod}"; + } + } + + sizeExpression ??= typeInfo.Type switch + { + PropertyType.None => $"{typeInfo.ComplexTypeName}.Size(in version, is32Bit)", + PropertyType.NativeInteger or PropertyType.UNativeInteger => + "is32Bit ? sizeof(uint) : sizeof(ulong)", + _ => $"sizeof({typeInfo.Type.GetTypeName()})" + }; + properties.Add(new PropertySerializationInfo( member.Name, readMethod, sizeExpression, - alignment, + typeInfo.Type, versionConditions.ToImmutableEquatableArray() )); } @@ -307,8 +315,7 @@ namespace VersionedSerialization.Generator classSymbol.ContainingNamespace.ToDisplayString(), classSymbol.Name, hasBaseType, - contextClass.Kind() == SyntaxKind.StructDeclaration, - true, + contextClass.Kind(), canGenerateSizeMethod, properties.ToImmutableEquatableArray() ); diff --git a/VersionedSerialization.Generator/Utils/Constants.cs b/VersionedSerialization.Generator/Utils/Constants.cs index db705d0..065fd50 100644 --- a/VersionedSerialization.Generator/Utils/Constants.cs +++ b/VersionedSerialization.Generator/Utils/Constants.cs @@ -5,9 +5,9 @@ public static class Constants private const string AttributeNamespace = "VersionedSerialization.Attributes"; public const string VersionedStructAttribute = $"{AttributeNamespace}.{nameof(VersionedStructAttribute)}"; - public const string AlignedAttribute = $"{AttributeNamespace}.{nameof(AlignedAttribute)}"; public const string VersionConditionAttribute = $"{AttributeNamespace}.{nameof(VersionConditionAttribute)}"; public const string CustomSerializationAttribute = $"{AttributeNamespace}.{nameof(CustomSerializationAttribute)}"; + public const string NativeIntegerAttribute = $"{AttributeNamespace}.{nameof(NativeIntegerAttribute)}"; public const string LessThan = nameof(LessThan); public const string GreaterThan = nameof(GreaterThan); diff --git a/VersionedSerialization/Attributes/AlignedAttribute.cs b/VersionedSerialization/Attributes/AlignedAttribute.cs deleted file mode 100644 index bfb6c04..0000000 --- a/VersionedSerialization/Attributes/AlignedAttribute.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace VersionedSerialization.Attributes; - -#pragma warning disable CS9113 // Parameter is unread. -[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] -public class AlignedAttribute(int alignment) : Attribute; -#pragma warning restore CS9113 // Parameter is unread. diff --git a/VersionedSerialization/Attributes/NativeIntegerAttribute.cs b/VersionedSerialization/Attributes/NativeIntegerAttribute.cs new file mode 100644 index 0000000..ae90d98 --- /dev/null +++ b/VersionedSerialization/Attributes/NativeIntegerAttribute.cs @@ -0,0 +1,3 @@ +namespace VersionedSerialization.Attributes; + +public class NativeIntegerAttribute : Attribute; \ No newline at end of file diff --git a/VersionedSerialization/IReader.cs b/VersionedSerialization/IReader.cs index c216fc2..764eac6 100644 --- a/VersionedSerialization/IReader.cs +++ b/VersionedSerialization/IReader.cs @@ -18,5 +18,6 @@ public interface IReader T ReadVersionedObject(in StructVersion version = default) where T : IReadable, new(); ImmutableArray ReadVersionedObjectArray(long count, in StructVersion version = default) where T : IReadable, new(); - public void Align(int alignment = 0); + void Align(int alignment = 0); + void Skip(int count); } \ No newline at end of file diff --git a/VersionedSerialization/SpanReader.cs b/VersionedSerialization/SpanReader.cs index de26c03..6402cd4 100644 --- a/VersionedSerialization/SpanReader.cs +++ b/VersionedSerialization/SpanReader.cs @@ -143,4 +143,9 @@ public ref struct SpanReader(ReadOnlySpan data, int offset = 0, bool littl if (rem != 0) Offset += alignment - rem; } + + public void Skip(int count) + { + Offset += count; + } } \ No newline at end of file