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;
private bool m_EnableTypeTree = true;
public List<SerializedType> m_Types;
public List<SerializedType> m_RefTypes;
public List<ObjectInfo> m_Objects;
private List<LocalSerializedObjectIdentifier> m_ScriptTypes;
public List<FileIdentifier> m_Externals;
@ -133,7 +134,6 @@ namespace AssetStudio
{
objectInfo.classID = reader.ReadUInt16();
objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID);
var isDestroyed = reader.ReadUInt16();
}
else
{
@ -141,6 +141,16 @@ namespace AssetStudio
objectInfo.serializedType = type;
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)
{
var stripped = reader.ReadByte();
@ -188,15 +198,22 @@ namespace AssetStudio
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)
@ -247,11 +264,7 @@ namespace AssetStudio
if (header.m_Version >= 21)
{
var count = reader.ReadInt32();
if (count > 0)
{
reader.Position += 4 * count;
}
type.m_TypeDependencies = reader.ReadInt32Array();
}
type.m_Nodes = typeTree;
@ -294,38 +307,33 @@ namespace AssetStudio
{
int numberOfNodes = reader.ReadInt32();
int stringBufferSize = reader.ReadInt32();
var nodeSize = 24;
if (header.m_Version >= 19)
for (int i = 0; i < numberOfNodes; i++)
{
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;
using (var stringBufferReader = new BinaryReader(new MemoryStream(reader.ReadBytes(stringBufferSize))))
var m_StringBuffer = reader.ReadBytes(stringBufferSize);
using (var stringBufferReader = new BinaryReader(new MemoryStream(m_StringBuffer)))
{
reader.Position -= numberOfNodes * nodeSize + stringBufferSize;
for (int i = 0; i < numberOfNodes; i++)
{
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();
var typeTreeNode = typeTree[i];
typeTreeNode.m_Type = ReadString(stringBufferReader, typeTreeNode.m_TypeStrOffset);
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)

View File

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

View File

@ -31,6 +31,7 @@ namespace AssetStudio
value = reader.ReadSByte();
break;
case "UInt8":
case "char":
value = reader.ReadByte();
break;
case "short":
@ -56,6 +57,7 @@ namespace AssetStudio
break;
case "UInt64":
case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64();
break;
case "float":
@ -73,26 +75,6 @@ namespace AssetStudio
sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str);
i += 3;
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":
{
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");
var size = reader.ReadInt32();
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;
map.RemoveRange(0, 4);
var first = GetMembers(map, map[0].m_Level, 0);
map.RemoveRange(0, first.Count);
var second = map;
var first = GetMembers(map, 4);
var next = 4 + first.Count;
var second = GetMembers(map, next);
for (int j = 0; j < size; j++)
{
sb.AppendFormat("{0}[{1}]\r\n", (new string('\t', level + 2)), j);
@ -131,20 +112,37 @@ namespace AssetStudio
}
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;
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++)
else //Class
{
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)
@ -168,7 +166,6 @@ namespace AssetStudio
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
{
var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type;
object value;
var align = (member.m_MetaFlag & 0x4000) != 0;
@ -178,6 +175,7 @@ namespace AssetStudio
value = reader.ReadSByte();
break;
case "UInt8":
case "char":
value = reader.ReadByte();
break;
case "short":
@ -203,6 +201,7 @@ namespace AssetStudio
break;
case "UInt64":
case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64();
break;
case "float":
@ -222,14 +221,13 @@ namespace AssetStudio
{
if ((members[i + 1].m_MetaFlag & 0x4000) != 0)
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 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++)
{
int tmp1 = 0;
@ -248,18 +246,17 @@ namespace AssetStudio
}
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)
align = true;
var vector = GetMembers(members, i);
i += vector.Count - 1;
var size = reader.ReadInt32();
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++)
{
int tmp = 0;
int tmp = 3;
list.Add(ReadValue(vector, reader, ref tmp));
}
value = list;
@ -267,11 +264,10 @@ namespace AssetStudio
}
else //Class
{
var @class = GetMembers(members, level, i);
@class.RemoveAt(0);
i += @class.Count;
var @class = GetMembers(members, i);
i += @class.Count - 1;
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 name = classmember.m_Name;
@ -287,10 +283,11 @@ namespace AssetStudio
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>();
member2.Add(members[0]);
member2.Add(members[index]);
var level = members[index].m_Level;
for (int i = index + 1; i < members.Count; i++)
{
var member = members[i];
@ -303,140 +300,5 @@ namespace AssetStudio
}
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 int m_ByteSize;
public int m_Index;
public int m_IsArray;
public int m_IsArray; //m_TypeFlags
public int m_Version;
public int m_MetaFlag;
public int m_Level;
public uint m_TypeStrOffset;
public uint m_NameStrOffset;
public ulong m_RefTypeHash;
}
}

View File

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