improve type read

This commit is contained in:
Perfare 2020-04-10 18:11:56 +08:00
parent 6678ce082b
commit 76d17bacf5
5 changed files with 114 additions and 289 deletions

View File

@ -24,6 +24,7 @@ namespace AssetStudio
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 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;
@ -133,7 +134,6 @@ namespace AssetStudio
{ {
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);
var isDestroyed = reader.ReadUInt16();
} }
else else
{ {
@ -141,6 +141,16 @@ namespace AssetStudio
objectInfo.serializedType = type; objectInfo.serializedType = type;
objectInfo.classID = type.classID; objectInfo.classID = type.classID;
} }
if (header.m_Version < 11)
{
var isDestroyed = reader.ReadUInt16();
}
if (header.m_Version >= 11 && header.m_Version < 17)
{
var m_ScriptTypeIndex = reader.ReadInt16();
if (objectInfo.serializedType != null)
objectInfo.serializedType.m_ScriptTypeIndex = m_ScriptTypeIndex;
}
if (header.m_Version == 15 || header.m_Version == 16) if (header.m_Version == 15 || header.m_Version == 16)
{ {
var stripped = reader.ReadByte(); var stripped = reader.ReadByte();
@ -188,15 +198,22 @@ namespace AssetStudio
m_Externals.Add(m_External); m_Externals.Add(m_External);
} }
if (header.m_Version >= 5) if (header.m_Version >= 20)
{ {
//var userInformation = reader.ReadStringToNull(); int refTypesCount = reader.ReadInt32();
m_RefTypes = new List<SerializedType>(refTypesCount);
for (int i = 0; i < refTypesCount; i++)
{
m_RefTypes.Add(ReadSerializedType());
}
} }
if (header.m_Version >= 21) if (header.m_Version >= 5)
{ {
//var unknown = reader.ReadInt32(); var userInformation = reader.ReadStringToNull();
} }
//reader.AlignStream(16);
} }
public void SetVersion(string stringVersion) public void SetVersion(string stringVersion)
@ -247,11 +264,7 @@ namespace AssetStudio
if (header.m_Version >= 21) if (header.m_Version >= 21)
{ {
var count = reader.ReadInt32(); type.m_TypeDependencies = reader.ReadInt32Array();
if (count > 0)
{
reader.Position += 4 * count;
}
} }
type.m_Nodes = typeTree; type.m_Nodes = typeTree;
@ -294,38 +307,33 @@ namespace AssetStudio
{ {
int numberOfNodes = reader.ReadInt32(); int numberOfNodes = reader.ReadInt32();
int stringBufferSize = reader.ReadInt32(); int stringBufferSize = reader.ReadInt32();
for (int i = 0; i < numberOfNodes; i++)
var nodeSize = 24;
if (header.m_Version >= 19)
{ {
nodeSize = 32; var typeTreeNode = new TypeTreeNode();
typeTree.Add(typeTreeNode);
typeTreeNode.m_Version = reader.ReadUInt16();
typeTreeNode.m_Level = reader.ReadByte();
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
typeTreeNode.m_TypeStrOffset = reader.ReadUInt32();
typeTreeNode.m_NameStrOffset = reader.ReadUInt32();
typeTreeNode.m_ByteSize = reader.ReadInt32();
typeTreeNode.m_Index = reader.ReadInt32();
typeTreeNode.m_MetaFlag = reader.ReadInt32();
if (header.m_Version >= 19)
{
typeTreeNode.m_RefTypeHash = reader.ReadUInt64();
}
} }
reader.Position += numberOfNodes * nodeSize; var m_StringBuffer = reader.ReadBytes(stringBufferSize);
using (var stringBufferReader = new BinaryReader(new MemoryStream(reader.ReadBytes(stringBufferSize))))
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_StringBuffer)))
{ {
reader.Position -= numberOfNodes * nodeSize + stringBufferSize;
for (int i = 0; i < numberOfNodes; i++) for (int i = 0; i < numberOfNodes; i++)
{ {
var typeTreeNode = new TypeTreeNode(); var typeTreeNode = typeTree[i];
typeTree.Add(typeTreeNode);
typeTreeNode.m_Version = reader.ReadUInt16();
typeTreeNode.m_Level = reader.ReadByte();
typeTreeNode.m_IsArray = reader.ReadBoolean() ? 1 : 0;
typeTreeNode.m_TypeStrOffset = reader.ReadUInt32();
typeTreeNode.m_NameStrOffset = reader.ReadUInt32();
typeTreeNode.m_ByteSize = reader.ReadInt32();
typeTreeNode.m_Index = reader.ReadInt32();
typeTreeNode.m_MetaFlag = reader.ReadInt32();
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset); typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset); typeTreeNode.m_Name = ReadString(stringBufferReader, typeTreeNode.m_NameStrOffset);
if (header.m_Version >= 19)
{
reader.Position += 8;
}
} }
reader.Position += stringBufferSize;
} }
string ReadString(BinaryReader stringBufferReader, uint value) string ReadString(BinaryReader stringBufferReader, uint value)

View File

@ -13,5 +13,6 @@ namespace AssetStudio
public List<TypeTreeNode> m_Nodes; public List<TypeTreeNode> m_Nodes;
public byte[] m_ScriptID; //Hash128 public byte[] m_ScriptID; //Hash128
public byte[] m_OldTypeHash; //Hash128 public byte[] m_OldTypeHash; //Hash128
public int[] m_TypeDependencies;
} }
} }

View File

@ -31,6 +31,7 @@ namespace AssetStudio
value = reader.ReadSByte(); value = reader.ReadSByte();
break; break;
case "UInt8": case "UInt8":
case "char":
value = reader.ReadByte(); value = reader.ReadByte();
break; break;
case "short": case "short":
@ -56,6 +57,7 @@ namespace AssetStudio
break; break;
case "UInt64": case "UInt64":
case "unsigned long long": case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64(); value = reader.ReadUInt64();
break; break;
case "float": case "float":
@ -73,26 +75,6 @@ namespace AssetStudio
sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str); sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str);
i += 3; i += 3;
break; break;
case "vector":
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
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 + 1)), "Array", "Array");
var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var vector = GetMembers(members, level, i);
i += vector.Count - 1;
vector.RemoveRange(0, 3);
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
int tmp = 0;
ReadStringValue(sb, vector, reader, ref tmp);
}
break;
}
case "map": case "map":
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
@ -102,12 +84,11 @@ namespace AssetStudio
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, level, i); var map = GetMembers(members, i);
i += map.Count - 1; i += map.Count - 1;
map.RemoveRange(0, 4); var first = GetMembers(map, 4);
var first = GetMembers(map, map[0].m_Level, 0); var next = 4 + first.Count;
map.RemoveRange(0, first.Count); var second = GetMembers(map, next);
var second = map;
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);
@ -131,20 +112,37 @@ namespace AssetStudio
} }
default: default:
{ {
if (i != members.Count && members[i + 1].m_Type == "Array") if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
{ {
goto case "vector"; if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
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 + 1)), "Array", "Array");
var size = reader.ReadInt32();
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level + 1)), "int", "size", size);
var vector = GetMembers(members, i);
i += vector.Count - 1;
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
int tmp = 3;
ReadStringValue(sb, vector, reader, ref tmp);
}
break;
} }
append = false; else //Class
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
var @class = GetMembers(members, level, i);
@class.RemoveAt(0);
i += @class.Count;
for (int j = 0; j < @class.Count; j++)
{ {
ReadStringValue(sb, @class, reader, ref j); append = false;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
var @class = GetMembers(members, i);
i += @class.Count - 1;
for (int j = 1; j < @class.Count; j++)
{
ReadStringValue(sb, @class, reader, ref j);
}
break;
} }
break;
} }
} }
if (append) if (append)
@ -168,7 +166,6 @@ namespace AssetStudio
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i) private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
{ {
var member = members[i]; var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type; var varTypeStr = member.m_Type;
object value; object value;
var align = (member.m_MetaFlag & 0x4000) != 0; var align = (member.m_MetaFlag & 0x4000) != 0;
@ -178,6 +175,7 @@ namespace AssetStudio
value = reader.ReadSByte(); value = reader.ReadSByte();
break; break;
case "UInt8": case "UInt8":
case "char":
value = reader.ReadByte(); value = reader.ReadByte();
break; break;
case "short": case "short":
@ -203,6 +201,7 @@ namespace AssetStudio
break; break;
case "UInt64": case "UInt64":
case "unsigned long long": case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64(); value = reader.ReadUInt64();
break; break;
case "float": case "float":
@ -222,14 +221,13 @@ namespace AssetStudio
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
var map = GetMembers(members, i);
i += map.Count - 1;
var first = GetMembers(map, 4);
var next = 4 + first.Count;
var second = GetMembers(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);
var map = GetMembers(members, level, i);
i += map.Count - 1;
map.RemoveRange(0, 4);
var first = GetMembers(map, map[0].m_Level, 0);
map.RemoveRange(0, first.Count);
var second = map;
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
int tmp1 = 0; int tmp1 = 0;
@ -248,18 +246,17 @@ namespace AssetStudio
} }
default: default:
{ {
if (i != members.Count && members[i + 1].m_Type == "Array") //Array if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
{ {
if ((members[i + 1].m_MetaFlag & 0x4000) != 0) if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true; align = true;
var vector = GetMembers(members, i);
i += vector.Count - 1;
var size = reader.ReadInt32(); var size = reader.ReadInt32();
var list = new List<object>(size); var list = new List<object>(size);
var vector = GetMembers(members, level, i);
i += vector.Count - 1;
vector.RemoveRange(0, 3);
for (int j = 0; j < size; j++) for (int j = 0; j < size; j++)
{ {
int tmp = 0; int tmp = 3;
list.Add(ReadValue(vector, reader, ref tmp)); list.Add(ReadValue(vector, reader, ref tmp));
} }
value = list; value = list;
@ -267,11 +264,10 @@ namespace AssetStudio
} }
else //Class else //Class
{ {
var @class = GetMembers(members, level, i); var @class = GetMembers(members, i);
@class.RemoveAt(0); i += @class.Count - 1;
i += @class.Count;
var obj = new UType(); var obj = new UType();
for (int j = 0; j < @class.Count; j++) for (int j = 1; j < @class.Count; j++)
{ {
var classmember = @class[j]; var classmember = @class[j];
var name = classmember.m_Name; var name = classmember.m_Name;
@ -287,10 +283,11 @@ namespace AssetStudio
return value; return value;
} }
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int level, int index) private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int index)
{ {
var member2 = new List<TypeTreeNode>(); var member2 = new List<TypeTreeNode>();
member2.Add(members[0]); member2.Add(members[index]);
var level = members[index].m_Level;
for (int i = index + 1; i < members.Count; i++) for (int i = index + 1; i < members.Count; i++)
{ {
var member = members[i]; var member = members[i];
@ -303,140 +300,5 @@ namespace AssetStudio
} }
return member2; return member2;
} }
public static byte[] WriteUType(UType obj, List<TypeTreeNode> members)
{
var stream = new MemoryStream();
var write = new BinaryWriter(stream);
for (int i = 0; i < members.Count; i++)
{
var member = members[i];
var varNameStr = member.m_Name;
WriteValue(obj[varNameStr], members, write, ref i);
}
return stream.ToArray();
}
private static void WriteValue(object value, List<TypeTreeNode> members, BinaryWriter write, ref int i)
{
var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type;
var align = (member.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr)
{
case "SInt8":
write.Write((sbyte)value);
break;
case "UInt8":
write.Write((byte)value);
break;
case "short":
case "SInt16":
write.Write((short)value);
break;
case "UInt16":
case "unsigned short":
write.Write((ushort)value);
break;
case "int":
case "SInt32":
write.Write((int)value);
break;
case "UInt32":
case "unsigned int":
case "Type*":
write.Write((uint)value);
break;
case "long long":
case "SInt64":
write.Write((long)value);
break;
case "UInt64":
case "unsigned long long":
write.Write((ulong)value);
break;
case "float":
write.Write((float)value);
break;
case "double":
write.Write((double)value);
break;
case "bool":
write.Write((bool)value);
break;
case "string":
write.WriteAlignedString((string)value);
i += 3;
break;
case "map":
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var dic = (List<KeyValuePair<object, object>>)value;
var size = dic.Count;
write.Write(size);
var map = GetMembers(members, level, i);
i += map.Count - 1;
map.RemoveRange(0, 4);
var first = GetMembers(map, map[0].m_Level, 0);
map.RemoveRange(0, first.Count);
var second = map;
for (int j = 0; j < size; j++)
{
int tmp1 = 0;
int tmp2 = 0;
WriteValue(dic[j].Key, first, write, ref tmp1);
WriteValue(dic[j].Value, second, write, ref tmp2);
}
break;
}
case "TypelessData":
{
var bytes = ((object[])value).Cast<byte>().ToArray();
var size = bytes.Length;
write.Write(size);
write.Write(bytes);
i += 2;
break;
}
default:
{
if (i != members.Count && members[i + 1].m_Type == "Array") //Array
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
align = true;
var list = (List<object>)value;
var size = list.Count;
write.Write(size);
var vector = GetMembers(members, level, i);
i += vector.Count - 1;
vector.RemoveRange(0, 3);
for (int j = 0; j < size; j++)
{
int tmp = 0;
WriteValue(list[j], vector, write, ref tmp);
}
break;
}
else //Class
{
var @class = GetMembers(members, level, i);
@class.RemoveAt(0);
i += @class.Count;
var obj = (UType)value;
for (int j = 0; j < @class.Count; j++)
{
var classmember = @class[j];
var name = classmember.m_Name;
WriteValue(obj[name], @class, write, ref j);
}
break;
}
}
}
if (align)
write.AlignStream(4);
}
} }
} }

View File

@ -11,11 +11,12 @@ namespace AssetStudio
public string m_Name; public string m_Name;
public int m_ByteSize; public int m_ByteSize;
public int m_Index; public int m_Index;
public int m_IsArray; public int m_IsArray; //m_TypeFlags
public int m_Version; public int m_Version;
public int m_MetaFlag; public int m_MetaFlag;
public int m_Level; public int m_Level;
public uint m_TypeStrOffset; public uint m_TypeStrOffset;
public uint m_NameStrOffset; public uint m_NameStrOffset;
public ulong m_RefTypeHash;
} }
} }

View File

@ -9,73 +9,37 @@ namespace AssetStudio
public class UType : IDictionary<string, object> public class UType : IDictionary<string, object>
{ {
private List<string> keys; private List<string> keys;
private List<object> values; private IDictionary<string, object> values;
public UType() public UType()
{ {
keys = new List<string>(); keys = new List<string>();
values = new List<object>(); values = new Dictionary<string, object>();
}
private int GetValueIndex(string name)
{
for (int i = 0, n = keys.Count; i < n; i++)
{
if (string.Equals(keys[i], name, StringComparison.Ordinal))
{
return i;
}
}
return -1;
}
public bool TryGetValue<T>(string key, out T value)
{
var index = GetValueIndex(key);
if (index != -1)
{
value = (T)values[index];
return true;
}
else
{
value = default(T);
return false;
}
} }
public object this[string key] public object this[string key]
{ {
get get
{ {
var index = GetValueIndex(key); if (!values.ContainsKey(key))
if (index != -1)
{
return values[index];
}
else
{ {
return null; return null;
} }
return values[key];
} }
set set
{ {
var index = GetValueIndex(key); if (!values.ContainsKey(key))
if (index == -1)
{ {
keys.Add(key); keys.Add(key);
values.Add(value);
}
else
{
values[index] = value;
} }
values[key] = value;
} }
} }
public ICollection<string> Keys => keys; public ICollection<string> Keys => keys;
public ICollection<object> Values => values; public ICollection<object> Values => values.Values;
public int Count => keys.Count; public int Count => keys.Count;
@ -84,13 +48,13 @@ namespace AssetStudio
public void Add(string key, object value) public void Add(string key, object value)
{ {
keys.Add(key); keys.Add(key);
values.Add(value); values.Add(key, value);
} }
public void Add(KeyValuePair<string, object> item) public void Add(KeyValuePair<string, object> item)
{ {
keys.Add(item.Key); keys.Add(item.Key);
values.Add(item.Value); values.Add(item);
} }
public void Clear() public void Clear()
@ -101,55 +65,44 @@ namespace AssetStudio
public bool Contains(KeyValuePair<string, object> item) public bool Contains(KeyValuePair<string, object> item)
{ {
throw new NotImplementedException(); return values.Contains(item);
} }
public bool ContainsKey(string key) public bool ContainsKey(string key)
{ {
return GetValueIndex(key) != -1; return values.ContainsKey(key);
} }
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{ {
throw new NotImplementedException(); values.CopyTo(array, arrayIndex);
} }
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{ {
for (int i = 0, n = keys.Count; i < n; i++) return values.GetEnumerator();
{
yield return new KeyValuePair<string, object>(keys[i], values[i]);
}
} }
public bool Remove(string key) public bool Remove(string key)
{ {
throw new NotImplementedException(); keys.Remove(key);
return values.Remove(key);
} }
public bool Remove(KeyValuePair<string, object> item) public bool Remove(KeyValuePair<string, object> item)
{ {
throw new NotImplementedException(); keys.Remove(item.Key);
return values.Remove(item);
} }
public bool TryGetValue(string key, out object value) public bool TryGetValue(string key, out object value)
{ {
var index = GetValueIndex(key); return values.TryGetValue(key, out value);
if (index != -1)
{
value = values[index];
return true;
}
else
{
value = null;
return false;
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()
{ {
return GetEnumerator(); return values.GetEnumerator();
} }
} }
} }