miniTool/minitool1/Program.cs
2024-11-13 23:38:42 +08:00

233 lines
8.2 KiB
C#

using K4os.Compression.LZ4;
using System.Text;
namespace minitool1
{
public class PkgChunk
{
public string pkg_path;
public long off;
public int len_comp;
public int len_uncomp;
}
public class Program
{
static void Main(string[] args)
{
if (args.Length != 1)
return;
if (!Path.Exists(args[0]))
return;
string streamingAssetsPath = args[0];
Dictionary<string, PkgChunk> file_map = [];
LoadFileHeader(file_map, streamingAssetsPath + "/data_bg_i.arc");
LoadFileHeader(file_map, streamingAssetsPath + "/data_st.arc");
LoadFileHeader(file_map, streamingAssetsPath + "/data_tb.arc");
LoadFileHeader(file_map, streamingAssetsPath + "/data_tr.arc");
LoadFileHeader(file_map, streamingAssetsPath + "/data_cgs_real.arc");
LoadFileHeader(file_map, streamingAssetsPath + "/data_game_sc_stand.arc");
LoadAbFile(file_map, args[0]);
Console.ReadKey();
}
private static void LoadAbFile(Dictionary<string, PkgChunk> file_map, string outputPath)
{
outputPath = Path.Combine(outputPath, "output");
if (!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath);
foreach (var kvp in file_map)
{
string key = kvp.Key;
byte[] data;
if (key.EndsWith(".co.bytes"))
{
byte[] array = LoadNormalFile(file_map, key);
int num = 0;
while (num < array.Length && array[num] != 0)
{
num++;
}
string @string = Encoding.UTF8.GetString(array, 0, num);
byte[] array2 = LoadNormalFile(file_map, @string);
data = Proc_dec(array2, array);
}
else
{
data = LoadNormalFile(file_map, key);
}
string newKey = key[..^".un.bytes".Length]; //.co.bytes顺带处理
WriteFile(data, Path.Combine(outputPath, newKey + ".asset"));
}
}
private static void WriteFile(byte[] data, string path)
{
try
{
File.WriteAllBytes(path, data);
Console.WriteLine($"{Path.GetFileName(path)} extraction successful.");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to write file to {path}. Error: {ex.Message}");
}
}
private static byte[] LoadNormalFile(Dictionary<string, PkgChunk> file_map, string file_name)
{
if (!file_map.TryGetValue(file_name, out PkgChunk? pkgChunk))
throw new Exception($"{file_name} not found");
int num = pkgChunk.len_uncomp;
if (pkgChunk.len_comp != 0)
num = pkgChunk.len_comp;
byte[] array2 = new byte[num];
FileStream fileStream = new(pkgChunk.pkg_path, FileMode.Open);
fileStream.Seek(pkgChunk.off, SeekOrigin.Begin);
fileStream.Read(array2, 0, num);
fileStream.Close();
if (pkgChunk.len_comp != 0)
return DecompressLz4(array2, pkgChunk.len_uncomp);
return array2;
}
private static byte[] DecompressLz4(byte[] src, int len_uncomp)
{
byte[] array = new byte[len_uncomp];
LZ4Codec.Decode(src, 0, src.Length, array, 0, array.Length);
return array;
}
private static int GetInt32(byte[] buf, int off)
{
return ((((((int)(0 | buf[off + 3]) << 8) | (int)buf[off + 2]) << 8) | (int)buf[off + 1]) << 8) | (int)buf[off];
}
private static long GetInt64(byte[] buf, int off)
{
return (long)(((((((((((((((0UL | (ulong)buf[off + 7]) << 8) | (ulong)buf[off + 6]) << 8) | (ulong)buf[off + 5]) << 8) | (ulong)buf[off + 4]) << 8) | (ulong)buf[off + 3]) << 8) | (ulong)buf[off + 2]) << 8) | (ulong)buf[off + 1]) << 8) | (ulong)buf[off]);
}
private static string GetString(byte[] buf, int off, ref int proc_len)
{
int num = 0;
while (num < buf.Length - off && buf[off + num] != 0)
{
num++;
}
string @string = Encoding.UTF8.GetString(buf, off, num);
proc_len = num + 1;
return @string;
}
private static void LoadFileHeader(Dictionary<string, PkgChunk> file_map, string file_path)
{
if (!File.Exists(file_path))
{
return;
}
FileStream fileStream = new(file_path, FileMode.Open);
byte[] array = new byte[16];
fileStream.Seek(0L, SeekOrigin.Begin);
fileStream.Read(array, 0, 16);
long @int = GetInt64(array, 0);
int int2 = GetInt32(array, 8);
int int3 = GetInt32(array, 12);
byte[] array2 = new byte[int2];
fileStream.Seek(@int, SeekOrigin.Begin);
fileStream.Read(array2, 0, int2);
fileStream.Close();
int num = 0;
for (int i = 0; i < int3; i++)
{
int num2 = 0;
string @string = GetString(array2, num, ref num2);
num += num2;
PkgChunk pkgChunk = new()
{
pkg_path = file_path,
off = GetInt64(array2, num)
};
num += 8;
pkgChunk.len_uncomp = GetInt32(array2, num);
num += 4;
pkgChunk.len_comp = GetInt32(array2, num);
num += 4;
file_map.Add(@string, pkgChunk);
}
}
private static byte[] Proc_dec(byte[] buf_base, byte[] buf_now)
{
int i = 0;
while (i < buf_now.Length && buf_now[i] != 0)
{
i++;
}
i++;
int @int = GetInt32(buf_now, i);
i += 4;
byte[] array = new byte[@int];
int num = 0;
int num2 = 0;
int num3 = buf_now.Length;
while (i < num3)
{
byte b = buf_now[i++];
if ((b & 128) != 0)
{
int num4 = (int)(b & 127);
Array.Copy(buf_now, i, array, num, num4);
i += num4;
num += num4;
num2 += num4;
}
else if (b == 0)
{
int num5 = (int)buf_now[i++];
num5 &= 255;
if ((num5 & 128) != 0)
{
num5 &= 127;
num5 -= 128;
}
num2 += num5;
}
else if (b == 1)
{
int num6 = (int)buf_now[i++];
Array.Copy(buf_base, num2, array, num, num6);
num2 += num6;
num += num6;
}
else if (b == 2)
{
int num7 = (int)buf_now[i++];
num7 <<= 8;
num7 |= (int)buf_now[i++];
Array.Copy(buf_base, num2, array, num, num7);
num2 += num7;
num += num7;
}
else if (b == 3)
{
int num8 = (int)buf_now[i++];
num8 <<= 8;
num8 |= (int)buf_now[i++];
num8 <<= 8;
num8 |= (int)buf_now[i++];
num8 <<= 8;
num8 |= (int)buf_now[i++];
Array.Copy(buf_base, num2, array, num, num8);
num2 += num8;
num += num8;
}
else
{
throw new Exception("Decompress Fail");
}
}
return array;
}
}
}