Example #1
0
        internal static GARCFile unpackGARC(string path)
        {
            GARCFile garc = new GARCFile();
            using (BinaryReader br = new BinaryReader(File.OpenRead(path)))
            {
                // GARC Header
                garc.Magic = br.ReadChars(4);
                garc.HeaderSize = br.ReadUInt32();
                garc.Endianess = br.ReadUInt16();
                garc.ChunkCount = br.ReadUInt16();
                garc.FileSize = br.ReadUInt32();

                garc.DataOffset = br.ReadUInt32();
                garc.FileSize = br.ReadUInt32();
                garc.LastSize = br.ReadUInt32();

                // FATO (File Allocation Table Offsets)
                garc.fato.Magic = br.ReadChars(4);
                garc.fato.HeaderSize = br.ReadInt32();
                garc.fato.EntryCount = br.ReadUInt16();
                garc.fato.Padding = br.ReadUInt16();

                garc.fato.Entries = new FATO_Entry[garc.fato.EntryCount];
                for (int i = 0; i < garc.fato.EntryCount; i++)
                    garc.fato.Entries[i].Offset = br.ReadInt32();

                // FATB (File Allocation Table Bits)
                garc.fatb.Magic = br.ReadChars(4);
                garc.fatb.HeaderSize = br.ReadInt32();
                garc.fatb.FileCount = br.ReadInt32();

                garc.fatb.Entries = new FATB_Entry[garc.fato.EntryCount];
                for (int i = 0; i < garc.fato.EntryCount; i++) // Loop through all FATO entries
                {
                    garc.fatb.Entries[i].Vector = br.ReadUInt32();
                    garc.fatb.Entries[i].SubEntries = new FATB_SubEntry[32];
                    uint bitvector = garc.fatb.Entries[i].Vector;
                    int ctr = 0;
                    for (int b = 0; b < 32; b++)
                    {
                        garc.fatb.Entries[i].SubEntries[b].Exists = (bitvector & 1) == 1;
                        bitvector >>= 1;
                        if (!garc.fatb.Entries[i].SubEntries[b].Exists) continue;
                        garc.fatb.Entries[i].SubEntries[b].Start = br.ReadInt32();
                        garc.fatb.Entries[i].SubEntries[b].End = br.ReadInt32();
                        garc.fatb.Entries[i].SubEntries[b].Length = br.ReadInt32();
                        ctr++;
                    }
                    garc.fatb.Entries[i].IsFolder = ctr > 1;
                }

                // FIMB (File IMage Bytes)
                garc.fimg.Magic = br.ReadChars(4);
                garc.fimg.HeaderSize = br.ReadInt32();
                garc.fimg.DataSize = br.ReadInt32();

                // Files data
                // Oftentimes too large to toss into a byte array. Fetch as needed with a BinaryReader.
            }
            return garc;
        }
Example #2
0
 public MemGARC(byte[] data)
 {
     Data = data;
     garc = unpackGARC(data);
 }
Example #3
0
        internal static bool garcPackMS(string folderPath, string garcPath, 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; }

            // Okay some basic proofing is done. Proceed.
            int filectr = 0;
            // Get the paths of the files to pack up.
            string[] files = Directory.GetFiles(folderPath);
            string[] folders = Directory.GetDirectories(folderPath, "*.*", SearchOption.TopDirectoryOnly);

            string[] packOrder = new string[files.Length + folders.Length];
            #region Reassemble a list of filenames.
            try
            {
                foreach (string f in files)
                {
                    string fn = Path.GetFileNameWithoutExtension(f);
                    int compressed = fn.IndexOf("dec_", StringComparison.Ordinal);
                    int fileNumber = (compressed < 0)
                        ? Int32.Parse(fn)
                        : Int32.Parse(fn.Substring(compressed + 4));

                    packOrder[fileNumber] = f;
                    filectr++;
                }
                foreach (string f in folders)
                {
                    packOrder[Int32.Parse(new DirectoryInfo(f).Name)] = f;
                    filectr += Directory.GetFiles(f).Length;
                }
            }
            catch (Exception e) { Util.Error("Invalid packing filenames", e.ToString()); return false; }
            #endregion

            #region Initialize Progress Update Display
            if (pBar1 == null) pBar1 = new ProgressBar();
            if (pBar1.InvokeRequired)
                pBar1.Invoke((MethodInvoker)delegate { pBar1.Minimum = 0; pBar1.Step = 1; pBar1.Value = 0; pBar1.Maximum = filectr; });
            else { pBar1.Minimum = 0; pBar1.Step = 1; pBar1.Value = 0; pBar1.Maximum = filectr; }
            if (label == null) label = new Label();
            if (label.InvokeRequired)
                label.Invoke((MethodInvoker)delegate { label.Visible = true; });
            #endregion

            // Set Up the GARC template.
            GARCFile garc = new GARCFile
            {
                fato =
                {
                    // Magic = new[] { 'O', 'T', 'A', 'F' },
                    Entries = new FATO_Entry[packOrder.Length],
                    EntryCount = (ushort)packOrder.Length,
                    HeaderSize = 0xC + packOrder.Length * 4,
                    Padding = 0xFFFF
                },
                fatb =
                {
                    // Magic = new[] { 'B', 'T', 'A', 'F' },
                    Entries = new FATB_Entry[packOrder.Length],
                    FileCount = filectr
                }
            };

            #region Start Reassembling the FAT* tables.
            {
                int op = 0;
                int od = 0;
                int v = 0;
                int index = 0;
                for (int i = 0; i < garc.fatb.Entries.Length; i++)
                {
                    garc.fato.Entries[i].Offset = op; // FATO offset
                    garc.fatb.Entries[i].SubEntries = new FATB_SubEntry[32];
                    op += 4; // Vector
                    if (!Directory.Exists(packOrder[i])) // is not folder
                    {
                        garc.fatb.Entries[i].IsFolder = false;
                        garc.fatb.Entries[i].SubEntries[0].Exists = true;

                        string fn = Path.GetFileNameWithoutExtension(packOrder[i]);
                        int compressed = fn.IndexOf("dec_", StringComparison.Ordinal);
                        int fileNumber = (compressed < 0)
                            ? Int32.Parse(fn)
                            : Int32.Parse(fn.Substring(compressed + 4));

                        if (compressed >= 0)
                        {
                            string old = packOrder[i];
                            LZSS.Compress(packOrder[i], packOrder[i] = Path.Combine(Path.GetDirectoryName(packOrder[i]), fileNumber.ToString()));
                            File.Delete(old);
                        }

                        // Assemble Vector
                        v = 1;

                        // Assemble Entry
                        FileInfo fi = new FileInfo(packOrder[i]);
                        int actualLength = (int)((fi.Length % 4 == 0) ? fi.Length : fi.Length + 4 - (fi.Length % 4));
                        garc.fatb.Entries[i].SubEntries[0].Start = od;
                        garc.fatb.Entries[i].SubEntries[0].End = actualLength + garc.fatb.Entries[i].SubEntries[0].Start;
                        garc.fatb.Entries[i].SubEntries[0].Length = (int)fi.Length;
                        od += actualLength;

                        op += 12;
                        #region Step
                        if (pBar1.InvokeRequired)
                            pBar1.Invoke((MethodInvoker)(() => pBar1.PerformStep()));
                        else { pBar1.PerformStep(); }
                        string update = String.Format("{0:P2} - {1}/{2} - {3}", ((float)index) / ((float)filectr), index, filectr, packOrder[i]);
                        index++;
                        if (label.InvokeRequired)
                            label.Invoke((MethodInvoker)delegate { label.Text = update; });
                        else { label.Text = update; }
                        #endregion
                    }
                    else
                    {
                        garc.fatb.Entries[i].IsFolder = true;
                        string[] subFiles = Directory.GetFiles(packOrder[i]);
                        foreach (string f in subFiles)
                        {
                            string s = f;
                            string fn = Path.GetFileNameWithoutExtension(f);
                            int compressed = fn.IndexOf("dec_", StringComparison.Ordinal);
                            int fileNumber = (compressed < 0)
                                ? Int32.Parse(fn)
                                : Int32.Parse(fn.Substring(compressed + 4));
                            garc.fatb.Entries[i].SubEntries[fileNumber].Exists = true;

                            if (compressed >= 0)
                            {
                                LZSS.Compress(f, s = Path.Combine(Path.GetDirectoryName(f), fileNumber.ToString()));
                                File.Delete(f);
                            }

                            // Assemble Vector
                            v |= 1 << fileNumber;

                            // Assemble Entry
                            FileInfo fi = new FileInfo(s);
                            int actualLength = (int)((fi.Length % 4 == 0) ? fi.Length : fi.Length + 4 - (fi.Length % 4));
                            garc.fatb.Entries[i].SubEntries[fileNumber].Start = od;
                            garc.fatb.Entries[i].SubEntries[fileNumber].End = actualLength + garc.fatb.Entries[i].SubEntries[fileNumber].Start;
                            garc.fatb.Entries[i].SubEntries[fileNumber].Length = (int)fi.Length;
                            od += actualLength;

                            op += 12;
                            #region Step
                            if (pBar1.InvokeRequired)
                                pBar1.Invoke((MethodInvoker)(() => pBar1.PerformStep()));
                            else { pBar1.PerformStep(); }
                            string update = String.Format("{0:P2} - {1}/{2} - {3}", ((float)index) / ((float)filectr), index, filectr, f);
                            index++;
                            if (label.InvokeRequired)
                                label.Invoke((MethodInvoker)delegate { label.Text = update; });
                            else { label.Text = update; }
                            #endregion
                        }
                    }
                    garc.fatb.Entries[i].Vector = (uint)v;
                }
                garc.fatb.HeaderSize = (0xC + op);
            }
            #endregion

            // Delete the old garc if it exists, then begin writing our new one
            try { File.Delete(garcPath); }
            catch { }

            // Set up the Header Info
            using (MemoryStream newGARC = new MemoryStream())
            using (MemoryStream GARCdata = new MemoryStream())
            using (BinaryWriter gw = new BinaryWriter(newGARC))
            {
                #region Write GARC Headers
                // Write GARC
                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((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)

                // Write FATO
                gw.Write((uint)0x4641544F);     // FATO
                gw.Write(garc.fato.HeaderSize); // Header Size
                gw.Write(garc.fato.EntryCount); // Entry Count
                gw.Write(garc.fato.Padding);    // Padding
                for (int i = 0; i < garc.fato.Entries.Length; i++)
                    gw.Write((uint)garc.fato.Entries[i].Offset);

                // Write FATB
                gw.Write((uint)0x46415442);     // FATB
                gw.Write(garc.fatb.HeaderSize); // Header Size
                gw.Write(garc.fatb.FileCount);  // File Count
                foreach (var e in garc.fatb.Entries)
                {
                    gw.Write(e.Vector);
                    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); }
                }
                #endregion

                #region Write Files
                long largestSize = 0; // Required memory to allocate to handle the largest file
                foreach (string e in packOrder)
                {
                    string[] fa = Directory.Exists(e) ? Directory.GetFiles(e) : new[] { e };
                    foreach (string f in fa)
                    {
                        // Update largest file length if necessary
                        long len = new FileInfo(f).Length;
                        if (len > largestSize) largestSize = 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);
                    }
                }
                #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.Write((uint)largestSize);                            // Write Largest File stat (?)

                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; }

                    // We're done.
                    SystemSounds.Exclamation.Play();
                    if (!supress) Util.Alert("Pack Successful!", filectr + " files packed to the GARC!");

                    return true;
                }
                catch (Exception e) { Util.Error("Packing Failed!", e.ToString()); return false; }
            }
        }
Example #4
0
        private static GARCFile unpackGARC(Stream stream)
        {
            GARCFile garc = new GARCFile();
            using (BinaryReader br = new BinaryReader(stream))
            {
                // GARC Header
                garc.Magic = br.ReadChars(4);
                garc.HeaderSize = br.ReadUInt32();
                garc.Endianess = br.ReadUInt16();
                garc.Version = br.ReadUInt16();
                garc.ChunkCount = br.ReadUInt32();

                garc.DataOffset = br.ReadUInt32();
                garc.FileSize = 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);
                garc.fato.HeaderSize = br.ReadInt32();
                garc.fato.EntryCount = br.ReadUInt16();
                garc.fato.Padding = br.ReadUInt16();

                garc.fato.Entries = new FATO_Entry[garc.fato.EntryCount];
                for (int i = 0; i < garc.fato.EntryCount; i++)
                    garc.fato.Entries[i].Offset = br.ReadInt32();

                // FATB (File Allocation Table Bits)
                garc.fatb.Magic = br.ReadChars(4);
                garc.fatb.HeaderSize = br.ReadInt32();
                garc.fatb.FileCount = br.ReadInt32();

                garc.fatb.Entries = new FATB_Entry[garc.fato.EntryCount];
                for (int i = 0; i < garc.fato.EntryCount; i++) // Loop through all FATO entries
                {
                    garc.fatb.Entries[i].Vector = br.ReadUInt32();
                    garc.fatb.Entries[i].SubEntries = new FATB_SubEntry[32];
                    uint bitvector = garc.fatb.Entries[i].Vector;
                    int ctr = 0;
                    for (int b = 0; b < 32; b++)
                    {
                        garc.fatb.Entries[i].SubEntries[b].Exists = (bitvector & 1) == 1;
                        bitvector >>= 1;
                        if (!garc.fatb.Entries[i].SubEntries[b].Exists) continue;
                        garc.fatb.Entries[i].SubEntries[b].Start = br.ReadInt32();
                        garc.fatb.Entries[i].SubEntries[b].End = br.ReadInt32();
                        garc.fatb.Entries[i].SubEntries[b].Length = br.ReadInt32();
                        ctr++;
                    }
                    garc.fatb.Entries[i].IsFolder = ctr > 1;
                }

                // FIMB (File IMage Bytes)
                garc.fimg.Magic = br.ReadChars(4);
                garc.fimg.HeaderSize = br.ReadInt32();
                garc.fimg.DataSize = br.ReadInt32();

                // Files data
                // Oftentimes too large to toss into a byte array. Fetch as needed with a BinaryReader.
            }
            return garc;
        }
Example #5
0
        public static MemGARC packGARC(byte[][] data, int version)
        {
            // Set Up the GARC template.
            GARCFile garc = new GARCFile
            {
                ContentPadToNearest = 4,
                fato =
                {
                    // Magic = new[] { 'O', 'T', 'A', 'F' },
                    Entries = new FATO_Entry[data.Length],
                    EntryCount = (ushort) data.Length,
                    HeaderSize = 0xC + data.Length*4,
                    Padding = 0xFFFF
                },
                fatb =
                {
                    // Magic = new[] { 'B', 'T', 'A', 'F' },
                    Entries = new FATB_Entry[data.Length],
                    FileCount = data.Length
                }
            };

            if (version == VER_6)
                garc.ContentPadToNearest = 4;

            int op = 0;
            int od = 0;
            for (int i = 0; i < garc.fatb.Entries.Length; i++)
            {
                garc.fato.Entries[i].Offset = op; // FATO offset
                garc.fatb.Entries[i].SubEntries = new FATB_SubEntry[32];
                op += 4; // Vector
                garc.fatb.Entries[i].IsFolder = false;
                garc.fatb.Entries[i].SubEntries[0].Exists = true;

                // Assemble Entry
                int actualLength = data[i].Length%4 == 0 ? data[i].Length : data[i].Length + 4 - data[i].Length%4;
                garc.fatb.Entries[i].SubEntries[0].Start = od;
                garc.fatb.Entries[i].SubEntries[0].End = actualLength + garc.fatb.Entries[i].SubEntries[0].Start;
                garc.fatb.Entries[i].SubEntries[0].Length = data[i].Length;
                od += actualLength;

                op += 12;
                garc.fatb.Entries[i].Vector = 1;
            }
            garc.fatb.HeaderSize = 0xC + op;

            // Set up the Header Info
            using (MemoryStream newGARC = new MemoryStream())
            using (MemoryStream GARCdata = new MemoryStream())
            using (BinaryWriter gw = new BinaryWriter(newGARC))
            {
                #region Write GARC Headers

                // Write GARC
                gw.Write((uint) 0x47415243); // GARC
                gw.Write((uint) (version == VER_6 ? 0x24 : 0x1C)); // Header Length
                gw.Write((ushort) 0xFEFF); // Endianness BOM
                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
                gw.Write(garc.fato.EntryCount); // Entry Count
                gw.Write(garc.fato.Padding); // Padding
                for (int i = 0; i < garc.fato.Entries.Length; i++)
                    gw.Write((uint) garc.fato.Entries[i].Offset);

                // Write FATB
                gw.Write((uint) 0x46415442); // FATB
                gw.Write(garc.fatb.HeaderSize); // Header Size
                gw.Write(garc.fatb.FileCount); // File Count
                foreach (var e in garc.fatb.Entries)
                {
                    gw.Write(e.Vector);
                    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);
                    }
                }

                #endregion

                #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 (byte[] e in data)
                {
                    // Update largest file length if necessary
                    long len = e.Length;
                    bool largest = len > largestSize;
                    if (largest)
                    {
                        largestSize = len;
                        largestPadded = len;
                    }

                    // Write to FIMB
                    using (var input = new MemoryStream(e))
                        input.CopyTo(GARCdata);

                    // While length is not divisible by 4, pad with FF (unused byte)
                    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
                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

                // 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.

                // Write in the data
                GARCdata.Position = 0;
                GARCdata.CopyTo(newGARC); // Copy the data.
                // New File is ready to be saved (memstream newGARC)
                return new MemGARC(newGARC.ToArray());
            }
        }
Example #6
0
            public byte[] Save()
            {
                byte[][] data = new byte[FileCount][];
                for (int i = 0; i < data.Length; i++)
                {
                    if (Storage[i] == null || !Storage[i].Saved) // retrieve original
                        data[i] = getFile(i, 0);
                    else // use modified
                        data[i] = Storage[i].Save();
                }

                var ng = packGARC(data, garc.Version, (int)garc.ContentPadToNearest);
                garc = ng.garc;
                Data = ng.Data;
                return Data;
            }
Example #7
0
 public lzGARC(byte[] data)
 {
     Data = data;
     garc = unpackGARC(data);
     Storage = new GARCEntry[FileCount];
 }
Example #8
0
 public void InitializePersonal()
 {
     GARCPersonal = getGARCData("personal");
     Personal = new PersonalTable(GARCPersonal.getFile(GARCPersonal.FileCount - 1), Version);
 }