mirror of
https://github.com/UltiNaruto/PKGTool
synced 2024-11-13 23:47:08 +00:00
Ajoutez des fichiers projet.
This commit is contained in:
parent
6cd06acb9c
commit
b6067401f4
6 changed files with 386 additions and 0 deletions
25
PKGTool.sln
Normal file
25
PKGTool.sln
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.31727.386
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PKGTool", "PKGTool\PKGTool.csproj", "{C882EC56-0245-481E-B2F2-3C7336B7963A}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C882EC56-0245-481E-B2F2-3C7336B7963A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C882EC56-0245-481E-B2F2-3C7336B7963A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C882EC56-0245-481E-B2F2-3C7336B7963A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C882EC56-0245-481E-B2F2-3C7336B7963A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {FBC66971-6591-422B-AF47-66D00A35825C}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
130
PKGTool/Dread/FileFormats/PKG.cs
Normal file
130
PKGTool/Dread/FileFormats/PKG.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Dread.FileFormats
|
||||||
|
{
|
||||||
|
public class PKG : Misc.Structs.BinaryStruct
|
||||||
|
{
|
||||||
|
public List<KeyValuePair<UInt64, MemoryStream>> Files = new List<KeyValuePair<UInt64, MemoryStream>>();
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
foreach (var file in Files)
|
||||||
|
file.Value.Close();
|
||||||
|
Files.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32[,] GenerateFileOffsets()
|
||||||
|
{
|
||||||
|
Int32 i = 0;
|
||||||
|
Int32[,] offsets = new Int32[Files.Count, 2];
|
||||||
|
Int32 cursor = 12 + Files.Count * 16;
|
||||||
|
if ((cursor % 8) != 0) cursor += 8 - (cursor % 8);
|
||||||
|
foreach (var file in Files)
|
||||||
|
{
|
||||||
|
offsets[i, 0] = cursor;
|
||||||
|
cursor += (Int32)file.Value.Length;
|
||||||
|
offsets[i, 1] = cursor;
|
||||||
|
if ((cursor % 8) != 0) cursor += 8 - (cursor % 8);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int StructSize
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int len = 12 + Files.Count * 16;
|
||||||
|
if ((len % 8) != 0) len += 8 - (len % 8);
|
||||||
|
foreach (var file in Files)
|
||||||
|
{
|
||||||
|
len += (int)file.Value.Length;
|
||||||
|
if((len % 8) != 0) len += 8 - (len % 8);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void import(Stream stream)
|
||||||
|
{
|
||||||
|
Int32 i, data_section_start;
|
||||||
|
List<UInt64> IDs = new List<UInt64>();
|
||||||
|
List<Int32[]> Offsets = new List<Int32[]>();
|
||||||
|
|
||||||
|
var reader = new BinaryReader(stream);
|
||||||
|
Int32 header_size = reader.ReadInt32();
|
||||||
|
Int32 data_section_size = reader.ReadInt32();
|
||||||
|
Int32 file_count = reader.ReadInt32();
|
||||||
|
|
||||||
|
for(i = 0; i< file_count;i++)
|
||||||
|
{
|
||||||
|
Files.Add(new KeyValuePair<UInt64, MemoryStream>(reader.ReadUInt64(), new MemoryStream()));
|
||||||
|
Offsets.Add(new Int32[] { reader.ReadInt32(), reader.ReadInt32() });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_size != (Int32)stream.Position)
|
||||||
|
throw new Exception("Invalid PKG file! (Guessed header size doesn't correspond to the real size)");
|
||||||
|
|
||||||
|
// padding
|
||||||
|
if ((stream.Position % 8) != 0) stream.Position += 8 - (stream.Position % 8);
|
||||||
|
|
||||||
|
data_section_start = (Int32)stream.Position;
|
||||||
|
|
||||||
|
for (i=0;i<file_count;i++)
|
||||||
|
{
|
||||||
|
if (Offsets[i][0] != (int)stream.Position)
|
||||||
|
throw new Exception("Wrong starting offset!");
|
||||||
|
Files[i].Value.Write(reader.ReadBytes(Offsets[i][1] - Offsets[i][0]));
|
||||||
|
Files[i].Value.Position = 0L;
|
||||||
|
|
||||||
|
// padding
|
||||||
|
if ((stream.Position % 8) != 0) stream.Position += 8 - (stream.Position % 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_section_size != (Int32)stream.Position - data_section_start)
|
||||||
|
throw new Exception("Invalid PKG file! (Guessed data section size doesn't correspond to the real size)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void export(Stream stream)
|
||||||
|
{
|
||||||
|
Int32 i, header_size, data_section_start, data_section_size;
|
||||||
|
Int32[,] offsets = GenerateFileOffsets();
|
||||||
|
|
||||||
|
var writer = new BinaryWriter(stream);
|
||||||
|
stream.Position += 8;
|
||||||
|
writer.Write(Files.Count);
|
||||||
|
for(i=0;i<Files.Count;i++)
|
||||||
|
{
|
||||||
|
writer.Write(Files[i].Key);
|
||||||
|
writer.Write(offsets[i, 0]);
|
||||||
|
writer.Write(offsets[i, 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
header_size = (Int32)stream.Position;
|
||||||
|
|
||||||
|
// padding
|
||||||
|
while (stream.Position % 8 != 0) writer.Write((byte)0);
|
||||||
|
|
||||||
|
data_section_start = (Int32)stream.Position;
|
||||||
|
|
||||||
|
for (i = 0; i < Files.Count; i++)
|
||||||
|
{
|
||||||
|
Files[i].Value.CopyTo(stream);
|
||||||
|
Files[i].Value.Position = 0L;
|
||||||
|
|
||||||
|
// padding
|
||||||
|
while (stream.Position % 8 != 0) writer.Write((byte)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_section_size = (Int32)stream.Position - data_section_start;
|
||||||
|
|
||||||
|
stream.Position = 0L;
|
||||||
|
|
||||||
|
writer.Write(header_size);
|
||||||
|
writer.Write(data_section_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
PKGTool/Misc/Structs/BinaryStruct.cs
Normal file
12
PKGTool/Misc/Structs/BinaryStruct.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Misc.Structs
|
||||||
|
{
|
||||||
|
public abstract class BinaryStruct
|
||||||
|
{
|
||||||
|
public BinaryStruct() { }
|
||||||
|
public abstract void import(Stream stream);
|
||||||
|
public abstract void export(Stream stream);
|
||||||
|
public abstract int StructSize { get; }
|
||||||
|
}
|
||||||
|
}
|
8
PKGTool/PKGTool.csproj
Normal file
8
PKGTool/PKGTool.csproj
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
203
PKGTool/Program.cs
Normal file
203
PKGTool/Program.cs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace PKGTool
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Usage()
|
||||||
|
{
|
||||||
|
Console.WriteLine("PKG Tool");
|
||||||
|
Console.WriteLine("-----------------------");
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Extract : PKGTool -x <input path> [-o <output path>");
|
||||||
|
Console.WriteLine("Create : PKGTool -c <input path> [-o <output path>");
|
||||||
|
}
|
||||||
|
|
||||||
|
static String GenerateFileName(UInt64 ID, MemoryStream File)
|
||||||
|
{
|
||||||
|
String fn = String.Empty;
|
||||||
|
BinaryReader reader = new BinaryReader(File);
|
||||||
|
String magic = Encoding.UTF8.GetString(reader.ReadBytes(4), 0, 4);
|
||||||
|
switch(magic)
|
||||||
|
{
|
||||||
|
case "\x1BLua":
|
||||||
|
fn = $"{ID:X16}.lc";
|
||||||
|
break;
|
||||||
|
case "\x6F\x7F\xF3\x73":
|
||||||
|
fn = $"{ID:X16}.bapd";
|
||||||
|
break;
|
||||||
|
case "BTXT":
|
||||||
|
fn = $"{ID:X16}.txt";
|
||||||
|
break;
|
||||||
|
case "CWAV":
|
||||||
|
fn = $"{ID:X16}.bcwav";
|
||||||
|
break;
|
||||||
|
case "FGRP":
|
||||||
|
fn = $"{ID:X16}.bfgrp";
|
||||||
|
break;
|
||||||
|
case "FSAR":
|
||||||
|
fn = $"{ID:X16}.bfsar";
|
||||||
|
break;
|
||||||
|
case "LSND":
|
||||||
|
fn = $"{ID:X16}.blsnd";
|
||||||
|
break;
|
||||||
|
case "LUT\x01":
|
||||||
|
fn = $"{ID:X16}.blut";
|
||||||
|
break;
|
||||||
|
case "MANM":
|
||||||
|
fn = $"{ID:X16}.bcskla";
|
||||||
|
break;
|
||||||
|
case "MFNT":
|
||||||
|
fn = $"{ID:X16}.bfont";
|
||||||
|
break;
|
||||||
|
case "MMDL":
|
||||||
|
fn = $"{ID:X16}.bcmdl";
|
||||||
|
break;
|
||||||
|
case "MNAV":
|
||||||
|
fn = $"{ID:X16}.bmnav";
|
||||||
|
break;
|
||||||
|
case "MPSI":
|
||||||
|
fn = $"{ID:X16}.bpsi";
|
||||||
|
break;
|
||||||
|
case "MSAD":
|
||||||
|
fn = $"{ID:X16}.bmsad";
|
||||||
|
break;
|
||||||
|
case "MSAS":
|
||||||
|
fn = $"{ID:X16}.bmsas";
|
||||||
|
break;
|
||||||
|
case "MSHD":
|
||||||
|
fn = $"{ID:X16}.bshdat";
|
||||||
|
break;
|
||||||
|
case "MSUR":
|
||||||
|
fn = $"{ID:X16}.bsmat";
|
||||||
|
break;
|
||||||
|
case "MTXT":
|
||||||
|
fn = $"{ID:X16}.bctex";
|
||||||
|
break;
|
||||||
|
case "MUCT":
|
||||||
|
fn = $"{ID:X16}.buct";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fn = $"{ID:X16}.bin";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
File.Position = 0;
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
FileStream tmp = null;
|
||||||
|
String fn = String.Empty;
|
||||||
|
String outPath = String.Empty;
|
||||||
|
Dread.FileFormats.PKG pkg = new Dread.FileFormats.PKG();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (args.Length >= 2)
|
||||||
|
{
|
||||||
|
if (args[0] == "-x")
|
||||||
|
{
|
||||||
|
if (!File.Exists(args[1]))
|
||||||
|
throw new FileNotFoundException($"Couldn't find the file {args[1]}");
|
||||||
|
|
||||||
|
pkg.import(File.OpenRead(args[1]));
|
||||||
|
|
||||||
|
if (args.Length == 4)
|
||||||
|
{
|
||||||
|
if (args[2] == "-o")
|
||||||
|
outPath = args[2];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.Length == 2)
|
||||||
|
outPath = String.Join(Path.DirectorySeparatorChar, Directory.GetCurrentDirectory(), Path.GetFileNameWithoutExtension(args[1]));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(outPath))
|
||||||
|
Directory.CreateDirectory(outPath);
|
||||||
|
|
||||||
|
using(var list = new StreamWriter(String.Join(Path.DirectorySeparatorChar, outPath, "files.list")))
|
||||||
|
{
|
||||||
|
foreach (var file in pkg.Files)
|
||||||
|
{
|
||||||
|
fn = GenerateFileName(file.Key, file.Value);
|
||||||
|
Console.WriteLine($"Extracting {fn}...");
|
||||||
|
tmp = File.Open(String.Join(Path.DirectorySeparatorChar, outPath, fn), FileMode.Create, FileAccess.Write);
|
||||||
|
file.Value.CopyTo(tmp);
|
||||||
|
file.Value.Position = 0L;
|
||||||
|
tmp.Close();
|
||||||
|
list.WriteLine(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg.Close();
|
||||||
|
}
|
||||||
|
else if (args[0] == "-c")
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(args[1]))
|
||||||
|
throw new FileNotFoundException($"Couldn't find the folder {args[1]}");
|
||||||
|
|
||||||
|
if (!File.Exists(String.Join(Path.DirectorySeparatorChar, args[1], "files.list")))
|
||||||
|
throw new FileNotFoundException($"Couldn't find the file files.list");
|
||||||
|
|
||||||
|
if (args.Length == 4)
|
||||||
|
{
|
||||||
|
if (args[2] == "-o")
|
||||||
|
outPath = args[2];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.Length == 2)
|
||||||
|
outPath = String.Join(Path.DirectorySeparatorChar, Directory.GetCurrentDirectory(), Path.GetFileNameWithoutExtension(args[1]));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Path.GetExtension(outPath) == String.Empty)
|
||||||
|
outPath += ".pkg";
|
||||||
|
else if (Path.GetExtension(outPath).ToLower() != ".pkg")
|
||||||
|
outPath = Path.ChangeExtension(outPath, ".pkg");
|
||||||
|
|
||||||
|
using (var list = new StreamReader(String.Join(Path.DirectorySeparatorChar, args[1], "files.list")))
|
||||||
|
{
|
||||||
|
while (!list.EndOfStream)
|
||||||
|
{
|
||||||
|
fn = list.ReadLine().TrimEnd('\r', '\n');
|
||||||
|
Console.WriteLine($"Adding {fn}...");
|
||||||
|
pkg.Files.Add(new KeyValuePair<UInt64, MemoryStream>(Convert.ToUInt64("0x" + Path.GetFileNameWithoutExtension(fn), 16), new MemoryStream(File.ReadAllBytes(String.Join(Path.DirectorySeparatorChar, args[1], fn)))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = File.Open(outPath, FileMode.Create, FileAccess.Write);
|
||||||
|
pkg.export(tmp);
|
||||||
|
tmp.Close();
|
||||||
|
pkg.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Usage();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Console.WriteLine("An error occured!");
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
Console.WriteLine(ex.StackTrace);
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
PKGTool/Properties/launchSettings.json
Normal file
8
PKGTool/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"PKGTool": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "-c \"D:\\Projects\\PKGTool\\PKGTool\\bin\\Debug\\net5.0\\s010_cave\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue