添加项目文件。
This commit is contained in:
parent
b0956c8536
commit
a4036e89d6
25
TmrHiroRepack.sln
Normal file
25
TmrHiroRepack.sln
Normal 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
148
TmrHiroRepack/Program.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
8
TmrHiroRepack/Properties/launchSettings.json
Normal file
8
TmrHiroRepack/Properties/launchSettings.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"TmrHiroRepack": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "G:\\x221.local\\test\\Agrd\r\n2"
|
||||
}
|
||||
}
|
||||
}
|
10
TmrHiroRepack/TmrHiroRepack.csproj
Normal file
10
TmrHiroRepack/TmrHiroRepack.csproj
Normal 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
126
TmrHiroRepack/Utils.cs
Normal 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}"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user