Last active
September 12, 2016 03:34
-
-
Save gdkchan/e852991a64f01dc0e1dc6caaa46e2e5b to your computer and use it in GitHub Desktop.
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
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Security.Cryptography; | |
using System.Text; | |
namespace KHPacker | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("KH ARD Packer/Unpacker v0.3 by gdkchan"); | |
Console.WriteLine(string.Empty); | |
if (args.Length == 0) | |
PrintUsage(); | |
else | |
{ | |
string Operation = args[0]; | |
string FileName = args[1]; | |
switch (Operation) | |
{ | |
case "-u": | |
if (FileName == "-all") | |
{ | |
string[] Files = Directory.GetFiles(Environment.CurrentDirectory); | |
foreach (string File in Files) if (Path.GetExtension(File).ToLower() == ".ard") Dump(File); | |
} | |
else | |
Dump(FileName); | |
Console.WriteLine("Done!"); | |
break; | |
case "-p": | |
if (FileName == "-all") | |
{ | |
string[] Folders = Directory.GetDirectories(Environment.CurrentDirectory); | |
foreach (string Folder in Folders) Create(Folder); | |
} | |
else | |
Create(FileName); | |
Console.WriteLine("Done!"); | |
break; | |
} | |
} | |
} | |
static void PrintUsage() | |
{ | |
Console.WriteLine("-u [file.ard] Unpack ARD to folder"); | |
Console.WriteLine("-p [folder] Pack folder to ARD"); | |
Console.WriteLine("-u -all Unpack all ARD files on current folder"); | |
Console.WriteLine("-p -all Pack all folders on current folder"); | |
} | |
static void Dump(string FileName) | |
{ | |
string Folder = Path.GetFileNameWithoutExtension(FileName); | |
Directory.CreateDirectory(Folder); | |
using (FileStream Input = new FileStream(FileName, FileMode.Open)) | |
{ | |
BinaryReader Reader = new BinaryReader(Input); | |
uint FilesCount = Reader.ReadUInt32(); | |
List<uint> PointerTable = new List<uint>(); | |
List<uint> AllPointers = new List<uint>(); | |
for (int i = 0; i < FilesCount + 1; i++) | |
{ | |
uint Address = Reader.ReadUInt32(); | |
AllPointers.Add(Address); | |
if (!PointerTable.Contains(Address)) PointerTable.Add(Address); | |
} | |
PointerTable.Sort(); | |
for (int i = 0; i < FilesCount; i++) | |
{ | |
Input.Seek(4 + i * 4, SeekOrigin.Begin); | |
uint Address = Reader.ReadUInt32(); | |
int Index = PointerTable.IndexOf(Address); | |
int Length = (int)(PointerTable[Index + 1] - PointerTable[Index]); | |
Input.Seek(Address, SeekOrigin.Begin); | |
byte[] Data = Reader.ReadBytes(Length); | |
bool Repeated = AllPointers.FindAll(a => a == Address).Count > 1; | |
string Name = string.Format("File_{0:D5}{1}.bin", i, Repeated ? "_R" : string.Empty); | |
File.WriteAllBytes(Path.Combine(Folder, Name), Data); | |
} | |
} | |
} | |
static void Create(string Folder) | |
{ | |
string[] Files = Directory.GetFiles(Folder); | |
using (FileStream Output = new FileStream(Folder + ".ard", FileMode.Create)) | |
{ | |
BinaryWriter Writer = new BinaryWriter(Output); | |
Writer.Write(Files.Length); | |
int HeaderLength = 4 + Files.Length * 4 + 4; | |
while ((HeaderLength & 0x7f) != 0) HeaderLength += 4; | |
Dictionary<string, uint> PointerTable = new Dictionary<string, uint>(); | |
using (MemoryStream DataStream = new MemoryStream()) | |
{ | |
foreach (string FName in Files) | |
{ | |
byte[] Data = File.ReadAllBytes(FName); | |
string Hash = GetMD5(Data); | |
bool IsRepeated = PointerTable.ContainsKey(Hash); | |
if (!Path.GetFileName(FName).Contains("_R") || !IsRepeated) | |
{ | |
uint Address = (uint)(DataStream.Position + HeaderLength); | |
if (!IsRepeated) PointerTable.Add(Hash, Address); | |
Writer.Write(Address); | |
DataStream.Write(Data, 0, Data.Length); | |
while ((DataStream.Position & 0x7f) != 0) DataStream.WriteByte(0); | |
} | |
else | |
Writer.Write((uint)PointerTable[Hash]); | |
} | |
Writer.Write((uint)(HeaderLength + DataStream.Length)); | |
Output.Seek(HeaderLength, SeekOrigin.Begin); | |
Writer.Write(DataStream.ToArray()); | |
} | |
} | |
} | |
static string GetMD5(byte[] Data) | |
{ | |
using (MD5 Hash = MD5.Create()) | |
{ | |
byte[] Hashed = Hash.ComputeHash(Data); | |
StringBuilder Output = new StringBuilder(); | |
foreach (byte HB in Hashed) Output.Append(HB.ToString("X2")); | |
return Output.ToString(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment