• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 12284614548

11 Dec 2024 08:46PM UTC coverage: 28.154% (-0.02%) from 28.172%
12284614548

Pull #390

github

web-flow
Merge 158ed402d into edbb9949b
Pull Request #390: Set AssemblyDefinition::PublicKey when generating AsmResolver assemblies

1266 of 6242 branches covered (20.28%)

Branch coverage included in aggregate %.

6 of 14 new or added lines in 4 files covered. (42.86%)

4 existing lines in 2 files now uncovered.

3385 of 10278 relevant lines covered (32.93%)

124847.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.6
/LibCpp2IL/Metadata/Il2CppMetadata.cs
1
using System;
2
using System.Collections.Concurrent;
3
using System.Collections.Generic;
4
using System.IO;
5
using System.Linq;
6
using System.Reflection;
7
using System.Text;
8
using AssetRipper.Primitives;
9
using LibCpp2IL.BinaryStructures;
10
using LibCpp2IL.Logging;
11

12
namespace LibCpp2IL.Metadata;
13

14
public class Il2CppMetadata : ClassReadingBinaryReader
15
{
16
    //Disable null check as this stuff is reflected.
17
#pragma warning disable 8618
18
    public Il2CppGlobalMetadataHeader metadataHeader;
19
    public Il2CppAssemblyDefinition[] AssemblyDefinitions;
20
    public Il2CppImageDefinition[] imageDefinitions;
21
    public Il2CppTypeDefinition[] typeDefs;
22
    internal Il2CppInterfaceOffset[] interfaceOffsets;
23
    public uint[] VTableMethodIndices;
24
    public Il2CppMethodDefinition[] methodDefs;
25
    public Il2CppParameterDefinition[] parameterDefs;
26
    public Il2CppFieldDefinition[] fieldDefs;
27
    private Il2CppFieldDefaultValue[] fieldDefaultValues;
28
    private Il2CppParameterDefaultValue[] parameterDefaultValues;
29
    public Il2CppPropertyDefinition[] propertyDefs;
30
    public List<Il2CppCustomAttributeTypeRange> attributeTypeRanges;
31
    private Il2CppStringLiteral[] stringLiterals;
32
    public Il2CppMetadataUsageList[] metadataUsageLists;
33
    private Il2CppMetadataUsagePair[] metadataUsagePairs;
34
    public Il2CppRGCTXDefinition[] RgctxDefinitions; //Moved to binary in v24.2
35

36
    //Pre-29
37
    public int[] attributeTypes;
38
    public int[] interfaceIndices;
39

40
    //Post-29
41
    public List<Il2CppCustomAttributeDataRange> AttributeDataRanges;
42

43
    //Moved to binary in v27.
44
    public Dictionary<uint, SortedDictionary<uint, uint>>? metadataUsageDic;
45

46
    public int[] nestedTypeIndices;
47
    public Il2CppEventDefinition[] eventDefs;
48
    public Il2CppGenericContainer[] genericContainers;
49
    public Il2CppFieldRef[] fieldRefs;
50
    public Il2CppGenericParameter[] genericParameters;
51
    public int[] constraintIndices;
52

53
    public int[] referencedAssemblies;
54

55
    private readonly Dictionary<int, Il2CppFieldDefaultValue> _fieldDefaultValueLookup = new Dictionary<int, Il2CppFieldDefaultValue>();
21✔
56
    private readonly Dictionary<Il2CppFieldDefinition, Il2CppFieldDefaultValue> _fieldDefaultLookupNew = new Dictionary<Il2CppFieldDefinition, Il2CppFieldDefaultValue>();
21✔
57

58
    public static bool HasMetadataHeader(byte[] bytes) => bytes.Length >= 4 && BitConverter.ToUInt32(bytes, 0) == 0xFAB11BAF;
21!
59

60
    public static Il2CppMetadata? ReadFrom(byte[] bytes, UnityVersion unityVersion)
61
    {
62
        if (!HasMetadataHeader(bytes))
21!
63
        {
64
            //Magic number is wrong
65
            throw new FormatException("Invalid or corrupt metadata (magic number check failed)");
×
66
        }
67

68
        var version = BitConverter.ToInt32(bytes, 4);
21✔
69
        if (version is < 23 or > 31)
21!
70
        {
71
            throw new FormatException("Unsupported metadata version found! We support 23-31, got " + version);
×
72
        }
73

74
        LibLogger.VerboseNewline($"\tIL2CPP Metadata Declares its version as {version}");
21✔
75

76
        float actualVersion;
77
        if (version == 24)
21✔
78
        {
79
            if (unityVersion.GreaterThanOrEquals(2020, 1, 11))
13!
80
                actualVersion = 24.4f; //2020.1.11-17 were released prior to 2019.4.21, so are still on 24.4
×
81
            else if (unityVersion.GreaterThanOrEquals(2020))
13!
82
                actualVersion = 24.3f; //2020.1.0-10 were released prior to to 2019.4.15, so are still on 24.3
×
83
            else if (unityVersion.GreaterThanOrEquals(2019, 4, 21))
13✔
84
                actualVersion = 24.5f; //2019.4.21 introduces v24.5
10✔
85
            else if (unityVersion.GreaterThanOrEquals(2019, 4, 15))
3✔
86
                actualVersion = 24.4f; //2019.4.15 introduces v24.4
1✔
87
            else if (unityVersion.GreaterThanOrEquals(2019, 3, 7))
2✔
88
                actualVersion = 24.3f; //2019.3.7 introduces v24.3
1✔
89
            else if (unityVersion.GreaterThanOrEquals(2019))
1!
90
                actualVersion = 24.2f; //2019.1.0 introduces v24.2
×
91
            else if (unityVersion.GreaterThanOrEquals(2018, 4, 34))
1!
92
                actualVersion = 24.15f; //2018.4.34 made a tiny little change which just removes HashValueIndex from AssemblyNameDefinition
×
93
            else if (unityVersion.GreaterThanOrEquals(2018, 3))
1!
94
                actualVersion = 24.1f; //2018.3.0 introduces v24.1
1✔
95
            else
96
                actualVersion = version; //2017.1.0 was the first v24 version
×
97
        }
98
        else if (version == 27)
8✔
99
        {
100
            if (unityVersion.GreaterThanOrEquals(2021, 1))
2!
101
                actualVersion = 27.2f; //2021.1 and up is v27.2, which just changes Il2CppType to have one new bit
×
102
            else if (unityVersion.GreaterThanOrEquals(2020, 2, 4))
2!
103
                actualVersion = 27.1f; //2020.2.4 and above is v27.1
2✔
104
            else
105
                actualVersion = version; //2020.2 and above is v27
×
106
        }
107
        else if (version == 29)
6!
108
        {
109
            if (unityVersion.GreaterThanOrEquals(2022, 1, 0, UnityVersionType.Beta, 7))
×
110
                actualVersion = 29.1f; //2022.1.0b7 introduces v29.1 which adds two new pointers to codereg
×
111
            else
112
                actualVersion = 29; //2021.3.0 introduces v29
×
113
        }
114
        else if (version == 31)
6!
115
        {
116
            //2022.3.33 introduces v31. Unity why would you bump this on a minor version.
117
            //Adds one new field (return type token) to method def
118
            actualVersion = 31;
6✔
119
        }
120
        else actualVersion = version;
×
121

122
        LibLogger.InfoNewline($"\tUsing actual IL2CPP Metadata version {actualVersion}");
21✔
123

124
        LibCpp2IlMain.MetadataVersion = actualVersion;
21✔
125

126
        return new Il2CppMetadata(new MemoryStream(bytes));
21✔
127
    }
128

129
    private Il2CppMetadata(MemoryStream stream) : base(stream)
21✔
130
    {
131
        metadataHeader = ReadReadable<Il2CppGlobalMetadataHeader>();
21✔
132
        if (metadataHeader.magicNumber != 0xFAB11BAF)
21!
133
        {
134
            throw new Exception("ERROR: Magic number mismatch. Expecting " + 0xFAB11BAF + " but got " + metadataHeader.magicNumber);
×
135
        }
136

137
        LibLogger.Verbose("\tReading image definitions...");
21✔
138
        var start = DateTime.Now;
21✔
139
        imageDefinitions = ReadMetadataClassArray<Il2CppImageDefinition>(metadataHeader.imagesOffset, metadataHeader.imagesCount);
21✔
140
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
141

142
        LibLogger.Verbose("\tReading assembly definitions...");
21✔
143
        start = DateTime.Now;
21✔
144
        AssemblyDefinitions = ReadMetadataClassArray<Il2CppAssemblyDefinition>(metadataHeader.assembliesOffset, metadataHeader.assembliesCount);
21✔
145
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
146

147
        LibLogger.Verbose("\tReading type definitions...");
21✔
148
        start = DateTime.Now;
21✔
149
        typeDefs = ReadMetadataClassArray<Il2CppTypeDefinition>(metadataHeader.typeDefinitionsOffset, metadataHeader.typeDefinitionsCount);
21✔
150
        LibLogger.VerboseNewline($"{typeDefs.Length} OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
151

152
        LibLogger.Verbose("\tReading interface offsets...");
21✔
153
        start = DateTime.Now;
21✔
154
        interfaceOffsets = ReadMetadataClassArray<Il2CppInterfaceOffset>(metadataHeader.interfaceOffsetsOffset, metadataHeader.interfaceOffsetsCount);
21✔
155
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
156

157
        LibLogger.Verbose("\tReading vtable indices...");
21✔
158
        start = DateTime.Now;
21✔
159
        VTableMethodIndices = ReadClassArrayAtRawAddr<uint>(metadataHeader.vtableMethodsOffset, metadataHeader.vtableMethodsCount / sizeof(uint));
21✔
160
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
161

162
        LibLogger.Verbose("\tReading method definitions...");
21✔
163
        start = DateTime.Now;
21✔
164
        methodDefs = ReadMetadataClassArray<Il2CppMethodDefinition>(metadataHeader.methodsOffset, metadataHeader.methodsCount);
21✔
165
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
166

167
        LibLogger.Verbose("\tReading method parameter definitions...");
21✔
168
        start = DateTime.Now;
21✔
169
        parameterDefs = ReadMetadataClassArray<Il2CppParameterDefinition>(metadataHeader.parametersOffset, metadataHeader.parametersCount);
21✔
170
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
171

172
        LibLogger.Verbose("\tReading field definitions...");
21✔
173
        start = DateTime.Now;
21✔
174
        fieldDefs = ReadMetadataClassArray<Il2CppFieldDefinition>(metadataHeader.fieldsOffset, metadataHeader.fieldsCount);
21✔
175
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
176

177
        LibLogger.Verbose("\tReading default field values...");
21✔
178
        start = DateTime.Now;
21✔
179
        fieldDefaultValues = ReadMetadataClassArray<Il2CppFieldDefaultValue>(metadataHeader.fieldDefaultValuesOffset, metadataHeader.fieldDefaultValuesCount);
21✔
180
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
181

182
        LibLogger.Verbose("\tReading default parameter values...");
21✔
183
        start = DateTime.Now;
21✔
184
        parameterDefaultValues = ReadMetadataClassArray<Il2CppParameterDefaultValue>(metadataHeader.parameterDefaultValuesOffset, metadataHeader.parameterDefaultValuesCount);
21✔
185
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
186

187
        LibLogger.Verbose("\tReading property definitions...");
21✔
188
        start = DateTime.Now;
21✔
189
        propertyDefs = ReadMetadataClassArray<Il2CppPropertyDefinition>(metadataHeader.propertiesOffset, metadataHeader.propertiesCount);
21✔
190
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
191

192
        LibLogger.Verbose("\tReading interface definitions...");
21✔
193
        start = DateTime.Now;
21✔
194
        interfaceIndices = ReadClassArrayAtRawAddr<int>(metadataHeader.interfacesOffset, metadataHeader.interfacesCount / 4);
21✔
195
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
196

197
        LibLogger.Verbose("\tReading nested type definitions...");
21✔
198
        start = DateTime.Now;
21✔
199
        nestedTypeIndices = ReadClassArrayAtRawAddr<int>(metadataHeader.nestedTypesOffset, metadataHeader.nestedTypesCount / 4);
21✔
200
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
201

202
        LibLogger.Verbose("\tReading event definitions...");
21✔
203
        start = DateTime.Now;
21✔
204
        eventDefs = ReadMetadataClassArray<Il2CppEventDefinition>(metadataHeader.eventsOffset, metadataHeader.eventsCount);
21✔
205
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
206

207
        LibLogger.Verbose("\tReading generic container definitions...");
21✔
208
        start = DateTime.Now;
21✔
209
        genericContainers = ReadMetadataClassArray<Il2CppGenericContainer>(metadataHeader.genericContainersOffset, metadataHeader.genericContainersCount);
21✔
210
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
211

212
        LibLogger.Verbose("\tReading generic parameter definitions...");
21✔
213
        start = DateTime.Now;
21✔
214
        genericParameters = ReadMetadataClassArray<Il2CppGenericParameter>(metadataHeader.genericParametersOffset, metadataHeader.genericParametersCount);
21✔
215
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
216

217
        LibLogger.Verbose("\tReading generic parameter constraint indices...");
21✔
218
        start = DateTime.Now;
21✔
219
        constraintIndices = ReadClassArrayAtRawAddr<int>(metadataHeader.genericParameterConstraintsOffset, metadataHeader.genericParameterConstraintsCount / sizeof(int));
21✔
220
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
221

222
        LibLogger.Verbose("\tReading referenced assemblies...");
21✔
223
        start = DateTime.Now;
21✔
224
        referencedAssemblies = ReadClassArrayAtRawAddr<int>(metadataHeader.referencedAssembliesOffset, metadataHeader.referencedAssembliesCount / sizeof(int));
21✔
225
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
226

227
        //v17+ fields
228
        LibLogger.Verbose("\tReading string definitions...");
21✔
229
        start = DateTime.Now;
21✔
230
        stringLiterals = ReadMetadataClassArray<Il2CppStringLiteral>(metadataHeader.stringLiteralOffset, metadataHeader.stringLiteralCount);
21✔
231
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
232

233
        if (LibCpp2IlMain.MetadataVersion < 24.2f)
21✔
234
        {
235
            LibLogger.Verbose("\tReading RGCTX data...");
1✔
236
            start = DateTime.Now;
1✔
237

238
            RgctxDefinitions = ReadMetadataClassArray<Il2CppRGCTXDefinition>(metadataHeader.rgctxEntriesOffset, metadataHeader.rgctxEntriesCount);
1✔
239

240
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
1✔
241
        }
242

243
        //Removed in v27 (2020.2) and also 24.5 (2019.4.21)
244
        if (LibCpp2IlMain.MetadataVersion < 27f)
21✔
245
        {
246
            LibLogger.Verbose("\tReading usage data...");
13✔
247
            start = DateTime.Now;
13✔
248
            metadataUsageLists = ReadMetadataClassArray<Il2CppMetadataUsageList>(metadataHeader.metadataUsageListsOffset, metadataHeader.metadataUsageListsCount);
13✔
249
            metadataUsagePairs = ReadMetadataClassArray<Il2CppMetadataUsagePair>(metadataHeader.metadataUsagePairsOffset, metadataHeader.metadataUsagePairsCount);
13✔
250

251
            DecipherMetadataUsage();
13✔
252
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
13✔
253
        }
254

255
        LibLogger.Verbose("\tReading field references...");
21✔
256
        start = DateTime.Now;
21✔
257
        fieldRefs = ReadMetadataClassArray<Il2CppFieldRef>(metadataHeader.fieldRefsOffset, metadataHeader.fieldRefsCount);
21✔
258
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
259

260
        //v21+ fields
261

262
        if (LibCpp2IlMain.MetadataVersion < 29)
21✔
263
        {
264
            //Removed in v29
265
            LibLogger.Verbose("\tReading attribute types...");
15✔
266
            start = DateTime.Now;
15✔
267
            attributeTypeRanges = ReadMetadataClassArray<Il2CppCustomAttributeTypeRange>(metadataHeader.attributesInfoOffset, metadataHeader.attributesInfoCount).ToList();
15✔
268
            attributeTypes = ReadClassArrayAtRawAddr<int>(metadataHeader.attributeTypesOffset, metadataHeader.attributeTypesCount / 4);
15✔
269
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
15✔
270
        }
271
        else
272
        {
273
            //Since v29
274
            LibLogger.Verbose("\tReading Attribute data...");
6✔
275
            start = DateTime.Now;
6✔
276

277
            //Pointer array
278
            AttributeDataRanges = ReadReadableArrayAtRawAddr<Il2CppCustomAttributeDataRange>(metadataHeader.attributeDataRangeOffset, metadataHeader.attributeDataRangeCount / 8).ToList();
6✔
279
            LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
6✔
280
        }
281

282
        LibLogger.Verbose("\tBuilding Lookup Table for field defaults...");
21✔
283
        start = DateTime.Now;
21✔
284
        foreach (var il2CppFieldDefaultValue in fieldDefaultValues)
299,528✔
285
        {
286
            _fieldDefaultValueLookup[il2CppFieldDefaultValue.fieldIndex] = il2CppFieldDefaultValue;
149,743✔
287
            _fieldDefaultLookupNew[fieldDefs[il2CppFieldDefaultValue.fieldIndex]] = il2CppFieldDefaultValue;
149,743✔
288
        }
289

290
        LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
21✔
291
        _hasFinishedInitialRead = true;
21✔
292
    }
21✔
293
#pragma warning restore 8618
294

295
    private T[] ReadMetadataClassArray<T>(int offset, int length) where T : ReadableClass, new()
296
    {
297
        //First things first, we're going to be moving the position around a lot, so we need to lock. 
298
        GetLockOrThrow();
357✔
299

300
        Position = offset;
357✔
301

302
        try
303
        {
304
            //Length is in bytes, not in elements, so we need to work out the element size to know how big of an array to allocate.
305
            //We do this by reading the first element, then count how many bytes we read.
306
            var first = ReadReadableHereNoLock<T>();
357✔
307

308
            //How many bytes did we read?
309
            var elementSize = (int)(Position - offset);
357✔
310

311
            //For build report purposes, we track that many bytes. FillReadableArrayHereNoLock will add the rest.
312
            TrackRead<T>(elementSize);
357✔
313

314
            //Now we can work out how many elements there are.
315
            var numElements = length / elementSize;
357✔
316

317
            if (numElements == 0) {
357!
318
                return [];
×
319
            }
320

321
            //And so we can allocate an array of that length, and assign the first element.
322
            var arr = new T[numElements];
357✔
323
            arr[0] = first;
357✔
324

325
            //And finally, read the rest of the elements, starting at index 1.
326
            FillReadableArrayHereNoLock(arr, 1);
357✔
327

328
            return arr;
357✔
329
        }
330
        finally
331
        {
332
            ReleaseLock();
357✔
333
        }
357✔
334
    }
357✔
335

336
    private void DecipherMetadataUsage()
337
    {
338
        metadataUsageDic = new();
13✔
339
        for (var i = 1u; i <= 6u; i++)
182✔
340
        {
341
            metadataUsageDic[i] = new();
78✔
342
        }
343

344
        foreach (var metadataUsageList in metadataUsageLists)
684,372✔
345
        {
346
            for (var i = 0; i < metadataUsageList.count; i++)
3,248,060✔
347
            {
348
                var offset = metadataUsageList.start + i;
1,281,857✔
349
                var metadataUsagePair = metadataUsagePairs[offset];
1,281,857✔
350
                var usage = GetEncodedIndexType(metadataUsagePair.encodedSourceIndex);
1,281,857✔
351
                var decodedIndex = GetDecodedMethodIndex(metadataUsagePair.encodedSourceIndex);
1,281,857✔
352
                metadataUsageDic[usage][metadataUsagePair.destinationIndex] = decodedIndex;
1,281,857✔
353
            }
354
        }
355
    }
13✔
356

357
    public uint GetMaxMetadataUsages()
358
    {
359
        if (metadataUsageDic == null)
21✔
360
            //V27+
361
            return 0;
8✔
362

363
        return metadataUsageDic.Max(x => x.Value.Max(y => y.Key)) + 1;
369,225✔
364
    }
365

366
    private uint GetEncodedIndexType(uint index)
367
    {
368
        return (index & 0xE0000000) >> 29;
1,281,857✔
369
    }
370

371
    private uint GetDecodedMethodIndex(uint index)
372
    {
373
        return index & 0x1FFFFFFFU;
1,281,857✔
374
    }
375

376
    //Getters for human readability
377
    public Il2CppFieldDefaultValue? GetFieldDefaultValueFromIndex(int index)
378
    {
379
        return _fieldDefaultValueLookup.GetOrDefault(index);
63,742✔
380
    }
381

382
    public Il2CppFieldDefaultValue? GetFieldDefaultValue(Il2CppFieldDefinition field)
383
    {
384
        return _fieldDefaultLookupNew.GetOrDefault(field);
×
385
    }
386

387
    public (int ptr, int type) GetFieldDefaultValue(int fieldIdx)
388
    {
389
        var fieldDef = fieldDefs[fieldIdx];
×
390
        var fieldType = LibCpp2IlMain.Binary!.GetType(fieldDef.typeIndex);
×
391
        if ((fieldType.Attrs & (int)FieldAttributes.HasFieldRVA) != 0)
×
392
        {
393
            var fieldDefault = GetFieldDefaultValueFromIndex(fieldIdx);
×
394

395
            if (fieldDefault == null)
×
396
                return (-1, -1);
×
397

398
            return (ptr: fieldDefault.dataIndex, type: fieldDefault.typeIndex);
×
399
        }
400

401
        return (-1, -1);
×
402
    }
403

404
    public Il2CppParameterDefaultValue? GetParameterDefaultValueFromIndex(int index)
405
    {
406
        return parameterDefaultValues.FirstOrDefault(x => x.parameterIndex == index);
53,702✔
407
    }
408

409
    public int GetDefaultValueFromIndex(int index)
410
    {
411
        return metadataHeader.fieldAndParameterDefaultValueDataOffset + index;
63,742✔
412
    }
413

414
    private ConcurrentDictionary<int, string> _cachedStrings = new ConcurrentDictionary<int, string>();
21✔
415

416
    public string GetStringFromIndex(int index)
417
    {
418
        GetLockOrThrow();
1,224,687✔
419
        try
420
        {
421
            return ReadStringFromIndexNoReadLock(index);
1,224,687✔
422
        }
423
        finally
424
        {
425
            ReleaseLock();
1,224,687✔
426
        }
1,224,687✔
427
    }
1,224,687✔
428

429
    /// <summary>
430
    /// Read a byte array from the string data section of the metadata.
431
    /// </summary>
432
    /// <param name="index">The offset relative to the start of the string section.</param>
433
    /// <returns>The </returns>
434
    public byte[] GetBytesFromIndex(int index)
435
    {
UNCOV
436
        var offset = metadataHeader.stringOffset + index;
×
UNCOV
437
        var count = ReadUnityCompressedUIntAtRawAddr(offset, out var bytesRead);
×
UNCOV
438
        return ReadByteArrayAtRawAddress(offset + bytesRead, (int)count);
×
439
    }
440

441
    internal string ReadStringFromIndexNoReadLock(int index)
442
    {
443
        if (!_cachedStrings.ContainsKey(index))
3,632,476✔
444
            _cachedStrings[index] = ReadStringToNullNoLock(metadataHeader.stringOffset + index);
832,074✔
445
        return _cachedStrings[index];
3,632,476✔
446
    }
447

448
    public Il2CppCustomAttributeTypeRange? GetCustomAttributeData(Il2CppImageDefinition imageDef, int customAttributeIndex, uint token, out int idx)
449
    {
450
        idx = -1;
548,870✔
451

452
        if (LibCpp2IlMain.MetadataVersion <= 24f)
548,870!
453
        {
454
            idx = customAttributeIndex;
×
455
            return attributeTypeRanges[customAttributeIndex];
×
456
        }
457

458
        var target = new Il2CppCustomAttributeTypeRange { token = token };
548,870✔
459

460
        if (imageDef.customAttributeStart < 0)
548,870!
461
            throw new("Image has customAttributeStart < 0");
×
462
        if (imageDef.customAttributeStart + imageDef.customAttributeCount > attributeTypeRanges.Count)
548,870!
463
            throw new($"Image has customAttributeStart + customAttributeCount > attributeTypeRanges.Count ({imageDef.customAttributeStart + imageDef.customAttributeCount} > {attributeTypeRanges.Count})");
×
464

465
        idx = attributeTypeRanges.BinarySearch(imageDef.customAttributeStart, (int)imageDef.customAttributeCount, target, new TokenComparer());
548,870✔
466

467
        return idx < 0 ? null : attributeTypeRanges[idx];
548,870✔
468
    }
469

470
    public string GetStringLiteralFromIndex(uint index)
471
    {
472
        var stringLiteral = stringLiterals[index];
×
473

474
        return Encoding.UTF8.GetString(ReadByteArrayAtRawAddress(metadataHeader.stringLiteralDataOffset + stringLiteral.dataIndex, (int)stringLiteral.length));
×
475
    }
476
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc