Improve SerializedFile reading.

This commit is contained in:
Perfare 2021-05-28 22:23:07 +08:00
parent caa45216ef
commit 432116d834
17 changed files with 218 additions and 159 deletions

View File

@ -135,10 +135,12 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResourceReader.cs" /> <Compile Include="ResourceReader.cs" />
<Compile Include="SerializedFile.cs" /> <Compile Include="SerializedFile.cs" />
<Compile Include="SerializedFileFormatVersion.cs" />
<Compile Include="SerializedFileHeader.cs" /> <Compile Include="SerializedFileHeader.cs" />
<Compile Include="SerializedType.cs" /> <Compile Include="SerializedType.cs" />
<Compile Include="SevenZipHelper.cs" /> <Compile Include="SevenZipHelper.cs" />
<Compile Include="StreamFile.cs" /> <Compile Include="StreamFile.cs" />
<Compile Include="TypeTree.cs" />
<Compile Include="TypeTreeHelper.cs" /> <Compile Include="TypeTreeHelper.cs" />
<Compile Include="TypeTreeNode.cs" /> <Compile Include="TypeTreeNode.cs" />
<Compile Include="WebFile.cs" /> <Compile Include="WebFile.cs" />

View File

@ -130,7 +130,7 @@ namespace AssetStudio
{ {
var assetsFile = new SerializedFile(this, fullName, reader); var assetsFile = new SerializedFile(this, fullName, reader);
assetsFile.originalPath = originalPath; assetsFile.originalPath = originalPath;
if (assetsFile.header.m_Version < 7) if (assetsFile.header.m_Version < SerializedFileFormatVersion.kUnknown_7)
{ {
assetsFile.SetVersion(unityVersion); assetsFile.SetVersion(unityVersion);
} }

View File

@ -1,7 +1,4 @@
using System.Collections.Generic; using System.Collections.Specialized;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
namespace AssetStudio namespace AssetStudio
{ {
@ -36,47 +33,38 @@ namespace AssetStudio
} }
} }
protected bool HasStructMember(string name)
{
return serializedType?.m_Nodes != null && serializedType.m_Nodes.Any(x => x.m_Name == name);
}
public string Dump() public string Dump()
{ {
if (serializedType?.m_Nodes != null) if (serializedType?.m_Type != null)
{ {
var sb = new StringBuilder(); return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader);
TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, reader);
return sb.ToString();
} }
return null; return null;
} }
public string Dump(List<TypeTreeNode> m_Nodes) public string Dump(TypeTree m_Type)
{ {
if (m_Nodes != null) if (m_Type != null)
{ {
var sb = new StringBuilder(); return TypeTreeHelper.ReadTypeString(m_Type, reader);
TypeTreeHelper.ReadTypeString(sb, m_Nodes, reader);
return sb.ToString();
} }
return null; return null;
} }
public OrderedDictionary ToType() public OrderedDictionary ToType()
{ {
if (serializedType?.m_Nodes != null) if (serializedType?.m_Type != null)
{ {
return TypeTreeHelper.ReadType(serializedType.m_Nodes, reader); return TypeTreeHelper.ReadType(serializedType.m_Type, reader);
} }
return null; return null;
} }
public OrderedDictionary ToType(List<TypeTreeNode> m_Nodes) public OrderedDictionary ToType(TypeTree m_Type)
{ {
if (m_Nodes != null) if (m_Type != null)
{ {
return TypeTreeHelper.ReadType(m_Nodes, reader); return TypeTreeHelper.ReadType(m_Type, reader);
} }
return null; return null;
} }

View File

@ -13,7 +13,7 @@ namespace AssetStudio
public PPtr(ObjectReader reader) public PPtr(ObjectReader reader)
{ {
m_FileID = reader.ReadInt32(); m_FileID = reader.ReadInt32();
m_PathID = reader.m_Version < 14 ? reader.ReadInt32() : reader.ReadInt64(); m_PathID = reader.m_Version < SerializedFileFormatVersion.kUnknown_14 ? reader.ReadInt32() : reader.ReadInt64();
assetsFile = reader.assetsFile; assetsFile = reader.assetsFile;
} }

View File

@ -11,6 +11,8 @@ namespace AssetStudio
public uint byteSize; public uint byteSize;
public int typeID; public int typeID;
public int classID; public int classID;
public ushort isDestroyed;
public byte stripped;
public long m_PathID; public long m_PathID;
public SerializedType serializedType; public SerializedType serializedType;

View File

@ -15,7 +15,7 @@ namespace AssetStudio
public ClassIDType type; public ClassIDType type;
public SerializedType serializedType; public SerializedType serializedType;
public BuildTarget platform; public BuildTarget platform;
public uint m_Version; public SerializedFileFormatVersion m_Version;
public int[] version => assetsFile.version; public int[] version => assetsFile.version;
public BuildType buildType => assetsFile.buildType; public BuildType buildType => assetsFile.buildType;

View File

@ -19,15 +19,17 @@ namespace AssetStudio
public Dictionary<long, Object> ObjectsDic; public Dictionary<long, Object> ObjectsDic;
public SerializedFileHeader header; public SerializedFileHeader header;
private EndianType m_FileEndianess; private byte m_FileEndianess;
public string unityVersion = "2.5.0f5"; public string unityVersion = "2.5.0f5";
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform; public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
private bool m_EnableTypeTree = true; private bool m_EnableTypeTree = true;
public List<SerializedType> m_Types; public List<SerializedType> m_Types;
public List<SerializedType> m_RefTypes; public int bigIDEnabled = 0;
public List<ObjectInfo> m_Objects; public List<ObjectInfo> m_Objects;
private List<LocalSerializedObjectIdentifier> m_ScriptTypes; private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
public List<FileIdentifier> m_Externals; public List<FileIdentifier> m_Externals;
public List<SerializedType> m_RefTypes;
public string userInformation;
public SerializedFile(AssetsManager assetsManager, string fullName, EndianBinaryReader reader) public SerializedFile(AssetsManager assetsManager, string fullName, EndianBinaryReader reader)
{ {
@ -36,26 +38,26 @@ namespace AssetStudio
this.fullName = fullName; this.fullName = fullName;
fileName = Path.GetFileName(fullName); fileName = Path.GetFileName(fullName);
//ReadHeader // ReadHeader
header = new SerializedFileHeader(); header = new SerializedFileHeader();
header.m_MetadataSize = reader.ReadUInt32(); header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadUInt32(); header.m_FileSize = reader.ReadUInt32();
header.m_Version = reader.ReadUInt32(); header.m_Version = (SerializedFileFormatVersion)reader.ReadUInt32();
header.m_DataOffset = reader.ReadUInt32(); header.m_DataOffset = reader.ReadUInt32();
if (header.m_Version >= 9) if (header.m_Version >= SerializedFileFormatVersion.kUnknown_9)
{ {
header.m_Endianess = reader.ReadByte(); header.m_Endianess = reader.ReadByte();
header.m_Reserved = reader.ReadBytes(3); header.m_Reserved = reader.ReadBytes(3);
m_FileEndianess = (EndianType)header.m_Endianess; m_FileEndianess = header.m_Endianess;
} }
else else
{ {
reader.Position = header.m_FileSize - header.m_MetadataSize; reader.Position = header.m_FileSize - header.m_MetadataSize;
m_FileEndianess = (EndianType)reader.ReadByte(); m_FileEndianess = reader.ReadByte();
} }
if (header.m_Version >= 22) if (header.m_Version >= SerializedFileFormatVersion.kLargeFilesSupport)
{ {
header.m_MetadataSize = reader.ReadUInt32(); header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadInt64(); header.m_FileSize = reader.ReadInt64();
@ -63,17 +65,17 @@ namespace AssetStudio
reader.ReadInt64(); // unknown reader.ReadInt64(); // unknown
} }
//ReadMetadata // ReadMetadata
if (m_FileEndianess == EndianType.LittleEndian) if (m_FileEndianess == 0)
{ {
reader.endian = EndianType.LittleEndian; reader.endian = EndianType.LittleEndian;
} }
if (header.m_Version >= 7) if (header.m_Version >= SerializedFileFormatVersion.kUnknown_7)
{ {
unityVersion = reader.ReadStringToNull(); unityVersion = reader.ReadStringToNull();
SetVersion(unityVersion); SetVersion(unityVersion);
} }
if (header.m_Version >= 8) if (header.m_Version >= SerializedFileFormatVersion.kUnknown_8)
{ {
m_TargetPlatform = (BuildTarget)reader.ReadInt32(); m_TargetPlatform = (BuildTarget)reader.ReadInt32();
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform)) if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
@ -81,26 +83,25 @@ namespace AssetStudio
m_TargetPlatform = BuildTarget.UnknownPlatform; m_TargetPlatform = BuildTarget.UnknownPlatform;
} }
} }
if (header.m_Version >= 13) if (header.m_Version >= SerializedFileFormatVersion.kHasTypeTreeHashes)
{ {
m_EnableTypeTree = reader.ReadBoolean(); m_EnableTypeTree = reader.ReadBoolean();
} }
//ReadTypes // Read Types
int typeCount = reader.ReadInt32(); int typeCount = reader.ReadInt32();
m_Types = new List<SerializedType>(typeCount); m_Types = new List<SerializedType>(typeCount);
for (int i = 0; i < typeCount; i++) for (int i = 0; i < typeCount; i++)
{ {
m_Types.Add(ReadSerializedType()); m_Types.Add(ReadSerializedType(false));
} }
var bigIDEnabled = 0; if (header.m_Version >= SerializedFileFormatVersion.kUnknown_7 && header.m_Version < SerializedFileFormatVersion.kUnknown_14)
if (header.m_Version >= 7 && header.m_Version < 14)
{ {
bigIDEnabled = reader.ReadInt32(); bigIDEnabled = reader.ReadInt32();
} }
//ReadObjects // Read Objects
int objectCount = reader.ReadInt32(); int objectCount = reader.ReadInt32();
m_Objects = new List<ObjectInfo>(objectCount); m_Objects = new List<ObjectInfo>(objectCount);
Objects = new List<Object>(objectCount); Objects = new List<Object>(objectCount);
@ -112,7 +113,7 @@ namespace AssetStudio
{ {
objectInfo.m_PathID = reader.ReadInt64(); objectInfo.m_PathID = reader.ReadInt64();
} }
else if (header.m_Version < 14) else if (header.m_Version < SerializedFileFormatVersion.kUnknown_14)
{ {
objectInfo.m_PathID = reader.ReadInt32(); objectInfo.m_PathID = reader.ReadInt32();
} }
@ -122,7 +123,7 @@ namespace AssetStudio
objectInfo.m_PathID = reader.ReadInt64(); objectInfo.m_PathID = reader.ReadInt64();
} }
if (header.m_Version >= 22) if (header.m_Version >= SerializedFileFormatVersion.kLargeFilesSupport)
objectInfo.byteStart = reader.ReadInt64(); objectInfo.byteStart = reader.ReadInt64();
else else
objectInfo.byteStart = reader.ReadUInt32(); objectInfo.byteStart = reader.ReadUInt32();
@ -130,7 +131,7 @@ namespace AssetStudio
objectInfo.byteStart += header.m_DataOffset; objectInfo.byteStart += header.m_DataOffset;
objectInfo.byteSize = reader.ReadUInt32(); objectInfo.byteSize = reader.ReadUInt32();
objectInfo.typeID = reader.ReadInt32(); objectInfo.typeID = reader.ReadInt32();
if (header.m_Version < 16) if (header.m_Version < SerializedFileFormatVersion.kRefactoredClassId)
{ {
objectInfo.classID = reader.ReadUInt16(); objectInfo.classID = reader.ReadUInt16();
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID); objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
@ -141,24 +142,24 @@ namespace AssetStudio
objectInfo.serializedType = type; objectInfo.serializedType = type;
objectInfo.classID = type.classID; objectInfo.classID = type.classID;
} }
if (header.m_Version < 11) if (header.m_Version < SerializedFileFormatVersion.kHasScriptTypeIndex)
{ {
var isDestroyed = reader.ReadUInt16(); objectInfo.isDestroyed = reader.ReadUInt16();
} }
if (header.m_Version >= 11 && header.m_Version < 17) if (header.m_Version >= SerializedFileFormatVersion.kHasScriptTypeIndex && header.m_Version < SerializedFileFormatVersion.kRefactorTypeData)
{ {
var m_ScriptTypeIndex = reader.ReadInt16(); var m_ScriptTypeIndex = reader.ReadInt16();
if (objectInfo.serializedType != null) if (objectInfo.serializedType != null)
objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex; objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex;
} }
if (header.m_Version == 15 || header.m_Version == 16) if (header.m_Version == SerializedFileFormatVersion.kSupportsStrippedObject || header.m_Version == SerializedFileFormatVersion.kRefactoredClassId)
{ {
var stripped = reader.ReadByte(); objectInfo.stripped = reader.ReadByte();
} }
m_Objects.Add(objectInfo); m_Objects.Add(objectInfo);
} }
if (header.m_Version >= 11) if (header.m_Version >= SerializedFileFormatVersion.kHasScriptTypeIndex)
{ {
int scriptCount = reader.ReadInt32(); int scriptCount = reader.ReadInt32();
m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount); m_ScriptTypes = new List<LocalSerializedObjectIdentifier>(scriptCount);
@ -166,7 +167,7 @@ namespace AssetStudio
{ {
var m_ScriptType = new LocalSerializedObjectIdentifier(); var m_ScriptType = new LocalSerializedObjectIdentifier();
m_ScriptType.localSerializedFileIndex = reader.ReadInt32(); m_ScriptType.localSerializedFileIndex = reader.ReadInt32();
if (header.m_Version < 14) if (header.m_Version < SerializedFileFormatVersion.kUnknown_14)
{ {
m_ScriptType.localIdentifierInFile = reader.ReadInt32(); m_ScriptType.localIdentifierInFile = reader.ReadInt32();
} }
@ -184,11 +185,11 @@ namespace AssetStudio
for (int i = 0; i < externalsCount; i++) for (int i = 0; i < externalsCount; i++)
{ {
var m_External = new FileIdentifier(); var m_External = new FileIdentifier();
if (header.m_Version >= 6) if (header.m_Version >= SerializedFileFormatVersion.kUnknown_6)
{ {
var tempEmpty = reader.ReadStringToNull(); var tempEmpty = reader.ReadStringToNull();
} }
if (header.m_Version >= 5) if (header.m_Version >= SerializedFileFormatVersion.kUnknown_5)
{ {
m_External.guid = new Guid(reader.ReadBytes(16)); m_External.guid = new Guid(reader.ReadBytes(16));
m_External.type = reader.ReadInt32(); m_External.type = reader.ReadInt32();
@ -198,19 +199,19 @@ namespace AssetStudio
m_Externals.Add(m_External); m_Externals.Add(m_External);
} }
if (header.m_Version >= 20) if (header.m_Version >= SerializedFileFormatVersion.kSupportsRefObject)
{ {
int refTypesCount = reader.ReadInt32(); int refTypesCount = reader.ReadInt32();
m_RefTypes = new List<SerializedType>(refTypesCount); m_RefTypes = new List<SerializedType>(refTypesCount);
for (int i = 0; i < refTypesCount; i++) for (int i = 0; i < refTypesCount; i++)
{ {
m_RefTypes.Add(ReadSerializedType()); m_RefTypes.Add(ReadSerializedType(true));
} }
} }
if (header.m_Version >= 5) if (header.m_Version >= SerializedFileFormatVersion.kUnknown_5)
{ {
var userInformation = reader.ReadStringToNull(); userInformation = reader.ReadStringToNull();
} }
//reader.AlignStream(16); //reader.AlignStream(16);
@ -225,73 +226,84 @@ namespace AssetStudio
version = versionSplit.Select(int.Parse).ToArray(); version = versionSplit.Select(int.Parse).ToArray();
} }
private SerializedType ReadSerializedType() private SerializedType ReadSerializedType(bool isRefType)
{ {
var type = new SerializedType(); var type = new SerializedType();
type.classID = reader.ReadInt32(); type.classID = reader.ReadInt32();
if (header.m_Version >= 16) if (header.m_Version >= SerializedFileFormatVersion.kRefactoredClassId)
{ {
type.m_IsStrippedType = reader.ReadBoolean(); type.m_IsStrippedType = reader.ReadBoolean();
} }
if (header.m_Version >= 17) if (header.m_Version >= SerializedFileFormatVersion.kRefactorTypeData)
{ {
type.m_ScriptTypeIndex = reader.ReadInt16(); type.m_ScriptTypeIndex = reader.ReadInt16();
} }
if (header.m_Version >= 13) if (header.m_Version >= SerializedFileFormatVersion.kHasTypeTreeHashes)
{ {
if ((header.m_Version < 16 && type.classID < 0) || (header.m_Version >= 16 && type.classID == 114)) if (isRefType && type.m_ScriptTypeIndex >= 0)
{ {
type.m_ScriptID = reader.ReadBytes(16); //Hash128 type.m_ScriptID = reader.ReadBytes(16);
} }
type.m_OldTypeHash = reader.ReadBytes(16); //Hash128 else if ((header.m_Version < SerializedFileFormatVersion.kRefactoredClassId && type.classID < 0) || (header.m_Version >= SerializedFileFormatVersion.kRefactoredClassId && type.classID == 114))
{
type.m_ScriptID = reader.ReadBytes(16);
}
type.m_OldTypeHash = reader.ReadBytes(16);
} }
if (m_EnableTypeTree) if (m_EnableTypeTree)
{ {
var typeTree = new List<TypeTreeNode>(); type.m_Type = new TypeTree();
if (header.m_Version >= 12 || header.m_Version == 10) type.m_Type.m_Nodes = new List<TypeTreeNode>();
if (header.m_Version >= SerializedFileFormatVersion.kUnknown_12 || header.m_Version == SerializedFileFormatVersion.kUnknown_10)
{ {
TypeTreeBlobRead(typeTree); TypeTreeBlobRead(type.m_Type);
} }
else else
{ {
ReadTypeTree(typeTree); ReadTypeTree(type.m_Type);
} }
if (header.m_Version >= SerializedFileFormatVersion.kStoresTypeDependencies)
if (header.m_Version >= 21)
{ {
type.m_TypeDependencies = reader.ReadInt32Array(); if (isRefType)
{
type.m_KlassName = reader.ReadStringToNull();
type.m_NameSpace = reader.ReadStringToNull();
type.m_AsmName = reader.ReadStringToNull();
}
else
{
type.m_TypeDependencies = reader.ReadInt32Array();
}
} }
type.m_Nodes = typeTree;
} }
return type; return type;
} }
private void ReadTypeTree(List<TypeTreeNode> typeTree, int level = 0) private void ReadTypeTree(TypeTree m_Type, int level = 0)
{ {
var typeTreeNode = new TypeTreeNode(); var typeTreeNode = new TypeTreeNode();
typeTree.Add(typeTreeNode); m_Type.m_Nodes.Add(typeTreeNode);
typeTreeNode.m_Level = level; typeTreeNode.m_Level = level;
typeTreeNode.m_Type = reader.ReadStringToNull(); typeTreeNode.m_Type = reader.ReadStringToNull();
typeTreeNode.m_Name = reader.ReadStringToNull(); typeTreeNode.m_Name = reader.ReadStringToNull();
typeTreeNode.m_ByteSize = reader.ReadInt32(); typeTreeNode.m_ByteSize = reader.ReadInt32();
if (header.m_Version == 2) if (header.m_Version == SerializedFileFormatVersion.kUnknown_2)
{ {
var variableCount = reader.ReadInt32(); var variableCount = reader.ReadInt32();
} }
if (header.m_Version != 3) if (header.m_Version != SerializedFileFormatVersion.kUnknown_3)
{ {
typeTreeNode.m_Index = reader.ReadInt32(); typeTreeNode.m_Index = reader.ReadInt32();
} }
typeTreeNode.m_IsArray = reader.ReadInt32(); typeTreeNode.m_IsArray = reader.ReadInt32();
typeTreeNode.m_Version = reader.ReadInt32(); typeTreeNode.m_Version = reader.ReadInt32();
if (header.m_Version != 3) if (header.m_Version != SerializedFileFormatVersion.kUnknown_3)
{ {
typeTreeNode.m_MetaFlag = reader.ReadInt32(); typeTreeNode.m_MetaFlag = reader.ReadInt32();
} }
@ -299,18 +311,18 @@ namespace AssetStudio
int childrenCount = reader.ReadInt32(); int childrenCount = reader.ReadInt32();
for (int i = 0; i < childrenCount; i++) for (int i = 0; i < childrenCount; i++)
{ {
ReadTypeTree(typeTree, level + 1); ReadTypeTree(m_Type, level + 1);
} }
} }
private void TypeTreeBlobRead(List<TypeTreeNode> typeTree) private void TypeTreeBlobRead(TypeTree m_Type)
{ {
int numberOfNodes = reader.ReadInt32(); int numberOfNodes = reader.ReadInt32();
int stringBufferSize = reader.ReadInt32(); int stringBufferSize = reader.ReadInt32();
for (int i = 0; i < numberOfNodes; i++) for (int i = 0; i < numberOfNodes; i++)
{ {
var typeTreeNode = new TypeTreeNode(); var typeTreeNode = new TypeTreeNode();
typeTree.Add(typeTreeNode); m_Type.m_Nodes.Add(typeTreeNode);
typeTreeNode.m_Version = reader.ReadUInt16(); typeTreeNode.m_Version = reader.ReadUInt16();
typeTreeNode.m_Level = reader.ReadByte(); typeTreeNode.m_Level = reader.ReadByte();
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0; typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
@ -319,20 +331,20 @@ namespace AssetStudio
typeTreeNode.m_ByteSize = reader.ReadInt32(); typeTreeNode.m_ByteSize = reader.ReadInt32();
typeTreeNode.m_Index = reader.ReadInt32(); typeTreeNode.m_Index = reader.ReadInt32();
typeTreeNode.m_MetaFlag = reader.ReadInt32(); typeTreeNode.m_MetaFlag = reader.ReadInt32();
if (header.m_Version >= 19) if (header.m_Version >= SerializedFileFormatVersion.kTypeTreeNodeWithTypeFlags)
{ {
typeTreeNode.m_RefTypeHash = reader.ReadUInt64(); typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
} }
} }
var m_StringBuffer = reader.ReadBytes(stringBufferSize); m_Type.m_StringBuffer = reader.ReadBytes(stringBufferSize);
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_StringBuffer))) using (var stringBufferReader = new BinaryReader(new MemoryStream(m_Type.m_StringBuffer)))
{ {
for (int i = 0; i < numberOfNodes; i++) for (int i = 0; i < numberOfNodes; i++)
{ {
var typeTreeNode = typeTree[i]; var m_Node = m_Type.m_Nodes[i];
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset); m_Node.m_Type = ReadString(stringBufferReader, m_Node.m_TypeStrOffset);
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset); m_Node.m_Name = ReadString(stringBufferReader, m_Node.m_NameStrOffset);
} }
} }

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AssetStudio
{
public enum SerializedFileFormatVersion
{
kUnsupported = 1,
kUnknown_2 = 2,
kUnknown_3 = 3,
kUnknown_5 = 5,
kUnknown_6 = 6,
kUnknown_7 = 7,
kUnknown_8 = 8,
kUnknown_9 = 9,
kUnknown_10 = 10,
kHasScriptTypeIndex = 11,
kUnknown_12 = 12,
kHasTypeTreeHashes = 13,
kUnknown_14 = 14,
kSupportsStrippedObject = 15,
kRefactoredClassId = 16,
kRefactorTypeData = 17,
kRefactorShareableTypeTreeData = 18,
kTypeTreeNodeWithTypeFlags = 19,
kSupportsRefObject = 20,
kStoresTypeDependencies = 21,
kLargeFilesSupport = 22
}
}

View File

@ -9,7 +9,7 @@ namespace AssetStudio
{ {
public uint m_MetadataSize; public uint m_MetadataSize;
public long m_FileSize; public long m_FileSize;
public uint m_Version; public SerializedFileFormatVersion m_Version;
public long m_DataOffset; public long m_DataOffset;
public byte m_Endianess; public byte m_Endianess;
public byte[] m_Reserved; public byte[] m_Reserved;

View File

@ -10,9 +10,12 @@ namespace AssetStudio
public int classID; public int classID;
public bool m_IsStrippedType; public bool m_IsStrippedType;
public short m_ScriptTypeIndex = -1; public short m_ScriptTypeIndex = -1;
public List<TypeTreeNode> m_Nodes; public TypeTree m_Type;
public byte[] m_ScriptID; //Hash128 public byte[] m_ScriptID; //Hash128
public byte[] m_OldTypeHash; //Hash128 public byte[] m_OldTypeHash; //Hash128
public int[] m_TypeDependencies; public int[] m_TypeDependencies;
public string m_KlassName;
public string m_NameSpace;
public string m_AsmName;
} }
} }

14
AssetStudio/TypeTree.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AssetStudio
{
public class TypeTree
{
public List<TypeTreeNode> m_Nodes;
public byte[] m_StringBuffer;
}
}

View File

@ -7,29 +7,32 @@ namespace AssetStudio
{ {
public static class TypeTreeHelper public static class TypeTreeHelper
{ {
public static void ReadTypeString(StringBuilder sb, List<TypeTreeNode> members, ObjectReader reader) public static string ReadTypeString(TypeTree m_Type, ObjectReader reader)
{ {
reader.Reset(); reader.Reset();
for (int i = 0; i < members.Count; i++) var sb = new StringBuilder();
var m_Nodes = m_Type.m_Nodes;
for (int i = 0; i < m_Nodes.Count; i++)
{ {
ReadStringValue(sb, members, reader, ref i); ReadStringValue(sb, m_Nodes, reader, ref i);
} }
var readed = reader.Position - reader.byteStart; var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize) if (readed != reader.byteSize)
{ {
Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes"); Logger.Info($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
} }
return sb.ToString();
} }
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader, ref int i) private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
{ {
var member = members[i]; var m_Node = m_Nodes[i];
var level = member.m_Level; var level = m_Node.m_Level;
var varTypeStr = member.m_Type; var varTypeStr = m_Node.m_Type;
var varNameStr = member.m_Name; var varNameStr = m_Node.m_Name;
object value = null; object value = null;
var append = true; var append = true;
var align = (member.m_MetaFlag & 0x4000) != 0; var align = (m_Node.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr) switch (varTypeStr)
{ {
case "SInt8": case "SInt8":
@ -82,18 +85,18 @@ namespace AssetStudio
break; break;
case "map": case "map":
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
append = false; append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array"); sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
var size = reader.ReadInt32(); var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size); sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var map = GetMembers(members, i); var map = GetNodes(m_Nodes, i);
i += map.Count - 1; i += map.Count - 1;
var first = GetMembers(map, 4); var first = GetNodes(map, 4);
var next = 4 + first.Count; var next = 4 + first.Count;
var second = GetMembers(map, next); var second = GetNodes(map, next);
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j); sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
@ -117,16 +120,16 @@ namespace AssetStudio
} }
default: default:
{ {
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
append = false; append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array"); sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 1)), "Array", "Array");
var size = reader.ReadInt32(); var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size); sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var vector = GetMembers(members, i); var vector = GetNodes(m_Nodes, i);
i += vector.Count - 1; i += vector.Count - 1;
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
@ -140,7 +143,7 @@ namespace AssetStudio
{ {
append = false; append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr); sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
var @class = GetMembers(members, i); var @class = GetNodes(m_Nodes, i);
i += @class.Count - 1; i += @class.Count - 1;
for (int j = 1; j < @class.Count; j++) for (int j = 1; j < @class.Count; j++)
{ {
@ -156,15 +159,16 @@ namespace AssetStudio
reader.AlignStream(); reader.AlignStream();
} }
public static OrderedDictionary ReadType(List<TypeTreeNode> members, ObjectReader reader) public static OrderedDictionary ReadType(TypeTree m_Types, ObjectReader reader)
{ {
reader.Reset(); reader.Reset();
var obj = new OrderedDictionary(); var obj = new OrderedDictionary();
for (int i = 1; i < members.Count; i++) var m_Nodes = m_Types.m_Nodes;
for (int i = 1; i < m_Nodes.Count; i++)
{ {
var member = members[i]; var m_Node = m_Nodes[i];
var varNameStr = member.m_Name; var varNameStr = m_Node.m_Name;
obj[varNameStr] = ReadValue(members, reader, ref i); obj[varNameStr] = ReadValue(m_Nodes, reader, ref i);
} }
var readed = reader.Position - reader.byteStart; var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize) if (readed != reader.byteSize)
@ -174,12 +178,12 @@ namespace AssetStudio
return obj; return obj;
} }
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i) private static object ReadValue(List<TypeTreeNode> m_Nodes, BinaryReader reader, ref int i)
{ {
var member = members[i]; var m_Node = m_Nodes[i];
var varTypeStr = member.m_Type; var varTypeStr = m_Node.m_Type;
object value; object value;
var align = (member.m_MetaFlag & 0x4000) != 0; var align = (m_Node.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr) switch (varTypeStr)
{ {
case "SInt8": case "SInt8":
@ -230,13 +234,13 @@ namespace AssetStudio
break; break;
case "map": case "map":
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
var map = GetMembers(members, i); var map = GetNodes(m_Nodes, i);
i += map.Count - 1; i += map.Count - 1;
var first = GetMembers(map, 4); var first = GetNodes(map, 4);
var next = 4 + first.Count; var next = 4 + first.Count;
var second = GetMembers(map, next); var second = GetNodes(map, next);
var size = reader.ReadInt32(); var size = reader.ReadInt32();
var dic = new List<KeyValuePair<object, object>>(size); var dic = new List<KeyValuePair<object, object>>(size);
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
@ -257,11 +261,11 @@ namespace AssetStudio
} }
default: default:
{ {
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array if (i < m_Nodes.Count - 1 && m_Nodes[i + 1].m_Type == "Array") //Array
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((m_Nodes[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
var vector = GetMembers(members, i); var vector = GetNodes(m_Nodes, i);
i += vector.Count - 1; i += vector.Count - 1;
var size = reader.ReadInt32(); var size = reader.ReadInt32();
var list = new List<object>(size); var list = new List<object>(size);
@ -275,7 +279,7 @@ namespace AssetStudio
} }
else //Class else //Class
{ {
var @class = GetMembers(members, i); var @class = GetNodes(m_Nodes, i);
i += @class.Count - 1; i += @class.Count - 1;
var obj = new OrderedDictionary(); var obj = new OrderedDictionary();
for (int j = 1; j < @class.Count; j++) for (int j = 1; j < @class.Count; j++)
@ -294,22 +298,22 @@ namespace AssetStudio
return value; return value;
} }
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int index) private static List<TypeTreeNode> GetNodes(List<TypeTreeNode> m_Nodes, int index)
{ {
var member2 = new List<TypeTreeNode>(); var nodes = new List<TypeTreeNode>();
member2.Add(members[index]); nodes.Add(m_Nodes[index]);
var level = members[index].m_Level; var level = m_Nodes[index].m_Level;
for (int i = index + 1; i < members.Count; i++) for (int i = index + 1; i < m_Nodes.Count; i++)
{ {
var member = members[i]; var member = m_Nodes[i];
var level2 = member.m_Level; var level2 = member.m_Level;
if (level2 <= level) if (level2 <= level)
{ {
return member2; return nodes;
} }
member2.Add(member); nodes.Add(member);
} }
return member2; return nodes;
} }
} }
} }

View File

@ -943,8 +943,8 @@ namespace AssetStudioGUI
var obj = m_MonoBehaviour.ToType(); var obj = m_MonoBehaviour.ToType();
if (obj == null) if (obj == null)
{ {
var nodes = MonoBehaviourToTypeTreeNodes(m_MonoBehaviour); var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
obj = m_MonoBehaviour.ToType(nodes); obj = m_MonoBehaviour.ToType(type);
} }
var str = JsonConvert.SerializeObject(obj, Formatting.Indented); var str = JsonConvert.SerializeObject(obj, Formatting.Indented);
PreviewText(str); PreviewText(str);

View File

@ -7,19 +7,19 @@ namespace AssetStudioGUI
{ {
internal class TypeTreeItem : ListViewItem internal class TypeTreeItem : ListViewItem
{ {
private List<TypeTreeNode> m_Nodes; private TypeTree m_Type;
public TypeTreeItem(int typeID, List<TypeTreeNode> m_Nodes) public TypeTreeItem(int typeID, TypeTree m_Type)
{ {
this.m_Nodes = m_Nodes; this.m_Type = m_Type;
Text = m_Nodes[0].m_Type + " " + m_Nodes[0].m_Name; Text = m_Type.m_Nodes[0].m_Type + " " + m_Type.m_Nodes[0].m_Name;
SubItems.Add(typeID.ToString()); SubItems.Add(typeID.ToString());
} }
public override string ToString() public override string ToString()
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var i in m_Nodes) foreach (var i in m_Type.m_Nodes)
{ {
sb.AppendFormat("{0}{1} {2} {3} {4}\r\n", new string('\t', i.m_Level), i.m_Type, i.m_Name, i.m_ByteSize, (i.m_MetaFlag & 0x4000) != 0); sb.AppendFormat("{0}{1} {2} {3} {4}\r\n", new string('\t', i.m_Level), i.m_Type, i.m_Name, i.m_ByteSize, (i.m_MetaFlag & 0x4000) != 0);
} }

View File

@ -120,8 +120,8 @@ namespace AssetStudioGUI
var type = m_MonoBehaviour.ToType(); var type = m_MonoBehaviour.ToType();
if (type == null) if (type == null)
{ {
var nodes = Studio.MonoBehaviourToTypeTreeNodes(m_MonoBehaviour); var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
type = m_MonoBehaviour.ToType(nodes); type = m_MonoBehaviour.ToType(m_Type);
} }
var str = JsonConvert.SerializeObject(type, Formatting.Indented); var str = JsonConvert.SerializeObject(type, Formatting.Indented);
File.WriteAllText(exportFullPath, str); File.WriteAllText(exportFullPath, str);
@ -373,8 +373,8 @@ namespace AssetStudioGUI
var str = item.Asset.Dump(); var str = item.Asset.Dump();
if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour) if (str == null && item.Asset is MonoBehaviour m_MonoBehaviour)
{ {
var nodes = Studio.MonoBehaviourToTypeTreeNodes(m_MonoBehaviour); var m_Type = Studio.MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(nodes); str = m_MonoBehaviour.Dump(m_Type);
} }
if (str != null) if (str != null)
{ {

View File

@ -341,27 +341,27 @@ namespace AssetStudioGUI
{ {
if (typeMap.TryGetValue(assetsFile.unityVersion, out var curVer)) if (typeMap.TryGetValue(assetsFile.unityVersion, out var curVer))
{ {
foreach (var type in assetsFile.m_Types.Where(x => x.m_Nodes != null)) foreach (var type in assetsFile.m_Types.Where(x => x.m_Type != null))
{ {
var key = type.classID; var key = type.classID;
if (type.m_ScriptTypeIndex >= 0) if (type.m_ScriptTypeIndex >= 0)
{ {
key = -1 - type.m_ScriptTypeIndex; key = -1 - type.m_ScriptTypeIndex;
} }
curVer[key] = new TypeTreeItem(key, type.m_Nodes); curVer[key] = new TypeTreeItem(key, type.m_Type);
} }
} }
else else
{ {
var items = new SortedDictionary<int, TypeTreeItem>(); var items = new SortedDictionary<int, TypeTreeItem>();
foreach (var type in assetsFile.m_Types.Where(x => x.m_Nodes != null)) foreach (var type in assetsFile.m_Types.Where(x => x.m_Type != null))
{ {
var key = type.classID; var key = type.classID;
if (type.m_ScriptTypeIndex >= 0) if (type.m_ScriptTypeIndex >= 0)
{ {
key = -1 - type.m_ScriptTypeIndex; key = -1 - type.m_ScriptTypeIndex;
} }
items[key] = new TypeTreeItem(key, type.m_Nodes); items[key] = new TypeTreeItem(key, type.m_Type);
} }
typeMap.Add(assetsFile.unityVersion, items); typeMap.Add(assetsFile.unityVersion, items);
} }
@ -680,7 +680,7 @@ namespace AssetStudioGUI
} }
} }
public static List<TypeTreeNode> MonoBehaviourToTypeTreeNodes(MonoBehaviour m_MonoBehaviour) public static TypeTree MonoBehaviourToTypeTree(MonoBehaviour m_MonoBehaviour)
{ {
if (!assemblyLoader.Loaded) if (!assemblyLoader.Loaded)
{ {
@ -695,7 +695,7 @@ namespace AssetStudioGUI
assemblyLoader.Loaded = true; assemblyLoader.Loaded = true;
} }
} }
return m_MonoBehaviour.ConvertToTypeTreeNodes(assemblyLoader); return m_MonoBehaviour.ConvertToTypeTree(assemblyLoader);
} }
public static string DumpAsset(Object obj) public static string DumpAsset(Object obj)
@ -703,8 +703,8 @@ namespace AssetStudioGUI
var str = obj.Dump(); var str = obj.Dump();
if (str == null && obj is MonoBehaviour m_MonoBehaviour) if (str == null && obj is MonoBehaviour m_MonoBehaviour)
{ {
var nodes = MonoBehaviourToTypeTreeNodes(m_MonoBehaviour); var type = MonoBehaviourToTypeTree(m_MonoBehaviour);
str = m_MonoBehaviour.Dump(nodes); str = m_MonoBehaviour.Dump(type);
} }
return str; return str;
} }

View File

@ -4,21 +4,22 @@ namespace AssetStudio
{ {
public static class MonoBehaviourConverter public static class MonoBehaviourConverter
{ {
public static List<TypeTreeNode> ConvertToTypeTreeNodes(this MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader) public static TypeTree ConvertToTypeTree(this MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader)
{ {
var nodes = new List<TypeTreeNode>(); var m_Type = new TypeTree();
m_Type.m_Nodes = new List<TypeTreeNode>();
var helper = new SerializedTypeHelper(m_MonoBehaviour.version); var helper = new SerializedTypeHelper(m_MonoBehaviour.version);
helper.AddMonoBehaviour(nodes, 0); helper.AddMonoBehaviour(m_Type.m_Nodes, 0);
if (m_MonoBehaviour.m_Script.TryGet(out var m_Script)) if (m_MonoBehaviour.m_Script.TryGet(out var m_Script))
{ {
var typeDef = assemblyLoader.GetTypeDefinition(m_Script.m_AssemblyName, string.IsNullOrEmpty(m_Script.m_Namespace) ? m_Script.m_ClassName : $"{m_Script.m_Namespace}.{m_Script.m_ClassName}"); var typeDef = assemblyLoader.GetTypeDefinition(m_Script.m_AssemblyName, string.IsNullOrEmpty(m_Script.m_Namespace) ? m_Script.m_ClassName : $"{m_Script.m_Namespace}.{m_Script.m_ClassName}");
if (typeDef != null) if (typeDef != null)
{ {
var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1); var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1);
nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes()); m_Type.m_Nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNodes());
} }
} }
return nodes; return m_Type;
} }
} }
} }