private void OnOpen(object sender, EventArgs e) { if (this.openDialog.ShowDialog() != DialogResult.OK) { return; } // ReSharper disable RedundantCheckBeforeAssignment if (this.openDialog.InitialDirectory != null) // ReSharper restore RedundantCheckBeforeAssignment { this.openDialog.InitialDirectory = null; } using (var input = this.openDialog.OpenFile()) { var table = new ArchiveTableFile(); table.Deserialize(input); this._Table = table; } /* * 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(); }
public void ShowSaveProgress( IWin32Window owner, Stream archive, ArchiveTableFile table, List <uint> saving, ProjectData.HashList <uint> fileNames, string basePath, SaveAllSettings settings) { SaveAllInformation info; info.BasePath = basePath; info.Archive = archive; info.Table = table; info.Saving = saving; info.FileNames = fileNames; info.Settings = settings; this.progressBar.Value = 0; this.progressBar.Maximum = 100; this._SaveThread = new Thread(this.SaveAll); this._SaveThread.Start(info); this.ShowDialog(owner); }
// the thread entry point private void _DoSearch() { this._ArchiveIndex = 0; this._CurrentFile.Add(null); // the arc file this._CurrentFile.Add(null); // the file inside the arc file // walk the TAB files foreach (var tabFile in this._FileList) { var tab = new ArchiveTableFile(); using (var input = File.OpenRead(tabFile)) { tab.Deserialize(input); } var arcFile = Path.ChangeExtension(tabFile, ".arc"); this._CurrentFile[0] = Path.GetFileName(Path.GetDirectoryName(arcFile)) + '/' + Path.GetFileName(arcFile); using (var input = File.OpenRead(arcFile)) { this._ArchiveEntryIndex = 0; this._ArchiveEntryCount = tab.Entries.Count; foreach (var entry in tab.Entries) { ++this._ArchiveEntryIndex; ++this.FileCount; this.PrintProgress(); input.Position = entry.Offset; string subtype = this.GetType(input); if (string.IsNullOrEmpty(subtype)) { continue; } // set the current file if (this._ProjectFileList.Contains(entry.NameHash)) { this._CurrentFile[1] = this._ProjectFileList[entry.NameHash]; } else { this._CurrentFile[1] = entry.NameHash.ToString("X8") + '.' + subtype; } this.UpdateCurrentFile(); // process that file using (var entryStream = entry.ReadToMemoryStream(input)) { this.HandleStream(entryStream, subtype); } } } ++this._ArchiveIndex; } this.flush(); this.PrintEnd(); }
// the thread entry point private void _DoSearch() { this._ArchiveIndex = 0; // walk the TAB files foreach (var tabFile in this._FileList) { var tab = new ArchiveTableFile(); using (var input = File.OpenRead(tabFile)) { tab.Deserialize(input); } var arcFile = Path.ChangeExtension(tabFile, ".arc"); using (var input = File.OpenRead(arcFile)) { this._ArchiveEntryIndex = 0; this._ArchiveEntryCount = tab.Entries.Count; foreach (var entry in tab.Entries) { ++this._ArchiveEntryIndex; ++this.FileCount; this.PrintProgress(); input.Position = entry.Offset; string subtype = this.GetType(input); if (string.IsNullOrEmpty(subtype)) { continue; } using (var entryStream = entry.ReadToMemoryStream(input)) { this.HandleStream(entryStream, subtype); } } } ++this._ArchiveIndex; } this.PrintEnd(); }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; string filterPattern = null; bool overwriteFiles = false; bool verbose = false; string currentProject = null; 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 }, { "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 }, { "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 < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_tab [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string tabPath = Path.GetFullPath(extras[0]); string outputPath = extras.Count > 1 ? Path.GetFullPath(extras[1]) : Path.ChangeExtension(tabPath, null) + "_unpack"; Regex filter = null; if (string.IsNullOrEmpty(filterPattern) == false) { filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } var manager = ProjectData.Manager.Load(currentProject); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadFileLists(null); var tab = new ArchiveTableFile(); using (var input = File.OpenRead(tabPath)) { tab.Deserialize(input); } var arcPath = Path.ChangeExtension(tabPath, ".arc"); using (var input = File.OpenRead(arcPath)) { long current = 0; long total = tab.Entries.Count; var padding = total.ToString(CultureInfo.InvariantCulture).Length; foreach (var entry in tab.Entries) { current++; string name = hashes[entry.NameHash]; if (name == null) { if (extractUnknowns == false) { continue; } var guess = new byte[32]; input.Seek(entry.Offset, SeekOrigin.Begin); var read = input.Read(guess, 0, (int)Math.Min(guess.Length, entry.Size)); var extension = FileDetection.Detect(guess, read); name = entry.NameHash.ToString("X8"); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine("__UNKNOWN", extension, name); } else { if (name.StartsWith("/") == true) { name = name.Substring(1); } name = name.Replace('/', Path.DirectorySeparatorChar); } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine( "[{0}/{1}] {2}", current.ToString(CultureInfo.InvariantCulture).PadLeft(padding), total, name); } var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory != null) { Directory.CreateDirectory(entryDirectory); } using (var output = File.Create(entryPath)) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.Size); } } } }
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.LoadFileLists(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 inputPaths = new List <string>(); var locations = new Dictionary <string, string>() { { "archives_win64", "game*.tab" }, { "dlc_win64", "*.tab" }, { "patch_win64", "*.tab" }, }; foreach (var kv in locations) { var locationPath = Path.Combine(installPath, kv.Key); if (Directory.Exists(locationPath) == true) { inputPaths.AddRange(Directory.GetFiles(locationPath, kv.Value, SearchOption.AllDirectories)); } } var outputPaths = new List <string>(); var breakdown = new Breakdown(); var allNames = new List <string>(); 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 tab = new ArchiveTableFile(); if (File.Exists(inputPath + ".bak") == true) { using (var input = File.OpenRead(inputPath + ".bak")) { tab.Deserialize(input); } } else { using (var input = File.OpenRead(inputPath)) { tab.Deserialize(input); } } var localBreakdown = new Breakdown(); var names = new List <string>(); foreach (var nameHash in tab.Entries.Select(kv => kv.NameHash).Distinct()) { var name = hashes[nameHash]; if (name != null) { if (names.Contains(name) == false) { names.Add(name); localBreakdown.Known++; } if (allNames.Contains(name) == false) { allNames.Add(name); } } localBreakdown.Total++; } breakdown.Known += localBreakdown.Known; breakdown.Total += 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); } } } allNames.Sort(); using (var output = File.Create(Path.Combine(listsPath, "files", "status.txt"))) using (var writer = new StreamWriter(output)) { writer.WriteLine("{0}", breakdown); } }
public static void Main(string[] args) { bool overwrite = false; bool showHelp = false; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwrite = 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 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ game[0-9]+_unpack", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string path = Path.GetFullPath(extras[0]); string base_name = Path.GetFileName(path).Replace("_unpack", ""); string base_path = Path.GetDirectoryName(path); string tabFile = Path.Combine(base_path, base_name + ".tab"); string arcFile = Path.Combine(base_path, base_name + ".arc"); if (File.Exists(arcFile) && !overwrite) { Console.Write("Refusing to do this: it will overwrite {0}", Path.GetFileName(arcFile)); return; } Console.WriteLine("Will generate {0} and {1}", Path.GetFileName(tabFile), Path.GetFileName(arcFile)); var fileList = Directory.GetFiles(path, "*", SearchOption.AllDirectories); Uri baseUri = new Uri(path + Path.DirectorySeparatorChar); ArchiveTableFile tabData = new ArchiveTableFile(); var arcStream = File.Create(arcFile); Console.WriteLine("Found {0} files", fileList.Length); Console.WriteLine("Writing the ARC file"); uint count = 0; uint skipCount = 0; SortedSet <uint> hashSet = new SortedSet <uint>(); foreach (var file in fileList) { if (count > 0 && count % 300 == 0) { Console.WriteLine("[{0:F1} %]", (float)count * 100 / (float)fileList.Length); } ++count; Uri fileUri = new Uri(file); string relPath = baseUri.MakeRelativeUri(fileUri).ToString(); string firstSegment = relPath.Split('/')[0]; switch (Path.GetExtension(file)) { case ".xml": case ".XML": case ".dll": case ".DLL": case ".exe": case ".EXE": { Console.WriteLine("Skipping {0} [that's a {1} file]", relPath, Path.GetExtension(file)); ++skipCount; continue; } } uint hash; if (firstSegment == "__UNKNOWN") { try { hash = uint.Parse(Path.GetFileNameWithoutExtension(file), System.Globalization.NumberStyles.AllowHexSpecifier); } catch { Console.WriteLine("Skipping {0} [wrong name: not a hash]", relPath); ++skipCount; continue; } } else { hash = relPath.HashJenkins(); } if (hashSet.Contains(hash)) { Console.WriteLine("Skipping {0} [HASH COLLISION FOUND]", relPath); ++skipCount; continue; } hashSet.Add(hash); uint position = (uint)arcStream.Position; uint size; // Copy the file contents into the .arc file using (var fileStream = File.OpenRead(file)) { size = (uint)fileStream.Length; arcStream.WriteFromStream(fileStream, fileStream.Length); } // Create the tab entry tabData.Entries.Add(new ArchiveTableFile.EntryInfo(hash, position, size)); // Align the next entry (pad with '0' (0x30), like avalanche do) while ((arcStream.Position % tabData.Alignment) != 0) { arcStream.WriteByte(0x30); } } arcStream.Close(); Console.WriteLine("Skipped {0}/{1} files", skipCount, count); // write the tab file var tabStream = File.Create(tabFile); tabData.Serialize(tabStream); }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; string filterPattern = null; bool overwriteFiles = false; bool verbose = false; string currentProject = null; 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 }, { "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 }, { "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 < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_tab [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string tabPath = Path.GetFullPath(extras[0]); string outputPath = extras.Count > 1 ? Path.GetFullPath(extras[1]) : Path.ChangeExtension(tabPath, null) + "_unpack"; Regex filter = null; if (string.IsNullOrEmpty(filterPattern) == false) { filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } var manager = ProjectData.Manager.Load(currentProject); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadFileLists(); var tab = new ArchiveTableFile(); using (var input = File.OpenRead(tabPath)) { tab.Deserialize(input); } var arcPath = Path.ChangeExtension(tabPath, ".arc"); var compressedBlockBytes = new byte[tab.MaxCompressedBlockSize]; var uncompressedBlockBytes = new byte[tab.UncompressedBlockSize]; var singleCompressedBlock = new List <ArchiveTableFile.CompressedBlockInfo>(); singleCompressedBlock.Add(new ArchiveTableFile.CompressedBlockInfo()); using (var input = File.OpenRead(arcPath)) { long current = 0; long total = tab.Entries.Count; var padding = total.ToString(CultureInfo.InvariantCulture).Length; foreach (var entry in tab.Entries) { current++; string name = hashes[entry.NameHash]; if (name == null) { if (extractUnknowns == false) { continue; } var guess = new byte[32]; input.Position = entry.Offset; int read; if (entry.CompressionType == CompressionType.None || entry.CompressedSize == entry.UncompressedSize) { read = input.Read(guess, 0, (int)Math.Min(guess.Length, entry.CompressedSize)); } else { var decompress = GetDecompress(entry.CompressionType); ArchiveTableFile.CompressedBlockInfo compressedBlock; if (entry.CompressedBlockIndex == 0) { compressedBlock = new ArchiveTableFile.CompressedBlockInfo( entry.CompressedSize, entry.UncompressedSize); } else { compressedBlock = tab.CompressedBlocks[entry.CompressedBlockIndex]; } read = input.Read(compressedBlockBytes, 0, (int)compressedBlock.CompressedSize); if (read != compressedBlock.CompressedSize) { throw new EndOfStreamException(); } read = decompress( compressedBlockBytes, 0, (int)compressedBlock.CompressedSize, uncompressedBlockBytes, 0, (int)compressedBlock.UncompressedSize); if (read != compressedBlock.UncompressedSize) { throw new InvalidOperationException(); } var guessSize = Math.Min(32, (int)compressedBlock.UncompressedSize); Array.Copy(uncompressedBlockBytes, 0, guess, 0, guessSize); } var extension = FileDetection.Detect(guess, read); name = entry.NameHash.ToString("X8"); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine("__UNKNOWN", extension, name); } else { if (name.StartsWith("/") == true) { name = name.Substring(1); } name = name.Replace('/', Path.DirectorySeparatorChar); } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine( "[{0}/{1}] {2}", current.ToString(CultureInfo.InvariantCulture).PadLeft(padding), total, name); } var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory != null) { Directory.CreateDirectory(entryDirectory); } input.Position = entry.Offset; using (var output = File.Create(entryPath)) { if (entry.CompressionType == CompressionType.None || entry.CompressedSize == entry.UncompressedSize) { if (entry.CompressedSize != entry.UncompressedSize) { throw new InvalidOperationException(); } output.WriteFromStream(input, entry.CompressedSize); } else { var decompress = GetDecompress(entry.CompressionType); List <ArchiveTableFile.CompressedBlockInfo> compressedBlocks; ushort compressedBlockCount; ushort compressedBlockIndex = entry.CompressedBlockIndex; if (compressedBlockIndex == 0) { compressedBlocks = singleCompressedBlock; compressedBlocks[0] = new ArchiveTableFile.CompressedBlockInfo( entry.CompressedSize, entry.UncompressedSize); compressedBlockCount = 1; } else { compressedBlocks = tab.CompressedBlocks; long uncompressedSize = 0; compressedBlockCount = 0; for (int i = compressedBlockIndex; uncompressedSize < entry.UncompressedSize; i++) { uncompressedSize += compressedBlocks[i].UncompressedSize; compressedBlockCount++; } } long remaining = entry.UncompressedSize; for (int i = 0; i < compressedBlockCount; i++) { var compressedBlock = compressedBlocks[compressedBlockIndex]; var read = input.Read(compressedBlockBytes, 0, (int)compressedBlock.CompressedSize); if (read != compressedBlock.CompressedSize) { throw new EndOfStreamException(); } var result = decompress( compressedBlockBytes, 0, (int)compressedBlock.CompressedSize, uncompressedBlockBytes, 0, (int)compressedBlock.UncompressedSize); if (result != compressedBlock.UncompressedSize) { throw new InvalidOperationException(); } output.Write(uncompressedBlockBytes, 0, (int)compressedBlock.UncompressedSize); remaining -= compressedBlock.UncompressedSize; compressedBlockIndex++; } if (remaining != 0) { throw new InvalidOperationException(); } } } } } }