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; }
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(); }
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); }
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(); } } } } }
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); }
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(), }); } }
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(), }); } }
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(); } } } } }
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); } } } } } }
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); } } } }
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); } } } }