Compare commits
2 Commits
a4036e89d6
...
857beaeab6
Author | SHA1 | Date | |
---|---|---|---|
857beaeab6 | |||
7a6ffec374 |
@ -63,7 +63,21 @@ namespace TmrHiroRepack
|
|||||||
Encoding? shiftJis = provider.GetEncoding("shift-jis");
|
Encoding? shiftJis = provider.GetEncoding("shift-jis");
|
||||||
string[] files = Directory.GetFiles(folderPath);
|
string[] files = Directory.GetFiles(folderPath);
|
||||||
short count = (short)files.Length; //文件数量
|
short count = (short)files.Length; //文件数量
|
||||||
byte name_length = 0x16; //文件名长度(貌似固定16?)
|
string[] extensions = [".ogg", ".grd", ".srp"]; //需要移除的文件后缀,因为这是Garbro添加的
|
||||||
|
int max_name_length = 0;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
string fileName = Path.GetFileName(file);
|
||||||
|
foreach (var extension in extensions)
|
||||||
|
{
|
||||||
|
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
fileName = fileName[..^extension.Length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_name_length = Math.Max(max_name_length, shiftJis.GetBytes(fileName).Length);
|
||||||
|
}
|
||||||
|
byte name_length = (byte)max_name_length; //文件名长度,每个封包值都不同
|
||||||
uint data_offset;
|
uint data_offset;
|
||||||
if (version == 1)
|
if (version == 1)
|
||||||
data_offset = 7 + ((uint)name_length + 8) * (uint)count; //Data区偏移
|
data_offset = 7 + ((uint)name_length + 8) * (uint)count; //Data区偏移
|
||||||
@ -72,8 +86,7 @@ namespace TmrHiroRepack
|
|||||||
else
|
else
|
||||||
throw new Exception("Invalid Version");
|
throw new Exception("Invalid Version");
|
||||||
long offset = 0; //Index区偏移
|
long offset = 0; //Index区偏移
|
||||||
List<Index> indexs = new();
|
List<Index> indexs = [];
|
||||||
string[] extensions = { ".ogg", ".grd", ".srp" }; //需要移除的文件后缀,因为这是Garbro添加的
|
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
Index i = new();
|
Index i = new();
|
||||||
@ -85,8 +98,6 @@ namespace TmrHiroRepack
|
|||||||
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
|
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
fileName = fileName[..^extension.Length];
|
fileName = fileName[..^extension.Length];
|
||||||
if (shiftJis.GetBytes(fileName).Length > name_length)
|
|
||||||
throw new Exception("Something Wrong, File name too long");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.name = fileName;
|
i.name = fileName;
|
||||||
@ -112,9 +123,8 @@ namespace TmrHiroRepack
|
|||||||
}
|
}
|
||||||
//准备开写
|
//准备开写
|
||||||
string outputPath = Path.Combine(Path.GetDirectoryName(folderPath), Path.GetFileName(folderPath) + ".pac");
|
string outputPath = Path.Combine(Path.GetDirectoryName(folderPath), Path.GetFileName(folderPath) + ".pac");
|
||||||
using (FileStream fs = new(outputPath, FileMode.Create))
|
using FileStream fs = new(outputPath, FileMode.Create);
|
||||||
using (BinaryWriter bw = new(fs))
|
using BinaryWriter bw = new(fs);
|
||||||
{
|
|
||||||
bw.Write(count);//文件数量
|
bw.Write(count);//文件数量
|
||||||
bw.Write(name_length);//文件名长度
|
bw.Write(name_length);//文件名长度
|
||||||
bw.Write(data_offset);//Data区偏移
|
bw.Write(data_offset);//Data区偏移
|
||||||
@ -136,11 +146,31 @@ namespace TmrHiroRepack
|
|||||||
}
|
}
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
using (FileStream fs2 = new(file, FileMode.Open))
|
//检查是否是脚本文件(文件后缀.srp)
|
||||||
|
if (Path.GetExtension(file) == ".srp") // Script file detected
|
||||||
{
|
{
|
||||||
|
byte[] DecryptData = File.ReadAllBytes(file);
|
||||||
|
uint offset2 = 0;
|
||||||
|
int record_count = BitConverter.ToInt32(DecryptData, (int)offset2);
|
||||||
|
offset2 += 4;
|
||||||
|
for (int i = 0; i < record_count; i++)
|
||||||
|
{
|
||||||
|
ushort chunk_size = (ushort)(BitConverter.ToUInt16(DecryptData, (int)offset2) - 4); //我知道这里有潜在的问题,但我不相信哪个游戏单个script文件有2G
|
||||||
|
offset2 += 6;
|
||||||
|
for (int j = 0; j < chunk_size; j++)
|
||||||
|
{
|
||||||
|
DecryptData[offset2] = Utils.RotByteL(DecryptData[offset2], 4);
|
||||||
|
offset2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bw.Write(DecryptData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using FileStream fs2 = new(file, FileMode.Open);
|
||||||
fs2.CopyTo(fs);
|
fs2.CopyTo(fs);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -122,5 +122,17 @@ namespace TmrHiroRepack
|
|||||||
_ => throw new NotSupportedException($"Unsupported column Size: {v}"),
|
_ => throw new NotSupportedException($"Unsupported column Size: {v}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte RotByteR(byte v, int count)
|
||||||
|
{
|
||||||
|
count &= 7;
|
||||||
|
return (byte)(v >> count | v << (8 - count));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte RotByteL(byte v, int count)
|
||||||
|
{
|
||||||
|
count &= 7;
|
||||||
|
return (byte)(v << count | v >> (8 - count));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
note/pac结构.txt
Normal file
28
note/pac结构.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
count short 2B
|
||||||
|
name_length uint 1B
|
||||||
|
data_offset uint 4B
|
||||||
|
|
||||||
|
如果data_offset=7+(name_length+8)*count ->v1
|
||||||
|
如果data_offset=7+(name_length+12)*count ->v2
|
||||||
|
|
||||||
|
index_offset=7
|
||||||
|
|
||||||
|
[ INDEX
|
||||||
|
name *string name_length
|
||||||
|
{ v1
|
||||||
|
entryOffset uint 4B (+data_offset *相对整个文件而言)
|
||||||
|
entrySize uint 4B
|
||||||
|
}
|
||||||
|
{ v2
|
||||||
|
entryOffset long 8B (+data_offset *同上)
|
||||||
|
entrySize uint 4B
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
[ DATA
|
||||||
|
]
|
||||||
|
|
||||||
|
文件处理
|
||||||
|
.ogg/.grd/.srp全部去掉
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user