static private string GetProgramForBinaryFile(string file) { using (var input = File.OpenRead(file)) { var guess = new byte[32]; var read = input.Read(guess, 0, (int)Math.Min(guess.Length, input.Length)); string extension = FileDetection.Detect(guess, read); if (_ExtensionLookup.ContainsKey(extension)) { return(_ExtensionLookup[extension]); } } return(null); }
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); } } } }
private static bool GetEntryName(Stream input, BigFile fat, Big.Entry entry, ProjectData.HashList <uint> hashes, bool extractUnknowns, bool onlyUnknowns, out string entryName) { entryName = hashes[entry.NameHash]; if (entryName == null) { if (extractUnknowns == false) { return(false); } string type; string extension; { var guess = new byte[64]; int read = 0; if (entry.CompressionScheme == Big.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 { using (var temp = new MemoryStream()) { EntryDecompression.Decompress(entry, input, temp); temp.Position = 0; read = temp.Read(guess, 0, (int)Math.Min(temp.Length, guess.Length)); } } var tuple = FileDetection.Detect(guess, Math.Min(guess.Length, read)); type = tuple != null ? tuple.Item1 : "unknown"; extension = tuple != null ? tuple.Item2 : null; } entryName = entry.NameHash.ToString("X8"); if (string.IsNullOrEmpty(extension) == false) { entryName = Path.ChangeExtension(entryName, "." + extension); } if (string.IsNullOrEmpty(type) == false) { entryName = Path.Combine(type, entryName); } entryName = Path.Combine("__UNKNOWN", entryName); } else { if (onlyUnknowns == true) { return(false); } entryName = FilterEntryName(entryName); } return(true); }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; string filterPattern = null; bool overwriteFiles = false; bool paranoia = false; bool verbose = 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 }, { "f|filter=", "only extract files using pattern", v => filterPattern = v }, { "p|paranoid", "be paranoid (validate hash when uncompressing files)", v => paranoia = 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_bix [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string bixPath = Path.GetFullPath(extras[0]); string outputPath = extras.Count > 1 ? Path.GetFullPath(extras[1]) : Path.ChangeExtension(bixPath, null) + "_unpack"; Regex filter = null; if (string.IsNullOrEmpty(filterPattern) == false) { filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } var manager = ProjectData.Manager.Load(); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadListsBigNames(); var bix = new BigFileInventory(); using (var input = File.OpenRead(bixPath)) { bix.Deserialize(input, Endian.Little); } var basePath = Path.GetDirectoryName(bixPath); if (string.IsNullOrEmpty(basePath) == true) { throw new InvalidOperationException(); } var bigPath = Path.Combine(basePath, bix.BigFileName + ".big"); using (var input = File.OpenRead(bigPath)) { long current = 0; long total = bix.Entries.Count; foreach (var entry in bix.Entries) { current++; string name = hashes[entry.Id]; if (name == null) { if (extractUnknowns == false) { continue; } KeyValuePair <string, string> extension; // detect type { var guess = new byte[64]; int read = 0; var offset = (entry.Offset << 2) + (entry.Size.LoadOffset & 0xFFF); if (entry.Size.CompressedSize == 0) { if (entry.Size.UncompressedSize > 0) { input.Seek(offset, SeekOrigin.Begin); read = input.Read(guess, 0, (int)Math.Min(entry.Size.UncompressedSize, guess.Length)); } } else { input.Seek(offset, SeekOrigin.Begin); // todo: don't uncompress everything var uncompressedData = QuickCompression.Decompress(input); read = Math.Min(guess.Length, uncompressedData.Length); Array.Copy(uncompressedData, 0, guess, 0, read); } extension = FileDetection.Detect(guess, Math.Min(guess.Length, read)); } name = entry.Id.ToString("X8"); name = Path.ChangeExtension(name, "." + extension.Value); name = Path.Combine(extension.Key, name); name = Path.Combine("__UNKNOWN", name); } else { name = name.Replace(@"/", @"\"); if (name.StartsWith(@"\") == true) { name = name.Substring(1); } } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } var entryParentPath = Path.GetDirectoryName(entryPath); if (string.IsNullOrEmpty(entryParentPath) == true) { throw new InvalidOperationException(); } Directory.CreateDirectory(entryParentPath); if (verbose == true) { Console.WriteLine("[{0}/{1}] {2}", current, total, name); } using (var output = File.Create(entryPath)) { if (entry.Size.CompressedSize == 0) { if (entry.Size.LoadOffset != 0 || entry.Size.CompressedExtra != 0) { throw new InvalidOperationException(); } if (entry.Size.UncompressedSize > 0) { input.Seek(entry.Offset << 2, SeekOrigin.Begin); output.WriteFromStream(input, entry.Size.UncompressedSize); } } else { var uncompressedSize = entry.Size.CompressedSize + entry.Size.LoadOffset - entry.Size.CompressedExtra; if (uncompressedSize != entry.Size.UncompressedSize) { } if (entry.Size.UncompressedSize > 0) { input.Seek((entry.Offset << 2) + (entry.Size.LoadOffset & 0xFFF), SeekOrigin.Begin); QuickCompression.Decompress(input, output); } } } } } }
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(); } } } } } }