private void ReadAssetsPreloadTable(EndianBinaryReader reader, int fileFormatVersion, uint dataOffset) { var assetCount = reader.ReadInt32(); var assetUniqueIDFormat = "D" + MathHelper.GetDigitCount(assetCount); var preloadDataList = new AssetPreloadData[assetCount]; for (var i = 0; i < assetCount; ++i) { if (fileFormatVersion >= 14) { reader.AlignBy(4); } var preloadData = new AssetPreloadData(this); preloadDataList[i] = preloadData; if (fileFormatVersion < 14) { preloadData.PathID = reader.ReadInt32(); } else { preloadData.PathID = reader.ReadInt64(); } var offset = reader.ReadUInt32(); offset += dataOffset; preloadData.Offset = offset; preloadData.Size = reader.ReadInt32(); int type1; int type2; if (fileFormatVersion > 15) { var index = reader.ReadInt32(); var t = _classIDs[index]; type1 = t.Type1; type2 = t.Type2; } else { type1 = reader.ReadInt32(); type2 = reader.ReadUInt16(); reader.Position += 2; } preloadData.Type1 = type1; preloadData.Type2 = type2; if (fileFormatVersion == 15) { var dummyByte = reader.ReadByte(); if (dummyByte == 0) { } } if (ClassIDReference.TryGetClassName(type2, out var typeName)) { preloadData.TypeName = typeName; } else { preloadData.TypeName = $"#{type2}"; } preloadData.UniqueID = i.ToString(assetUniqueIDFormat); if (fileFormatVersion == 6 && type2 == 141) { var nextAssetPosition = reader.Position; var buildSettings = new BuildSettings(reader, preloadData.Offset, fileFormatVersion, VersionComponents, BuildType); Version = buildSettings.Version; reader.Position = nextAssetPosition; } } PreloadDataList = preloadDataList; }
private void Initialize(EndianBinaryReader reader, string fileName) { var tableSize = reader.ReadInt32(); var dataEnd = reader.ReadInt32(); var fileFormatVersion = reader.ReadInt32(); var dataOffset = reader.ReadUInt32(); FileFormatVersion = fileFormatVersion; FullFileName = Path.GetFullPath(fileName); var baseDefinitions = false; var platform = 0; switch (fileFormatVersion) { case 6: reader.Position = dataEnd - tableSize; reader.Position += 1; break; case 7: reader.Position = dataEnd - tableSize; reader.Position += 1; Version = reader.ReadStringToNull(); break; case 8: reader.Position = dataEnd - tableSize; reader.Position += 1; Version = reader.ReadStringToNull(); platform = reader.ReadInt32(); break; case 9: reader.Position += 4; Version = reader.ReadStringToNull(); platform = reader.ReadInt32(); break; case 14: case 15: case 16: case 17: reader.Position += 4; Version = reader.ReadStringToNull(); platform = reader.ReadInt32(); baseDefinitions = reader.ReadBoolean(); break; default: throw new FormatException(); } if (platform > 255 || platform < 0) { platform = EndianHelper.SwapEndian(platform); reader.Endian = Endian.LittleEndian; } Platform = (AssetPlatform)platform; ReadClasses(reader, fileFormatVersion, baseDefinitions); if (7 <= fileFormatVersion && fileFormatVersion < 14) { reader.Position += 4; } ReadAssetsPreloadTable(reader, fileFormatVersion, dataOffset); // May be buggy... // The original author assumes these two properties are not used in Unity 2.5.x (in BuildSettings class). VersionComponents = VersionSplitter .Split(Version) .Select(str => Convert.ToInt32(str)) .ToArray(); BuildType = BuildTypePattern.Match(Version).Groups["build"].Value; // 2017.x version handling is solved by better pattern splitting, so we skipped here. if (fileFormatVersion >= 14) { var someCount = reader.ReadInt32(); for (var i = 0; i < someCount; ++i) { var dummy1 = reader.ReadInt32(); reader.AlignBy(4); var pathID = reader.ReadInt64(); } } var sharedFileCount = reader.ReadInt32(); var sharedFileList = new SharedAssetInfo[sharedFileCount]; for (var i = 0; i < sharedFileCount; ++i) { var shared = new SharedAssetInfo(); shared.SomeName = reader.ReadStringToNull(); reader.Position += 20; var sharedFileName = reader.ReadStringToNull(); shared.FileName = sharedFileName; sharedFileList[i] = shared; } SharedAssetList = sharedFileList; }
private static IReadOnlyDictionary <string, object> Read(EndianBinaryReader reader, IReadOnlyList <ClassMember> classMembers, int startIndex, int baseLevel, bool fastReturn) { var dict = new Dictionary <string, object>(); for (var i = startIndex; i < classMembers.Count; ++i) { var member = classMembers[i]; var level = member.Level; if (level <= baseLevel && fastReturn) { return(dict); } var varName = member.Name; var varType = member.TypeName; var shouldAlign = (member.Flags & 0x4000) != 0; object value; IReadOnlyList <ClassMember> subList; switch (varType) { case "SInt8": value = reader.ReadSByte(); break; case "UInt8": value = reader.ReadByte(); break; case "SInt16": case "short": value = reader.ReadInt16(); break; case "UInt16": case "unsigned short": value = reader.ReadUInt16(); break; case "SInt32": case "int": value = reader.ReadInt32(); break; case "UInt32": case "unsigned int": value = reader.ReadUInt32(); break; case "SInt64": case "long long": value = reader.ReadInt64(); break; case "UInt64": case "unsigned long long": value = reader.ReadUInt64(); break; case "float": value = reader.ReadSingle(); break; case "double": value = reader.ReadDouble(); break; case "bool": value = reader.ReadBoolean(); break; case "string": var strLen = reader.ReadInt32(); value = reader.ReadAlignedString(strLen); i += 3; break; case "Array": if (i > 0 && (classMembers[i - 1].Flags & 0x4000) != 0) { shouldAlign = true; } var size = reader.ReadInt32(); subList = ReadSubObjectList(classMembers, level, i + 2); var list = new List <object>(); for (var j = 0; j < size; ++j) { var d2 = Read(reader, subList); list.Add(d2); } // '1' for "size" field. i += 1 + subList.Count; value = list; break; default: var customType = new CustomType { TypeName = varType, Name = varName, Level = level }; subList = ReadSubObjectList(classMembers, level, i + 1); var objects = Read(reader, subList); customType.Variables = objects; value = customType; i += subList.Count; shouldAlign = false; break; } dict[varName] = value; if (shouldAlign) { reader.AlignBy(4); } } return(dict); }