Skip to content

Commit 94e58b8

Browse files
Read objectlist out of metadata section
1 parent 6eb0ab5 commit 94e58b8

4 files changed

Lines changed: 89 additions & 11 deletions

File tree

Analyzer.Tests/FileDetectionTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,44 @@ public void TryParseMetadata_V23ExtractedMonoscriptBundle_ReturnsExpectedTypeTre
410410
}
411411
}
412412

413+
[Test]
414+
public void TryParseMetadata_V22PrefabWithSerializedReference_ReturnsExpectedObjectList()
415+
{
416+
var testFile = Path.Combine(m_TestDataPath, "AssetBundleTypeTreeVariations", "v22",
417+
"prefab_with_serializedreference.serializedfile");
418+
419+
bool headerResult = SerializedFileDetector.TryDetectSerializedFile(testFile, out var headerInfo);
420+
Assert.IsTrue(headerResult, "File should be detected as a valid SerializedFile");
421+
422+
bool result = SerializedFileDetector.TryParseMetadata(testFile, headerInfo, out var metadata, out var errorMessage);
423+
Assert.IsTrue(result, $"Metadata parsing should succeed. Error: {errorMessage}");
424+
Assert.IsNotNull(metadata);
425+
426+
Assert.IsNotNull(metadata.ObjectList, "ObjectList should be populated");
427+
Assert.That(metadata.ObjectList.Length, Is.EqualTo(6), "Should have 6 objects");
428+
429+
// Verify exact values for each object entry.
430+
// Expected data from the file's object table (fileID, typeID, offset, size):
431+
var expected = new (long Id, int TypeId, long Offset, long Size)[]
432+
{
433+
( 1L, 142, 5552L, 300L), // AssetBundle
434+
( 674343093664966924L, 4, 5856L, 68L), // Transform
435+
(4902368549205534988L, 4, 5936L, 80L), // Transform
436+
(5206304541755795724L, 1, 6016L, 51L), // GameObject
437+
(6854740422901983500L, 1, 6080L, 35L), // GameObject
438+
(8430482813342345484L, 114, 6128L, 104L), // MonoBehaviour
439+
};
440+
441+
for (int i = 0; i < expected.Length; i++)
442+
{
443+
var obj = metadata.ObjectList[i];
444+
Assert.That(obj.Id, Is.EqualTo(expected[i].Id), $"ObjectList[{i}].Id");
445+
Assert.That(obj.TypeId, Is.EqualTo(expected[i].TypeId), $"ObjectList[{i}].TypeId");
446+
Assert.That(obj.Offset, Is.EqualTo(expected[i].Offset), $"ObjectList[{i}].Offset");
447+
Assert.That(obj.Size, Is.EqualTo(expected[i].Size), $"ObjectList[{i}].Size");
448+
}
449+
}
450+
413451
#endregion
414452

415453
#region YAML SerializedFile Detection Tests

Analyzer/Util/BinaryFileHelper.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ public static uint ReadUInt32(BinaryReader reader, bool swap)
6767
return swap ? SwapUInt32(raw) : raw;
6868
}
6969

70+
public static ulong ReadUInt64(BinaryReader reader, bool swap)
71+
{
72+
ulong raw = reader.ReadUInt64();
73+
return swap ? SwapUInt64(raw) : raw;
74+
}
75+
76+
public static long ReadInt64(BinaryReader reader, bool swap)
77+
{
78+
ulong raw = reader.ReadUInt64();
79+
return (long)(swap ? SwapUInt64(raw) : raw);
80+
}
81+
7082
public static UnityHash128 ReadHash128(BinaryReader reader, bool swap)
7183
{
7284
return new UnityHash128

Analyzer/Util/SerializedFileDetector.cs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using ObjectInfo = UnityDataTools.FileSystem.ObjectInfo;
34

45
namespace UnityDataTools.Analyzer.Util;
56

@@ -166,6 +167,12 @@ public class SerializedFileMetadata
166167
/// Empty array for files with version < 20.
167168
/// </summary>
168169
public TypeTreeInfo[] SerializedReferenceTypeTrees { get; set; }
170+
171+
/// <summary>
172+
/// List of all objects recorded in the file's object table.
173+
/// Null until the metadata section has been parsed.
174+
/// </summary>
175+
public ObjectInfo[] ObjectList { get; set; }
169176
}
170177

171178
/// <summary>
@@ -567,28 +574,41 @@ private static void ParseExtendedMetadata(BinaryReader reader, SerializedFileInf
567574
typeTrees[i] = ReadTypeEntry(reader, version, swap, isRefType: false, enableTypeTree);
568575
metadata.TypeTrees = typeTrees;
569576

570-
// m_RefTypes (version >= 20) is not located immediately after m_Types.
571-
// It appears at the end of the metadata section, after the object list,
572-
// script type list, and externals list. We must skip those three sections.
573-
if (version < SupportsRefObjectVersion)
574-
return;
575-
576-
// --- Skip the object list ---
577+
// --- Object list ---
577578
// Per-object layout (version >= 19):
578579
// [4-byte alignment relative to metadata start]
579580
// [int64 fileID]
580581
// [uint32 byteStart] or [uint64 byteStart] (version >= 22)
581582
// [uint32 byteSize]
582583
// [uint32 typeID]
583584
int objectCount = BinaryFileHelper.ReadInt32(reader, swap);
585+
var objectList = new ObjectInfo[objectCount];
584586
for (int i = 0; i < objectCount; i++)
585587
{
586588
BinaryFileHelper.AlignTo4(stream, metadataOffset);
587-
stream.Seek(8, SeekOrigin.Current); // int64 fileID
588-
stream.Seek(version >= LargeFilesSupportVersion ? 8 : 4, SeekOrigin.Current); // byteStart
589-
stream.Seek(4, SeekOrigin.Current); // uint32 byteSize
590-
stream.Seek(4, SeekOrigin.Current); // uint32 typeID
589+
long fileID = BinaryFileHelper.ReadInt64(reader, swap);
590+
// byteStart is relative to the data section; add DataOffset to get the absolute file offset,
591+
// matching the behaviour of the native DLL which returns the absolute offset in ObjectInfo.Offset.
592+
long byteStart = version >= LargeFilesSupportVersion
593+
? (long)BinaryFileHelper.ReadUInt64(reader, swap)
594+
: BinaryFileHelper.ReadUInt32(reader, swap);
595+
byteStart += (long)headerInfo.DataOffset;
596+
long byteSize = BinaryFileHelper.ReadUInt32(reader, swap);
597+
// typeIndex is a 0-based index into the m_Types array, not the persistent type ID.
598+
// Resolve it to the persistent type ID to match the behaviour of the native DLL.
599+
int typeIndex = BinaryFileHelper.ReadInt32(reader, swap);
600+
int persistentTypeID = (typeIndex >= 0 && typeIndex < typeTrees.Length)
601+
? typeTrees[typeIndex].PersistentTypeID
602+
: typeIndex;
603+
objectList[i] = new ObjectInfo(fileID, byteStart, byteSize, persistentTypeID);
591604
}
605+
metadata.ObjectList = objectList;
606+
607+
// m_RefTypes (version >= 20) is not located immediately after m_Types.
608+
// It appears at the end of the metadata section, after the object list,
609+
// script type list, and externals list. We must skip those three sections.
610+
if (version < SupportsRefObjectVersion)
611+
return;
592612

593613
// --- Skip the script type list ---
594614
// Per-entry layout (version >= 14, applies to all our versions):

UnityFileSystem/DllWrapper.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ public struct ObjectInfo
119119
public readonly long Offset;
120120
public readonly long Size;
121121
public readonly int TypeId;
122+
123+
public ObjectInfo(long id, long offset, long size, int typeId)
124+
{
125+
Id = id;
126+
Offset = offset;
127+
Size = size;
128+
TypeId = typeId;
129+
}
122130
}
123131
[Flags]
124132
public enum TypeTreeFlags

0 commit comments

Comments
 (0)