添加项目文件。

This commit is contained in:
Chenx221 2024-10-19 13:50:35 +08:00
parent b0956c8536
commit a4036e89d6
5 changed files with 317 additions and 0 deletions

25
TmrHiroRepack.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35327.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TmrHiroRepack", "TmrHiroRepack\TmrHiroRepack.csproj", "{F4FBB98A-9511-4CFA-B6C1-D1505E52ACB9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F4FBB98A-9511-4CFA-B6C1-D1505E52ACB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F4FBB98A-9511-4CFA-B6C1-D1505E52ACB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4FBB98A-9511-4CFA-B6C1-D1505E52ACB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4FBB98A-9511-4CFA-B6C1-D1505E52ACB9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {21903E7F-A268-4FD1-880E-7DD9BDC671B8}
EndGlobalSection
EndGlobal

148
TmrHiroRepack/Program.cs Normal file
View File

@ -0,0 +1,148 @@

using System.IO;
using System.Text;
namespace TmrHiroRepack
{
public class Entry
{
public string Name { get; set; }
public long Offset { get; set; }
public uint Size { get; set; }
}
public class Index
{
public string name;
public EntryInfoV1 entryInfoV1;
public EntryInfoV2 entryInfoV2;
}
public class EntryInfoV1
{
public uint entryOffset;
public uint entrySize;
}
public class EntryInfoV2
{
public long entryOffset;
public uint entrySize;
}
internal class Program
{
static void Main(string[] args)
{
if (args.Length < 2)
{
Console.WriteLine("Usage: TmrHiroRepack <FolderPath> <Version>");
return;
}
string folderPath = args[0];
string versionArg = args[1];
if (!Directory.Exists(folderPath))
{
Console.WriteLine("Invalid FolderPath");
return;
}
if (!int.TryParse(versionArg, out int version) || (version != 1 && version != 2))
{
Console.WriteLine("Invalid Version");
return;
}
Console.WriteLine($"Repacking {Path.GetFileName(folderPath)}");
bool status = Repack(folderPath, version);
Console.WriteLine(status ? "Repack Successful" : "Repack Failed");
}
private static bool Repack(string folderPath, int version)
{
EncodingProvider provider = CodePagesEncodingProvider.Instance;
Encoding? shiftJis = provider.GetEncoding("shift-jis");
string[] files = Directory.GetFiles(folderPath);
short count = (short)files.Length; //文件数量
byte name_length = 0x16; //文件名长度(貌似固定16?)
uint data_offset;
if (version == 1)
data_offset = 7 + ((uint)name_length + 8) * (uint)count; //Data区偏移
else if (version == 2)
data_offset = 7 + ((uint)name_length + 12) * (uint)count; //Data区偏移
else
throw new Exception("Invalid Version");
long offset = 0; //Index区偏移
List<Index> indexs = new();
string[] extensions = { ".ogg", ".grd", ".srp" }; //需要移除的文件后缀因为这是Garbro添加的
foreach (string file in files)
{
Index i = new();
string fileName = Path.GetFileName(file);
FileInfo fileInfo = new(file);
//remove .ogg/.grd/.srp
foreach (var extension in extensions)
{
if (fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
{
fileName = fileName[..^extension.Length];
if (shiftJis.GetBytes(fileName).Length > name_length)
throw new Exception("Something Wrong, File name too long");
}
}
i.name = fileName;
if (version == 1)
{
i.entryInfoV1 = new()
{
entryOffset = (uint)offset,
entrySize = (uint)fileInfo.Length
};
}
else if (version == 2)
{
i.entryInfoV2 = new()
{
entryOffset = offset,
entrySize = (uint)fileInfo.Length
};
}
offset += fileInfo.Length;
indexs.Add(i);
}
//准备开写
string outputPath = Path.Combine(Path.GetDirectoryName(folderPath), Path.GetFileName(folderPath) + ".pac");
using (FileStream fs = new(outputPath, FileMode.Create))
using (BinaryWriter bw = new(fs))
{
bw.Write(count);//文件数量
bw.Write(name_length);//文件名长度
bw.Write(data_offset);//Data区偏移
foreach (Index i in indexs)
{
byte[] name = new byte[name_length];
Array.Copy(shiftJis.GetBytes(i.name), name, shiftJis.GetBytes(i.name).Length);
bw.Write(name);//文件名
if (version == 1)
{
bw.Write(i.entryInfoV1.entryOffset);//文件偏移
bw.Write(i.entryInfoV1.entrySize);//文件大小
}
else if (version == 2)
{
bw.Write(i.entryInfoV2.entryOffset);//文件偏移
bw.Write(i.entryInfoV2.entrySize);//文件大小
}
}
foreach (string file in files)
{
using (FileStream fs2 = new(file, FileMode.Open))
{
fs2.CopyTo(fs);
}
}
}
return true;
}
}
}

View File

@ -0,0 +1,8 @@
{
"profiles": {
"TmrHiroRepack": {
"commandName": "Project",
"commandLineArgs": "G:\\x221.local\\test\\Agrd\r\n2"
}
}
}

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

126
TmrHiroRepack/Utils.cs Normal file
View File

@ -0,0 +1,126 @@
using System.Reflection;
using System.Text;
namespace TmrHiroRepack
{
public class Utils
{
public static string ReadStringFromTextData(byte[] sheet_text, int offset)
{
return ReadStringFromTextData(sheet_text, offset, -1);
}
public static string ReadStringFromTextData(byte[] sheet_text, int offset, int length_limit)
{
EncodingProvider provider = CodePagesEncodingProvider.Instance;
Encoding? shiftJis = provider.GetEncoding("shift-jis") ?? throw new InvalidOperationException("Shift-JIS encoding not supported.");
return ReadStringFromTextData(sheet_text, offset, length_limit, shiftJis);
}
public static string ReadStringFromTextData(byte[] sheet_text, int offset, int length_limit, Encoding enc)
{
List<byte> stringBytes = [];
int end = length_limit != -1 ? Math.Min(offset + length_limit, sheet_text.Length) : sheet_text.Length;
for (int i = offset; i < end && sheet_text[i] != 0x00; i++)
{
stringBytes.Add(sheet_text[i]);
}
return enc.GetString(stringBytes.ToArray());
}
public static byte[] ReadBytes(BinaryReader reader, ulong length)
{
const int bufferSize = 8192;
byte[] data = new byte[length];
ulong bytesRead = 0;
while (bytesRead < length)
{
int toRead = (int)Math.Min(bufferSize, length - bytesRead);
int read = reader.Read(data, (int)bytesRead, toRead);
if (read == 0)
break;
bytesRead += (ulong)read;
}
return data;
}
public static uint ToUInt32<TArray>(TArray value, int index) where TArray : IList<byte>
{
return (uint)(value[index] | value[index + 1] << 8 | value[index + 2] << 16 | value[index + 3] << 24);
}
public static uint ReadUInt32(BinaryReader reader)
{
byte[] bytes = reader.ReadBytes(4);
if (bytes.Length < 4)
throw new EndOfStreamException("Unexpected end of stream while reading UInt32.");
return BitConverter.ToUInt32(bytes, 0);
}
public static void ExtractEmbeddedDatabase(string outputPath)
{
if (File.Exists(outputPath))
{
Console.WriteLine($"File {outputPath} already exists. Do you want to overwrite it? (y/n)");
string? input = Console.ReadLine();
if (input?.ToLower() != "y")
{
Console.WriteLine("Task cancelled, Exporting database aborted.");
return;
}
}
var assembly = Assembly.GetExecutingAssembly();
string resourceName = "EscudeTools.empty.db";
using Stream stream = assembly.GetManifestResourceStream(resourceName) ?? throw new Exception($"Error, No resource with name {resourceName} found.");
using FileStream fileStream = new(outputPath, FileMode.Create, FileAccess.Write);
stream.CopyTo(fileStream);
}
public static string GetSQLiteColumnType(ushort type)
{
return type switch
{
// int
0x1 => "INTEGER",
// float
0x2 => "REAL",
// string
0x3 => "TEXT",
// bool
0x4 => "INTEGER",
_ => throw new NotSupportedException($"Unsupported column type: {type}"),
};
throw new NotImplementedException();
}
public static bool ISKANJI(byte x)
{
return (x ^ 0x20) - 0xa1 <= 0x3b;
}
public static ushort GetColumnTypeFromSQLite(string v)
{
return v[^2] switch
{
'1' => 0x1,
'2' => 0x2,
'3' => 0x3,
'4' => 0x4,
_ => throw new NotSupportedException($"Unsupported column type: {v}"),
};
}
public static ushort GetColumnSize(string v)
{
return v[^1] switch
{
'1' => 0x1,
'2' => 0x2,
'3' => 0x3,
'4' => 0x4,
_ => throw new NotSupportedException($"Unsupported column Size: {v}"),
};
}
}
}