public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; bool overwriteFiles = false; bool verbose = false; bool uncompress = false; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null }, { "v|verbose", "be verbose", v => verbose = v != null }, { "u|uncompress", "uncompress DCX compressed files", v => uncompress = 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_bhd5 [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string headerPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(headerPath, null) + "_unpack"; string dataPath; if (Path.GetExtension(headerPath) == ".bdt") { dataPath = headerPath; headerPath = Path.ChangeExtension(headerPath, ".bhd5"); } else { dataPath = Path.ChangeExtension(headerPath, ".bdt"); } var manager = ProjectData.Manager.Load(); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadListsFileNames(); var bhd = new Binder5File(); using (var input = File.OpenRead(headerPath)) { bhd.Deserialize(input); } using (var input = File.OpenRead(dataPath)) { long current = 0; long total = bhd.Entries.Count; foreach (var entry in bhd.Entries) { bool uncompressing = false; 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; extension = "unknown"; // TODO: fix me } 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 (uncompress == true && entry.Size >= 76) { input.Seek(entry.Offset, SeekOrigin.Begin); if (input.ReadValueU32(Endian.Big) == 0x44435800) { uncompressing = true; var extension = Path.GetExtension(name); if (extension != null && extension.EndsWith(".dcx") == true) { name = name.Substring(0, name.Length - 4); } } } var entryPath = Path.Combine(outputPath, name); var parentPath = Path.GetDirectoryName(entryPath); if (parentPath != null) { Directory.CreateDirectory(parentPath); } 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.Size > 0) { if (uncompress == false || uncompressing == false) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.Size); } else { input.Seek(entry.Offset, SeekOrigin.Begin); using (var temp = CompressedFile.Decompress(input)) { output.WriteFromStream(temp, temp.Length); } } } } } } }
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 = Gibbed.ProjectData.Manager.Load(currentProject); if (manager.ActiveProject == null) { Console.WriteLine("Nothing to do: no active project loaded."); return; } var project = manager.ActiveProject; var hashes = manager.LoadListsFileNames(); 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 inputPaths = new List <string>(); inputPaths.AddRange(Directory.GetFiles(installPath, "*.bhd5", SearchOption.AllDirectories)); var outputPaths = new List <string>(); var breakdown = new Breakdown(); Console.WriteLine("Processing..."); foreach (var inputPath in inputPaths) { 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 bhd = new Binder5File(); if (File.Exists(inputPath + ".bak") == true) { using (var input = File.OpenRead(inputPath + ".bak")) bhd.Deserialize(input); } else { using (var input = File.OpenRead(inputPath)) bhd.Deserialize(input); } var localBreakdown = new Breakdown(); var names = new List <string>(); foreach (var nameHash in bhd.Entries.Select(e => e.NameHash).Distinct()) { var name = hashes[nameHash]; if (name != null) { if (names.Contains(name) == false) { names.Add(name); localBreakdown.Known++; } } localBreakdown.Total++; } breakdown.Known += localBreakdown.Known; breakdown.Total += localBreakdown.Total; names.Sort(); var parentPath = Path.GetDirectoryName(outputPath); if (parentPath != null) { Directory.CreateDirectory(parentPath); } using (var output = new StreamWriter(outputPath)) { output.WriteLine("; {0}", localBreakdown); foreach (string name in names) { output.WriteLine(name); } } } using (var output = new StreamWriter(Path.Combine(Path.Combine(listsPath, "files"), "status.txt"))) output.WriteLine("{0}", breakdown); }