- [Core] Added new entries.

This commit is contained in:
Razmoth
2024-02-28 16:28:36 +04:00
parent 566444132c
commit c27ebec10e
9 changed files with 141 additions and 153 deletions

View File

@@ -20,7 +20,7 @@ namespace AssetStudio
if (shader.m_SubProgramBlob != null) //5.3 - 5.4 if (shader.m_SubProgramBlob != null) //5.3 - 5.4
{ {
var decompressedBytes = new byte[shader.decompressedSize]; 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) if (numWrite != shader.decompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {shader.decompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {shader.decompressedSize} bytes");
@@ -59,7 +59,7 @@ namespace AssetStudio
} }
else 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) if (numWrite != decompressedLength)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {decompressedLength} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {decompressedLength} bytes");

View File

@@ -160,7 +160,7 @@ namespace AssetStudio
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize); var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
reader.Read(compressedBytesSpan); reader.Read(compressedBytesSpan);
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan); var numWrite = LZ4.Instance.Decompress(compressedBytesSpan, uncompressedBytesSpan);
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");

View File

@@ -37,7 +37,9 @@ namespace AssetStudio
Lzham, Lzham,
Lz4Mr0k, Lz4Mr0k,
Lz4Inv = 5, Lz4Inv = 5,
Zstd = 5 Zstd = 5,
Lz4Lit4 = 4,
Lz4Lit5 = 5,
} }
public class BundleFile public class BundleFile
@@ -450,7 +452,15 @@ namespace AssetStudio
try try
{ {
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, (int)uncompressedSize); 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) 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");
@@ -584,7 +594,7 @@ namespace AssetStudio
{ {
OPFPUtils.Decrypt(compressedBytesSpan, reader.FullPath); OPFPUtils.Decrypt(compressedBytesSpan, reader.FullPath);
} }
var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan); var numWrite = LZ4.Instance.Decompress(compressedBytesSpan, uncompressedBytesSpan);
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");
@@ -615,9 +625,37 @@ namespace AssetStudio
if (i == 0) if (i == 0)
{ {
FairGuardUtils.Decrypt(compressedBytesSpan); 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) 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");

View File

@@ -48,6 +48,8 @@ namespace AssetStudio
Games.Add(index++, new Game(GameType.PartyAnimals)); Games.Add(index++, new Game(GameType.PartyAnimals));
Games.Add(index++, new Game(GameType.LoveAndDeepspace)); Games.Add(index++, new Game(GameType.LoveAndDeepspace));
Games.Add(index++, new Game(GameType.SchoolGirlStrikers)); 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(GameType gameType) => GetGame((int)gameType);
public static Game GetGame(int index) public static Game GetGame(int index)
@@ -167,6 +169,8 @@ namespace AssetStudio
PartyAnimals, PartyAnimals,
LoveAndDeepspace, LoveAndDeepspace,
SchoolGirlStrikers, SchoolGirlStrikers,
ExAstris,
PerpetualNovelty,
} }
public static class GameTypes public static class GameTypes
@@ -191,6 +195,8 @@ namespace AssetStudio
public static bool IsNetEase(this GameType type) => type == GameType.NetEase; public static bool IsNetEase(this GameType type) => type == GameType.NetEase;
public static bool IsArknightsEndfield(this GameType type) => type == GameType.ArknightsEndfield; public static bool IsArknightsEndfield(this GameType type) => type == GameType.ArknightsEndfield;
public static bool IsLoveAndDeepspace(this GameType type) => type == GameType.LoveAndDeepspace; 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 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, 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
View 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;
}
}

View 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;
}

View 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);
}

View File

@@ -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;
}
}

View File

@@ -63,7 +63,7 @@ namespace AssetStudio
try try
{ {
var numWrite = LZ4.Decompress(compressedBlocksInfo, uncompressedBlocksInfoSpan); var numWrite = LZ4.Instance.Decompress(compressedBlocksInfo, uncompressedBlocksInfoSpan);
if (numWrite != m_Header.uncompressedBlocksInfoSize) if (numWrite != m_Header.uncompressedBlocksInfoSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
@@ -144,7 +144,7 @@ namespace AssetStudio
DescrambleEntry(compressedBytesSpan); DescrambleEntry(compressedBytesSpan);
Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}"); 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) 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");