Add GARC Version 6 handling

This commit is contained in:
Kaphotics
2016-10-30 11:52:19 -07:00
parent 8c713d3217
commit f57e9fa7e7
4 changed files with 93 additions and 26 deletions

View File

@@ -8,13 +8,19 @@
namespace CTR
{
#region GARC Class & Struct
public class GARC
public static class GARC
{
internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar pBar1 = null, Label label = null, bool supress = false)
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)
{
// Check to see if our input folder exists.
if (!new DirectoryInfo(folderPath).Exists) { Util.Error("Folder does not exist."); return false; }
if (version != VER_4 && version != VER_6)
throw new FormatException("Invalid GARC Version: 0x" + version.ToString("X4"));
// Okay some basic proofing is done. Proceed.
int filectr = 0;
// Get the paths of the files to pack up.
@@ -58,12 +64,13 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
// Set Up the GARC template.
GARCFile garc = new GARCFile
{
ContentPadToNearest = 4,
fato =
{
// Magic = new[] { 'O', 'T', 'A', 'F' },
Entries = new FATO_Entry[packOrder.Length],
EntryCount = (ushort)packOrder.Length,
HeaderSize = 0xC + packOrder.Length * 4,
EntryCount = (ushort) packOrder.Length,
HeaderSize = 0xC + packOrder.Length*4,
Padding = 0xFFFF
},
fatb =
@@ -73,6 +80,12 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
FileCount = filectr
}
};
if (version == VER_6)
{
// Some files have larger bytes-to-pad values (ex/ 0x80 for a109)
// Hopefully there's no problems defining this with a constant number.
garc.ContentPadToNearest = 4;
}
#region Start Reassembling the FAT* tables.
{
@@ -190,12 +203,18 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
gw.Write((uint)0x47415243); // GARC
gw.Write((uint)0x0000001C); // Header Length
gw.Write((ushort)0xFEFF); // Endianness BOM
gw.Write((ushort)0x0400); // Const (4)
gw.Write((ushort)version); // Version
gw.Write((uint)0x00000004); // Section Count (4)
gw.Write((uint)0x00000000); // Data Offset (temp)
gw.Write((uint)0x00000000); // File Length (temp)
gw.Write((uint)0x00000000); // Largest File Size (temp)
if (version == VER_6)
{
gw.Write((uint)0x0);
gw.Write((uint)0x0);
}
// Write FATO
gw.Write((uint)0x4641544F); // FATO
gw.Write(garc.fato.HeaderSize); // Header Size
@@ -218,6 +237,7 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
#region Write Files
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)
{
string[] fa = Directory.Exists(e) ? Directory.GetFiles(e) : new[] { e };
@@ -225,16 +245,28 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
{
// Update largest file length if necessary
long len = new FileInfo(f).Length;
if (len > largestSize) largestSize = len;
bool largest = len > largestSize;
if (largest)
{
largestSize = len;
largestPadded = len;
}
// Write to FIMB
using (var input = File.OpenRead(f))
input.CopyTo(GARCdata);
// While length is not divisible by 4, pad with FF (unused byte)
while (GARCdata.Length % 4 > 0) GARCdata.WriteByte(0xFF);
while (GARCdata.Length%garc.ContentPadToNearest != 0)
{
GARCdata.WriteByte(0xFF);
if (largest)
largestPadded++;
}
}
}
garc.ContentLargestUnpadded = (uint)largestSize;
garc.ContentLargestPadded = (uint)largestPadded;
#endregion
gw.Write((uint)0x46494D42); // FIMB
@@ -244,7 +276,18 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
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.Write((uint)largestSize); // Write Largest File stat (?)
// 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.
@@ -268,7 +311,7 @@ internal static bool garcPackMS(string folderPath, string garcPath, ProgressBar
catch (Exception e) { Util.Error("Packing Failed!", e.ToString()); return false; }
}
}
internal static bool garcUnpack(string garcPath, string outPath, bool skipDecompression, ProgressBar pBar1 = null, Label label = null, bool supress = false, bool bypassExt = false)
public static bool garcUnpack(string garcPath, string outPath, bool skipDecompression, ProgressBar pBar1 = null, Label label = null, bool supress = false, bool bypassExt = false)
{
if (!File.Exists(garcPath) && !supress) { Util.Alert("File does not exist"); return false; }
@@ -378,7 +421,7 @@ internal static bool garcUnpack(string garcPath, string outPath, bool skipDecomp
return true;
}
internal static GARCFile unpackGARC(string path)
public static GARCFile unpackGARC(string path)
{
GARCFile garc = new GARCFile();
using (BinaryReader br = new BinaryReader(File.OpenRead(path)))
@@ -387,12 +430,25 @@ internal static GARCFile unpackGARC(string path)
garc.Magic = br.ReadChars(4);
garc.HeaderSize = br.ReadUInt32();
garc.Endianess = br.ReadUInt16();
garc.ChunkCount = br.ReadUInt16();
garc.FileSize = br.ReadUInt32();
garc.Version = br.ReadUInt16();
garc.ChunkCount = br.ReadUInt32();
garc.DataOffset = br.ReadUInt32();
garc.FileSize = br.ReadUInt32();
garc.LastSize = br.ReadUInt32();
if (garc.Version == VER_4)
{
garc.ContentLargestUnpadded = br.ReadUInt32();
}
else if (garc.Version == VER_6)
{
garc.ContentLargestPadded = br.ReadUInt32();
garc.ContentLargestUnpadded = br.ReadUInt32();
garc.ContentPadToNearest = br.ReadUInt32();
}
else
throw new FormatException("Invalid GARC Version: 0x" + garc.Version.ToString("X4"));
if (garc.ChunkCount != 4)
throw new FormatException("Invalid GARC Chunk Count: " + garc.ChunkCount);
// FATO (File Allocation Table Offsets)
garc.fato.Magic = br.ReadChars(4);
@@ -442,14 +498,18 @@ internal static GARCFile unpackGARC(string path)
public struct GARCFile
{
public Char[] Magic; // Always GARC = 0x4E415243
public char[] Magic; // Always GARC = 0x4E415243
public uint HeaderSize; // Always 0x001C
public UInt16 Endianess; // 0xFFFE
public UInt16 ChunkCount; // Always 0x0400 chunk count
public ushort Endianess; // 0xFFFE
public ushort Version; // 4: gen6, 6: gen7
public uint ChunkCount; // Always 0x0400 chunk count
public uint DataOffset;
public uint FileSize;
public uint LastSize;
public uint ContentLargestPadded; // Format 6 Only
public uint ContentLargestUnpadded;
public uint ContentPadToNearest; // Format 6 Only (4 bytes is standard in VER_4, and is not stored)
public FATO fato;
public FATB fatb;
@@ -458,10 +518,10 @@ public struct GARCFile
public struct FATO
{
public Char[] Magic;
public char[] Magic;
public int HeaderSize;
public UInt16 EntryCount;
public UInt16 Padding;
public ushort EntryCount;
public ushort Padding;
public FATO_Entry[] Entries;
}
@@ -472,7 +532,7 @@ public struct FATO_Entry
public struct FATB
{
public Char[] Magic;
public char[] Magic;
public int HeaderSize;
public int FileCount;
@@ -481,12 +541,12 @@ public struct FATB
public struct FATB_Entry
{
public uint Vector;
public Boolean IsFolder;
public bool IsFolder;
public FATB_SubEntry[] SubEntries;
}
public struct FATB_SubEntry
{
public Boolean Exists;
public bool Exists;
public int Start;
public int End;
public int Length;
@@ -494,7 +554,7 @@ public struct FATB_SubEntry
public struct FIMG
{
public Char[] Magic;
public char[] Magic;
public int HeaderSize;
public int DataSize;
}

View File

@@ -83,6 +83,7 @@ private void getGameData(GameVersion game)
public bool ORAS => Version == GameVersion.ORAS || Version == GameVersion.ORASDEMO;
public bool SM => Version == GameVersion.SM || Version == GameVersion.SMDEMO;
public int MaxSpeciesID => XY || ORAS ? 722 : 802;
public int GARCVersion => XY || ORAS ? CTR.GARC.VER_4 : CTR.GARC.VER_6;
public bool IsRebuildable(int fileCount)
{
switch (fileCount)

View File

@@ -911,7 +911,7 @@ private bool setGARC(string outfile, string infolder, bool PB)
try
{
bool success = CTR.GARC.garcPackMS(infolder, outfile, PB ? pBar1 : null, null, true);
bool success = CTR.GARC.garcPackMS(infolder, outfile, Config.GARCVersion, PB ? pBar1 : null, null, true);
threads--;
updateStatus(string.Format(success ? "Success!" : "Failed!"), false);
return success;

View File

@@ -173,9 +173,15 @@ private void saveARC(string path)
case 1: // GARC Pack
{
if (threads > 0) { Util.Alert("Please wait for all operations to finish first."); return; }
DialogResult dr = Util.Prompt(MessageBoxButtons.YesNoCancel, "Format Selection:",
"Yes: Sun/Moon (Version 6)\nNo: XY/ORAS (Version 4)");
if (dr == DialogResult.Cancel)
return;
var version = dr == DialogResult.Yes ? CTR.GARC.VER_6 : CTR.GARC.VER_4;
new Thread(() =>
{
bool r = CTR.GARC.garcPackMS(path, folderName + ".garc", pBar1);
bool r = CTR.GARC.garcPackMS(path, folderName + ".garc", version, pBar1);
if (!r) { Util.Alert("Packing failed."); return; }
// Delete path after repacking
if (CHK_Delete.Checked && Directory.Exists(path))