- [Core] Added new entries.
This commit is contained in:
@@ -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");
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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
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
|
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");
|
||||||
|
|||||||
Reference in New Issue
Block a user