diff --git a/Unity Studio/Unity Studio Classes/Lz4DecoderStream.cs b/Unity Studio/Lz4DecoderStream.cs similarity index 96% rename from Unity Studio/Unity Studio Classes/Lz4DecoderStream.cs rename to Unity Studio/Lz4DecoderStream.cs index 213bd7a..1ff219e 100644 --- a/Unity Studio/Unity Studio Classes/Lz4DecoderStream.cs +++ b/Unity Studio/Lz4DecoderStream.cs @@ -31,9 +31,20 @@ namespace Lz4 inBufEnd = DecBufLen; } - public override void Close() + protected override void Dispose(bool disposing) { - input = null; + try + { + if (disposing && input != null) + { + input.Close(); + } + input = null; + } + finally + { + base.Dispose(disposing); + } } private long inputLength; @@ -500,15 +511,12 @@ namespace Lz4 { } - public override long Length - { - get { throw new NotSupportedException(); } - } + public override long Length => throw new NotSupportedException(); public override long Position { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) diff --git a/Unity Studio/Unity Classes/Shader.cs b/Unity Studio/Unity Classes/Shader.cs index 6051659..68b23d8 100644 --- a/Unity Studio/Unity Classes/Shader.cs +++ b/Unity Studio/Unity Classes/Shader.cs @@ -60,11 +60,9 @@ namespace Unity_Studio var decompressedSize = reader.ReadUInt32(); var m_SubProgramBlob = reader.ReadBytes(reader.ReadInt32()); var decompressedBytes = new byte[decompressedSize]; - using (var mstream = new MemoryStream(m_SubProgramBlob)) + using (var decoder = new Lz4DecoderStream(new MemoryStream(m_SubProgramBlob))) { - var decoder = new Lz4DecoderStream(mstream); decoder.Read(decompressedBytes, 0, (int)decompressedSize); - decoder.Dispose(); } m_Script = m_Script.Concat(decompressedBytes.ToArray()).ToArray(); } diff --git a/Unity Studio/Unity Studio Classes/AssetsFile.cs b/Unity Studio/Unity Studio Classes/AssetsFile.cs index 7b9b456..1aa0387 100644 --- a/Unity Studio/Unity Studio Classes/AssetsFile.cs +++ b/Unity Studio/Unity Studio Classes/AssetsFile.cs @@ -162,7 +162,7 @@ namespace Unity_Studio int dataEnd = assetsFileReader.ReadInt32(); fileGen = assetsFileReader.ReadInt32(); uint dataOffset = assetsFileReader.ReadUInt32(); - sharedAssetsList[0].fileName = Path.GetFileName(fullName); //reference itself because sharedFileIDs start from 1 + sharedAssetsList[0].fileName = fileName; //reference itself because sharedFileIDs start from 1 switch (fileGen) { diff --git a/Unity Studio/Unity Studio Classes/BundleFile.cs b/Unity Studio/Unity Studio Classes/BundleFile.cs index e07d5b2..31ad5c4 100644 --- a/Unity Studio/Unity Studio Classes/BundleFile.cs +++ b/Unity Studio/Unity Studio Classes/BundleFile.cs @@ -5,19 +5,18 @@ using SevenZip.Compression.LZMA; namespace Unity_Studio { + public class MemoryFile + { + public string fileName; + public MemoryStream stream; + } + public class BundleFile { public int format; public string versionPlayer; public string versionEngine; - public List MemoryAssetsFileList = new List(); - - public class MemoryAssetsFile - { - public string fileName; - public MemoryStream memStream; - } - + public List fileList = new List(); public BundleFile(EndianBinaryReader bundleReader) { @@ -92,16 +91,16 @@ namespace Unity_Studio int fileCount = reader.ReadInt32(); for (int i = 0; i < fileCount; i++) { - var memFile = new MemoryAssetsFile(); - memFile.fileName = reader.ReadStringToNull(); + var file = new MemoryFile(); + file.fileName = reader.ReadStringToNull(); int fileOffset = reader.ReadInt32(); fileOffset += offset; int fileSize = reader.ReadInt32(); long nextFile = reader.Position; reader.Position = fileOffset; var buffer = reader.ReadBytes(fileSize); - memFile.memStream = new MemoryStream(buffer); - MemoryAssetsFileList.Add(memFile); + file.stream = new MemoryStream(buffer); + fileList.Add(file); reader.Position = nextFile; } } @@ -143,11 +142,9 @@ namespace Unity_Studio case 3://LZ4HC { byte[] uncompressedBytes = new byte[uncompressedSize]; - using (var mstream = new MemoryStream(blocksInfoBytes)) + using (var decoder = new Lz4DecoderStream(new MemoryStream(blocksInfoBytes))) { - var decoder = new Lz4DecoderStream(mstream); decoder.Read(uncompressedBytes, 0, uncompressedSize); - decoder.Dispose(); } blocksInfoStream = new MemoryStream(uncompressedBytes); break; @@ -188,11 +185,9 @@ namespace Unity_Studio case 3://LZ4HC { var uncompressedBytes = new byte[uncompressedSize]; - using (var mstream = new MemoryStream(compressedBytes)) + using (var decoder = new Lz4DecoderStream(new MemoryStream(compressedBytes))) { - var decoder = new Lz4DecoderStream(mstream); decoder.Read(uncompressedBytes, 0, uncompressedSize); - decoder.Dispose(); } assetsDataStream.Write(uncompressedBytes, 0, uncompressedSize); break; @@ -205,15 +200,15 @@ namespace Unity_Studio var entryinfo_count = blocksInfo.ReadInt32(); for (int i = 0; i < entryinfo_count; i++) { - var memFile = new MemoryAssetsFile(); + var file = new MemoryFile(); var entryinfo_offset = blocksInfo.ReadInt64(); var entryinfo_size = blocksInfo.ReadInt64(); flag = blocksInfo.ReadInt32(); - memFile.fileName = blocksInfo.ReadStringToNull(); + file.fileName = Path.GetFileName(blocksInfo.ReadStringToNull()); assetsDataReader.Position = entryinfo_offset; var buffer = assetsDataReader.ReadBytes((int)entryinfo_size); - memFile.memStream = new MemoryStream(buffer); - MemoryAssetsFileList.Add(memFile); + file.stream = new MemoryStream(buffer); + fileList.Add(file); } } } diff --git a/Unity Studio/Unity Studio Classes/UnityImporter.cs b/Unity Studio/Unity Studio Classes/UnityImporter.cs index 8d66ac4..bf2deca 100644 --- a/Unity Studio/Unity Studio Classes/UnityImporter.cs +++ b/Unity Studio/Unity Studio Classes/UnityImporter.cs @@ -16,13 +16,17 @@ namespace Unity_Studio public static void LoadFile(string fullName) { - if (CheckBundleFile(fullName, out var reader)) + switch (CheckFileType(fullName, out var reader)) { - LoadBundleFile(fullName, reader); - } - else - { - LoadAssetsFile(fullName, reader); + case FileType.AssetsFile: + LoadAssetsFile(fullName, reader); + break; + case FileType.BundleFile: + LoadBundleFile(fullName, reader); + break; + case FileType.WebFile: + LoadWebFile(fullName, reader); + break; } } @@ -94,12 +98,12 @@ namespace Unity_Studio var fileName = Path.GetFileName(fullName); StatusStripUpdate("Decompressing " + fileName); var bundleFile = new BundleFile(reader); - foreach (var memFile in bundleFile.MemoryAssetsFileList) + foreach (var file in bundleFile.fileList) { - if (!assetsfileListHash.Contains(memFile.fileName.ToUpper())) + if (!assetsfileListHash.Contains(file.fileName.ToUpper())) { - StatusStripUpdate("Loading " + memFile.fileName); - var assetsFile = new AssetsFile(Path.GetDirectoryName(fullName) + "\\" + memFile.fileName, new EndianBinaryReader(memFile.memStream)); + StatusStripUpdate("Loading " + file.fileName); + var assetsFile = new AssetsFile(Path.GetDirectoryName(fullName) + "\\" + file.fileName, new EndianBinaryReader(file.stream)); if (assetsFile.valid) { assetsFile.bundlePath = fullName; @@ -124,6 +128,30 @@ namespace Unity_Studio reader.Dispose(); } + private static void LoadWebFile(string fullName, EndianBinaryReader reader) + { + var fileName = Path.GetFileName(fullName); + StatusStripUpdate("Loading " + fileName); + var bundleFile = new WebFile(reader); + reader.Dispose(); + foreach (var file in bundleFile.fileList) + { + var dummyName = Path.GetDirectoryName(fullName) + "\\" + file.fileName; + switch (CheckFileType(file.stream, out reader)) + { + case FileType.AssetsFile: + LoadAssetsFile(dummyName, reader); + break; + case FileType.BundleFile: + LoadBundleFile(dummyName, reader); + break; + case FileType.WebFile: + LoadWebFile(dummyName, reader); + break; + } + } + } + public static void MergeSplitAssets(string dirPath) { string[] splitFiles = Directory.GetFiles(dirPath, "*.split0"); diff --git a/Unity Studio/Unity Studio Classes/UnityStudio.cs b/Unity Studio/Unity Studio Classes/UnityStudio.cs index 81ad526..1770d8a 100644 --- a/Unity Studio/Unity Studio Classes/UnityStudio.cs +++ b/Unity Studio/Unity Studio Classes/UnityStudio.cs @@ -29,17 +29,23 @@ namespace Unity_Studio public static Action StatusStripUpdate; public static Action ProgressBarMaximumAdd; + public enum FileType + { + AssetsFile, + BundleFile, + WebFile + } public static int ExtractBundleFile(string bundleFileName) { int extractedCount = 0; - if (CheckBundleFile(bundleFileName, out var reader)) + if (CheckFileType(bundleFileName, out var reader) == FileType.BundleFile) { StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ..."); var extractPath = bundleFileName + "_unpacked\\"; Directory.CreateDirectory(extractPath); var bundleFile = new BundleFile(reader); - foreach (var memFile in bundleFile.MemoryAssetsFileList) + foreach (var memFile in bundleFile.fileList) { var filePath = extractPath + memFile.fileName.Replace('/', '\\'); if (!Directory.Exists(Path.GetDirectoryName(filePath))) @@ -52,8 +58,8 @@ namespace Unity_Studio extractedCount += 1; using (var file = File.Create(filePath)) { - memFile.memStream.WriteTo(file); - memFile.memStream.Close(); + memFile.stream.WriteTo(file); + memFile.stream.Close(); } } } @@ -355,9 +361,20 @@ namespace Unity_Studio return Path.GetInvalidFileNameChars().Aggregate(str, (current, c) => current.Replace(c, '_')); } - public static bool CheckBundleFile(string fileName, out EndianBinaryReader reader) + public static FileType CheckFileType(MemoryStream stream, out EndianBinaryReader reader) + { + reader = new EndianBinaryReader(stream); + return CheckFileType(reader); + } + + public static FileType CheckFileType(string fileName, out EndianBinaryReader reader) { reader = new EndianBinaryReader(File.OpenRead(fileName)); + return CheckFileType(reader); + } + + public static FileType CheckFileType(EndianBinaryReader reader) + { var signature = reader.ReadStringToNull(); reader.Position = 0; switch (signature) @@ -366,9 +383,20 @@ namespace Unity_Studio case "UnityRaw": case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA": case "UnityFS": - return true; + return FileType.BundleFile; + case "UnityWebData1.0": + return FileType.WebFile; default: - return false; + { + var magic = reader.ReadBytes(2); + reader.Position = 0; + if (WebFile.gzipMagic.SequenceEqual(magic)) + { + return FileType.WebFile; + } + + return FileType.AssetsFile; + } } } diff --git a/Unity Studio/Unity Studio Classes/WebFile.cs b/Unity Studio/Unity Studio Classes/WebFile.cs new file mode 100644 index 0000000..c43cd5b --- /dev/null +++ b/Unity Studio/Unity Studio Classes/WebFile.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class WebFile + { + public static byte[] gzipMagic = { 0x1f, 0x8b }; + public List fileList = new List(); + + + public class WebData + { + public int dataOffset; + public int dataLength; + public string path; + } + + + public WebFile(EndianBinaryReader reader) + { + var magic = reader.ReadBytes(2); + reader.Position = 0; + if (gzipMagic.SequenceEqual(magic)) + { + var stream = new MemoryStream(); + using (var gstream = new GZipStream(reader.BaseStream, CompressionMode.Decompress)) + { + gstream.CopyTo(stream); + } + stream.Position = 0; + using (reader = new EndianBinaryReader(stream, EndianType.LittleEndian)) + { + ReadUnityWebData(reader); + } + } + else + { + ReadUnityWebData(reader); + } + } + + private void ReadUnityWebData(EndianBinaryReader reader) + { + var signature = reader.ReadStringToNull(); + if (signature != "UnityWebData1.0") + return; + var headLength = reader.ReadInt32(); + var dataList = new List(); + while (reader.Position < headLength) + { + var data = new WebData(); + data.dataOffset = reader.ReadInt32(); + data.dataLength = reader.ReadInt32(); + var pathLength = reader.ReadInt32(); + data.path = Encoding.UTF8.GetString(reader.ReadBytes(pathLength)); + dataList.Add(data); + } + + foreach (var data in dataList) + { + var file = new MemoryFile(); + file.fileName = Path.GetFileName(data.path); + reader.Position = data.dataOffset; + file.stream = new MemoryStream(reader.ReadBytes(data.dataLength)); + fileList.Add(file); + } + } + } +} diff --git a/Unity Studio/Unity Studio-x86.csproj b/Unity Studio/Unity Studio-x86.csproj index 565180a..9f9cf52 100644 --- a/Unity Studio/Unity Studio-x86.csproj +++ b/Unity Studio/Unity Studio-x86.csproj @@ -169,7 +169,7 @@ Component - + @@ -187,6 +187,7 @@ + Form diff --git a/Unity Studio/Unity Studio.csproj b/Unity Studio/Unity Studio.csproj index 69250bf..06e41a2 100644 --- a/Unity Studio/Unity Studio.csproj +++ b/Unity Studio/Unity Studio.csproj @@ -169,7 +169,7 @@ Component - + @@ -187,6 +187,7 @@ + Form