Created
February 24, 2024 07:13
-
-
Save donnaken15/47f2a31f8c8b9b7743a2e184a9694a37 to your computer and use it in GitHub Desktop.
pakdir, before hardcore EXE optimization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Created by SharpDevelop. | |
* User: Wesley | |
* Date: 2/21/2024 | |
* Time: 3:55 PM | |
* | |
* To change this template use Tools | Options | Coding | Edit Standard Headers. | |
*/ | |
using System; | |
using System.IO; | |
static class Program | |
{ | |
public static byte[] STH(string hex) | |
{ | |
if ((hex.Length & 1) == 1) | |
throw new ArgumentException("Uneven hex string: "+hex); | |
byte[] test = new byte[hex.Length >> 1]; | |
for (int i = 0; i < test.Length; i++) | |
test[i] = byte.Parse(hex.Substring(i << 1, 2), System.Globalization.NumberStyles.HexNumber); | |
return test; | |
} | |
public static uint[] crctable = new uint[256]; | |
public static void initCRC32() | |
{ | |
uint crc, poly = 0xEDB88320; | |
for (uint i = 0; i < 256; i++) | |
{ | |
crc = i; | |
for (int j = 0; j < 8; j++) | |
{ | |
if ((crc & 1) == 1) | |
crc = crc >> 1 ^ poly; | |
else | |
crc >>= 1; | |
} | |
crctable[i] = crc; | |
} | |
} | |
public static uint crc32(string text) | |
{ | |
text = text.Replace('/', '\\').ToLower(); | |
if (text.Length == 8) | |
try { | |
byte[] alreadykey = STH(text); | |
Array.Reverse(alreadykey); | |
return BitConverter.ToUInt32(alreadykey, 0); | |
} | |
catch { } | |
uint crc = 0xFFFFFFFF; | |
for (int i = 0; i < text.Length; i++) | |
{ | |
crc = crc >> 8 & 0x00FFFFFF ^ crctable[(crc ^ text[i]) & 0xFF]; | |
} | |
return crc; | |
} | |
static readonly string[] exts = { | |
"", ".xen", ".ps3", ".ps2", ".ngc" | |
}; | |
static int iOZ(string[] arr, string path) | |
// test for strings in array | |
{ | |
int ii = -1; | |
for (int i = 0; i < exts.Length; i++) | |
if ((ii = Array.IndexOf(arr, path + exts[i])) != -1) | |
return ii; | |
return ii; | |
} | |
static uint Eswap(uint value) | |
{ | |
return ((value & 0xFF) << 24) | | |
((value & 0xFF00) << 8) | | |
((value & 0xFF0000) >> 8) | | |
((value & 0xFF000000) >> 24); | |
} | |
static string ext(bool b) | |
{ | |
return ".pa" + (b ? 'b' : 'k') + ".xen"; | |
} | |
static uint align(uint a, uint b) | |
{ | |
b = (uint)unchecked(1<<(int)b); | |
a = a&(uint)(b-1); | |
return (a!=0) ? (b-a) : 0; | |
} | |
static bool platext(string i) | |
{ | |
string e = Path.GetExtension(i); | |
return e == ".xen" || | |
e == ".ps3" || | |
e == ".ps2" || | |
e == ".ngc"; | |
} | |
// main data boundary is 4096 = 1 << 12 | |
// file data aligns to 16 = 1 << 4 | |
static void AlignFile(BinaryWriter w, uint b) | |
{ | |
b = (uint)unchecked(1<<(int)b); | |
uint a = (uint)w.BaseStream.Position & (uint)(b-1); | |
if (a != 0) | |
{ | |
byte[] pad = new byte[b-a]; | |
w.Write(pad); | |
} | |
} | |
public static int Main(string[] args) | |
{ | |
if (args.Length <= 0 && args.Length > 3) | |
{ | |
//Console.WriteLine("GH3 PAK BUILDER"); | |
Console.WriteLine("usage: pakdir [input folder] [output name] [-b|-z]"); | |
Console.WriteLine(" -b | split output to PAK/PAB"); | |
Console.WriteLine(" -z | build zones, requires TEX/SCN and implies -b"); | |
return 2; | |
} | |
if (!Directory.Exists(args[0])) | |
{ | |
Console.WriteLine("Input folder not found: "+Directory.GetCurrentDirectory()+'\\'+args[0]); | |
return 1; | |
} | |
string output = Path.GetFullPath(args[1]); | |
string name = Path.GetFileName(args[1]); | |
Directory.SetCurrentDirectory(args[0]); | |
bool c_pab = false, c_zone = false; | |
const string zstr = "zones\\global\\global_gfx"; | |
if (args.Length == 3) | |
{ | |
string _switch = args[2]; | |
if (_switch.Length != 2 || _switch[0] != '-') | |
{ | |
// WHY CAN'T I GOTO | |
Console.WriteLine("Invalid switch string: "+_switch); | |
return 1; | |
} | |
switch (_switch[1]) | |
{ | |
case 's': | |
c_pab = true; | |
break; | |
case 'z': | |
c_zone = true; | |
break; | |
default: | |
Console.WriteLine("Invalid switch string: "+_switch); | |
return 1; | |
} | |
} | |
initCRC32(); | |
string[] dir = Directory.GetFiles(".", "*", SearchOption.AllDirectories); | |
uint filecount = (uint)dir.Length; | |
uint wadstart = (uint)((filecount + 2) * 0x20); | |
uint wadoff = wadstart; | |
//wadstart = wadstart + align(wadstart, 12); | |
//Console.WriteLine(wadstart.ToString("X8")); | |
//return; | |
int scn = -1, tex = -1; | |
if (c_zone) | |
{ | |
scn = iOZ(dir, ".\\" + zstr + ".scn"); | |
tex = iOZ(dir, ".\\" + zstr + ".tex"); | |
if (scn < 0 || tex < 0) | |
{ | |
Console.WriteLine("Matching TEX/SCN cannot be found. It is required for building zone PAKs."); | |
return 1; | |
} | |
if (scn != 1 && tex != 1) | |
{ | |
if (tex > scn) | |
{ | |
string swapval = dir[tex]; | |
dir[tex] = dir[scn]; | |
dir[scn] = swapval; | |
} | |
// apparently TEX has to come first | |
} | |
} | |
Stream pak = File.Create(output + ext(false)); | |
Stream pab = null; | |
if (c_zone) | |
c_pab = true; | |
if (c_pab) | |
{ | |
pab = File.Create(output + ext(true)); | |
} | |
BinaryWriter hed = new BinaryWriter(pak); | |
BinaryWriter wad = new BinaryWriter(c_pab ? pab : pak); | |
for (uint i = 0; i < filecount; i++) | |
{ | |
//Console.WriteLine(dir[i]); | |
FileInfo f = new FileInfo(dir[i].Substring(2)); | |
bool subf = Path.GetDirectoryName(f.ToString()) != ""; | |
bool _platext = platext(f.ToString()); | |
string name_noplat = Path.GetFileNameWithoutExtension(f.ToString()); | |
string _ext = _platext ? | |
Path.GetExtension(name_noplat) : f.Extension; | |
string fn = _platext ? name_noplat : f.Name; | |
hed.Write(Eswap(crc32(_ext))); | |
hed.Write(Eswap(wadoff)); | |
hed.Write(Eswap((uint)f.Length)); | |
hed.Write((uint)0); | |
if (!(_ext == ".tex" || _ext == ".scn")) // wtf | |
fn = Path.GetFileNameWithoutExtension(fn); | |
string realpath = (subf ? (Path.GetDirectoryName(f.ToString()) + '\\') : "") + fn; | |
//Console.WriteLine(realpath); | |
//Console.WriteLine(fn); | |
hed.Write(Eswap(crc32(realpath))); | |
hed.Write(Eswap(crc32(fn))); | |
if (c_zone && i == tex) | |
hed.Write(Eswap(crc32(zstr + ".tex"))); | |
else | |
hed.Write((uint)0); | |
hed.Write(Eswap((uint)((i == tex || i == scn) ? 4 : 0))); | |
wadoff += (uint)f.Length + align((uint)f.Length, 4) - 0x20; | |
} | |
hed.Write(Eswap(crc32(".last"))); | |
hed.Write(Eswap(wadoff)); | |
hed.Write(Eswap(4)); | |
hed.Write((uint)0); | |
hed.Write(Eswap(0x897ABB4A)); | |
hed.Write(Eswap(0x6AF98ED1)); | |
hed.Write((uint)0); | |
hed.Write((uint)0); | |
for (byte i = 0; i < 8; i++) | |
hed.Write(0); | |
for (uint i = 0; i < filecount; i++) | |
{ | |
wad.Write(File.ReadAllBytes(dir[i])); | |
AlignFile(wad, 4); | |
} | |
wad.Write(0xABABABAB); | |
AlignFile(wad, 4); | |
return 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment