public static void Main(string[] args) { bool showHelp = false; bool? extractUnknowns = null; bool overwriteFiles = false; bool verbose = true; string currentProject = null; string filterPattern = 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 ? false : extractUnknowns }, { "ou|only-unknowns", "only extract unknown files", v => extractUnknowns = v != null ? true : extractUnknowns }, { "f|filter=", "filter 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 || Is000(extras[0]) == false) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_file.000.tiger [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } var inputPath = extras[0]; var basePath = GetBasePath(inputPath); var outputPath = extras.Count > 1 ? extras[1] : basePath + "_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 header = new TigerArchiveFile(); using (var input = File.OpenRead(inputPath)) { header.Deserialize(input); } var hashes = manager.LoadLists("*.filelist", s => s.HashFileName(), s => s.ToLowerInvariant()); Directory.CreateDirectory(outputPath); var settings = new XmlWriterSettings() { Indent = true, }; var xmlPath = Path.Combine(outputPath, "@tiger.xml"); using (var xml = XmlWriter.Create(xmlPath, settings)) { xml.WriteStartDocument(); xml.WriteStartElement("files"); xml.WriteAttributeString("endian", header.Endian.ToString()); xml.WriteAttributeString("basepath", header.BasePath); xml.WriteAttributeString("priority", header.Priority.ToString(CultureInfo.InvariantCulture)); Stream data = null; byte? dataIndex = null; uint? lastLocale = null; { long current = 0; long total = header.Entries.Count; //long? lastOffset = null; foreach (var entry in header.Entries.OrderBy(e => e.Offset).ThenBy(e => e.DataIndex)) { current++; if (dataIndex.HasValue == false || dataIndex.Value != entry.DataIndex) { if (data != null) { data.Close(); } dataIndex = entry.DataIndex; var dataPath = basePath + GetExtension(dataIndex.Value); if (verbose == true) { Console.WriteLine(dataPath); } data = File.OpenRead(dataPath); } string name = hashes[entry.NameHash]; if (name == null) { if (extractUnknowns.HasValue == true && extractUnknowns.Value == false) { continue; } string extension; // detect type { var guess = new byte[64]; int read = 0; if (entry.Size > 0) { data.Position = entry.Offset; read = data.Read(guess, 0, (int)Math.Min(entry.Size, guess.Length)); } extension = FileExtensions.Detect(guess, Math.Min(guess.Length, read)); } name = entry.NameHash.ToString("X8", CultureInfo.InvariantCulture); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine(extension, name); name = Path.Combine("__UNKNOWN", name); } else { if (extractUnknowns.HasValue == true && extractUnknowns.Value == true) { continue; } name = name.Replace("/", "\\"); if (name.StartsWith("\\") == true) { name = name.Substring(1); } } if (entry.Locale == 0xFFFFFFFF) { name = Path.Combine("default", name); } else { name = Path.Combine(entry.Locale.ToString("X8"), name); } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); var entryParentPath = Path.GetDirectoryName(entryPath); if (string.IsNullOrEmpty(entryParentPath) == false) { Directory.CreateDirectory(entryParentPath); } if (lastLocale.HasValue == false || lastLocale.Value != entry.Locale) { xml.WriteComment(string.Format( " {0} = {1} ", entry.Locale.ToString("X8", CultureInfo.InvariantCulture), ((ArchiveLocale)entry.Locale))); lastLocale = entry.Locale; } /* * if (lastOffset != null) * { * xml.WriteComment(string.Format(" padding = {0} @ {1}", * entry.Offset - lastOffset.Value, * lastOffset.Value)); * } * lastOffset = entry.Offset + entry.Size; * * xml.WriteComment(string.Format(" offset = {0} ", entry.Offset)); */ xml.WriteStartElement("entry"); xml.WriteAttributeString("hash", entry.NameHash.ToString("X8", CultureInfo.InvariantCulture)); xml.WriteAttributeString("locale", entry.Locale.ToString("X8", CultureInfo.InvariantCulture)); if (entry.Priority != header.Priority) { xml.WriteAttributeString("priority", entry.Priority.ToString(CultureInfo.InvariantCulture)); } xml.WriteValue(name); xml.WriteEndElement(); 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) { data.Position = entry.Offset; output.WriteFromStream(data, entry.Size); } } } } if (data != null) { data.Close(); } xml.WriteEndElement(); xml.WriteEndDocument(); xml.Flush(); } }
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 = 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.LoadLists("*.filelist", s => s.HashFileName(), s => s.ToLowerInvariant()); 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, "*.000.tiger", SearchOption.AllDirectories)); var outputPaths = new List <string>(); var breakdown = new Breakdown(); Console.WriteLine("Processing..."); foreach (var inputPath in inputPaths) { var outputPath = GetListPath(installPath, Path.ChangeExtension(inputPath, null)); 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 TigerArchiveFile(); 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 nameHash in big.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++; } names.Sort(); var outputParentPath = Path.GetDirectoryName(outputPath); if (string.IsNullOrEmpty(outputParentPath) == false) { Directory.CreateDirectory(outputParentPath); } using (var output = new StreamWriter(outputPath)) { output.WriteLine("; {0}", localBreakdown); foreach (string name in names) { output.WriteLine(name); } } breakdown.Known += localBreakdown.Known; breakdown.Total += localBreakdown.Total; } using (var output = new StreamWriter(Path.Combine(Path.Combine(listsPath, "files"), "status.txt"))) { output.WriteLine("{0}", breakdown); } }