Update garc packing from files

Closes #95, adds padding length option for files that may need it
This commit is contained in:
Kurt
2017-01-19 23:05:38 -08:00
parent 30f43d0600
commit 9b253c8aa4
4 changed files with 100 additions and 34 deletions

View File

@@ -13,7 +13,7 @@ public static class GARC
public const ushort VER_6 = 0x0600;
public const ushort VER_4 = 0x0400;
public static bool garcPackMS(string folderPath, string garcPath, int version, ProgressBar pBar1 = null, Label label = null, bool supress = false)
public static bool garcPackMS(string folderPath, string garcPath, int version, int bytesPadding, ProgressBar pBar1 = null, Label label = null, bool supress = false)
{
// Check to see if our input folder exists.
if (!new DirectoryInfo(folderPath).Exists) { Util.Error("Folder does not exist."); return false; }
@@ -194,8 +194,7 @@ public static bool garcPackMS(string folderPath, string garcPath, int version, P
catch { }
// Set up the Header Info
using (MemoryStream newGARC = new MemoryStream())
using (MemoryStream GARCdata = new MemoryStream())
using (var newGARC = new FileStream(garcPath, FileMode.Create))
using (BinaryWriter gw = new BinaryWriter(newGARC))
{
#region Write GARC Headers
@@ -233,9 +232,37 @@ public static bool garcPackMS(string folderPath, string garcPath, int version, P
foreach (var s in e.SubEntries.Where(s => s.Exists))
{ gw.Write((uint)s.Start); gw.Write((uint)s.End); gw.Write((uint)s.Length); }
}
// Write FIMB
gw.Write((uint)0x46494D42); // FIMB
gw.Write((uint)0x0000000C); // Header Length
var dataLen = gw.BaseStream.Position;
gw.Write((uint)0); // Data Length - TEMP
gw.Seek(0x10, SeekOrigin.Begin); // Goto the start of the un-set 0 data we set earlier and set it.
var hdrLen = gw.BaseStream.Position;
gw.Write((uint)0); // Write Data Offset - TEMP
gw.Write((uint)0); // Write total GARC Length - TEMP
// Write Handling information
if (version == VER_4)
{
gw.Write(garc.ContentLargestUnpadded); // Write Largest File stat
}
else if (version == VER_6)
{
gw.Write(garc.ContentLargestPadded); // Write Largest With Padding
gw.Write(garc.ContentLargestUnpadded); // Write Largest Without Padding
gw.Write(garc.ContentPadToNearest);
}
newGARC.Seek(0, SeekOrigin.End); // Goto the end so we can copy the filedata after the GARC headers.
#endregion
#region Write Files
var ghLength = gw.BaseStream.Length;
long largestSize = 0; // Required memory to allocate to handle the largest file
long largestPadded = 0; // Required memory to allocate to handle the largest PADDED file (Ver6 only)
foreach (string e in packOrder)
@@ -245,37 +272,34 @@ public static bool garcPackMS(string folderPath, string garcPath, int version, P
{
// Update largest file length if necessary
long len = new FileInfo(f).Length;
int padding = (int)(len % bytesPadding);
if (padding != 0) padding = bytesPadding - padding;
bool largest = len > largestSize;
if (largest)
{
largestSize = len;
largestPadded = len;
largestPadded = len + padding;
}
// Write to FIMB
using (var input = File.OpenRead(f))
input.CopyTo(GARCdata);
using (var x = File.OpenRead(f))
x.CopyTo(newGARC);
// While length is not divisible by 4, pad with FF (unused byte)
while (GARCdata.Length%garc.ContentPadToNearest != 0)
{
GARCdata.WriteByte(0xFF);
if (largest)
largestPadded++;
}
while (padding-- > 0)
gw.Write((byte)0xFF);
}
}
garc.ContentLargestUnpadded = (uint)largestSize;
garc.ContentLargestPadded = (uint)largestPadded;
var gdLength = gw.BaseStream.Length - ghLength;
#endregion
gw.Write((uint)0x46494D42); // FIMB
gw.Write((uint)0x0000000C); // Header Length
gw.Write((uint)GARCdata.Length); // Data Length
gw.Seek(0x10, SeekOrigin.Begin); // Goto the start of the un-set 0 data we set earlier and set it.
gw.Write((uint)newGARC.Length); // Write Data Offset
gw.Write((uint)(newGARC.Length + GARCdata.Length)); // Write total GARC Length
gw.Seek((int)dataLen, SeekOrigin.Begin);
gw.Write((uint)gdLength); // Data Length
gw.Seek((int)hdrLen, SeekOrigin.Begin);
gw.Write((uint)ghLength); // Write Data Offset
gw.Write((uint)gw.BaseStream.Length); // Write total GARC Length
// Write Handling information
if (version == VER_4)
@@ -289,15 +313,8 @@ public static bool garcPackMS(string folderPath, string garcPath, int version, P
gw.Write(garc.ContentPadToNearest);
}
newGARC.Seek(0, SeekOrigin.End); // Goto the end so we can copy the filedata after the GARC headers.
// Write in the data
GARCdata.Position = 0;
GARCdata.CopyTo(newGARC); // Copy the data.
// New File is ready to be saved (memstream newGARC)
try
{
File.WriteAllBytes(garcPath, newGARC.ToArray());
if (label.InvokeRequired)
label.Invoke((MethodInvoker)delegate { label.Visible = false; });
else { label.Visible = false; }
@@ -672,6 +689,17 @@ public static MemGARC packGARC(byte[][] data, int version, int contentpadnearest
gw.Seek((int)hdrLen, SeekOrigin.Begin);
gw.Write((uint)ghLength); // Write Data Offset
gw.Write((uint)gw.BaseStream.Length); // Write total GARC Length
if (version == VER_4)
{
gw.Write(garc.ContentLargestUnpadded); // Write Largest File stat
}
else if (version == VER_6)
{
gw.Write(garc.ContentLargestPadded); // Write Largest With Padding
gw.Write(garc.ContentLargestUnpadded); // Write Largest Without Padding
gw.Write(garc.ContentPadToNearest);
}
}
byte[] GARCdata = File.ReadAllBytes(tempFile);

View File

@@ -799,7 +799,7 @@ private void fileSet(IEnumerable<string> files, bool keep = false)
{
string GARC = Config.getGARCFileName(toEdit);
updateStatus($"GARC Set: {toEdit} @ {GARC}... ");
threadSet(Path.Combine(RomFSPath, GARC), toEdit);
threadSet(Path.Combine(RomFSPath, GARC), toEdit, 4); // 4 bytes for Gen6
while (threads > 0) Thread.Sleep(50);
if (!keep && Directory.Exists(toEdit)) Directory.Delete(toEdit, true);
resetStatus();
@@ -1144,14 +1144,14 @@ private bool getGARC(string infile, string outfolder, bool PB, bool bypassExt =
}
catch (Exception e) { Util.Error("Could not get the GARC:", e.ToString()); threads--; return false; }
}
private bool setGARC(string outfile, string infolder, bool PB)
private bool setGARC(string outfile, string infolder, int padBytes, bool PB)
{
if (skipBoth || (ModifierKeys == Keys.Control && Util.Prompt(MessageBoxButtons.YesNo, "Cancel writing data back to GARC?") == DialogResult.Yes))
{ threads--; updateStatus("Aborted!", false); return false; }
try
{
bool success = CTR.GARC.garcPackMS(infolder, outfile, Config.GARCVersion, PB ? pBar1 : null, null, true);
bool success = CTR.GARC.garcPackMS(infolder, outfile, Config.GARCVersion, padBytes, PB ? pBar1 : null, null, true);
threads--;
updateStatus(string.Format(success ? "Success!" : "Failed!"), false);
return success;
@@ -1165,10 +1165,10 @@ private void threadGet(string infile, string outfolder, bool PB = true, bool byp
catch { }
new Thread(() => getGARC(infile, outfolder, PB, bypassExt)).Start();
}
private void threadSet(string outfile, string infolder, bool PB = true)
private void threadSet(string outfile, string infolder, int padBytes, bool PB = true)
{
threads++;
new Thread(() => setGARC(outfile, infolder, PB)).Start();
new Thread(() => setGARC(outfile, infolder, padBytes, PB)).Start();
}
private static void backupGARCs(bool overwrite, params string[] g)

View File

@@ -39,7 +39,10 @@ private void InitializeComponent()
this.B_Reset = new System.Windows.Forms.Button();
this.CHK_Delete = new System.Windows.Forms.CheckBox();
this.pBar1 = new System.Windows.Forms.ProgressBar();
this.NUD_Padding = new System.Windows.Forms.NumericUpDown();
this.L_Padding = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.PB_BCLIM)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_Padding)).BeginInit();
this.SuspendLayout();
//
// PB_Unpack
@@ -147,12 +150,41 @@ private void InitializeComponent()
this.pBar1.Size = new System.Drawing.Size(300, 12);
this.pBar1.TabIndex = 11;
//
// NUD_Padding
//
this.NUD_Padding.Hexadecimal = true;
this.NUD_Padding.Location = new System.Drawing.Point(118, 164);
this.NUD_Padding.Maximum = new decimal(new int[] {
65536,
0,
0,
0});
this.NUD_Padding.Name = "NUD_Padding";
this.NUD_Padding.Size = new System.Drawing.Size(44, 20);
this.NUD_Padding.TabIndex = 12;
this.NUD_Padding.Value = new decimal(new int[] {
4,
0,
0,
0});
//
// L_Padding
//
this.L_Padding.Location = new System.Drawing.Point(12, 164);
this.L_Padding.Name = "L_Padding";
this.L_Padding.Size = new System.Drawing.Size(100, 20);
this.L_Padding.TabIndex = 13;
this.L_Padding.Text = "GARC Padding:";
this.L_Padding.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// ToolsUI
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(324, 362);
this.Controls.Add(this.L_Padding);
this.Controls.Add(this.NUD_Padding);
this.Controls.Add(this.pBar1);
this.Controls.Add(this.CHK_Delete);
this.Controls.Add(this.B_Reset);
@@ -171,6 +203,7 @@ private void InitializeComponent()
this.Text = "Tools";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.closeForm);
((System.ComponentModel.ISupportInitialize)(this.PB_BCLIM)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_Padding)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@@ -189,5 +222,7 @@ private void InitializeComponent()
private System.Windows.Forms.Button B_Reset;
private System.Windows.Forms.CheckBox CHK_Delete;
private System.Windows.Forms.ProgressBar pBar1;
private System.Windows.Forms.NumericUpDown NUD_Padding;
private System.Windows.Forms.Label L_Padding;
}
}

View File

@@ -153,7 +153,6 @@ private void saveARC(string path)
{
if (!Directory.Exists(path)) { Util.Error("Input path is not a Folder", path); return; }
string folderName = Path.GetFileName(path);
if (folderName == null) return;
string parentName = Directory.GetParent(path).FullName;
int type = CB_Repack.SelectedIndex;
switch (type)
@@ -179,10 +178,14 @@ private void saveARC(string path)
return;
var version = dr == DialogResult.Yes ? CTR.GARC.VER_6 : CTR.GARC.VER_4;
int padding = (int)NUD_Padding.Value;
if (version == CTR.GARC.VER_4)
padding = 4;
string outfolder = Directory.GetParent(path).FullName;
new Thread(() =>
{
string outfolder = Directory.GetParent(path).FullName;
bool r = CTR.GARC.garcPackMS(path, Path.Combine(outfolder, folderName + ".garc"), version, pBar1);
bool r = CTR.GARC.garcPackMS(path, Path.Combine(outfolder, folderName + ".garc"), version, padding, pBar1);
if (!r) { Util.Alert("Packing failed."); return; }
// Delete path after repacking
if (CHK_Delete.Checked && Directory.Exists(path))