AssetStudio/AssetStudio/StudioClasses/AssetsFile.cs

458 lines
17 KiB
C#
Raw Normal View History

2015-10-30 02:41:37 +00:00
using System;
using System.Collections.Generic;
using System.IO;
2017-04-21 03:14:05 +00:00
using System.Linq;
2017-01-15 11:57:41 +00:00
using System.Text;
2017-04-21 03:14:05 +00:00
using System.Text.RegularExpressions;
2017-11-13 09:04:29 +00:00
using System.Windows.Forms;
2015-10-30 02:41:37 +00:00
2018-04-02 22:51:22 +00:00
namespace AssetStudio
2015-10-30 02:41:37 +00:00
{
2018-09-26 21:23:10 +00:00
public class SerializedFileHeader
{
public uint m_MetadataSize;
public uint m_FileSize;
public uint m_Version;
public uint m_DataOffset;
public byte m_Endianess;
public byte[] m_Reserved;
}
2015-10-30 02:41:37 +00:00
public class AssetsFile
{
2018-05-02 18:41:47 +00:00
public EndianBinaryReader reader;
2018-09-26 21:23:10 +00:00
public SerializedFileHeader header;
private EndianType m_FileEndianess;
public string unityVersion = "2.5.0f5";
public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform;
private bool serializedTypeTrees;
public SortedDictionary<int, List<TypeTree>> m_Type = new SortedDictionary<int, List<TypeTree>>();
private List<int[]> classIDs = new List<int[]>();//use for 5.5.0
2015-10-30 02:41:37 +00:00
public string filePath;
2018-03-27 22:29:28 +00:00
public string parentPath;
public string fileName;
2018-02-28 19:42:43 +00:00
public string upperFileName;
2018-01-16 22:20:06 +00:00
public int[] version = { 0, 0, 0, 0 };
2015-10-30 02:41:37 +00:00
public string[] buildType;
public string platformStr = "";
2018-09-26 21:23:10 +00:00
2015-10-30 02:41:37 +00:00
public Dictionary<long, AssetPreloadData> preloadTable = new Dictionary<long, AssetPreloadData>();
2015-11-02 08:11:26 +00:00
public Dictionary<long, GameObject> GameObjectList = new Dictionary<long, GameObject>();
public Dictionary<long, Transform> TransformList = new Dictionary<long, Transform>();
2015-10-30 02:41:37 +00:00
public List<AssetPreloadData> exportableAssets = new List<AssetPreloadData>();
2018-04-02 22:51:22 +00:00
public List<SharedAssets> sharedAssetsList = new List<SharedAssets> { new SharedAssets() };
2015-10-30 02:41:37 +00:00
2018-09-26 21:23:10 +00:00
public bool valid;
2017-02-20 07:38:04 +00:00
#region cmmon string
2018-02-27 10:20:12 +00:00
private static Dictionary<int, string> baseStrings = new Dictionary<int, string>
2017-02-20 07:38:04 +00:00
{
{0, "AABB"},
{5, "AnimationClip"},
{19, "AnimationCurve"},
{34, "AnimationState"},
{49, "Array"},
{55, "Base"},
{60, "BitField"},
{69, "bitset"},
{76, "bool"},
{81, "char"},
{86, "ColorRGBA"},
{96, "Component"},
{106, "data"},
{111, "deque"},
{117, "double"},
{124, "dynamic_array"},
{138, "FastPropertyName"},
{155, "first"},
{161, "float"},
{167, "Font"},
{172, "GameObject"},
{183, "Generic Mono"},
{196, "GradientNEW"},
{208, "GUID"},
{213, "GUIStyle"},
{222, "int"},
{226, "list"},
{231, "long long"},
{241, "map"},
{245, "Matrix4x4f"},
{256, "MdFour"},
{263, "MonoBehaviour"},
{277, "MonoScript"},
{288, "m_ByteSize"},
{299, "m_Curve"},
{307, "m_EditorClassIdentifier"},
{331, "m_EditorHideFlags"},
{349, "m_Enabled"},
{359, "m_ExtensionPtr"},
{374, "m_GameObject"},
{387, "m_Index"},
{395, "m_IsArray"},
{405, "m_IsStatic"},
{416, "m_MetaFlag"},
{427, "m_Name"},
{434, "m_ObjectHideFlags"},
{452, "m_PrefabInternal"},
{469, "m_PrefabParentObject"},
{490, "m_Script"},
{499, "m_StaticEditorFlags"},
{519, "m_Type"},
{526, "m_Version"},
{536, "Object"},
{543, "pair"},
{548, "PPtr<Component>"},
{564, "PPtr<GameObject>"},
{581, "PPtr<Material>"},
{596, "PPtr<MonoBehaviour>"},
{616, "PPtr<MonoScript>"},
{633, "PPtr<Object>"},
{646, "PPtr<Prefab>"},
{659, "PPtr<Sprite>"},
{672, "PPtr<TextAsset>"},
{688, "PPtr<Texture>"},
{702, "PPtr<Texture2D>"},
{718, "PPtr<Transform>"},
{734, "Prefab"},
{741, "Quaternionf"},
{753, "Rectf"},
{759, "RectInt"},
{767, "RectOffset"},
{778, "second"},
{785, "set"},
{789, "short"},
{795, "size"},
{800, "SInt16"},
{807, "SInt32"},
{814, "SInt64"},
{821, "SInt8"},
{827, "staticvector"},
{840, "string"},
{847, "TextAsset"},
{857, "TextMesh"},
{866, "Texture"},
{874, "Texture2D"},
{884, "Transform"},
{894, "TypelessData"},
{907, "UInt16"},
{914, "UInt32"},
{921, "UInt64"},
{928, "UInt8"},
{934, "unsigned int"},
{947, "unsigned long long"},
{966, "unsigned short"},
{981, "vector"},
{988, "Vector2f"},
{997, "Vector3f"},
{1006, "Vector4f"},
{1015, "m_ScriptingClassIdentifier"},
{1042, "Gradient"},
{1051, "Type*"}
2017-02-20 07:38:04 +00:00
};
#endregion
2018-04-02 22:51:22 +00:00
public class SharedAssets
2015-10-30 02:41:37 +00:00
{
2018-02-28 19:42:43 +00:00
public int Index = -2; //-2 - Prepare, -1 - Missing
2015-10-30 02:41:37 +00:00
public string aName = "";
public string fileName = "";
}
2018-02-28 19:42:43 +00:00
public AssetsFile(string fullName, EndianBinaryReader reader)
2015-10-30 02:41:37 +00:00
{
2018-05-02 18:41:47 +00:00
this.reader = reader;
filePath = fullName;
fileName = Path.GetFileName(fullName);
2018-02-28 19:42:43 +00:00
upperFileName = fileName.ToUpper();
2017-06-21 21:29:51 +00:00
try
2015-10-30 02:41:37 +00:00
{
2018-09-26 21:23:10 +00:00
//SerializedFile::ReadHeader
header = new SerializedFileHeader();
header.m_MetadataSize = reader.ReadUInt32();
header.m_FileSize = reader.ReadUInt32();
header.m_Version = reader.ReadUInt32();
header.m_DataOffset = reader.ReadUInt32();
if (header.m_Version >= 9)
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
header.m_Endianess = reader.ReadByte();
header.m_Reserved = reader.ReadBytes(3);
m_FileEndianess = (EndianType)header.m_Endianess;
2017-06-21 21:29:51 +00:00
}
2018-09-26 21:23:10 +00:00
else
2018-07-24 05:02:08 +00:00
{
2018-09-26 21:23:10 +00:00
reader.Position = header.m_FileSize - header.m_MetadataSize;
m_FileEndianess = (EndianType)reader.ReadByte();
2018-07-24 05:02:08 +00:00
}
2018-09-26 21:23:10 +00:00
//SerializedFile::ReadMetadata
if (m_FileEndianess == EndianType.LittleEndian)
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
reader.endian = EndianType.LittleEndian;
2017-06-21 21:29:51 +00:00
}
2018-09-26 21:23:10 +00:00
if (header.m_Version >= 7)
{
unityVersion = reader.ReadStringToNull();
}
if (header.m_Version >= 8)
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
m_TargetPlatform = (BuildTarget)reader.ReadInt32();
if (!Enum.IsDefined(typeof(BuildTarget), m_TargetPlatform))
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
m_TargetPlatform = BuildTarget.UnknownPlatform;
}
}
platformStr = m_TargetPlatform.ToString();
if (header.m_Version >= 14)
{
serializedTypeTrees = reader.ReadBoolean();
}
2017-06-21 21:29:51 +00:00
2018-09-26 21:23:10 +00:00
// Read types
int typeCount = reader.ReadInt32();
for (int i = 0; i < typeCount; i++)
{
if (header.m_Version < 14)
{
int classID = reader.ReadInt32();
var typeTreeList = new List<TypeTree>();
ReadTypeTree(typeTreeList, 0);
m_Type.Add(classID, typeTreeList);
2015-10-30 02:41:37 +00:00
}
2017-06-21 21:29:51 +00:00
else
2015-10-30 02:41:37 +00:00
{
2018-09-26 21:23:10 +00:00
ReadTypeTree5();
2015-10-30 02:41:37 +00:00
}
2017-06-21 21:29:51 +00:00
}
2018-09-26 21:23:10 +00:00
if (header.m_Version >= 7 && header.m_Version < 14)
2015-10-30 02:41:37 +00:00
{
2018-09-26 21:23:10 +00:00
var bigIDEnabled = reader.ReadInt32();
2015-10-30 02:41:37 +00:00
}
2018-09-26 21:23:10 +00:00
// Read Objects
int objectCount = reader.ReadInt32();
2015-10-30 02:41:37 +00:00
2018-09-26 21:23:10 +00:00
string assetIDfmt = "D" + objectCount.ToString().Length; //format for unique ID
2015-11-02 08:11:26 +00:00
2018-09-26 21:23:10 +00:00
for (int i = 0; i < objectCount; i++)
2017-01-15 11:57:41 +00:00
{
2017-06-21 21:29:51 +00:00
//each table entry is aligned individually, not the whole table
2018-09-26 21:23:10 +00:00
if (header.m_Version >= 14)
2015-11-02 08:11:26 +00:00
{
2018-09-26 21:23:10 +00:00
reader.AlignStream(4);
2015-11-02 08:11:26 +00:00
}
2015-10-30 02:41:37 +00:00
2017-06-21 21:29:51 +00:00
AssetPreloadData asset = new AssetPreloadData();
2018-09-26 21:23:10 +00:00
asset.m_PathID = header.m_Version < 14 ? reader.ReadInt32() : reader.ReadInt64();
asset.Offset = reader.ReadUInt32();
asset.Offset += header.m_DataOffset;
asset.Size = reader.ReadInt32();
if (header.m_Version > 15)
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
int index = reader.ReadInt32();
2017-06-21 21:29:51 +00:00
asset.Type1 = classIDs[index][0];
2018-01-18 00:08:48 +00:00
asset.Type2 = classIDs[index][1];
2017-06-21 21:29:51 +00:00
}
else
{
2018-09-26 21:23:10 +00:00
asset.Type1 = reader.ReadInt32();
asset.Type2 = reader.ReadUInt16();
reader.Position += 2;
2017-06-21 21:29:51 +00:00
}
2018-09-26 21:23:10 +00:00
if (header.m_Version == 15)
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
byte unknownByte = reader.ReadByte();
2017-06-21 21:29:51 +00:00
//this is a single byte, not an int32
//the next entry is aligned after this
//but not the last!
}
2015-10-30 02:41:37 +00:00
2018-03-27 22:29:28 +00:00
if (Enum.IsDefined(typeof(ClassIDReference), asset.Type2))
2017-06-21 21:29:51 +00:00
{
2018-03-27 22:29:28 +00:00
asset.Type = (ClassIDReference)asset.Type2;
asset.TypeString = asset.Type.ToString();
2017-06-21 21:29:51 +00:00
}
else
{
2018-03-27 22:29:28 +00:00
asset.Type = ClassIDReference.UnknownType;
asset.TypeString = "UnknownType " + asset.Type2;
2017-06-21 21:29:51 +00:00
}
2017-06-21 21:29:51 +00:00
asset.uniqueID = i.ToString(assetIDfmt);
2017-11-09 16:04:27 +00:00
asset.fullSize = asset.Size;
2017-06-21 21:29:51 +00:00
asset.sourceFile = this;
2015-10-30 02:41:37 +00:00
2017-06-21 21:29:51 +00:00
preloadTable.Add(asset.m_PathID, asset);
2018-04-02 22:51:22 +00:00
#region read BuildSettings to get version for version 2.x files
2018-09-26 21:23:10 +00:00
if (asset.Type == ClassIDReference.BuildSettings && header.m_Version == 6)
2017-06-21 21:29:51 +00:00
{
2018-09-26 21:23:10 +00:00
long nextAsset = reader.Position;
2015-10-30 02:41:37 +00:00
2017-06-21 21:29:51 +00:00
BuildSettings BSettings = new BuildSettings(asset);
2018-09-26 21:23:10 +00:00
unityVersion = BSettings.m_Version;
2015-10-30 02:41:37 +00:00
2018-09-26 21:23:10 +00:00
reader.Position = nextAsset;
2017-06-21 21:29:51 +00:00
}
#endregion
2015-10-30 02:41:37 +00:00
}
2015-11-02 08:11:26 +00:00
2018-09-26 21:23:10 +00:00
if (header.m_Version >= 14)
2017-06-21 21:29:51 +00:00
{
//this looks like a list of assets that need to be preloaded in memory before anytihng else
2018-09-26 21:23:10 +00:00
int someCount = reader.ReadInt32();
2017-06-21 21:29:51 +00:00
for (int i = 0; i < someCount; i++)
{
2018-09-26 21:23:10 +00:00
int num1 = reader.ReadInt32();
reader.AlignStream(4);
long m_PathID = reader.ReadInt64();
2017-06-21 21:29:51 +00:00
}
}
2018-09-26 21:23:10 +00:00
sharedAssetsList[0].fileName = fileName; //reference itself because sharedFileIDs start from 1
int sharedFileCount = reader.ReadInt32();
2017-06-21 21:29:51 +00:00
for (int i = 0; i < sharedFileCount; i++)
2015-11-02 08:11:26 +00:00
{
2018-04-02 22:51:22 +00:00
var shared = new SharedAssets();
2018-09-26 21:23:10 +00:00
shared.aName = reader.ReadStringToNull();
reader.Position += 20;
var sharedFilePath = reader.ReadStringToNull(); //relative path
2018-02-27 10:20:12 +00:00
shared.fileName = Path.GetFileName(sharedFilePath);
2017-06-21 21:29:51 +00:00
sharedAssetsList.Add(shared);
2015-11-02 08:11:26 +00:00
}
2018-09-26 21:23:10 +00:00
buildType = Regex.Replace(unityVersion, @"\d", "").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
var firstVersion = int.Parse(unityVersion.Split('.')[0]);
version = Regex.Matches(unityVersion, @"\d").Cast<Match>().Select(m => int.Parse(m.Value)).ToArray();
if (firstVersion > 5)//2017 and up
{
var nversion = new int[version.Length - 3];
nversion[0] = firstVersion;
Array.Copy(version, 4, nversion, 1, version.Length - 4);
version = nversion;
}
2017-06-21 21:29:51 +00:00
valid = true;
2015-10-30 02:41:37 +00:00
}
2017-06-21 22:59:16 +00:00
catch
2015-10-30 02:41:37 +00:00
{
}
}
2018-09-26 21:23:10 +00:00
private void ReadTypeTree(List<TypeTree> typeTreeList, int depth)
2015-10-30 02:41:37 +00:00
{
2018-09-26 21:23:10 +00:00
var typeTree = new TypeTree();
typeTreeList.Add(typeTree);
typeTree.m_Depth = depth;
typeTree.m_Type = reader.ReadStringToNull();
typeTree.m_Name = reader.ReadStringToNull();
typeTree.m_ByteSize = reader.ReadInt32();
if (header.m_Version == 2)
{
var variableCount = reader.ReadInt32();
}
if (header.m_Version != 3)
{
typeTree.m_Index = reader.ReadInt32();
}
typeTree.m_IsArray = reader.ReadInt32();
typeTree.m_Version = reader.ReadInt32();
if (header.m_Version != 3)
{
typeTree.m_MetaFlag = reader.ReadInt32();
}
2015-11-02 08:11:26 +00:00
2018-09-26 21:23:10 +00:00
int childrenCount = reader.ReadInt32();
for (int i = 0; i < childrenCount; i++)
2017-01-25 11:38:44 +00:00
{
2018-09-26 21:23:10 +00:00
ReadTypeTree(typeTreeList, depth + 1);
}
2015-10-30 02:41:37 +00:00
}
2018-09-26 21:23:10 +00:00
private void ReadTypeTree5()
2015-10-30 02:41:37 +00:00
{
2018-05-02 18:41:47 +00:00
int classID = reader.ReadInt32();
2018-09-26 21:23:10 +00:00
if (header.m_Version > 15)//5.5.0 and up
2017-01-15 11:57:41 +00:00
{
2018-05-02 18:41:47 +00:00
reader.ReadByte();
2018-09-26 21:23:10 +00:00
int typeID = reader.ReadInt16();
if (typeID >= 0)
2017-01-15 11:57:41 +00:00
{
2018-09-26 21:23:10 +00:00
typeID = -1 - typeID;
2017-01-15 11:57:41 +00:00
}
else
{
2018-09-26 21:23:10 +00:00
typeID = classID;
2017-01-15 11:57:41 +00:00
}
2018-09-26 21:23:10 +00:00
classIDs.Add(new[] { typeID, classID });
2018-01-08 15:53:15 +00:00
if (classID == 114)
2017-02-16 07:30:11 +00:00
{
2018-05-02 18:41:47 +00:00
reader.Position += 16;
2017-02-16 07:30:11 +00:00
}
2018-09-26 21:23:10 +00:00
classID = typeID;
2017-01-15 11:57:41 +00:00
}
2017-02-09 19:49:13 +00:00
else if (classID < 0)
{
2018-05-02 18:41:47 +00:00
reader.Position += 16;
2017-02-09 19:49:13 +00:00
}
2018-05-02 18:41:47 +00:00
reader.Position += 16;
2015-10-30 02:41:37 +00:00
2018-09-26 21:23:10 +00:00
if (serializedTypeTrees)
2015-10-30 02:41:37 +00:00
{
2018-05-02 18:41:47 +00:00
int varCount = reader.ReadInt32();
int stringSize = reader.ReadInt32();
2015-10-30 02:41:37 +00:00
2018-05-02 18:41:47 +00:00
reader.Position += varCount * 24;
using (var stringReader = new BinaryReader(new MemoryStream(reader.ReadBytes(stringSize))))
2015-10-30 02:41:37 +00:00
{
2018-09-26 21:23:10 +00:00
var typeTreeList = new List<TypeTree>();
2018-05-02 18:41:47 +00:00
reader.Position -= varCount * 24 + stringSize;
2018-04-06 15:57:36 +00:00
for (int i = 0; i < varCount; i++)
2018-01-08 15:53:15 +00:00
{
2018-09-26 21:23:10 +00:00
var typeTree = new TypeTree();
typeTreeList.Add(typeTree);
typeTree.m_Version = reader.ReadUInt16();
typeTree.m_Depth = reader.ReadByte();
typeTree.m_IsArray = reader.ReadBoolean() ? 1 : 0;
2018-04-06 15:57:36 +00:00
2018-05-02 18:41:47 +00:00
ushort varTypeIndex = reader.ReadUInt16();
ushort test = reader.ReadUInt16();
2018-04-06 15:57:36 +00:00
if (test == 0) //varType is an offset in the string block
{
stringReader.BaseStream.Position = varTypeIndex;
2018-09-26 21:23:10 +00:00
typeTree.m_Type = stringReader.ReadStringToNull();
2018-04-06 15:57:36 +00:00
}
else //varType is an index in an internal strig array
{
2018-09-26 21:23:10 +00:00
typeTree.m_Type = baseStrings.ContainsKey(varTypeIndex) ? baseStrings[varTypeIndex] : varTypeIndex.ToString();
2018-04-06 15:57:36 +00:00
}
2015-10-30 02:41:37 +00:00
2018-05-02 18:41:47 +00:00
ushort varNameIndex = reader.ReadUInt16();
test = reader.ReadUInt16();
2018-04-06 15:57:36 +00:00
if (test == 0)
{
stringReader.BaseStream.Position = varNameIndex;
2018-09-26 21:23:10 +00:00
typeTree.m_Name = stringReader.ReadStringToNull();
2018-04-06 15:57:36 +00:00
}
else
{
2018-09-26 21:23:10 +00:00
typeTree.m_Name = baseStrings.ContainsKey(varNameIndex) ? baseStrings[varNameIndex] : varNameIndex.ToString();
2018-04-06 15:57:36 +00:00
}
2015-10-30 02:41:37 +00:00
2018-09-26 21:23:10 +00:00
typeTree.m_ByteSize = reader.ReadInt32();
typeTree.m_Index = reader.ReadInt32();
typeTree.m_MetaFlag = reader.ReadInt32();
}
2018-05-02 18:41:47 +00:00
reader.Position += stringSize;
2018-09-26 21:23:10 +00:00
m_Type[classID] = typeTreeList;
2015-10-30 02:41:37 +00:00
}
}
}
}
}