mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
Fixes & Cleanup
This commit is contained in:
parent
0d2aebc1f4
commit
2f6d9ec77f
@ -53,21 +53,21 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public void LoadFilesAndFolders(params string[] path)
|
public void LoadFilesAndFolders(params string[] path)
|
||||||
{
|
{
|
||||||
List<string> pathList = new List<string>();
|
var pathList = new List<string>();
|
||||||
pathList.AddRange(path);
|
pathList.AddRange(path);
|
||||||
LoadFilesAndFolders(out _, pathList);
|
LoadFilesAndFolders(out _, pathList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadFilesAndFolders(out string parentPath, params string[] path)
|
public void LoadFilesAndFolders(out string parentPath, params string[] path)
|
||||||
{
|
{
|
||||||
List<string> pathList = new List<string>();
|
var pathList = new List<string>();
|
||||||
pathList.AddRange(path);
|
pathList.AddRange(path);
|
||||||
LoadFilesAndFolders(out parentPath, pathList);
|
LoadFilesAndFolders(out parentPath, pathList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadFilesAndFolders(out string parentPath, List<string> pathList)
|
public void LoadFilesAndFolders(out string parentPath, List<string> pathList)
|
||||||
{
|
{
|
||||||
List<string> fileList = new List<string>();
|
var fileList = new List<string>();
|
||||||
bool filesInPath = false;
|
bool filesInPath = false;
|
||||||
parentPath = "";
|
parentPath = "";
|
||||||
foreach (var path in pathList)
|
foreach (var path in pathList)
|
||||||
@ -113,8 +113,14 @@ namespace AssetStudio
|
|||||||
//use a for loop because list size can change
|
//use a for loop because list size can change
|
||||||
for (var i = 0; i < importFiles.Count; i++)
|
for (var i = 0; i < importFiles.Count; i++)
|
||||||
{
|
{
|
||||||
LoadFile(importFiles[i]);
|
if (LoadFile(importFiles[i]))
|
||||||
Progress.Report(i + 1, importFiles.Count);
|
{
|
||||||
|
Progress.Report(i + 1, importFiles.Count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
importFiles.Clear();
|
importFiles.Clear();
|
||||||
@ -126,13 +132,13 @@ namespace AssetStudio
|
|||||||
ProcessAssets();
|
ProcessAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadFile(string fullName)
|
private bool LoadFile(string fullName)
|
||||||
{
|
{
|
||||||
var reader = new FileReader(fullName);
|
var reader = new FileReader(fullName);
|
||||||
LoadFile(reader);
|
return LoadFile(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadFile(FileReader reader)
|
private bool LoadFile(FileReader reader)
|
||||||
{
|
{
|
||||||
switch (reader?.FileType)
|
switch (reader?.FileType)
|
||||||
{
|
{
|
||||||
@ -140,8 +146,7 @@ namespace AssetStudio
|
|||||||
LoadAssetsFile(reader);
|
LoadAssetsFile(reader);
|
||||||
break;
|
break;
|
||||||
case FileType.BundleFile:
|
case FileType.BundleFile:
|
||||||
LoadBundleFile(reader);
|
return LoadBundleFile(reader);
|
||||||
break;
|
|
||||||
case FileType.WebFile:
|
case FileType.WebFile:
|
||||||
LoadWebFile(reader);
|
LoadWebFile(reader);
|
||||||
break;
|
break;
|
||||||
@ -154,7 +159,10 @@ namespace AssetStudio
|
|||||||
case FileType.ZipFile:
|
case FileType.ZipFile:
|
||||||
LoadZipFile(reader);
|
LoadZipFile(reader);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadAssetsFile(FileReader reader)
|
private void LoadAssetsFile(FileReader reader)
|
||||||
@ -248,7 +256,7 @@ namespace AssetStudio
|
|||||||
Logger.Info($"Skipping {originalPath} ({reader.FileName})");
|
Logger.Info($"Skipping {originalPath} ({reader.FileName})");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadBundleFile(FileReader reader, string originalPath = null)
|
private bool LoadBundleFile(FileReader reader, string originalPath = null)
|
||||||
{
|
{
|
||||||
Logger.Info("Loading " + reader.FullPath);
|
Logger.Info("Loading " + reader.FullPath);
|
||||||
try
|
try
|
||||||
@ -267,10 +275,12 @@ namespace AssetStudio
|
|||||||
resourceFileReaders.Add(file.fileName, subReader);
|
resourceFileReaders.Add(file.fileName, subReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (NotSupportedException e)
|
catch (NotSupportedException e)
|
||||||
{
|
{
|
||||||
Logger.Error(e.Message);
|
Logger.Error(e.Message);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -280,6 +290,7 @@ namespace AssetStudio
|
|||||||
str += $" from {Path.GetFileName(originalPath)}";
|
str += $" from {Path.GetFileName(originalPath)}";
|
||||||
}
|
}
|
||||||
Logger.Warning($"{str}\r\n{e}");
|
Logger.Warning($"{str}\r\n{e}");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,11 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public static class BigArrayPool<T>
|
public static class BigArrayPool<T>
|
||||||
{
|
{
|
||||||
private static readonly ArrayPool<T> s_shared = ArrayPool<T>.Create(64 * 1024 * 1024, 3);
|
public static ArrayPool<T> Shared { get; }
|
||||||
public static ArrayPool<T> Shared => s_shared;
|
|
||||||
|
static BigArrayPool()
|
||||||
|
{
|
||||||
|
Shared = ArrayPool<T>.Create(256 * 1024 * 1024, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@ -100,16 +101,16 @@ namespace AssetStudio
|
|||||||
case "UnityFS":
|
case "UnityFS":
|
||||||
ReadHeader(reader);
|
ReadHeader(reader);
|
||||||
|
|
||||||
bool isUnityCnEnc = false;
|
var isUnityCnEnc = false;
|
||||||
string unityVer = string.IsNullOrEmpty(specUnityVer) ? m_Header.unityRevision : specUnityVer;
|
var unityVerStr = string.IsNullOrEmpty(specUnityVer) ? m_Header.unityRevision : specUnityVer;
|
||||||
int[] ver = new string(unityVer.SkipWhile(x => !char.IsDigit(x)).TakeWhile(x => char.IsDigit(x) || x == '.').ToArray()).Split('.').Select(x => int.Parse(x)).ToArray();
|
int[] ver = Regex.Matches(unityVerStr, @"\d+").Cast<Match>().Select(x => int.Parse(x.Value)).ToArray();
|
||||||
if (ver[0] != 0)
|
if (ver.Length > 0 && ver[0] != 0)
|
||||||
{
|
{
|
||||||
// https://issuetracker.unity3d.com/issues/files-within-assetbundles-do-not-start-on-aligned-boundaries-breaking-patching-on-nintendo-switch
|
// https://issuetracker.unity3d.com/issues/files-within-assetbundles-do-not-start-on-aligned-boundaries-breaking-patching-on-nintendo-switch
|
||||||
if (ver[0] < 2020 ||
|
if (ver[0] < 2020
|
||||||
(ver[0] == 2020 && ver[1] <= 3 && ver[2] < 34) ||
|
|| (ver[0] == 2020 && ver[1] <= 3 && ver[2] < 34)
|
||||||
(ver[0] == 2021 && ver[1] <= 3 && ver[2] < 2) ||
|
|| (ver[0] == 2021 && ver[1] <= 3 && ver[2] < 2)
|
||||||
(ver[0] == 2022 && ver[1] <= 1 && ver[2] < 1))
|
|| (ver[0] == 2022 && ver[1] <= 1 && ver[2] < 1))
|
||||||
{
|
{
|
||||||
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.OldFlag) != 0;
|
isUnityCnEnc = ((CnEncryptionFlags)m_Header.flags & CnEncryptionFlags.OldFlag) != 0;
|
||||||
}
|
}
|
||||||
@ -133,7 +134,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
|
private void ReadHeaderAndBlocksInfo(FileReader reader)
|
||||||
{
|
{
|
||||||
if (m_Header.version >= 4)
|
if (m_Header.version >= 4)
|
||||||
{
|
{
|
||||||
@ -185,7 +186,7 @@ namespace AssetStudio
|
|||||||
return blocksStream;
|
return blocksStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
|
private void ReadBlocksAndDirectory(FileReader reader, Stream blocksStream)
|
||||||
{
|
{
|
||||||
var isCompressed = m_Header.signature == "UnityWeb";
|
var isCompressed = m_Header.signature == "UnityWeb";
|
||||||
foreach (var blockInfo in m_BlocksInfo)
|
foreach (var blockInfo in m_BlocksInfo)
|
||||||
@ -246,7 +247,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadHeader(EndianBinaryReader reader)
|
private void ReadHeader(FileReader reader)
|
||||||
{
|
{
|
||||||
m_Header.size = reader.ReadInt64();
|
m_Header.size = reader.ReadInt64();
|
||||||
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
||||||
@ -258,7 +259,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader, int[] unityVer)
|
private void ReadBlocksInfoAndDirectory(FileReader reader, int[] unityVer)
|
||||||
{
|
{
|
||||||
byte[] blocksInfoBytes;
|
byte[] blocksInfoBytes;
|
||||||
|
|
||||||
@ -290,42 +291,44 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||||
}
|
}
|
||||||
MemoryStream blocksInfoUncompresseddStream;
|
MemoryStream blocksInfoUncompressedStream;
|
||||||
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
|
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
|
||||||
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
|
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
|
||||||
switch (compressionType)
|
switch (compressionType)
|
||||||
{
|
{
|
||||||
case CompressionType.None:
|
case CompressionType.None:
|
||||||
{
|
{
|
||||||
blocksInfoUncompresseddStream = new MemoryStream(blocksInfoBytes);
|
blocksInfoUncompressedStream = new MemoryStream(blocksInfoBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CompressionType.Lzma:
|
case CompressionType.Lzma:
|
||||||
|
{
|
||||||
|
blocksInfoUncompressedStream = new MemoryStream((int) (uncompressedSize));
|
||||||
|
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
|
||||||
{
|
{
|
||||||
blocksInfoUncompresseddStream = new MemoryStream((int)(uncompressedSize));
|
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompressedStream,
|
||||||
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
|
m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
||||||
{
|
|
||||||
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
|
||||||
}
|
|
||||||
blocksInfoUncompresseddStream.Position = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
blocksInfoUncompressedStream.Position = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CompressionType.Lz4:
|
case CompressionType.Lz4:
|
||||||
case CompressionType.Lz4HC:
|
case CompressionType.Lz4HC:
|
||||||
|
{
|
||||||
|
var uncompressedBytes = new byte[uncompressedSize];
|
||||||
|
var numWrite = LZ4Codec.Decode(blocksInfoBytes, uncompressedBytes);
|
||||||
|
if (numWrite != uncompressedSize)
|
||||||
{
|
{
|
||||||
var uncompressedBytes = new byte[uncompressedSize];
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
var numWrite = LZ4Codec.Decode(blocksInfoBytes, uncompressedBytes);
|
|
||||||
if (numWrite != uncompressedSize)
|
|
||||||
{
|
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
|
||||||
}
|
|
||||||
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytes);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
blocksInfoUncompressedStream = new MemoryStream(uncompressedBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new IOException($"Unsupported compression type {compressionType}");
|
throw new IOException($"Unsupported compression type {compressionType}");
|
||||||
}
|
}
|
||||||
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream))
|
|
||||||
|
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompressedStream))
|
||||||
{
|
{
|
||||||
var uncompressedDataHash = blocksInfoReader.ReadBytes(16);
|
var uncompressedDataHash = blocksInfoReader.ReadBytes(16);
|
||||||
var blocksInfoCount = blocksInfoReader.ReadInt32();
|
var blocksInfoCount = blocksInfoReader.ReadInt32();
|
||||||
@ -359,7 +362,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
|
private void ReadBlocks(FileReader reader, Stream blocksStream)
|
||||||
{
|
{
|
||||||
foreach (var blockInfo in m_BlocksInfo)
|
foreach (var blockInfo in m_BlocksInfo)
|
||||||
{
|
{
|
||||||
@ -367,33 +370,39 @@ namespace AssetStudio
|
|||||||
switch (compressionType)
|
switch (compressionType)
|
||||||
{
|
{
|
||||||
case CompressionType.None:
|
case CompressionType.None:
|
||||||
{
|
{
|
||||||
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
|
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CompressionType.Lzma:
|
case CompressionType.Lzma:
|
||||||
{
|
{
|
||||||
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CompressionType.Lz4:
|
case CompressionType.Lz4:
|
||||||
case CompressionType.Lz4HC:
|
case CompressionType.Lz4HC:
|
||||||
|
{
|
||||||
|
var compressedSize = (int)blockInfo.compressedSize;
|
||||||
|
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
||||||
|
_ = reader.Read(compressedBytes, 0, compressedSize);
|
||||||
|
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||||
|
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var compressedSize = (int)blockInfo.compressedSize;
|
|
||||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
|
||||||
reader.Read(compressedBytes, 0, compressedSize);
|
|
||||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
|
||||||
var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
||||||
if (numWrite != uncompressedSize)
|
if (numWrite != uncompressedSize)
|
||||||
{
|
{
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
}
|
}
|
||||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
||||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
BigArrayPool<byte>.Shared.Return(compressedBytes, clearArray: true);
|
||||||
|
BigArrayPool<byte>.Shared.Return(uncompressedBytes, clearArray: true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new IOException($"Unsupported compression type {compressionType}");
|
throw new IOException($"Unsupported compression type {compressionType}");
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,6 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
reader.AlignStream();
|
reader.AlignStream();
|
||||||
var m_MipmapLimitGroupName = reader.ReadAlignedString();
|
var m_MipmapLimitGroupName = reader.ReadAlignedString();
|
||||||
reader.AlignStream();
|
|
||||||
}
|
}
|
||||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||||
{
|
{
|
||||||
|
22
AssetStudio/EndianSpanReader.cs
Normal file
22
AssetStudio/EndianSpanReader.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class EndianSpanReader
|
||||||
|
{
|
||||||
|
public static uint SpanToUint32(Span<byte> data, int start, bool isBigEndian)
|
||||||
|
{
|
||||||
|
return isBigEndian
|
||||||
|
? BinaryPrimitives.ReadUInt32BigEndian(data.Slice(start))
|
||||||
|
: BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(start));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long SpanToInt64(Span<byte> data, int start, bool isBigEndian)
|
||||||
|
{
|
||||||
|
return isBigEndian
|
||||||
|
? BinaryPrimitives.ReadInt64BigEndian(data.Slice(start))
|
||||||
|
: BinaryPrimitives.ReadInt64LittleEndian(data.Slice(start));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,7 @@ namespace AssetStudio
|
|||||||
if (encoding?.CodePage == 1200) //Unicode (UTF-16LE)
|
if (encoding?.CodePage == 1200) //Unicode (UTF-16LE)
|
||||||
return reader.ReadUnicodeStringToNull(maxLength * 2);
|
return reader.ReadUnicodeStringToNull(maxLength * 2);
|
||||||
|
|
||||||
var bytes = new List<byte>();
|
Span<byte> bytes = stackalloc byte[maxLength];
|
||||||
var count = 0;
|
var count = 0;
|
||||||
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||||
{
|
{
|
||||||
@ -49,9 +49,10 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytes.Add(b);
|
bytes[count] = b;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
bytes = bytes.Slice(0, count);
|
||||||
return encoding?.GetString(bytes.ToArray()) ?? Encoding.UTF8.GetString(bytes.ToArray());
|
return encoding?.GetString(bytes.ToArray()) ?? Encoding.UTF8.GetString(bytes.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
|
using static AssetStudio.EndianSpanReader;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@ -37,66 +38,69 @@ namespace AssetStudio
|
|||||||
case "UnityWebData1.0":
|
case "UnityWebData1.0":
|
||||||
return FileType.WebFile;
|
return FileType.WebFile;
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
|
var buff = ReadBytes(40).AsSpan();
|
||||||
|
var magic = Span<byte>.Empty;
|
||||||
|
Position = 0;
|
||||||
|
|
||||||
|
magic = buff.Length > 2 ? buff.Slice(0, 2) : magic;
|
||||||
|
if (magic.SequenceEqual(gzipMagic))
|
||||||
{
|
{
|
||||||
byte[] magic = ReadBytes(2);
|
return FileType.GZipFile;
|
||||||
Position = 0;
|
|
||||||
if (gzipMagic.SequenceEqual(magic))
|
|
||||||
{
|
|
||||||
return FileType.GZipFile;
|
|
||||||
}
|
|
||||||
Position = 0x20;
|
|
||||||
magic = ReadBytes(6);
|
|
||||||
Position = 0;
|
|
||||||
if (brotliMagic.SequenceEqual(magic))
|
|
||||||
{
|
|
||||||
return FileType.BrotliFile;
|
|
||||||
}
|
|
||||||
if (IsSerializedFile())
|
|
||||||
{
|
|
||||||
return FileType.AssetsFile;
|
|
||||||
}
|
|
||||||
magic = ReadBytes(4);
|
|
||||||
Position = 0;
|
|
||||||
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
|
|
||||||
return FileType.ZipFile;
|
|
||||||
return FileType.ResourceFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
magic = buff.Length > 38 ? buff.Slice(32, 6) : magic;
|
||||||
|
if (magic.SequenceEqual(brotliMagic))
|
||||||
|
{
|
||||||
|
return FileType.BrotliFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsSerializedFile(buff))
|
||||||
|
{
|
||||||
|
return FileType.AssetsFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
magic = buff.Length > 4 ? buff.Slice(0, 4): magic;
|
||||||
|
if (magic.SequenceEqual(zipMagic) || magic.SequenceEqual(zipSpannedMagic))
|
||||||
|
{
|
||||||
|
return FileType.ZipFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileType.ResourceFile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsSerializedFile()
|
private bool IsSerializedFile(Span<byte> buff)
|
||||||
{
|
{
|
||||||
var fileSize = BaseStream.Length;
|
var fileSize = BaseStream.Length;
|
||||||
if (fileSize < 20)
|
if (fileSize < 20)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var m_MetadataSize = ReadUInt32();
|
var isBigEndian = Endian == EndianType.BigEndian;
|
||||||
long m_FileSize = ReadUInt32();
|
|
||||||
var m_Version = ReadUInt32();
|
//var m_MetadataSize = SpanToUint32(buff, 0, isBigEndian);
|
||||||
long m_DataOffset = ReadUInt32();
|
long m_FileSize = SpanToUint32(buff, 4, isBigEndian);
|
||||||
var m_Endianess = ReadByte();
|
var m_Version = SpanToUint32(buff, 8, isBigEndian);
|
||||||
var m_Reserved = ReadBytes(3);
|
long m_DataOffset = SpanToUint32(buff, 12, isBigEndian);
|
||||||
|
//var m_Endianess = buff[16];
|
||||||
|
//var m_Reserved = buff.Slice(17, 3);
|
||||||
if (m_Version >= 22)
|
if (m_Version >= 22)
|
||||||
{
|
{
|
||||||
if (fileSize < 48)
|
if (fileSize < 48)
|
||||||
{
|
{
|
||||||
Position = 0;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_MetadataSize = ReadUInt32();
|
//m_MetadataSize = SpanToUint32(buff, 20, isBigEndian);
|
||||||
m_FileSize = ReadInt64();
|
m_FileSize = SpanToInt64(buff, 24, isBigEndian);
|
||||||
m_DataOffset = ReadInt64();
|
m_DataOffset = SpanToInt64(buff, 32, isBigEndian);
|
||||||
}
|
}
|
||||||
Position = 0;
|
if (m_FileSize != fileSize || m_DataOffset > fileSize)
|
||||||
if (m_FileSize != fileSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (m_DataOffset > fileSize)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,6 @@ namespace AssetStudioGUI
|
|||||||
public Bitmap Bitmap => m_bitmap;
|
public Bitmap Bitmap => m_bitmap;
|
||||||
|
|
||||||
private Bitmap m_bitmap;
|
private Bitmap m_bitmap;
|
||||||
private readonly GCHandle m_handle;
|
private GCHandle m_handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace AssetStudio
|
|||||||
private TextureFormat m_TextureFormat;
|
private TextureFormat m_TextureFormat;
|
||||||
private int[] version;
|
private int[] version;
|
||||||
private BuildTarget platform;
|
private BuildTarget platform;
|
||||||
private int outPutSize;
|
public int outPutSize;
|
||||||
|
|
||||||
public Texture2DConverter(Texture2D m_Texture2D)
|
public Texture2DConverter(Texture2D m_Texture2D)
|
||||||
{
|
{
|
||||||
@ -33,183 +33,189 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
var flag = false;
|
var flag = false;
|
||||||
var buff = BigArrayPool<byte>.Shared.Rent(reader.Size);
|
var buff = BigArrayPool<byte>.Shared.Rent(reader.Size);
|
||||||
reader.GetData(buff);
|
try
|
||||||
switch (m_TextureFormat)
|
|
||||||
{
|
{
|
||||||
case TextureFormat.Alpha8: //test pass
|
reader.GetData(buff);
|
||||||
flag = DecodeAlpha8(buff, bytes);
|
switch (m_TextureFormat)
|
||||||
break;
|
{
|
||||||
case TextureFormat.ARGB4444: //test pass
|
case TextureFormat.Alpha8: //test pass
|
||||||
SwapBytesForXbox(buff);
|
flag = DecodeAlpha8(buff, bytes);
|
||||||
flag = DecodeARGB4444(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.ARGB4444: //test pass
|
||||||
case TextureFormat.RGB24: //test pass
|
SwapBytesForXbox(buff);
|
||||||
flag = DecodeRGB24(buff, bytes);
|
flag = DecodeARGB4444(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGBA32: //test pass
|
case TextureFormat.RGB24: //test pass
|
||||||
flag = DecodeRGBA32(buff, bytes);
|
flag = DecodeRGB24(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ARGB32: //test pass
|
case TextureFormat.RGBA32: //test pass
|
||||||
flag = DecodeARGB32(buff, bytes);
|
flag = DecodeRGBA32(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGB565: //test pass
|
case TextureFormat.ARGB32: //test pass
|
||||||
SwapBytesForXbox(buff);
|
flag = DecodeARGB32(buff, bytes);
|
||||||
flag = DecodeRGB565(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.RGB565: //test pass
|
||||||
case TextureFormat.R16: //test pass
|
SwapBytesForXbox(buff);
|
||||||
flag = DecodeR16(buff, bytes);
|
flag = DecodeRGB565(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.DXT1: //test pass
|
case TextureFormat.R16: //test pass
|
||||||
SwapBytesForXbox(buff);
|
flag = DecodeR16(buff, bytes);
|
||||||
flag = DecodeDXT1(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.DXT1: //test pass
|
||||||
case TextureFormat.DXT3:
|
SwapBytesForXbox(buff);
|
||||||
break;
|
flag = DecodeDXT1(buff, bytes);
|
||||||
case TextureFormat.DXT5: //test pass
|
break;
|
||||||
SwapBytesForXbox(buff);
|
case TextureFormat.DXT3:
|
||||||
flag = DecodeDXT5(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.DXT5: //test pass
|
||||||
case TextureFormat.RGBA4444: //test pass
|
SwapBytesForXbox(buff);
|
||||||
flag = DecodeRGBA4444(buff, bytes);
|
flag = DecodeDXT5(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.BGRA32: //test pass
|
case TextureFormat.RGBA4444: //test pass
|
||||||
flag = DecodeBGRA32(buff, bytes);
|
flag = DecodeRGBA4444(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RHalf:
|
case TextureFormat.BGRA32: //test pass
|
||||||
flag = DecodeRHalf(buff, bytes);
|
flag = DecodeBGRA32(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGHalf:
|
case TextureFormat.RHalf:
|
||||||
flag = DecodeRGHalf(buff, bytes);
|
flag = DecodeRHalf(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGBAHalf: //test pass
|
case TextureFormat.RGHalf:
|
||||||
flag = DecodeRGBAHalf(buff, bytes);
|
flag = DecodeRGHalf(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RFloat:
|
case TextureFormat.RGBAHalf: //test pass
|
||||||
flag = DecodeRFloat(buff, bytes);
|
flag = DecodeRGBAHalf(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGFloat:
|
case TextureFormat.RFloat:
|
||||||
flag = DecodeRGFloat(buff, bytes);
|
flag = DecodeRFloat(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGBAFloat:
|
case TextureFormat.RGFloat:
|
||||||
flag = DecodeRGBAFloat(buff, bytes);
|
flag = DecodeRGFloat(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.YUY2: //test pass
|
case TextureFormat.RGBAFloat:
|
||||||
flag = DecodeYUY2(buff, bytes);
|
flag = DecodeRGBAFloat(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGB9e5Float: //test pass
|
case TextureFormat.YUY2: //test pass
|
||||||
flag = DecodeRGB9e5Float(buff, bytes);
|
flag = DecodeYUY2(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.BC6H: //test pass
|
case TextureFormat.RGB9e5Float: //test pass
|
||||||
flag = DecodeBC6H(buff, bytes);
|
flag = DecodeRGB9e5Float(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.BC7: //test pass
|
case TextureFormat.BC6H: //test pass
|
||||||
flag = DecodeBC7(buff, bytes);
|
flag = DecodeBC6H(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.BC4: //test pass
|
case TextureFormat.BC7: //test pass
|
||||||
flag = DecodeBC4(buff, bytes);
|
flag = DecodeBC7(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.BC5: //test pass
|
case TextureFormat.BC4: //test pass
|
||||||
flag = DecodeBC5(buff, bytes);
|
flag = DecodeBC4(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.DXT1Crunched: //test pass
|
case TextureFormat.BC5: //test pass
|
||||||
flag = DecodeDXT1Crunched(buff, bytes);
|
flag = DecodeBC5(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.DXT5Crunched: //test pass
|
case TextureFormat.DXT1Crunched: //test pass
|
||||||
flag = DecodeDXT5Crunched(buff, bytes);
|
flag = DecodeDXT1Crunched(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.PVRTC_RGB2: //test pass
|
case TextureFormat.DXT5Crunched: //test pass
|
||||||
case TextureFormat.PVRTC_RGBA2: //test pass
|
flag = DecodeDXT5Crunched(buff, bytes);
|
||||||
flag = DecodePVRTC(buff, bytes, true);
|
break;
|
||||||
break;
|
case TextureFormat.PVRTC_RGB2: //test pass
|
||||||
case TextureFormat.PVRTC_RGB4: //test pass
|
case TextureFormat.PVRTC_RGBA2: //test pass
|
||||||
case TextureFormat.PVRTC_RGBA4: //test pass
|
flag = DecodePVRTC(buff, bytes, true);
|
||||||
flag = DecodePVRTC(buff, bytes, false);
|
break;
|
||||||
break;
|
case TextureFormat.PVRTC_RGB4: //test pass
|
||||||
case TextureFormat.ETC_RGB4: //test pass
|
case TextureFormat.PVRTC_RGBA4: //test pass
|
||||||
case TextureFormat.ETC_RGB4_3DS:
|
flag = DecodePVRTC(buff, bytes, false);
|
||||||
flag = DecodeETC1(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.ETC_RGB4: //test pass
|
||||||
case TextureFormat.ATC_RGB4: //test pass
|
case TextureFormat.ETC_RGB4_3DS:
|
||||||
flag = DecodeATCRGB4(buff, bytes);
|
flag = DecodeETC1(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ATC_RGBA8: //test pass
|
case TextureFormat.ATC_RGB4: //test pass
|
||||||
flag = DecodeATCRGBA8(buff, bytes);
|
flag = DecodeATCRGB4(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.EAC_R: //test pass
|
case TextureFormat.ATC_RGBA8: //test pass
|
||||||
flag = DecodeEACR(buff, bytes);
|
flag = DecodeATCRGBA8(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.EAC_R_SIGNED:
|
case TextureFormat.EAC_R: //test pass
|
||||||
flag = DecodeEACRSigned(buff, bytes);
|
flag = DecodeEACR(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.EAC_RG: //test pass
|
case TextureFormat.EAC_R_SIGNED:
|
||||||
flag = DecodeEACRG(buff, bytes);
|
flag = DecodeEACRSigned(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.EAC_RG_SIGNED:
|
case TextureFormat.EAC_RG: //test pass
|
||||||
flag = DecodeEACRGSigned(buff, bytes);
|
flag = DecodeEACRG(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ETC2_RGB: //test pass
|
case TextureFormat.EAC_RG_SIGNED:
|
||||||
flag = DecodeETC2(buff, bytes);
|
flag = DecodeEACRGSigned(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ETC2_RGBA1: //test pass
|
case TextureFormat.ETC2_RGB: //test pass
|
||||||
flag = DecodeETC2A1(buff, bytes);
|
flag = DecodeETC2(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ETC2_RGBA8: //test pass
|
case TextureFormat.ETC2_RGBA1: //test pass
|
||||||
case TextureFormat.ETC_RGBA8_3DS:
|
flag = DecodeETC2A1(buff, bytes);
|
||||||
flag = DecodeETC2A8(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.ETC2_RGBA8: //test pass
|
||||||
case TextureFormat.ASTC_RGB_4x4: //test pass
|
case TextureFormat.ETC_RGBA8_3DS:
|
||||||
case TextureFormat.ASTC_RGBA_4x4: //test pass
|
flag = DecodeETC2A8(buff, bytes);
|
||||||
case TextureFormat.ASTC_HDR_4x4: //test pass
|
break;
|
||||||
flag = DecodeASTC(buff, bytes, 4);
|
case TextureFormat.ASTC_RGB_4x4: //test pass
|
||||||
break;
|
case TextureFormat.ASTC_RGBA_4x4: //test pass
|
||||||
case TextureFormat.ASTC_RGB_5x5: //test pass
|
case TextureFormat.ASTC_HDR_4x4: //test pass
|
||||||
case TextureFormat.ASTC_RGBA_5x5: //test pass
|
flag = DecodeASTC(buff, bytes, 4);
|
||||||
case TextureFormat.ASTC_HDR_5x5: //test pass
|
break;
|
||||||
flag = DecodeASTC(buff, bytes, 5);
|
case TextureFormat.ASTC_RGB_5x5: //test pass
|
||||||
break;
|
case TextureFormat.ASTC_RGBA_5x5: //test pass
|
||||||
case TextureFormat.ASTC_RGB_6x6: //test pass
|
case TextureFormat.ASTC_HDR_5x5: //test pass
|
||||||
case TextureFormat.ASTC_RGBA_6x6: //test pass
|
flag = DecodeASTC(buff, bytes, 5);
|
||||||
case TextureFormat.ASTC_HDR_6x6: //test pass
|
break;
|
||||||
flag = DecodeASTC(buff, bytes, 6);
|
case TextureFormat.ASTC_RGB_6x6: //test pass
|
||||||
break;
|
case TextureFormat.ASTC_RGBA_6x6: //test pass
|
||||||
case TextureFormat.ASTC_RGB_8x8: //test pass
|
case TextureFormat.ASTC_HDR_6x6: //test pass
|
||||||
case TextureFormat.ASTC_RGBA_8x8: //test pass
|
flag = DecodeASTC(buff, bytes, 6);
|
||||||
case TextureFormat.ASTC_HDR_8x8: //test pass
|
break;
|
||||||
flag = DecodeASTC(buff, bytes, 8);
|
case TextureFormat.ASTC_RGB_8x8: //test pass
|
||||||
break;
|
case TextureFormat.ASTC_RGBA_8x8: //test pass
|
||||||
case TextureFormat.ASTC_RGB_10x10: //test pass
|
case TextureFormat.ASTC_HDR_8x8: //test pass
|
||||||
case TextureFormat.ASTC_RGBA_10x10: //test pass
|
flag = DecodeASTC(buff, bytes, 8);
|
||||||
case TextureFormat.ASTC_HDR_10x10: //test pass
|
break;
|
||||||
flag = DecodeASTC(buff, bytes, 10);
|
case TextureFormat.ASTC_RGB_10x10: //test pass
|
||||||
break;
|
case TextureFormat.ASTC_RGBA_10x10: //test pass
|
||||||
case TextureFormat.ASTC_RGB_12x12: //test pass
|
case TextureFormat.ASTC_HDR_10x10: //test pass
|
||||||
case TextureFormat.ASTC_RGBA_12x12: //test pass
|
flag = DecodeASTC(buff, bytes, 10);
|
||||||
case TextureFormat.ASTC_HDR_12x12: //test pass
|
break;
|
||||||
flag = DecodeASTC(buff, bytes, 12);
|
case TextureFormat.ASTC_RGB_12x12: //test pass
|
||||||
break;
|
case TextureFormat.ASTC_RGBA_12x12: //test pass
|
||||||
case TextureFormat.RG16: //test pass
|
case TextureFormat.ASTC_HDR_12x12: //test pass
|
||||||
flag = DecodeRG16(buff, bytes);
|
flag = DecodeASTC(buff, bytes, 12);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.R8: //test pass
|
case TextureFormat.RG16: //test pass
|
||||||
flag = DecodeR8(buff, bytes);
|
flag = DecodeRG16(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ETC_RGB4Crunched: //test pass
|
case TextureFormat.R8: //test pass
|
||||||
flag = DecodeETC1Crunched(buff, bytes);
|
flag = DecodeR8(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.ETC2_RGBA8Crunched: //test pass
|
case TextureFormat.ETC_RGB4Crunched: //test pass
|
||||||
flag = DecodeETC2A8Crunched(buff, bytes);
|
flag = DecodeETC1Crunched(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RG32: //test pass
|
case TextureFormat.ETC2_RGBA8Crunched: //test pass
|
||||||
flag = DecodeRG32(buff, bytes);
|
flag = DecodeETC2A8Crunched(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGB48: //test pass
|
case TextureFormat.RG32: //test pass
|
||||||
flag = DecodeRGB48(buff, bytes);
|
flag = DecodeRG32(buff, bytes);
|
||||||
break;
|
break;
|
||||||
case TextureFormat.RGBA64: //test pass
|
case TextureFormat.RGB48: //test pass
|
||||||
flag = DecodeRGBA64(buff, bytes);
|
flag = DecodeRGB48(buff, bytes);
|
||||||
break;
|
break;
|
||||||
|
case TextureFormat.RGBA64: //test pass
|
||||||
|
flag = DecodeRGBA64(buff, bytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
BigArrayPool<byte>.Shared.Return(buff);
|
||||||
}
|
}
|
||||||
BigArrayPool<byte>.Shared.Return(buff);
|
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace AssetStudio
|
|||||||
public static Image<Bgra32> ConvertToImage(this Texture2D m_Texture2D, bool flip)
|
public static Image<Bgra32> ConvertToImage(this Texture2D m_Texture2D, bool flip)
|
||||||
{
|
{
|
||||||
var converter = new Texture2DConverter(m_Texture2D);
|
var converter = new Texture2DConverter(m_Texture2D);
|
||||||
var buff = BigArrayPool<byte>.Shared.Rent(m_Texture2D.m_Width * m_Texture2D.m_Height * 4);
|
var buff = BigArrayPool<byte>.Shared.Rent(converter.outPutSize);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (converter.DecodeTexture2D(buff))
|
if (converter.DecodeTexture2D(buff))
|
||||||
@ -26,7 +26,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BigArrayPool<byte>.Shared.Return(buff);
|
BigArrayPool<byte>.Shared.Return(buff, clearArray: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user