diff --git a/AssetStudio/7zip/SevenZipHelper.cs b/AssetStudio/7zip/SevenZipHelper.cs
deleted file mode 100644
index 34584c8..0000000
--- a/AssetStudio/7zip/SevenZipHelper.cs
+++ /dev/null
@@ -1,144 +0,0 @@
-using System;
-using System.IO;
-
-
-namespace SevenZip.Compression.LZMA
-{
- public static class SevenZipHelper
- {
-
- static int dictionary = 1 << 23;
-
- // static Int32 posStateBits = 2;
- // static Int32 litContextBits = 3; // for normal files
- // UInt32 litContextBits = 0; // for 32-bit data
- // static Int32 litPosBits = 0;
- // UInt32 litPosBits = 2; // for 32-bit data
- // static Int32 algorithm = 2;
- // static Int32 numFastBytes = 128;
-
- static bool eos = false;
-
-
-
-
-
- static CoderPropID[] propIDs =
- {
- CoderPropID.DictionarySize,
- CoderPropID.PosStateBits,
- CoderPropID.LitContextBits,
- CoderPropID.LitPosBits,
- CoderPropID.Algorithm,
- CoderPropID.NumFastBytes,
- CoderPropID.MatchFinder,
- CoderPropID.EndMarker
- };
-
- // these are the default properties, keeping it simple for now:
- static object[] properties =
- {
- (Int32)(dictionary),
- (Int32)(2),
- (Int32)(3),
- (Int32)(0),
- (Int32)(2),
- (Int32)(128),
- "bt4",
- eos
- };
-
-
- public static byte[] Compress(byte[] inputBytes)
- {
-
- MemoryStream inStream = new MemoryStream(inputBytes);
- MemoryStream outStream = new MemoryStream();
- Encoder encoder = new Encoder();
- encoder.SetCoderProperties(propIDs, properties);
- encoder.WriteCoderProperties(outStream);
- long fileSize = inStream.Length;
- for (int i = 0; i < 8; i++)
- outStream.WriteByte((Byte)(fileSize >> (8 * i)));
- encoder.Code(inStream, outStream, -1, -1, null);
- return outStream.ToArray();
- }
-
- public static byte[] Decompress(byte[] inputBytes)
- {
- MemoryStream newInStream = new MemoryStream(inputBytes);
-
- Decoder decoder = new Decoder();
-
- newInStream.Seek(0, 0);
- MemoryStream newOutStream = new MemoryStream();
-
- byte[] properties2 = new byte[5];
- if (newInStream.Read(properties2, 0, 5) != 5)
- throw (new Exception("input .lzma is too short"));
- long outSize = 0;
- for (int i = 0; i < 8; i++)
- {
- int v = newInStream.ReadByte();
- if (v < 0)
- throw (new Exception("Can't Read 1"));
- outSize |= ((long)(byte)v) << (8 * i);
- }
- decoder.SetDecoderProperties(properties2);
-
- long compressedSize = newInStream.Length - newInStream.Position;
- decoder.Code(newInStream, newOutStream, compressedSize, outSize, null);
-
- byte[] b = newOutStream.ToArray();
-
- return b;
- }
-
-
- public static MemoryStream StreamDecompress(MemoryStream newInStream)
- {
- Decoder decoder = new Decoder();
-
- newInStream.Seek(0, 0);
- MemoryStream newOutStream = new MemoryStream();
-
- byte[] properties2 = new byte[5];
- if (newInStream.Read(properties2, 0, 5) != 5)
- throw (new Exception("input .lzma is too short"));
- long outSize = 0;
- for (int i = 0; i < 8; i++)
- {
- int v = newInStream.ReadByte();
- if (v < 0)
- throw (new Exception("Can't Read 1"));
- outSize |= ((long)(byte)v) << (8 * i);
- }
- decoder.SetDecoderProperties(properties2);
-
- long compressedSize = newInStream.Length - newInStream.Position;
- decoder.Code(newInStream, newOutStream, compressedSize, outSize, null);
-
- newOutStream.Position = 0;
- return newOutStream;
- }
-
- public static MemoryStream StreamDecompress(MemoryStream newInStream, long outSize)
- {
- Decoder decoder = new Decoder();
-
- newInStream.Seek(0, 0);
- MemoryStream newOutStream = new MemoryStream();
-
- byte[] properties2 = new byte[5];
- if (newInStream.Read(properties2, 0, 5) != 5)
- throw (new Exception("input .lzma is too short"));
- decoder.SetDecoderProperties(properties2);
-
- long compressedSize = newInStream.Length - newInStream.Position;
- decoder.Code(newInStream, newOutStream, compressedSize, outSize, null);
-
- newOutStream.Position = 0;
- return newOutStream;
- }
- }
-}
diff --git a/AssetStudio/AssetStudio-x86.csproj b/AssetStudio/AssetStudio-x86.csproj
index 375d318..95d6196 100644
--- a/AssetStudio/AssetStudio-x86.csproj
+++ b/AssetStudio/AssetStudio-x86.csproj
@@ -136,9 +136,6 @@
Code
-
- Code
-
Form
@@ -170,6 +167,7 @@
+
ShaderResource.resx
True
@@ -179,6 +177,7 @@
+
diff --git a/AssetStudio/AssetStudio.csproj b/AssetStudio/AssetStudio.csproj
index 3a86871..4074f12 100644
--- a/AssetStudio/AssetStudio.csproj
+++ b/AssetStudio/AssetStudio.csproj
@@ -136,7 +136,7 @@
Code
-
+
Code
@@ -172,6 +172,7 @@
+
diff --git a/AssetStudio/StudioClasses/BundleFile.cs b/AssetStudio/StudioClasses/BundleFile.cs
index 6e48069..a8f98d5 100644
--- a/AssetStudio/StudioClasses/BundleFile.cs
+++ b/AssetStudio/StudioClasses/BundleFile.cs
@@ -1,25 +1,34 @@
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using Lz4;
using SevenZip.Compression.LZMA;
namespace AssetStudio
{
- public class MemoryFile
+ public class StreamFile
{
public string fileName;
- public MemoryStream stream;
+ public Stream stream;
+ }
+
+ public class BlockInfo
+ {
+ public uint compressedSize;
+ public uint uncompressedSize;
+ public short flag;
}
public class BundleFile
{
- public int format;
+ private string path;
public string versionPlayer;
public string versionEngine;
- public List fileList = new List();
+ public List fileList = new List();
- public BundleFile(EndianBinaryReader bundleReader)
+ public BundleFile(EndianBinaryReader bundleReader, string path)
{
+ this.path = path;
var signature = bundleReader.ReadStringToNull();
switch (signature)
{
@@ -27,7 +36,7 @@ namespace AssetStudio
case "UnityRaw":
case "\xFA\xFA\xFA\xFA\xFA\xFA\xFA\xFA":
{
- format = bundleReader.ReadInt32();
+ var format = bundleReader.ReadInt32();
versionPlayer = bundleReader.ReadStringToNull();
versionEngine = bundleReader.ReadStringToNull();
if (format < 6)
@@ -75,14 +84,16 @@ namespace AssetStudio
break;
}
case "UnityFS":
- format = bundleReader.ReadInt32();
- versionPlayer = bundleReader.ReadStringToNull();
- versionEngine = bundleReader.ReadStringToNull();
- if (format == 6)
{
- ReadFormat6(bundleReader);
+ var format = bundleReader.ReadInt32();
+ versionPlayer = bundleReader.ReadStringToNull();
+ versionEngine = bundleReader.ReadStringToNull();
+ if (format == 6)
+ {
+ ReadFormat6(bundleReader);
+ }
+ break;
}
- break;
}
}
@@ -91,7 +102,7 @@ namespace AssetStudio
int fileCount = reader.ReadInt32();
for (int i = 0; i < fileCount; i++)
{
- var file = new MemoryFile();
+ var file = new StreamFile();
file.fileName = reader.ReadStringToNull();
int fileOffset = reader.ReadInt32();
fileOffset += offset;
@@ -151,63 +162,82 @@ namespace AssetStudio
}
//case 4:LZHAM?
}
- using (var blocksInfo = new EndianBinaryReader(blocksInfoStream))
+ using (var blocksInfoReader = new EndianBinaryReader(blocksInfoStream))
{
- blocksInfo.Position = 0x10;
- int blockcount = blocksInfo.ReadInt32();
- var assetsDataStream = new MemoryStream();
+ blocksInfoReader.Position = 0x10;
+ int blockcount = blocksInfoReader.ReadInt32();
+ var blockInfos = new BlockInfo[blockcount];
for (int i = 0; i < blockcount; i++)
{
- uncompressedSize = blocksInfo.ReadInt32();
- compressedSize = blocksInfo.ReadInt32();
- flag = blocksInfo.ReadInt16();
- var compressedBytes = bundleReader.ReadBytes(compressedSize);
- switch (flag & 0x3F)
+ blockInfos[i] = new BlockInfo
+ {
+ uncompressedSize = blocksInfoReader.ReadUInt32(),
+ compressedSize = blocksInfoReader.ReadUInt32(),
+ flag = blocksInfoReader.ReadInt16()
+ };
+ }
+ Stream dataStream;
+ var uncompressedSizeSum = blockInfos.Sum(x => x.uncompressedSize);
+ if (uncompressedSizeSum > int.MaxValue)
+ {
+ /*var memoryMappedFile = MemoryMappedFile.CreateNew(Path.GetFileName(path), uncompressedSizeSum);
+ assetsDataStream = memoryMappedFile.CreateViewStream();*/
+ dataStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
+ }
+ else
+ {
+ dataStream = new MemoryStream();
+ }
+ foreach (var blockInfo in blockInfos)
+ {
+ switch (blockInfo.flag & 0x3F)
{
default://None
{
- assetsDataStream.Write(compressedBytes, 0, compressedSize);
+ bundleReader.BaseStream.CopyTo(dataStream, blockInfo.compressedSize);
break;
}
case 1://LZMA
{
- var uncompressedBytes = new byte[uncompressedSize];
- using (var mstream = new MemoryStream(compressedBytes))
- {
- var decoder = SevenZipHelper.StreamDecompress(mstream, uncompressedSize);
- decoder.Read(uncompressedBytes, 0, uncompressedSize);
- decoder.Dispose();
- }
- assetsDataStream.Write(uncompressedBytes, 0, uncompressedSize);
+ SevenZipHelper.StreamDecompress(bundleReader.BaseStream, dataStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
break;
}
case 2://LZ4
case 3://LZ4HC
{
- var uncompressedBytes = new byte[uncompressedSize];
- using (var decoder = new Lz4DecoderStream(new MemoryStream(compressedBytes)))
- {
- decoder.Read(uncompressedBytes, 0, uncompressedSize);
- }
- assetsDataStream.Write(uncompressedBytes, 0, uncompressedSize);
+ var lz4Stream = new Lz4DecoderStream(bundleReader.BaseStream, blockInfo.compressedSize);
+ lz4Stream.CopyTo(dataStream, blockInfo.uncompressedSize);
break;
}
//case 4:LZHAM?
}
}
- using (var assetsDataReader = new EndianBinaryReader(assetsDataStream))
+ dataStream.Position = 0;
+ using (dataStream)
{
- var entryinfo_count = blocksInfo.ReadInt32();
+ var entryinfo_count = blocksInfoReader.ReadInt32();
for (int i = 0; i < entryinfo_count; i++)
{
- var file = new MemoryFile();
- var entryinfo_offset = blocksInfo.ReadInt64();
- var entryinfo_size = blocksInfo.ReadInt64();
- flag = blocksInfo.ReadInt32();
- file.fileName = Path.GetFileName(blocksInfo.ReadStringToNull());
- assetsDataReader.Position = entryinfo_offset;
- var buffer = assetsDataReader.ReadBytes((int)entryinfo_size);
- file.stream = new MemoryStream(buffer);
+ var file = new StreamFile();
+ var entryinfo_offset = blocksInfoReader.ReadInt64();
+ var entryinfo_size = blocksInfoReader.ReadInt64();
+ flag = blocksInfoReader.ReadInt32();
+ file.fileName = Path.GetFileName(blocksInfoReader.ReadStringToNull());
+ if (entryinfo_size > int.MaxValue)
+ {
+ /*var memoryMappedFile = MemoryMappedFile.CreateNew(file.fileName, entryinfo_size);
+ file.stream = memoryMappedFile.CreateViewStream();*/
+ var extractPath = path + "_unpacked\\";
+ Directory.CreateDirectory(extractPath);
+ file.stream = new FileStream(extractPath + file.fileName, FileMode.Create);
+ }
+ else
+ {
+ file.stream = new MemoryStream();
+ }
+ dataStream.Position = entryinfo_offset;
+ dataStream.CopyTo(file.stream, entryinfo_size);
+ file.stream.Position = 0;
fileList.Add(file);
}
}
diff --git a/AssetStudio/StudioClasses/Importer.cs b/AssetStudio/StudioClasses/Importer.cs
index 659bfad..95d81a6 100644
--- a/AssetStudio/StudioClasses/Importer.cs
+++ b/AssetStudio/StudioClasses/Importer.cs
@@ -100,7 +100,7 @@ namespace AssetStudio
{
var fileName = Path.GetFileName(fullName);
StatusStripUpdate("Decompressing " + fileName);
- var bundleFile = new BundleFile(reader);
+ var bundleFile = new BundleFile(reader, fullName);
reader.Dispose();
foreach (var file in bundleFile.fileList)
{
diff --git a/AssetStudio/StudioClasses/SevenZipHelper.cs b/AssetStudio/StudioClasses/SevenZipHelper.cs
new file mode 100644
index 0000000..e3a550e
--- /dev/null
+++ b/AssetStudio/StudioClasses/SevenZipHelper.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using SevenZip.Compression.LZMA;
+
+
+namespace AssetStudio
+{
+ public static class SevenZipHelper
+ {
+ public static MemoryStream StreamDecompress(MemoryStream inStream)
+ {
+ var decoder = new Decoder();
+
+ inStream.Seek(0, 0);
+ var newOutStream = new MemoryStream();
+
+ var properties = new byte[5];
+ if (inStream.Read(properties, 0, 5) != 5)
+ throw (new Exception("input .lzma is too short"));
+ long outSize = 0;
+ for (var i = 0; i < 8; i++)
+ {
+ var v = inStream.ReadByte();
+ if (v < 0)
+ throw (new Exception("Can't Read 1"));
+ outSize |= ((long)(byte)v) << (8 * i);
+ }
+ decoder.SetDecoderProperties(properties);
+
+ var compressedSize = inStream.Length - inStream.Position;
+ decoder.Code(inStream, newOutStream, compressedSize, outSize, null);
+
+ newOutStream.Position = 0;
+ return newOutStream;
+ }
+
+ public static void StreamDecompress(Stream inStream, Stream outStream, long inSize, long outSize)
+ {
+ var decoder = new Decoder();
+ var properties = new byte[5];
+ if (inStream.Read(properties, 0, 5) != 5)
+ throw new Exception("input .lzma is too short");
+ decoder.SetDecoderProperties(properties);
+ inSize -= 5L;
+ decoder.Code(inStream, outStream, inSize, outSize, null);
+ }
+ }
+}
diff --git a/AssetStudio/StudioClasses/StreamExtensions.cs b/AssetStudio/StudioClasses/StreamExtensions.cs
new file mode 100644
index 0000000..87757ca
--- /dev/null
+++ b/AssetStudio/StudioClasses/StreamExtensions.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace AssetStudio
+{
+ public static class StreamExtensions
+ {
+ private const int BufferSize = 81920;
+
+ public static void CopyTo(this Stream source, Stream destination, long size)
+ {
+ var buffer = new byte[BufferSize];
+ for (var left = size; left > 0; left -= BufferSize)
+ {
+ int toRead = BufferSize < left ? BufferSize : (int)left;
+ int read = source.Read(buffer, 0, toRead);
+ destination.Write(buffer, 0, read);
+ if (read != toRead)
+ {
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/AssetStudio/StudioClasses/Studio.cs b/AssetStudio/StudioClasses/Studio.cs
index 5be7ed0..806b591 100644
--- a/AssetStudio/StudioClasses/Studio.cs
+++ b/AssetStudio/StudioClasses/Studio.cs
@@ -36,7 +36,7 @@ namespace AssetStudio
WebFile
}
- public static FileType CheckFileType(MemoryStream stream, out EndianBinaryReader reader)
+ public static FileType CheckFileType(Stream stream, out EndianBinaryReader reader)
{
reader = new EndianBinaryReader(stream);
return CheckFileType(reader);
@@ -103,48 +103,48 @@ namespace AssetStudio
private static int ExtractBundleFile(string bundleFileName, EndianBinaryReader reader)
{
- var bundleFile = new BundleFile(reader);
+ StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ...");
+ var bundleFile = new BundleFile(reader, bundleFileName);
reader.Dispose();
if (bundleFile.fileList.Count > 0)
{
- StatusStripUpdate($"Decompressing {Path.GetFileName(bundleFileName)} ...");
var extractPath = bundleFileName + "_unpacked\\";
Directory.CreateDirectory(extractPath);
- return ExtractMemoryFile(extractPath, bundleFile.fileList);
+ return ExtractStreamFile(extractPath, bundleFile.fileList);
}
return 0;
}
private static int ExtractWebDataFile(string webFileName, EndianBinaryReader reader)
{
+ StatusStripUpdate($"Decompressing {Path.GetFileName(webFileName)} ...");
var webFile = new WebFile(reader);
reader.Dispose();
if (webFile.fileList.Count > 0)
{
- StatusStripUpdate($"Decompressing {Path.GetFileName(webFileName)} ...");
var extractPath = webFileName + "_unpacked\\";
Directory.CreateDirectory(extractPath);
- return ExtractMemoryFile(extractPath, webFile.fileList);
+ return ExtractStreamFile(extractPath, webFile.fileList);
}
return 0;
}
- private static int ExtractMemoryFile(string extractPath, List fileList)
+ private static int ExtractStreamFile(string extractPath, List fileList)
{
int extractedCount = 0;
- foreach (var memFile in fileList)
+ foreach (var file in fileList)
{
- var filePath = extractPath + memFile.fileName;
+ var filePath = extractPath + file.fileName;
if (!Directory.Exists(extractPath))
{
Directory.CreateDirectory(extractPath);
}
- if (!File.Exists(filePath))
+ if (!File.Exists(filePath) && file.stream is MemoryStream stream)
{
- File.WriteAllBytes(filePath, memFile.stream.ToArray());
- memFile.stream.Dispose();
+ File.WriteAllBytes(filePath, stream.ToArray());
extractedCount += 1;
}
+ file.stream.Dispose();
}
return extractedCount;
}
diff --git a/AssetStudio/StudioClasses/WebFile.cs b/AssetStudio/StudioClasses/WebFile.cs
index d56c172..5f1e932 100644
--- a/AssetStudio/StudioClasses/WebFile.cs
+++ b/AssetStudio/StudioClasses/WebFile.cs
@@ -12,7 +12,7 @@ namespace AssetStudio
{
public static byte[] gzipMagic = { 0x1f, 0x8b };
public static byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
- public List fileList = new List();
+ public List fileList = new List();
public class WebData
@@ -82,7 +82,7 @@ namespace AssetStudio
foreach (var data in dataList)
{
- var file = new MemoryFile();
+ var file = new StreamFile();
file.fileName = Path.GetFileName(data.path);
reader.Position = data.dataOffset;
file.stream = new MemoryStream(reader.ReadBytes(data.dataLength));