예제 #1
0
        private void OnOpen(object sender, EventArgs e)
        {
            if (this.openDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (this.openDialog.InitialDirectory != null)
            {
                this.openDialog.InitialDirectory = null;
            }

            BigFile archive;

            using (var input = this.openDialog.OpenFile())
            {
                archive = new BigFile();
                archive.Deserialize(input);
            }
            this.Archive = archive;

            this.BuildFileTree();

            var exists = File.Exists(Path.ChangeExtension(this.openDialog.FileName, ".dat"));

            this.saveAllButton.Enabled         = exists;
            this.saveToolStripMenuItem.Enabled = exists;
        }
예제 #2
0
        private void OnOpen(object sender, EventArgs e)
        {
            if (this.openDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (this.openDialog.InitialDirectory != null)
            {
                this.openDialog.InitialDirectory = null;
            }

            BigFile archive;

            using (var input = this.openDialog.OpenFile())
            {
                archive = new BigFile();
                archive.Deserialize(input);
            }
            this.Archive = archive;

            /*
             * TextWriter writer = new StreamWriter("all_file_hashes.txt");
             * foreach (var hash in table.Keys.OrderBy(k => k))
             * {
             *  writer.WriteLine(hash.ToString("X8"));
             * }
             * writer.Close();
             */

            this.BuildFileTree();
        }
예제 #3
0
        private static bool FileExistsInBig(string fatPath, string fileName)
        {
            if (File.Exists(fatPath) == false)
            {
                return(false);
            }

            var big = new BigFile();

            using (var input = File.OpenRead(fatPath))
            {
                big.Deserialize(input);
            }

            var entries = big.Entries.Where(e => e.NameHash == fileName.HashFileNameCRC32());

            if (entries.Count() == 0)
            {
                return(false);
            }

            return(true);
        }
예제 #4
0
        public static void Main(string[] args)
        {
            bool showHelp       = false;
            bool overwriteFiles = false;
            bool verbose        = false;

            var options = new OptionSet()
            {
                {
                    "v|verbose",
                    "be verbose",
                    v => verbose = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 || extras.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_fat [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath  = extras[0];
            string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack";

            var manager = ProjectData.Manager.Load();

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }

            var hashes = manager.LoadLists(
                "*.filelist",
                s => s.HashFileNameCRC32(),
                s => s.ToLowerInvariant());

            var map = new MapFile();

            using (var input = File.OpenRead(inputPath))
            {
                map.Deserialize(input);
            }

            Directory.CreateDirectory(outputPath);
            using (var output = File.Create(Path.Combine(outputPath, "map.xml")))
            {
                var settings = new XmlWriterSettings();
                settings.Indent = true;

                using (var writer = XmlWriter.Create(output, settings))
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement("map");

                    writer.WriteStartElement("info");
                    writer.WriteElementString("name", map.Info.Name);
                    writer.WriteElementString("creator", map.Info.Creator);
                    writer.WriteElementString("author", map.Info.Author);
                    writer.WriteElementString("size", map.Info.Size.ToString());
                    writer.WriteElementString("players", map.Info.Players.ToString());
                    writer.WriteElementString("unknown2", map.Info.Unknown2.ToString());
                    writer.WriteElementString("unknown3", map.Info.Unknown3.ToString());
                    writer.WriteElementString("unknown4", map.Info.Unknown4.ToString());
                    writer.WriteElementString("unknown5", map.Info.Unknown5.ToString());
                    writer.WriteElementString("unknown7", map.Info.Unknown7.ToString());
                    writer.WriteElementString("unknown10", map.Info.Unknown10.ToString());
                    writer.WriteStartElement("unknown11");
                    writer.WriteBinHex(map.Info.Unknown11, 0, map.Info.Unknown11.Length);
                    writer.WriteEndElement();
                    writer.WriteStartElement("unknown12");
                    writer.WriteBinHex(map.Info.Unknown12, 0, map.Info.Unknown12.Length);
                    writer.WriteEndElement();
                    writer.WriteElementString("unknown15", map.Info.Unknown15.ToString());
                    writer.WriteEndElement();

                    writer.WriteStartElement("snapshot");
                    writer.WriteElementString("width", map.Snapshot.Width.ToString());
                    writer.WriteElementString("height", map.Snapshot.Height.ToString());
                    writer.WriteElementString("bpp", map.Snapshot.BytesPerPixel.ToString());
                    writer.WriteElementString("unknown4", map.Snapshot.Unknown4.ToString());
                    writer.WriteEndElement();

                    writer.WriteStartElement("data");
                    writer.WriteElementString("unknown1", map.Data.Unknown1);
                    writer.WriteEndElement();

                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                }
            }

            using (var input = map.Archive.XML.Unpack())
            {
                using (var output = File.Create(Path.Combine(outputPath, "archive.xml")))
                {
                    output.WriteFromStream(input, input.Length);
                }
            }

            using (var output = File.Create(Path.Combine(outputPath, "snapshot.bin")))
            {
                output.Write(map.Snapshot.Data, 0, map.Snapshot.Data.Length);
            }

            var big = new BigFile();

            using (var input = map.Archive.FAT.Unpack())
            {
                big.Deserialize(input);
            }

            var dataPath = Path.Combine(outputPath, "archive");

            Directory.CreateDirectory(dataPath);

            using (var input = map.Archive.DAT.Unpack())
            {
                long current = 0;
                long total   = big.Entries.Count;

                foreach (var entry in big.Entries)
                {
                    current++;

                    string name = hashes[entry.NameHash];
                    if (name == null)
                    {
                        string extension;

                        // detect type
                        {
                            var guess = new byte[64];
                            int read  = 0;

                            if (entry.CompressionScheme == CompressionScheme.None)
                            {
                                if (entry.CompressedSize > 0)
                                {
                                    input.Seek(entry.Offset, SeekOrigin.Begin);
                                    read = input.Read(guess, 0, (int)Math.Min(
                                                          entry.CompressedSize, guess.Length));
                                }
                            }
                            else if (entry.CompressionScheme == CompressionScheme.LZO1x)
                            {
                                input.Seek(entry.Offset, SeekOrigin.Begin);

                                var compressedData = new byte[entry.CompressedSize];
                                if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length)
                                {
                                    throw new EndOfStreamException();
                                }

                                var  uncompressedData = new byte[entry.UncompressedSize];
                                uint uncompressedSize = entry.UncompressedSize;

                                var result = LZO1x.Decompress(
                                    compressedData,
                                    entry.CompressedSize,
                                    uncompressedData,
                                    ref uncompressedSize);
                                if (result != 0)
                                {
                                    throw new InvalidOperationException("decompression error: " + result.ToString());
                                }
                                else if (uncompressedSize != entry.UncompressedSize)
                                {
                                    throw new InvalidOperationException("did not decompress correct amount of data");
                                }

                                Array.Copy(uncompressedData, 0, guess, 0, Math.Min(guess.Length, uncompressedData.Length));
                                read = uncompressedData.Length;
                            }
                            else
                            {
                                throw new NotSupportedException();
                            }

                            extension = FileExtensions.Detect(guess, Math.Min(guess.Length, read));
                        }

                        name = entry.NameHash.ToString("X8");
                        name = Path.ChangeExtension(name, "." + extension);
                        name = Path.Combine(extension, name);
                        name = Path.Combine("__UNKNOWN", name);
                    }
                    else
                    {
                        name = name.Replace("/", "\\");
                        if (name.StartsWith("\\") == true)
                        {
                            name = name.Substring(1);
                        }
                    }

                    var entryPath = Path.Combine(dataPath, name);
                    Directory.CreateDirectory(Path.GetDirectoryName(entryPath));

                    if (overwriteFiles == false &&
                        File.Exists(entryPath) == true)
                    {
                        continue;
                    }

                    if (verbose == true)
                    {
                        Console.WriteLine("[{0}/{1}] {2}",
                                          current, total, name);
                    }

                    using (var output = File.Create(entryPath))
                    {
                        if (entry.CompressionScheme == CompressionScheme.None)
                        {
                            if (entry.CompressedSize > 0)
                            {
                                input.Seek(entry.Offset, SeekOrigin.Begin);
                                output.WriteFromStream(input, entry.CompressedSize);
                            }
                        }
                        else if (entry.CompressionScheme == CompressionScheme.LZO1x)
                        {
                            if (entry.UncompressedSize > 0)
                            {
                                input.Seek(entry.Offset, SeekOrigin.Begin);

                                var compressedData = new byte[entry.CompressedSize];
                                if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length)
                                {
                                    throw new EndOfStreamException();
                                }

                                var  uncompressedData = new byte[entry.UncompressedSize];
                                uint uncompressedSize = entry.UncompressedSize;

                                var result = LZO1x.Decompress(
                                    compressedData,
                                    entry.CompressedSize,
                                    uncompressedData,
                                    ref uncompressedSize);
                                if (result != 0)
                                {
                                    throw new InvalidOperationException("decompression error: " + result.ToString());
                                }
                                else if (uncompressedSize != entry.UncompressedSize)
                                {
                                    throw new InvalidOperationException("did not decompress correct amount of data");
                                }

                                output.Write(uncompressedData, 0, uncompressedData.Length);
                            }
                        }
                        else
                        {
                            throw new NotSupportedException();
                        }
                    }
                }
            }
        }
예제 #5
0
        private static bool UnpackFileFromBig(string fatPath, string fileName, string outputPath)
        {
            var datPath = Path.ChangeExtension(fatPath, ".dat");

            if (File.Exists(fatPath) == false ||
                File.Exists(datPath) == false)
            {
                return(false);
            }

            var big = new BigFile();

            using (var input = File.OpenRead(fatPath))
            {
                big.Deserialize(input);
            }

            var entries = big.Entries.Where(e => e.NameHash == fileName.HashFileNameCRC32());

            if (entries.Count() == 0)
            {
                return(false);
            }

            var entry = entries.First();

            using (var input = File.OpenRead(datPath))
            {
                using (var output = File.Create(outputPath))
                {
                    if (entry.CompressionScheme == Big.CompressionScheme.None)
                    {
                        if (entry.CompressedSize > 0)
                        {
                            input.Seek(entry.Offset, SeekOrigin.Begin);
                            output.WriteFromStream(input, entry.CompressedSize);
                        }
                    }
                    else if (entry.CompressionScheme == Big.CompressionScheme.LZO1x)
                    {
                        if (entry.UncompressedSize > 0)
                        {
                            input.Seek(entry.Offset, SeekOrigin.Begin);

                            var compressedData = new byte[entry.CompressedSize];
                            if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length)
                            {
                                throw new EndOfStreamException();
                            }

                            var uncompressedData = new byte[entry.UncompressedSize];
                            int uncompressedSize = (int)entry.UncompressedSize;

                            var result = MiniLZO.LZO.DecompressSafe(
                                compressedData,
                                0,
                                (int)entry.CompressedSize,
                                uncompressedData,
                                0,
                                ref uncompressedSize);
                            if (result != MiniLZO.ErrorCode.Success)
                            {
                                throw new InvalidOperationException("decompression error: " + result.ToString());
                            }
                            else if (uncompressedSize != entry.UncompressedSize)
                            {
                                throw new InvalidOperationException("did not decompress correct amount of data");
                            }

                            output.Write(uncompressedData, 0, uncompressedData.Length);
                        }
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                }
            }

            return(true);
        }
예제 #6
0
        public static void Main(string[] args)
        {
            bool   showHelp       = false;
            string currentProject = null;

            var options = new OptionSet()
            {
                { "h|help", "show this message and exit", v => showHelp = v != null },
                { "p|project=", "override current project", v => currentProject = v },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count != 0 || showHelp)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            Console.WriteLine("Loading project...");

            var manager = Manager.Load(currentProject);

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Nothing to do: no active project loaded.");
                return;
            }

            var             project     = manager.ActiveProject;
            var             version     = -1;
            HashList <uint> knownHashes = null;

            var installPath = project.InstallPath;
            var listsPath   = project.ListsPath;

            if (installPath == null)
            {
                Console.WriteLine("Could not detect install path.");
                return;
            }

            if (listsPath == null)
            {
                Console.WriteLine("Could not detect lists path.");
                return;
            }

            Console.WriteLine("Searching for .fat archives in game directory...");
            var fatPaths = new List <string>();

            fatPaths.AddRange(Directory.GetFiles(installPath, "*.fat", SearchOption.AllDirectories));

            var outputPaths = new List <string>();

            var breakdown = new Breakdown();
            var tracking  = new Tracking();

            Console.WriteLine("Processing...");
            for (int i = 0; i < fatPaths.Count; i++)
            {
                var fatPath = fatPaths[i];

                var outputPath = GetListPath(installPath, fatPath);
                if (outputPath == null)
                {
                    throw new InvalidOperationException();
                }

                Console.WriteLine("Found file: " + outputPath);
                outputPath = Path.Combine(listsPath, outputPath);

                if (outputPaths.Contains(outputPath))
                {
                    throw new InvalidOperationException();
                }

                outputPaths.Add(outputPath);

                if (File.Exists(fatPath + ".bak"))
                {
                    fatPath += ".bak";
                }

                var fat = new BigFile();
                using (var input = File.OpenRead(fatPath))
                {
                    fat.Deserialize(input);
                }

                if (version == -1)
                {
                    version     = fat.Version;
                    knownHashes = manager.LoadListsFileNames(fat.Version);
                }
                else if (version != fat.Version)
                {
                    throw new InvalidOperationException();
                }

                if (knownHashes == null)
                {
                    throw new InvalidOperationException();
                }

                HandleEntries(fat.Entries.Select(e => e.NameHash).Distinct(),
                              knownHashes,
                              tracking,
                              breakdown,
                              outputPath);
            }

            using (var output = new StreamWriter(Path.Combine(Path.Combine(listsPath, "files"), "status.txt")))
            {
                output.WriteLine("{0}",
                                 new Breakdown()
                {
                    Known = tracking.Names.Distinct().Count(),
                    Total = tracking.Hashes.Distinct().Count(),
                });
            }
        }
예제 #7
0
        public static void Main(string[] args)
        {
            bool   showHelp       = false;
            string currentProject = null;

            var options = new OptionSet()
            {
                { "h|help", "show this message and exit", v => showHelp = v != null },
                { "p|project=", "override current project", v => currentProject = v },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count != 0 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            Console.WriteLine("Loading project...");

            var manager = Manager.Load(currentProject);

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Nothing to do: no active project loaded.");
                return;
            }

            var project = manager.ActiveProject;
            var version = -1;
            HashList <ulong> knownHashes  = null;
            HashList <ulong> subFatHashes = null;

            var installPath = project.InstallPath;
            var listsPath   = project.ListsPath;

            if (installPath == null)
            {
                Console.WriteLine("Could not detect install path.");
                return;
            }

            if (listsPath == null)
            {
                Console.WriteLine("Could not detect lists path.");
                return;
            }

            Console.WriteLine("Searching for archives...");
            var fatPaths = new List <string>();

            fatPaths.AddRange(Directory.GetFiles(installPath, "*.fat", SearchOption.AllDirectories));

            var outputPaths = new List <string>();

            var breakdown = new Breakdown();
            var tracking  = new Tracking();

            Console.WriteLine("Processing...");
            for (int i = 0; i < fatPaths.Count; i++)
            {
                var fatPath = fatPaths[i];
                var datPath = Path.ChangeExtension(fatPath, ".dat");

                var outputPath = GetListPath(installPath, fatPath);
                if (outputPath == null)
                {
                    throw new InvalidOperationException();
                }

                Console.WriteLine(outputPath);
                outputPath = Path.Combine(listsPath, outputPath);

                if (outputPaths.Contains(outputPath) == true)
                {
                    throw new InvalidOperationException();
                }

                outputPaths.Add(outputPath);

                if (File.Exists(fatPath + ".bak") == true)
                {
                    fatPath += ".bak";
                    datPath += ".bak";
                }

                var fat = new BigFile();
                using (var input = File.OpenRead(fatPath))
                {
                    fat.Deserialize(input);
                }

                if (version == -1)
                {
                    version      = fat.Version;
                    knownHashes  = manager.LoadListsFileNames(fat.Version);
                    subFatHashes = manager.LoadListsSubFatNames(fat.Version);
                }
                else if (version != fat.Version)
                {
                    throw new InvalidOperationException();
                }

                if (knownHashes == null ||
                    subFatHashes == null)
                {
                    throw new InvalidOperationException();
                }

                HandleEntries(fat.Entries.Select(e => e.NameHash).Distinct(),
                              knownHashes,
                              tracking,
                              breakdown,
                              outputPath);

                using (var input = File.OpenRead(datPath))
                {
                    foreach (var headerEntry in fat.Entries.Where(e => subFatHashes.Contains(e.NameHash) == true))
                    {
                        var subFat = new SubFatFile();
                        using (var temp = new MemoryStream())
                        {
                            Big.EntryDecompression.Decompress(headerEntry, input, temp);
                            temp.Position = 0;
                            subFat.Deserialize(temp, fat);
                        }

                        var matchingSubFats = fat.SubFats
                                              .Where(sf => subFat.Entries.SequenceEqual(sf.Entries))
                                              .ToArray();

                        if (matchingSubFats.Length == 0)
                        {
                            continue;
                        }

                        if (matchingSubFats.Length > 1)
                        {
                            throw new InvalidOperationException();
                        }

                        var subfatPath = GetListPath(installPath,
                                                     fatPath,
                                                     FilterEntryName(subFatHashes[headerEntry.NameHash]));
                        if (subfatPath == null)
                        {
                            throw new InvalidOperationException();
                        }

                        Console.WriteLine(subfatPath);
                        subfatPath = Path.Combine(listsPath, subfatPath);

                        HandleEntries(subFat.Entries.Select(e => e.NameHash),
                                      knownHashes,
                                      tracking,
                                      breakdown,
                                      subfatPath);
                    }
                }
            }

            using (var output = new StreamWriter(Path.Combine(Path.Combine(listsPath, "files"), "status.txt")))
            {
                output.WriteLine("{0}",
                                 new Breakdown()
                {
                    Known = tracking.Names.Distinct().Count(),
                    Total = tracking.Hashes.Distinct().Count(),
                });
            }
        }
예제 #8
0
        public static void Main(string[] args)
        {
            bool showHelp        = false;
            bool extractUnknowns = true;
            bool noArt           = true;
            bool overwriteFiles  = false;
            bool verbose         = false;

            var options = new OptionSet()
            {
                {
                    "o|overwrite",
                    "overwrite existing files",
                    v => overwriteFiles = v != null
                },
                {
                    "na|no-art",
                    "don't extract art files (textures, models, etc)",
                    v => noArt = v != null
                },
                {
                    "nu|no-unknowns",
                    "don't extract unknown files",
                    v => extractUnknowns = v == null
                },
                {
                    "v|verbose",
                    "be verbose",
                    v => verbose = v != null
                },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 || extras.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_fat [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string fatPath    = extras[0];
            string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(fatPath, null) + "_unpack";
            string datPath;

            if (Path.GetExtension(fatPath) == ".dat")
            {
                datPath = fatPath;
                fatPath = Path.ChangeExtension(fatPath, ".fat");
            }
            else
            {
                datPath = Path.ChangeExtension(fatPath, ".dat");
            }

            var manager = ProjectData.Manager.Load();

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }

            var hashes = manager.LoadLists(
                "*.filelist",
                s => s.HashFileNameCRC32(),
                s => s.ToLowerInvariant());

            var big = new BigFile();

            using (var input = File.OpenRead(fatPath))
            {
                big.Deserialize(input);
            }

            using (var input = File.OpenRead(datPath))
            {
                long current = 0;
                long total   = big.Entries.Count;

                foreach (var entry in big.Entries)
                {
                    current++;

                    string name = hashes[entry.NameHash];
                    if (name == null)
                    {
                        if (extractUnknowns == false)
                        {
                            continue;
                        }

                        string extension;

                        // detect type
                        {
                            var guess = new byte[64];
                            int read  = 0;

                            if (entry.CompressionScheme == CompressionScheme.None)
                            {
                                if (entry.CompressedSize > 0)
                                {
                                    input.Seek(entry.Offset, SeekOrigin.Begin);
                                    read = input.Read(guess, 0, (int)Math.Min(
                                                          entry.CompressedSize, guess.Length));
                                }
                            }
                            else if (entry.CompressionScheme == CompressionScheme.LZO1x)
                            {
                                input.Seek(entry.Offset, SeekOrigin.Begin);

                                var compressedData = new byte[entry.CompressedSize];
                                if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length)
                                {
                                    throw new EndOfStreamException();
                                }

                                var  uncompressedData = new byte[entry.UncompressedSize];
                                uint uncompressedSize = entry.UncompressedSize;

                                var result = LZO1x.Decompress(
                                    compressedData,
                                    entry.CompressedSize,
                                    uncompressedData,
                                    ref uncompressedSize);
                                if (result != 0)
                                {
                                    throw new InvalidOperationException("decompression error: " + result.ToString());
                                }
                                else if (uncompressedSize != entry.UncompressedSize)
                                {
                                    throw new InvalidOperationException("did not decompress correct amount of data");
                                }

                                Array.Copy(uncompressedData, 0, guess, 0, Math.Min(guess.Length, uncompressedData.Length));
                                read = uncompressedData.Length;
                            }
                            else
                            {
                                throw new NotSupportedException();
                            }

                            extension = FileExtensions.Detect(guess, Math.Min(guess.Length, read));
                        }

                        name = entry.NameHash.ToString("X8");
                        name = Path.ChangeExtension(name, "." + extension);
                        name = Path.Combine(extension, name);
                        name = Path.Combine("__UNKNOWN", name);
                    }
                    else
                    {
                        name = name.Replace("/", "\\");
                        if (name.StartsWith("\\") == true)
                        {
                            name = name.Substring(1);
                        }
                    }

                    if (noArt == true)
                    {
                        var ext = Path.GetExtension(name);
                        if (ext == ".xbt" ||
                            ext == ".xbg" ||
                            ext == ".xbm" ||
                            ext == ".spk" ||
                            ext == ".mab" ||
                            ext == ".lfe" ||
                            ext == ".lfa" ||
                            ext == ".rtx" ||
                            ext == ".apm")
                        {
                            continue;
                        }
                    }

                    var entryPath = Path.Combine(outputPath, name);
                    Directory.CreateDirectory(Path.GetDirectoryName(entryPath));

                    if (overwriteFiles == false &&
                        File.Exists(entryPath) == true)
                    {
                        continue;
                    }

                    if (verbose == true)
                    {
                        Console.WriteLine("[{0}/{1}] {2}",
                                          current, total, name);
                    }

                    using (var output = File.Create(entryPath))
                    {
                        if (entry.CompressionScheme == CompressionScheme.None)
                        {
                            if (entry.CompressedSize > 0)
                            {
                                input.Seek(entry.Offset, SeekOrigin.Begin);
                                output.WriteFromStream(input, entry.CompressedSize);
                            }
                        }
                        else if (entry.CompressionScheme == CompressionScheme.LZO1x)
                        {
                            if (entry.UncompressedSize > 0)
                            {
                                input.Seek(entry.Offset, SeekOrigin.Begin);

                                var compressedData = new byte[entry.CompressedSize];
                                if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length)
                                {
                                    throw new EndOfStreamException();
                                }

                                var  uncompressedData = new byte[entry.UncompressedSize];
                                uint uncompressedSize = entry.UncompressedSize;

                                var result = LZO1x.Decompress(
                                    compressedData,
                                    entry.CompressedSize,
                                    uncompressedData,
                                    ref uncompressedSize);
                                if (result != 0)
                                {
                                    throw new InvalidOperationException("decompression error: " + result.ToString());
                                }
                                else if (uncompressedSize != entry.UncompressedSize)
                                {
                                    throw new InvalidOperationException("did not decompress correct amount of data");
                                }

                                output.Write(uncompressedData, 0, uncompressedData.Length);
                            }
                        }
                        else
                        {
                            throw new NotSupportedException();
                        }
                    }
                }
            }
        }
예제 #9
0
        public static void Main(string[] args)
        {
            bool   showHelp        = false;
            bool   extractUnknowns = true;
            bool   onlyUnknowns    = false;
            bool   extractFiles    = true;
            string filterPattern   = null;
            bool   overwriteFiles  = false;
            bool   verbose         = false;

            var options = new OptionSet()
            {
                { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null },
                { "nf|no-files", "don't extract files", v => extractFiles = v == null },
                { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null },
                { "ou|only-unknowns", "only extract unknown files", v => onlyUnknowns = v != null },
                { "f|filter=", "only extract files using pattern", v => filterPattern = v },
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "h|help", "show this message and exit", v => showHelp = v != null },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 || extras.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_fat [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Unpack files from a Big File (FAT/DAT pair).");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string fatPath    = extras[0];
            string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(fatPath, null) + "_unpack";
            string datPath;

            Regex filter = null;

            if (string.IsNullOrEmpty(filterPattern) == false)
            {
                filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            }

            if (Path.GetExtension(fatPath) == ".dat")
            {
                datPath = fatPath;
                fatPath = Path.ChangeExtension(fatPath, ".fat");
            }
            else
            {
                datPath = Path.ChangeExtension(fatPath, ".dat");
            }

            if (verbose == true)
            {
                Console.WriteLine("Loading project...");
            }

            var manager = ProjectData.Manager.Load();

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }

            if (verbose == true)
            {
                Console.WriteLine("Reading FAT...");
            }

            BigFile fat;

            using (var input = File.OpenRead(fatPath))
            {
                fat = new BigFile();
                fat.Deserialize(input);
            }

            var hashes = manager.LoadListsFileNames(fat.Version);

            using (var input = File.OpenRead(datPath))
            {
                if (extractFiles == true)
                {
                    Big.Entry[] entries = fat.Entries.OrderBy(e => e.Offset).ToArray();

                    if (entries.Length > 0)
                    {
                        if (verbose == true)
                        {
                            Console.WriteLine("Unpacking files...");
                        }

                        long current = 0;
                        long total   = entries.Length;
                        var  padding = total.ToString(CultureInfo.InvariantCulture).Length;

                        var duplicates = new Dictionary <ulong, int>();

                        foreach (var entry in entries)
                        {
                            current++;

                            string entryName;
                            if (GetEntryName(input,
                                             fat,
                                             entry,
                                             hashes,
                                             extractUnknowns,
                                             onlyUnknowns,
                                             out entryName) == false)
                            {
                                continue;
                            }

                            if (duplicates.ContainsKey(entry.NameHash) == true)
                            {
                                var number = duplicates[entry.NameHash]++;
                                var e      = Path.GetExtension(entryName);
                                var nn     =
                                    Path.ChangeExtension(
                                        Path.ChangeExtension(entryName, null) + "__DUPLICATE_" +
                                        number.ToString(CultureInfo.InvariantCulture),
                                        e);
                                entryName = Path.Combine("__DUPLICATE", nn);
                            }
                            else
                            {
                                duplicates[entry.NameHash] = 0;
                            }

                            if (filter != null &&
                                filter.IsMatch(entryName) == false)
                            {
                                continue;
                            }

                            var entryPath = Path.Combine(outputPath, entryName);
                            if (overwriteFiles == false &&
                                File.Exists(entryPath) == true)
                            {
                                continue;
                            }

                            if (verbose == true)
                            {
                                Console.WriteLine("[{0}/{1}] {2}",
                                                  current.ToString(CultureInfo.InvariantCulture).PadLeft(padding),
                                                  total,
                                                  entryName);
                            }

                            input.Seek(entry.Offset, SeekOrigin.Begin);

                            var entryParent = Path.GetDirectoryName(entryPath);
                            if (string.IsNullOrEmpty(entryParent) == false)
                            {
                                Directory.CreateDirectory(entryParent);
                            }

                            using (var output = File.Create(entryPath))
                            {
                                EntryDecompression.Decompress(entry, input, output);
                            }
                        }
                    }
                }
            }
        }
예제 #10
0
        public static void Main(string[] args)
        {
            bool showHelp = false;

            var options = new OptionSet()
            {
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count != 0 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            Console.WriteLine("Loading project...");

            var manager = ProjectData.Manager.Load();

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Nothing to do: no active project loaded.");
                return;
            }

            var project = manager.ActiveProject;
            var hashes  = project.LoadLists(
                "*.filelist",
                s => s.HashFileNameCRC32(),
                s => s.ToLowerInvariant());

            var installPath = project.InstallPath;
            var listsPath   = project.ListsPath;

            if (installPath == null)
            {
                Console.WriteLine("Could not detect install path.");
                return;
            }
            else if (listsPath == null)
            {
                Console.WriteLine("Could not detect lists path.");
                return;
            }

            Console.WriteLine("Searching for archives...");
            var inputPaths = new List <string>();

            inputPaths.AddRange(Directory.GetFiles(installPath, "*.fat", SearchOption.AllDirectories));

            var outputPaths = new List <string>();

            Console.WriteLine("Processing...");
            foreach (var inputPath in inputPaths)
            {
                // f**k you, colliding fat *g*
                if (Path.GetFileNameWithoutExtension(inputPath).ToLowerInvariant()
                    == "shadersobj")
                {
                    continue;
                }

                var outputPath = GetListPath(installPath, inputPath);
                if (outputPath == null)
                {
                    throw new InvalidOperationException();
                }

                Console.WriteLine(outputPath);
                outputPath = Path.Combine(listsPath, outputPath);

                if (outputPaths.Contains(outputPath) == true)
                {
                    throw new InvalidOperationException();
                }

                outputPaths.Add(outputPath);

                var big = new BigFile();

                if (File.Exists(inputPath + ".bak") == true)
                {
                    using (var input = File.OpenRead(inputPath + ".bak"))
                    {
                        big.Deserialize(input);
                    }
                }
                else
                {
                    using (var input = File.OpenRead(inputPath))
                    {
                        big.Deserialize(input);
                    }
                }

                var localBreakdown = new Breakdown();

                var names = new List <string>();
                foreach (var entry in big.Entries)
                {
                    if (entry.UncompressedSize == 4680308)
                    {
                    }

                    var name = hashes[entry.NameHash];
                    if (name != null)
                    {
                        if (names.Contains(name) == false)
                        {
                            names.Add(name);
                            localBreakdown.Known++;
                        }
                    }

                    localBreakdown.Total++;
                }

                names.Sort();

                Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
                using (var output = new StreamWriter(outputPath))
                {
                    output.WriteLine("; {0}", localBreakdown);

                    foreach (string name in names)
                    {
                        output.WriteLine(name);
                    }
                }
            }
        }
예제 #11
0
        public static void Main(string[] args)
        {
            bool   showHelp        = false;
            bool   extractUnknowns = true;
            bool   extractFiles    = true;
            bool   extractSubFats  = true;
            bool   unpackSubFats   = false;
            string filterPattern   = null;
            bool   overwriteFiles  = false;
            bool   verbose         = false;

            var options = new OptionSet()
            {
                { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null },
                { "nf|no-files", "don't extract files", v => extractFiles = v == null },
                { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null },
                { "ns|no-subfats", "don't extract subfats", v => extractSubFats = v == null },
                { "us|unpack-subfats", "unpack files from subfats", v => unpackSubFats = v != null },
                { "f|filter=", "only extract files using pattern", v => filterPattern = v },
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "h|help", "show this message and exit", v => showHelp = v != null },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 || extras.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_fat [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Unpack files from a Big File (FAT/DAT pair).");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string fatPath    = extras[0];
            string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(fatPath, null) + "_unpack";
            string datPath;

            Regex filter = null;

            if (string.IsNullOrEmpty(filterPattern) == false)
            {
                filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            }

            if (Path.GetExtension(fatPath) == ".dat")
            {
                datPath = fatPath;
                fatPath = Path.ChangeExtension(fatPath, ".fat");
            }
            else
            {
                datPath = Path.ChangeExtension(fatPath, ".dat");
            }

            if (verbose == true)
            {
                Console.WriteLine("Loading project...");
            }

            var manager = ProjectData.Manager.Load();

            if (manager.ActiveProject == null)
            {
                Console.WriteLine("Warning: no active project loaded.");
            }

            if (verbose == true)
            {
                Console.WriteLine("Reading FAT...");
            }

            BigFile fat;

            using (var input = File.OpenRead(fatPath))
            {
                fat = new BigFile();
                fat.Deserialize(input);
            }

            var hashes       = manager.LoadListsFileNames(fat.Version);
            var subFatHashes = manager.LoadListsSubFatNames(fat.Version);

            using (var input = File.OpenRead(datPath))
            {
                if (extractFiles == true)
                {
                    Big.Entry[] entries;
                    if (extractSubFats == true &&
                        unpackSubFats == true)
                    {
                        entries =
                            fat.Entries.Concat(fat.SubFats.SelectMany(sf => sf.Entries))
                            .OrderBy(e => e.Offset)
                            .ToArray();
                    }
                    else
                    {
                        entries = fat.Entries.OrderBy(e => e.Offset).ToArray();
                    }

                    if (entries.Length > 0)
                    {
                        if (verbose == true)
                        {
                            Console.WriteLine("Unpacking files...");
                        }

                        long current = 0;
                        long total   = entries.Length;
                        var  padding = total.ToString(CultureInfo.InvariantCulture).Length;

                        var duplicates = new Dictionary <ulong, int>();

                        foreach (var entry in entries)
                        {
                            current++;

                            if (subFatHashes.Contains(entry.NameHash) == true)
                            {
                                continue;
                            }

                            string entryName;
                            if (GetEntryName(input, fat, entry, hashes, extractUnknowns, out entryName) == false)
                            {
                                continue;
                            }

                            if (duplicates.ContainsKey(entry.NameHash) == true)
                            {
                                var number = duplicates[entry.NameHash]++;
                                var e      = Path.GetExtension(entryName);
                                var nn     =
                                    Path.ChangeExtension(
                                        Path.ChangeExtension(entryName, null) + "__DUPLICATE_" +
                                        number.ToString(CultureInfo.InvariantCulture),
                                        e);
                                entryName = Path.Combine("__DUPLICATE", nn);
                            }
                            else
                            {
                                duplicates[entry.NameHash] = 0;
                            }

                            if (filter != null &&
                                filter.IsMatch(entryName) == false)
                            {
                                continue;
                            }

                            var entryPath = Path.Combine(outputPath, entryName);
                            if (overwriteFiles == false &&
                                File.Exists(entryPath) == true)
                            {
                                continue;
                            }

                            if (verbose == true)
                            {
                                Console.WriteLine("[{0}/{1}] {2}",
                                                  current.ToString(CultureInfo.InvariantCulture).PadLeft(padding),
                                                  total,
                                                  entryName);
                            }

                            input.Seek(entry.Offset, SeekOrigin.Begin);

                            var entryParent = Path.GetDirectoryName(entryPath);
                            if (string.IsNullOrEmpty(entryParent) == false)
                            {
                                Directory.CreateDirectory(entryParent);
                            }

                            using (var output = File.Create(entryPath))
                            {
                                EntryDecompression.Decompress(entry, input, output);
                            }
                        }
                    }
                }

                if (extractSubFats == true &&
                    unpackSubFats == false &&
                    fat.SubFats.Count > 0)
                {
                    if (verbose == true)
                    {
                        Console.WriteLine("Unpacking subfats...");
                    }

                    var subFatsFromFat = fat.SubFats.ToList();

                    long current = 0;
                    long total   = subFatsFromFat.Count;
                    var  padding = total.ToString(CultureInfo.InvariantCulture).Length;

                    foreach (var headerEntry in fat.Entries.Where(e => subFatHashes.Contains(e.NameHash) == true))
                    {
                        current++;

                        var subFat = new SubFatFile();
                        using (var temp = new MemoryStream())
                        {
                            EntryDecompression.Decompress(headerEntry, input, temp);
                            temp.Position = 0;
                            subFat.Deserialize(temp, fat);
                        }

                        var matchingSubFats = subFatsFromFat
                                              .Where(sf => subFat.Entries.SequenceEqual(sf.Entries))
                                              .ToArray();

                        if (matchingSubFats.Length == 0)
                        {
                            continue;
                        }

                        if (matchingSubFats.Length > 1)
                        {
                            throw new InvalidOperationException();
                        }

                        var entryName = subFatHashes[headerEntry.NameHash];
                        entryName = FilterEntryName(entryName);

                        var entryHeaderPath = Path.Combine(outputPath, "__SUBFAT", entryName);
                        if (overwriteFiles == false &&
                            File.Exists(entryHeaderPath) == true)
                        {
                            continue;
                        }

                        if (verbose == true)
                        {
                            Console.WriteLine("[{0}/{1}] {2}",
                                              current.ToString(CultureInfo.InvariantCulture).PadLeft(padding),
                                              total,
                                              entryName);
                        }

                        var entryParent = Path.GetDirectoryName(entryHeaderPath);
                        if (string.IsNullOrEmpty(entryParent) == false)
                        {
                            Directory.CreateDirectory(entryParent);
                        }

                        var entryDataPath = Path.ChangeExtension(entryHeaderPath, ".dat");

                        var rebuiltFat = new BigFile
                        {
                            Version   = fat.Version,
                            Platform  = fat.Platform,
                            Unknown74 = fat.Unknown74
                        };

                        using (var output = File.Create(entryDataPath))
                        {
                            var rebuiltEntries = new List <Big.Entry>();
                            foreach (var entry in subFat.Entries.OrderBy(e => e.Offset))
                            {
                                var rebuiltEntry = new Big.Entry
                                {
                                    NameHash          = entry.NameHash,
                                    UncompressedSize  = entry.UncompressedSize,
                                    CompressedSize    = entry.CompressedSize,
                                    Offset            = output.Position,
                                    CompressionScheme = entry.CompressionScheme
                                };

                                input.Seek(entry.Offset, SeekOrigin.Begin);
                                output.WriteFromStream(input, entry.CompressedSize);
                                output.Seek(output.Position.Align(16), SeekOrigin.Begin);

                                rebuiltEntries.Add(rebuiltEntry);
                            }
                            rebuiltFat.Entries.AddRange(rebuiltEntries.OrderBy(e => e.NameHash));
                        }

                        using (var output = File.Create(entryHeaderPath))
                        {
                            rebuiltFat.Serialize(output);
                        }

                        foreach (var matchingSubFat in matchingSubFats)
                        {
                            subFatsFromFat.Remove(matchingSubFat);
                        }
                    }

                    if (subFatsFromFat.Count > 0)
                    {
                        Console.WriteLine("Warning: could not identify {0} subfats", subFatsFromFat.Count);
                    }
                }
            }
        }