- [Core] Fix bug where some buffers are unintentionally cached, causing undesired side effects.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Texture2DDecoder;
|
using Texture2DDecoder;
|
||||||
|
|
||||||
@@ -32,185 +33,192 @@ namespace AssetStudio
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var flag = false;
|
var flag = false;
|
||||||
var buff = BigArrayPool<byte>.Shared.Rent(reader.Size);
|
var buff = ArrayPool<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);
|
||||||
case TextureFormat.R16_Alt: //test pass
|
flag = DecodeRGB565(buff, bytes);
|
||||||
flag = DecodeR16(buff, bytes);
|
break;
|
||||||
break;
|
case TextureFormat.R16: //test pass
|
||||||
case TextureFormat.DXT1: //test pass
|
case TextureFormat.R16_Alt: //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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BigArrayPool<byte>.Shared.Return(buff);
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(buff, true);
|
||||||
|
}
|
||||||
|
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using System.Buffers;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
@@ -17,7 +18,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 = ArrayPool<byte>.Shared.Rent(m_Texture2D.m_Width * m_Texture2D.m_Height * 4);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (converter.DecodeTexture2D(buff))
|
if (converter.DecodeTexture2D(buff))
|
||||||
@@ -33,7 +34,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BigArrayPool<byte>.Shared.Return(buff);
|
ArrayPool<byte>.Shared.Return(buff, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
using System.Buffers;
|
|
||||||
|
|
||||||
namespace AssetStudio
|
|
||||||
{
|
|
||||||
public static class BigArrayPool<T>
|
|
||||||
{
|
|
||||||
private static readonly ArrayPool<T> s_shared = ArrayPool<T>.Create(64 * 1024 * 1024, 3);
|
|
||||||
public static ArrayPool<T> Shared => s_shared;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -124,22 +125,28 @@ namespace AssetStudio
|
|||||||
var compressedSize = (int)blockInfo.compressedSize;
|
var compressedSize = (int)blockInfo.compressedSize;
|
||||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||||
|
|
||||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
var compressedBytes = ArrayPool<byte>.Shared.Rent(compressedSize);
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
var uncompressedBytes = ArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||||
reader.Read(compressedBytes, 0, compressedSize);
|
try
|
||||||
|
|
||||||
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
|
||||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
|
||||||
|
|
||||||
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
|
||||||
if (numWrite != uncompressedSize)
|
|
||||||
{
|
{
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
reader.Read(compressedBytes, 0, compressedSize);
|
||||||
}
|
|
||||||
|
|
||||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
||||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
|
||||||
|
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||||
|
if (numWrite != uncompressedSize)
|
||||||
|
{
|
||||||
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(compressedBytes, true);
|
||||||
|
ArrayPool<byte>.Shared.Return(uncompressedBytes, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Buffers;
|
||||||
|
|
||||||
namespace AssetStudio
|
namespace AssetStudio
|
||||||
{
|
{
|
||||||
@@ -445,15 +446,21 @@ namespace AssetStudio
|
|||||||
case CompressionType.Lz4: //LZ4
|
case CompressionType.Lz4: //LZ4
|
||||||
case CompressionType.Lz4HC: //LZ4HC
|
case CompressionType.Lz4HC: //LZ4HC
|
||||||
{
|
{
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent((int)uncompressedSize);
|
var uncompressedBytes = ArrayPool<byte>.Shared.Rent((int)uncompressedSize);
|
||||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, (int)uncompressedSize);
|
try
|
||||||
var numWrite = LZ4.Decompress(blocksInfoBytesSpan, uncompressedBytesSpan);
|
|
||||||
if (numWrite != uncompressedSize)
|
|
||||||
{
|
{
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, (int)uncompressedSize);
|
||||||
|
var numWrite = LZ4.Decompress(blocksInfoBytesSpan, uncompressedBytesSpan);
|
||||||
|
if (numWrite != uncompressedSize)
|
||||||
|
{
|
||||||
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
|
}
|
||||||
|
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytesSpan.ToArray());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(uncompressedBytes, true);
|
||||||
}
|
}
|
||||||
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytesSpan.ToArray());
|
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CompressionType.Lz4Mr0k: //Lz4Mr0k
|
case CompressionType.Lz4Mr0k: //Lz4Mr0k
|
||||||
@@ -544,94 +551,114 @@ namespace AssetStudio
|
|||||||
case CompressionType.Lz4Mr0k when Game.Type.IsMhyGroup(): //Lz4Mr0k
|
case CompressionType.Lz4Mr0k when Game.Type.IsMhyGroup(): //Lz4Mr0k
|
||||||
{
|
{
|
||||||
var compressedSize = (int)blockInfo.compressedSize;
|
var compressedSize = (int)blockInfo.compressedSize;
|
||||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
|
||||||
reader.Read(compressedBytes, 0, compressedSize);
|
|
||||||
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
|
||||||
if (compressionType == CompressionType.Lz4Mr0k && Mr0kUtils.IsMr0k(compressedBytes))
|
|
||||||
{
|
|
||||||
Logger.Verbose($"Block encrypted with mr0k, decrypting...");
|
|
||||||
compressedBytesSpan = Mr0kUtils.Decrypt(compressedBytesSpan, (Mr0k)Game);
|
|
||||||
}
|
|
||||||
if (Game.Type.IsUnityCN() && ((int)blockInfo.flags & 0x100) != 0)
|
|
||||||
{
|
|
||||||
Logger.Verbose($"Decrypting block with UnityCN...");
|
|
||||||
UnityCN.DecryptBlock(compressedBytes, compressedSize, i);
|
|
||||||
}
|
|
||||||
if (Game.Type.IsNetEase() && i == 0)
|
|
||||||
{
|
|
||||||
NetEaseUtils.DecryptWithHeader(compressedBytesSpan);
|
|
||||||
}
|
|
||||||
if (Game.Type.IsArknightsEndfield() && i == 0)
|
|
||||||
{
|
|
||||||
FairGuardUtils.Decrypt(compressedBytesSpan);
|
|
||||||
}
|
|
||||||
if (Game.Type.IsOPFP())
|
|
||||||
{
|
|
||||||
OPFPUtils.Decrypt(compressedBytesSpan, reader.FullPath);
|
|
||||||
}
|
|
||||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
|
||||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
var compressedBytes = ArrayPool<byte>.Shared.Rent(compressedSize);
|
||||||
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
var uncompressedBytes = ArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||||
if (numWrite != uncompressedSize)
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
||||||
|
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||||
|
|
||||||
|
reader.Read(compressedBytesSpan);
|
||||||
|
if (compressionType == CompressionType.Lz4Mr0k && Mr0kUtils.IsMr0k(compressedBytes))
|
||||||
|
{
|
||||||
|
Logger.Verbose($"Block encrypted with mr0k, decrypting...");
|
||||||
|
compressedBytesSpan = Mr0kUtils.Decrypt(compressedBytesSpan, (Mr0k)Game);
|
||||||
|
}
|
||||||
|
if (Game.Type.IsUnityCN() && ((int)blockInfo.flags & 0x100) != 0)
|
||||||
|
{
|
||||||
|
Logger.Verbose($"Decrypting block with UnityCN...");
|
||||||
|
UnityCN.DecryptBlock(compressedBytes, compressedSize, i);
|
||||||
|
}
|
||||||
|
if (Game.Type.IsNetEase() && i == 0)
|
||||||
|
{
|
||||||
|
NetEaseUtils.DecryptWithHeader(compressedBytesSpan);
|
||||||
|
}
|
||||||
|
if (Game.Type.IsArknightsEndfield() && i == 0)
|
||||||
|
{
|
||||||
|
FairGuardUtils.Decrypt(compressedBytesSpan);
|
||||||
|
}
|
||||||
|
if (Game.Type.IsOPFP())
|
||||||
|
{
|
||||||
|
OPFPUtils.Decrypt(compressedBytesSpan, reader.FullPath);
|
||||||
|
}
|
||||||
|
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||||
|
if (numWrite != uncompressedSize)
|
||||||
|
{
|
||||||
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
|
}
|
||||||
|
blocksStream.Write(uncompressedBytesSpan);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(compressedBytes, true);
|
||||||
|
ArrayPool<byte>.Shared.Return(uncompressedBytes, true);
|
||||||
}
|
}
|
||||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
|
||||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CompressionType.Lz4Inv when Game.Type.IsArknightsEndfield():
|
case CompressionType.Lz4Inv when Game.Type.IsArknightsEndfield():
|
||||||
{
|
{
|
||||||
var compressedSize = (int)blockInfo.compressedSize;
|
var compressedSize = (int)blockInfo.compressedSize;
|
||||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
|
||||||
reader.Read(compressedBytes, 0, compressedSize);
|
|
||||||
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
FairGuardUtils.Decrypt(compressedBytesSpan);
|
|
||||||
|
|
||||||
}
|
|
||||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
|
||||||
|
var compressedBytes = ArrayPool<byte>.Shared.Rent(compressedSize);
|
||||||
|
var uncompressedBytes = ArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||||
|
|
||||||
|
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
||||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||||
var numWrite = LZ4Inv.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
|
||||||
if (numWrite != uncompressedSize)
|
try
|
||||||
{
|
{
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
reader.Read(compressedBytesSpan);
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
FairGuardUtils.Decrypt(compressedBytesSpan);
|
||||||
|
|
||||||
|
}
|
||||||
|
var numWrite = LZ4Inv.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||||
|
if (numWrite != uncompressedSize)
|
||||||
|
{
|
||||||
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
|
}
|
||||||
|
blocksStream.Write(uncompressedBytesSpan);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(compressedBytes, true);
|
||||||
|
ArrayPool<byte>.Shared.Return(uncompressedBytes, true);
|
||||||
}
|
}
|
||||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
|
||||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CompressionType.Zstd when !Game.Type.IsMhyGroup(): //Zstd
|
case CompressionType.Zstd when !Game.Type.IsMhyGroup(): //Zstd
|
||||||
{
|
{
|
||||||
var compressedSize = (int)blockInfo.compressedSize;
|
var compressedSize = (int)blockInfo.compressedSize;
|
||||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
|
||||||
reader.Read(compressedBytes, 0, compressedSize);
|
|
||||||
|
|
||||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
|
||||||
|
var compressedBytes = ArrayPool<byte>.Shared.Rent(compressedSize);
|
||||||
|
var uncompressedBytes = ArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
reader.Read(compressedBytes, 0, compressedSize);
|
||||||
using var decompressor = new Decompressor();
|
using var decompressor = new Decompressor();
|
||||||
var numWrite = decompressor.Unwrap(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
var numWrite = decompressor.Unwrap(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
||||||
if (numWrite != uncompressedSize)
|
if (numWrite != uncompressedSize)
|
||||||
{
|
{
|
||||||
throw new IOException($"Zstd decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
throw new IOException($"Zstd decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
}
|
}
|
||||||
|
blocksStream.Write(uncompressedBytes.ToArray(), 0, uncompressedSize);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Zstd decompression error:\n{ex}");
|
Console.WriteLine($"Zstd decompression error:\n{ex}");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
blocksStream.Write(uncompressedBytes.ToArray(), 0, uncompressedSize);
|
{
|
||||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
ArrayPool<byte>.Shared.Return(compressedBytes, true);
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
ArrayPool<byte>.Shared.Return(uncompressedBytes, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1981,7 +1981,7 @@ namespace AssetStudio
|
|||||||
var aclClip = m_MuscleClip.m_Clip.m_ACLClip as GIACLClip;
|
var aclClip = m_MuscleClip.m_Clip.m_ACLClip as GIACLClip;
|
||||||
|
|
||||||
var resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
var resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
||||||
var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
ms.Write(aclClip.m_DatabaseData);
|
ms.Write(aclClip.m_DatabaseData);
|
||||||
|
|
||||||
ms.Write(resourceReader.GetData());
|
ms.Write(resourceReader.GetData());
|
||||||
|
|||||||
@@ -815,7 +815,7 @@ namespace AssetStudio
|
|||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryStream ms = new MemoryStream();
|
MemoryStream ms = new();
|
||||||
if (version == 0x10)
|
if (version == 0x10)
|
||||||
{
|
{
|
||||||
var buffer = (stackalloc byte[8]);
|
var buffer = (stackalloc byte[8]);
|
||||||
@@ -929,7 +929,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logger.Verbose("Decrypted Reverse: 1999 file successfully !!");
|
Logger.Verbose("Decrypted Reverse: 1999 file successfully !!");
|
||||||
var stream = new MemoryStream();
|
MemoryStream stream = new();
|
||||||
stream.Write(signatureBytes);
|
stream.Write(signatureBytes);
|
||||||
stream.Write(remaining);
|
stream.Write(remaining);
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -46,59 +47,65 @@ namespace AssetStudio
|
|||||||
|
|
||||||
private void ReadBlocksInfoAndDirectory(FileReader reader)
|
private void ReadBlocksInfoAndDirectory(FileReader reader)
|
||||||
{
|
{
|
||||||
int offset = 0x20;
|
|
||||||
var blocksInfo = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
var blocksInfo = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||||
DescrambleHeader(blocksInfo);
|
DescrambleHeader(blocksInfo);
|
||||||
|
|
||||||
Logger.Verbose($"Descrambled blocksInfo signature {Convert.ToHexString(blocksInfo, 0 , 4)}");
|
Logger.Verbose($"Descrambled blocksInfo signature {Convert.ToHexString(blocksInfo, 0 , 4)}");
|
||||||
using var blocksInfoStream = new MemoryStream(blocksInfo, offset, (int)m_Header.compressedBlocksInfoSize - offset);
|
using var blocksInfoStream = new MemoryStream(blocksInfo, 0x20, (int)m_Header.compressedBlocksInfoSize - 0x20);
|
||||||
using var blocksInfoReader = new EndianBinaryReader(blocksInfoStream);
|
using var blocksInfoReader = new EndianBinaryReader(blocksInfoStream);
|
||||||
m_Header.uncompressedBlocksInfoSize = blocksInfoReader.ReadMhyUInt();
|
m_Header.uncompressedBlocksInfoSize = blocksInfoReader.ReadMhyUInt();
|
||||||
Logger.Verbose($"uncompressed blocksInfo size: 0x{m_Header.uncompressedBlocksInfoSize:X8}");
|
Logger.Verbose($"uncompressed blocksInfo size: 0x{m_Header.uncompressedBlocksInfoSize:X8}");
|
||||||
var compressedBlocksInfo = blocksInfoReader.ReadBytes((int)blocksInfoReader.Remaining);
|
var compressedBlocksInfo = blocksInfoReader.ReadBytes((int)blocksInfoReader.Remaining);
|
||||||
var uncompressedBlocksInfo = BigArrayPool<byte>.Shared.Rent((int)m_Header.uncompressedBlocksInfoSize);
|
|
||||||
|
var uncompressedBlocksInfo = ArrayPool<byte>.Shared.Rent((int)m_Header.uncompressedBlocksInfoSize);
|
||||||
var uncompressedBlocksInfoSpan = uncompressedBlocksInfo.AsSpan(0, (int)m_Header.uncompressedBlocksInfoSize);
|
var uncompressedBlocksInfoSpan = uncompressedBlocksInfo.AsSpan(0, (int)m_Header.uncompressedBlocksInfoSize);
|
||||||
var numWrite = LZ4.Decompress(compressedBlocksInfo, uncompressedBlocksInfoSpan);
|
|
||||||
if (numWrite != m_Header.uncompressedBlocksInfoSize)
|
|
||||||
{
|
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.Verbose($"Writing block and directory to blocks stream...");
|
try
|
||||||
using var blocksInfoUncompressedStream = new MemoryStream(uncompressedBlocksInfo);
|
|
||||||
using var blocksInfoUncompressedReader = new EndianBinaryReader(blocksInfoUncompressedStream);
|
|
||||||
var nodesCount = blocksInfoUncompressedReader.ReadMhyInt();
|
|
||||||
m_DirectoryInfo = new List<BundleFile.Node>();
|
|
||||||
Logger.Verbose($"Directory count: {nodesCount}");
|
|
||||||
for (int i = 0; i < nodesCount; i++)
|
|
||||||
{
|
{
|
||||||
m_DirectoryInfo.Add(new BundleFile.Node
|
var numWrite = LZ4.Decompress(compressedBlocksInfo, uncompressedBlocksInfoSpan);
|
||||||
|
if (numWrite != m_Header.uncompressedBlocksInfoSize)
|
||||||
{
|
{
|
||||||
path = blocksInfoUncompressedReader.ReadMhyString(),
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
|
||||||
flags = blocksInfoUncompressedReader.ReadBoolean() ? 4u : 0,
|
}
|
||||||
offset = blocksInfoUncompressedReader.ReadMhyInt(),
|
|
||||||
size = blocksInfoUncompressedReader.ReadMhyUInt()
|
|
||||||
});
|
|
||||||
|
|
||||||
Logger.Verbose($"Directory {i} Info: {m_DirectoryInfo[i]}");
|
Logger.Verbose($"Writing block and directory to blocks stream...");
|
||||||
}
|
using var blocksInfoUncompressedStream = new MemoryStream(uncompressedBlocksInfo, 0, (int)m_Header.uncompressedBlocksInfoSize);
|
||||||
|
using var blocksInfoUncompressedReader = new EndianBinaryReader(blocksInfoUncompressedStream);
|
||||||
var blocksInfoCount = blocksInfoUncompressedReader.ReadMhyInt();
|
var nodesCount = blocksInfoUncompressedReader.ReadMhyInt();
|
||||||
m_BlocksInfo = new List<BundleFile.StorageBlock>();
|
m_DirectoryInfo = new List<BundleFile.Node>();
|
||||||
Logger.Verbose($"Blocks count: {blocksInfoCount}");
|
Logger.Verbose($"Directory count: {nodesCount}");
|
||||||
for (int i = 0; i < blocksInfoCount; i++)
|
for (int i = 0; i < nodesCount; i++)
|
||||||
{
|
|
||||||
m_BlocksInfo.Add(new BundleFile.StorageBlock
|
|
||||||
{
|
{
|
||||||
compressedSize = (uint)blocksInfoUncompressedReader.ReadMhyInt(),
|
m_DirectoryInfo.Add(new BundleFile.Node
|
||||||
uncompressedSize = blocksInfoUncompressedReader.ReadMhyUInt(),
|
{
|
||||||
flags = (StorageBlockFlags)0x43
|
path = blocksInfoUncompressedReader.ReadMhyString(),
|
||||||
});
|
flags = blocksInfoUncompressedReader.ReadBoolean() ? 4u : 0,
|
||||||
|
offset = blocksInfoUncompressedReader.ReadMhyInt(),
|
||||||
|
size = blocksInfoUncompressedReader.ReadMhyUInt()
|
||||||
|
});
|
||||||
|
|
||||||
Logger.Verbose($"Block {i} Info: {m_BlocksInfo[i]}");
|
Logger.Verbose($"Directory {i} Info: {m_DirectoryInfo[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var blocksInfoCount = blocksInfoUncompressedReader.ReadMhyInt();
|
||||||
|
m_BlocksInfo = new List<BundleFile.StorageBlock>();
|
||||||
|
Logger.Verbose($"Blocks count: {blocksInfoCount}");
|
||||||
|
for (int i = 0; i < blocksInfoCount; i++)
|
||||||
|
{
|
||||||
|
m_BlocksInfo.Add(new BundleFile.StorageBlock
|
||||||
|
{
|
||||||
|
compressedSize = (uint)blocksInfoUncompressedReader.ReadMhyInt(),
|
||||||
|
uncompressedSize = blocksInfoUncompressedReader.ReadMhyUInt(),
|
||||||
|
flags = (StorageBlockFlags)0x43
|
||||||
|
});
|
||||||
|
|
||||||
|
Logger.Verbose($"Block {i} Info: {m_BlocksInfo[i]}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(uncompressedBlocksInfo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBlocksInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream CreateBlocksStream(string path)
|
private Stream CreateBlocksStream(string path)
|
||||||
@@ -124,25 +131,31 @@ namespace AssetStudio
|
|||||||
throw new Exception($"Wrong compressed length: {compressedSize}");
|
throw new Exception($"Wrong compressed length: {compressedSize}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var compressedBytes = BigArrayPool<byte>.Shared.Rent(compressedSize);
|
var compressedBytes = ArrayPool<byte>.Shared.Rent(compressedSize);
|
||||||
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
|
var uncompressedBytes = ArrayPool<byte>.Shared.Rent(uncompressedSize);
|
||||||
reader.Read(compressedBytes, 0, compressedSize);
|
|
||||||
|
|
||||||
var offset = 0xC;
|
try
|
||||||
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
|
||||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
|
||||||
DescrambleEntry(compressedBytesSpan);
|
|
||||||
|
|
||||||
Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}");
|
|
||||||
var numWrite = LZ4.Decompress(compressedBytesSpan[offset..], uncompressedBytesSpan);
|
|
||||||
if (numWrite != uncompressedSize)
|
|
||||||
{
|
{
|
||||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
|
||||||
}
|
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||||
|
|
||||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
reader.Read(compressedBytesSpan);
|
||||||
BigArrayPool<byte>.Shared.Return(compressedBytes);
|
DescrambleEntry(compressedBytesSpan);
|
||||||
BigArrayPool<byte>.Shared.Return(uncompressedBytes);
|
|
||||||
|
Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}");
|
||||||
|
var numWrite = LZ4.Decompress(compressedBytesSpan[0xC..], uncompressedBytesSpan);
|
||||||
|
if (numWrite != uncompressedSize)
|
||||||
|
{
|
||||||
|
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksStream.Write(uncompressedBytesSpan);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(compressedBytes, true);
|
||||||
|
ArrayPool<byte>.Shared.Return(uncompressedBytes, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -94,23 +95,29 @@ namespace AssetStudio
|
|||||||
Logger.Verbose($"Prased signature: {signature}");
|
Logger.Verbose($"Prased signature: {signature}");
|
||||||
|
|
||||||
var signatureBytes = Encoding.UTF8.GetBytes(signature);
|
var signatureBytes = Encoding.UTF8.GetBytes(signature);
|
||||||
var buffer = BigArrayPool<byte>.Shared.Rent(BufferSize);
|
var buffer = ArrayPool<byte>.Shared.Rent(BufferSize);
|
||||||
while (Remaining > 0)
|
try
|
||||||
{
|
{
|
||||||
var index = 0;
|
while (Remaining > 0)
|
||||||
var absOffset = AbsolutePosition;
|
|
||||||
var read = Read(buffer);
|
|
||||||
while (index < read)
|
|
||||||
{
|
{
|
||||||
index = buffer.AsSpan(0, read).Search(signatureBytes, index);
|
var index = 0;
|
||||||
if (index == -1) break;
|
var absOffset = AbsolutePosition;
|
||||||
var offset = absOffset + index;
|
var read = Read(buffer);
|
||||||
Offset = offset;
|
while (index < read)
|
||||||
yield return offset;
|
{
|
||||||
index++;
|
index = buffer.AsSpan(0, read).Search(signatureBytes, index);
|
||||||
|
if (index == -1) break;
|
||||||
|
var offset = absOffset + index;
|
||||||
|
Offset = offset;
|
||||||
|
yield return offset;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BigArrayPool<byte>.Shared.Return(buffer);
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user