- [Core] Added new entries.
This commit is contained in:
@@ -20,7 +20,7 @@ namespace AssetStudio
|
||||
if (shader.m_SubProgramBlob != null) //5.3 - 5.4
|
||||
{
|
||||
var decompressedBytes = new byte[shader.decompressedSize];
|
||||
var numWrite = LZ4.Decompress(shader.m_SubProgramBlob, decompressedBytes);
|
||||
var numWrite = LZ4.Instance.Decompress(shader.m_SubProgramBlob, decompressedBytes);
|
||||
if (numWrite != shader.decompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {shader.decompressedSize} bytes");
|
||||
@@ -59,7 +59,7 @@ namespace AssetStudio
|
||||
}
|
||||
else
|
||||
{
|
||||
var numWrite = LZ4.Decompress(shader.compressedBlob.AsSpan().Slice((int)offset, (int)compressedLength), decompressedBytes.AsSpan().Slice(0, (int)decompressedLength));
|
||||
var numWrite = LZ4.Instance.Decompress(shader.compressedBlob.AsSpan().Slice((int)offset, (int)compressedLength), decompressedBytes.AsSpan().Slice(0, (int)decompressedLength));
|
||||
if (numWrite != decompressedLength)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {decompressedLength} bytes");
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace AssetStudio
|
||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
|
||||
|
||||
reader.Read(compressedBytesSpan);
|
||||
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||
var numWrite = LZ4.Instance.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
|
||||
@@ -37,7 +37,9 @@ namespace AssetStudio
|
||||
Lzham,
|
||||
Lz4Mr0k,
|
||||
Lz4Inv = 5,
|
||||
Zstd = 5
|
||||
Zstd = 5,
|
||||
Lz4Lit4 = 4,
|
||||
Lz4Lit5 = 5,
|
||||
}
|
||||
|
||||
public class BundleFile
|
||||
@@ -450,7 +452,15 @@ namespace AssetStudio
|
||||
try
|
||||
{
|
||||
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, (int)uncompressedSize);
|
||||
var numWrite = LZ4.Decompress(blocksInfoBytesSpan, uncompressedBytesSpan);
|
||||
if (Game.Type.IsPerpetualNovelty())
|
||||
{
|
||||
var key = blocksInfoBytesSpan[1];
|
||||
for (int j = 0; j < Math.Min(0x32, blocksInfoBytesSpan.Length); j++)
|
||||
{
|
||||
blocksInfoBytesSpan[j] ^= key;
|
||||
}
|
||||
}
|
||||
var numWrite = LZ4.Instance.Decompress(blocksInfoBytesSpan, uncompressedBytesSpan);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
@@ -584,7 +594,7 @@ namespace AssetStudio
|
||||
{
|
||||
OPFPUtils.Decrypt(compressedBytesSpan, reader.FullPath);
|
||||
}
|
||||
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||
var numWrite = LZ4.Instance.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
@@ -615,9 +625,37 @@ namespace AssetStudio
|
||||
if (i == 0)
|
||||
{
|
||||
FairGuardUtils.Decrypt(compressedBytesSpan);
|
||||
|
||||
}
|
||||
var numWrite = LZ4Inv.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||
|
||||
var numWrite = LZ4Inv.Instance.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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lz4Lit4 or CompressionType.Lz4Lit5 when Game.Type.IsExAstris():
|
||||
{
|
||||
var compressedSize = (int)blockInfo.compressedSize;
|
||||
var uncompressedSize = (int)blockInfo.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);
|
||||
|
||||
try
|
||||
{
|
||||
reader.Read(compressedBytesSpan);
|
||||
var numWrite = LZ4Lit.Instance.Decompress(compressedBytesSpan, uncompressedBytesSpan);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
|
||||
@@ -48,6 +48,8 @@ namespace AssetStudio
|
||||
Games.Add(index++, new Game(GameType.PartyAnimals));
|
||||
Games.Add(index++, new Game(GameType.LoveAndDeepspace));
|
||||
Games.Add(index++, new Game(GameType.SchoolGirlStrikers));
|
||||
Games.Add(index++, new Game(GameType.ExAstris));
|
||||
Games.Add(index++, new Game(GameType.PerpetualNovelty));
|
||||
}
|
||||
public static Game GetGame(GameType gameType) => GetGame((int)gameType);
|
||||
public static Game GetGame(int index)
|
||||
@@ -167,6 +169,8 @@ namespace AssetStudio
|
||||
PartyAnimals,
|
||||
LoveAndDeepspace,
|
||||
SchoolGirlStrikers,
|
||||
ExAstris,
|
||||
PerpetualNovelty,
|
||||
}
|
||||
|
||||
public static class GameTypes
|
||||
@@ -191,6 +195,8 @@ namespace AssetStudio
|
||||
public static bool IsNetEase(this GameType type) => type == GameType.NetEase;
|
||||
public static bool IsArknightsEndfield(this GameType type) => type == GameType.ArknightsEndfield;
|
||||
public static bool IsLoveAndDeepspace(this GameType type) => type == GameType.LoveAndDeepspace;
|
||||
public static bool IsExAstris(this GameType type) => type == GameType.ExAstris;
|
||||
public static bool IsPerpetualNovelty(this GameType type) => type == GameType.PerpetualNovelty;
|
||||
public static bool IsGIGroup(this GameType type) => type switch
|
||||
{
|
||||
GameType.GI or GameType.GI_Pack or GameType.GI_CB1 or GameType.GI_CB2 or GameType.GI_CB3 or GameType.GI_CB3Pre => true,
|
||||
|
||||
70
AssetStudio/LZ4/LZ4.cs
Normal file
70
AssetStudio/LZ4/LZ4.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio;
|
||||
public class LZ4
|
||||
{
|
||||
public static LZ4 Instance => new();
|
||||
public virtual int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec)
|
||||
{
|
||||
int cmpPos = 0;
|
||||
int decPos = 0;
|
||||
|
||||
do
|
||||
{
|
||||
var (encCount, litCount) = GetLiteralToken(cmp, ref cmpPos);
|
||||
|
||||
//Copy literal chunk
|
||||
litCount = GetLength(litCount, cmp, ref cmpPos);
|
||||
|
||||
cmp.Slice(cmpPos, litCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
cmpPos += litCount;
|
||||
decPos += litCount;
|
||||
|
||||
if (cmpPos >= cmp.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//Copy compressed chunk
|
||||
int back = GetChunkEnd(cmp, ref cmpPos);
|
||||
|
||||
encCount = GetLength(encCount, cmp, ref cmpPos) + 4;
|
||||
|
||||
int encPos = decPos - back;
|
||||
|
||||
if (encCount <= back)
|
||||
{
|
||||
dec.Slice(encPos, encCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
decPos += encCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (encCount-- > 0)
|
||||
{
|
||||
dec[decPos++] = dec[encPos++];
|
||||
}
|
||||
}
|
||||
} while (cmpPos < cmp.Length &&
|
||||
decPos < dec.Length);
|
||||
|
||||
return decPos;
|
||||
}
|
||||
protected virtual (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) => ((cmp[cmpPos] >> 0) & 0xf, (cmp[cmpPos++] >> 4) & 0xf);
|
||||
protected virtual int GetChunkEnd(ReadOnlySpan<byte> cmp, ref int cmpPos) => cmp[cmpPos++] << 0 | cmp[cmpPos++] << 8;
|
||||
protected virtual int GetLength(int length, ReadOnlySpan<byte> cmp, ref int cmpPos)
|
||||
{
|
||||
byte sum;
|
||||
|
||||
if (length == 0xf)
|
||||
{
|
||||
do
|
||||
{
|
||||
length += sum = cmp[cmpPos++];
|
||||
} while (sum == 0xff);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
9
AssetStudio/LZ4/LZ4Inv.cs
Normal file
9
AssetStudio/LZ4/LZ4Inv.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio;
|
||||
public class LZ4Inv : LZ4
|
||||
{
|
||||
public new static LZ4Inv Instance => new();
|
||||
protected override (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) => ((cmp[cmpPos] >> 4) & 0xf, (cmp[cmpPos++] >> 0) & 0xf);
|
||||
protected override int GetChunkEnd(ReadOnlySpan<byte> cmp, ref int cmpPos) => cmp[cmpPos++] << 8 | cmp[cmpPos++] << 0;
|
||||
}
|
||||
8
AssetStudio/LZ4/LZ4Lit.cs
Normal file
8
AssetStudio/LZ4/LZ4Lit.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio;
|
||||
public class LZ4Lit : LZ4
|
||||
{
|
||||
public new static LZ4Lit Instance => new();
|
||||
protected override (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) => ((cmp[cmpPos] >> 4) & 0xf, (cmp[cmpPos++] >> 0) & 0xf);
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio;
|
||||
public static class LZ4
|
||||
{
|
||||
public static int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec)
|
||||
{
|
||||
int cmpPos = 0;
|
||||
int decPos = 0;
|
||||
|
||||
// ReSharper disable once VariableHidesOuterVariable
|
||||
int GetLength(int length, ReadOnlySpan<byte> cmp)
|
||||
{
|
||||
byte sum;
|
||||
|
||||
if (length == 0xf)
|
||||
{
|
||||
do
|
||||
{
|
||||
length += sum = cmp[cmpPos++];
|
||||
} while (sum == 0xff);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
byte token = cmp[cmpPos++];
|
||||
|
||||
int encCount = (token >> 0) & 0xf;
|
||||
int litCount = (token >> 4) & 0xf;
|
||||
|
||||
//Copy literal chunk
|
||||
litCount = GetLength(litCount, cmp);
|
||||
|
||||
cmp.Slice(cmpPos, litCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
cmpPos += litCount;
|
||||
decPos += litCount;
|
||||
|
||||
if (cmpPos >= cmp.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//Copy compressed chunk
|
||||
int back = cmp[cmpPos++] << 0 |
|
||||
cmp[cmpPos++] << 8;
|
||||
|
||||
encCount = GetLength(encCount, cmp) + 4;
|
||||
|
||||
int encPos = decPos - back;
|
||||
|
||||
if (encCount <= back)
|
||||
{
|
||||
dec.Slice(encPos, encCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
decPos += encCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (encCount-- > 0)
|
||||
{
|
||||
dec[decPos++] = dec[encPos++];
|
||||
}
|
||||
}
|
||||
} while (cmpPos < cmp.Length &&
|
||||
decPos < dec.Length);
|
||||
|
||||
return decPos;
|
||||
}
|
||||
}
|
||||
public static class LZ4Inv
|
||||
{
|
||||
public static int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec)
|
||||
{
|
||||
int cmpPos = 0;
|
||||
int decPos = 0;
|
||||
|
||||
// ReSharper disable once VariableHidesOuterVariable
|
||||
int GetLength(int length, ReadOnlySpan<byte> cmp)
|
||||
{
|
||||
byte sum;
|
||||
|
||||
if (length == 0xf)
|
||||
{
|
||||
do
|
||||
{
|
||||
length += sum = cmp[cmpPos++];
|
||||
} while (sum == 0xff);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
byte token = cmp[cmpPos++];
|
||||
|
||||
int encCount = (token >> 4) & 0xf;
|
||||
int litCount = (token >> 0) & 0xf;
|
||||
|
||||
//Copy literal chunk
|
||||
litCount = GetLength(litCount, cmp);
|
||||
|
||||
cmp.Slice(cmpPos, litCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
cmpPos += litCount;
|
||||
decPos += litCount;
|
||||
|
||||
if (cmpPos >= cmp.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//Copy compressed chunk
|
||||
int back = cmp[cmpPos++] << 8 |
|
||||
cmp[cmpPos++] << 0;
|
||||
|
||||
encCount = GetLength(encCount, cmp) + 4;
|
||||
|
||||
int encPos = decPos - back;
|
||||
|
||||
if (encCount <= back)
|
||||
{
|
||||
dec.Slice(encPos, encCount).CopyTo(dec.Slice(decPos));
|
||||
|
||||
decPos += encCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (encCount-- > 0)
|
||||
{
|
||||
dec[decPos++] = dec[encPos++];
|
||||
}
|
||||
}
|
||||
} while (cmpPos < cmp.Length &&
|
||||
decPos < dec.Length);
|
||||
|
||||
return decPos;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace AssetStudio
|
||||
|
||||
try
|
||||
{
|
||||
var numWrite = LZ4.Decompress(compressedBlocksInfo, uncompressedBlocksInfoSpan);
|
||||
var numWrite = LZ4.Instance.Decompress(compressedBlocksInfo, uncompressedBlocksInfoSpan);
|
||||
if (numWrite != m_Header.uncompressedBlocksInfoSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
|
||||
@@ -144,7 +144,7 @@ namespace AssetStudio
|
||||
DescrambleEntry(compressedBytesSpan);
|
||||
|
||||
Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}");
|
||||
var numWrite = LZ4.Decompress(compressedBytesSpan[0xC..], uncompressedBytesSpan);
|
||||
var numWrite = LZ4.Instance.Decompress(compressedBytesSpan[0xC..], uncompressedBytesSpan);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
|
||||
Reference in New Issue
Block a user