AssetStudio/AssetStudio/TypeTreeHelper.cs

316 lines
13 KiB
C#

using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
namespace AssetStudio
{
public static class TypeTreeHelper
{
public static void ReadTypeString(StringBuilder sb, List<TypeTreeNode> members, ObjectReader reader)
{
reader.Reset();
for (int i = 0; i < members.Count; i++)
{
ReadStringValue(sb, members, reader, ref i);
}
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Error($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
}
}
private static void ReadStringValue(StringBuilder sb, List<TypeTreeNode> members, BinaryReader reader, ref int i)
{
var member = members[i];
var level = member.m_Level;
var varTypeStr = member.m_Type;
var varNameStr = member.m_Name;
object value = null;
var append = true;
var align = (member.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr)
{
case "SInt8":
value = reader.ReadSByte();
break;
case "UInt8":
case "char":
value = reader.ReadByte();
break;
case "short":
case "SInt16":
value = reader.ReadInt16();
break;
case "UInt16":
case "unsigned short":
value = reader.ReadUInt16();
break;
case "int":
case "SInt32":
value = reader.ReadInt32();
break;
case "UInt32":
case "unsigned int":
case "Type*":
value = reader.ReadUInt32();
break;
case "long long":
case "SInt64":
value = reader.ReadInt64();
break;
case "UInt64":
case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64();
break;
case "float":
value = reader.ReadSingle();
break;
case "double":
value = reader.ReadDouble();
break;
case "bool":
value = reader.ReadBoolean();
break;
case "string":
append = false;
var str = reader.ReadAlignedString();
sb.AppendFormat("{0}{1} {2} = \"{3}\"\r\n", (new string('\t', level)), varTypeStr, varNameStr, str);
i += 3;
break;
case "map":
{
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 map = GetMembers(members, i);
i += map.Count - 1;
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);
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level + 2)), "pair", "data");
int tmp1 = 0;
int tmp2 = 0;
ReadStringValue(sb, first, reader, ref tmp1);
ReadStringValue(sb, second, reader, ref tmp2);
}
break;
}
case "TypelessData":
{
append = false;
var size = reader.ReadInt32();
reader.ReadBytes(size);
i += 2;
sb.AppendFormat("{0}{1} {2}\r\n", (new string('\t', level)), varTypeStr, varNameStr);
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), "int", "size", size);
break;
}
default:
{
if (i < members.Count - 1 && members[i + 1].m_Type == "Array") //Array
{
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;
}
else //Class
{
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;
}
}
}
if (append)
sb.AppendFormat("{0}{1} {2} = {3}\r\n", (new string('\t', level)), varTypeStr, varNameStr, value);
if (align)
reader.AlignStream();
}
public static OrderedDictionary ReadType(List<TypeTreeNode> members, ObjectReader reader)
{
reader.Reset();
var obj = new OrderedDictionary();
for (int i = 1; i < members.Count; i++)
{
var member = members[i];
var varNameStr = member.m_Name;
obj[varNameStr] = ReadValue(members, reader, ref i);
}
var readed = reader.Position - reader.byteStart;
if (readed != reader.byteSize)
{
Logger.Error($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes");
}
return obj;
}
private static object ReadValue(List<TypeTreeNode> members, BinaryReader reader, ref int i)
{
var member = members[i];
var varTypeStr = member.m_Type;
object value;
var align = (member.m_MetaFlag & 0x4000) != 0;
switch (varTypeStr)
{
case "SInt8":
value = reader.ReadSByte();
break;
case "UInt8":
case "char":
value = reader.ReadByte();
break;
case "short":
case "SInt16":
value = reader.ReadInt16();
break;
case "UInt16":
case "unsigned short":
value = reader.ReadUInt16();
break;
case "int":
case "SInt32":
value = reader.ReadInt32();
break;
case "UInt32":
case "unsigned int":
case "Type*":
value = reader.ReadUInt32();
break;
case "long long":
case "SInt64":
value = reader.ReadInt64();
break;
case "UInt64":
case "unsigned long long":
case "FileSize":
value = reader.ReadUInt64();
break;
case "float":
value = reader.ReadSingle();
break;
case "double":
value = reader.ReadDouble();
break;
case "bool":
value = reader.ReadBoolean();
break;
case "string":
value = reader.ReadAlignedString();
i += 3;
break;
case "map":
{
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);
for (int j = 0; j < size; j++)
{
int tmp1 = 0;
int tmp2 = 0;
dic.Add(new KeyValuePair<object, object>(ReadValue(first, reader, ref tmp1), ReadValue(second, reader, ref tmp2)));
}
value = dic;
break;
}
case "TypelessData":
{
var size = reader.ReadInt32();
value = reader.ReadBytes(size);
i += 2;
break;
}
default:
{
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);
for (int j = 0; j < size; j++)
{
int tmp = 3;
list.Add(ReadValue(vector, reader, ref tmp));
}
value = list;
break;
}
else //Class
{
var @class = GetMembers(members, i);
i += @class.Count - 1;
var obj = new OrderedDictionary();
for (int j = 1; j < @class.Count; j++)
{
var classmember = @class[j];
var name = classmember.m_Name;
obj[name] = ReadValue(@class, reader, ref j);
}
value = obj;
break;
}
}
}
if (align)
reader.AlignStream();
return value;
}
private static List<TypeTreeNode> GetMembers(List<TypeTreeNode> members, int index)
{
var member2 = new List<TypeTreeNode>();
member2.Add(members[index]);
var level = members[index].m_Level;
for (int i = index + 1; i < members.Count; i++)
{
var member = members[i];
var level2 = member.m_Level;
if (level2 <= level)
{
return member2;
}
member2.Add(member);
}
return member2;
}
}
}