static void Main(string[] args) { if (args.Length < 3) { Console.WriteLine("Usage:"); Console.WriteLine("EditPackfile <source> <destination> <new file 1> <new file 2>..."); return; } string sourcePath = args[0]; string destinationPath = args[1]; List <string> newFiles = new List <string>(); for (int i = 2; i < args.Length; i++) { newFiles.Add(args[i]); } string sourceExtension = Path.GetExtension(sourcePath); bool sourceIsStr2 = sourceExtension.ToLowerInvariant() == ".str2_pc"; Dictionary <string, NewFileEntry> filenameToPathMap = new Dictionary <string, NewFileEntry>(StringComparer.OrdinalIgnoreCase); foreach (string newFile in newFiles) { filenameToPathMap.Add(Path.GetFileName(newFile), new NewFileEntry(newFile)); } using (Stream sourceStream = File.OpenRead(sourcePath)) { using (IPackfile source = Packfile.FromStream(sourceStream, sourceIsStr2)) { using (IPackfile destination = Packfile.FromVersion(source.Version, sourceIsStr2)) { destination.IsCompressed = source.IsCompressed; destination.IsCondensed = source.IsCondensed; foreach (IPackfileEntry entry in source.Files) { string filename = entry.Name; if (filenameToPathMap.ContainsKey(filename)) { NewFileEntry newFilePath = filenameToPathMap[filename]; destination.AddFile(File.OpenRead(newFilePath.Path), entry.Name); newFilePath.Inserted = true; Console.WriteLine("Replaced {0}.", filename); } else { destination.AddFile(entry.GetStream(), entry.Name); } } foreach (var pair in filenameToPathMap) { NewFileEntry nfe = pair.Value; if (!nfe.Inserted) { string filename = Path.GetFileName(nfe.Path); destination.AddFile(File.OpenRead(nfe.Path), filename); Console.WriteLine("Inserted {0}.", filename); } } using (Stream destinationStream = File.Create(destinationPath)) { destination.Save(destinationStream); } } } } #if DEBUG Console.ReadLine(); #endif }
static void Main(string[] args) { //Todo: Add warning when unpacking large amount of files or folders //Todo: Add timer //Todo: Add support for custom unpack folder/location Parser.Default.ParseArguments <Program.Options>(args).WithParsed(delegate(Program.Options options) { Console.WriteLine("Debug options output:"); Console.WriteLine("Input: {0}", options.Input); Console.WriteLine("Verbose: {0}", options.Verbose); Console.WriteLine("Recursive: {0}", options.Recursive); Console.WriteLine("Search: {0}", options.Search); using var errorStream = new FileStream("PackfileUnpackerErrors.txt", FileMode.OpenOrCreate); using var error = new StreamWriter(errorStream); //Loop through all input paths foreach (string input in options.Input) { //Handle path being a directory if (Directory.Exists(input)) { Console.WriteLine("Input exists and is a directory"); FileInfo[] inputFolder = new FileInfo[0]; if (options.Search) { inputFolder = new DirectoryInfo(input).GetFiles("*", SearchOption.AllDirectories); } else { inputFolder = new DirectoryInfo(input).GetFiles(); } //Extract all packfiles in folder foreach (FileInfo file in inputFolder) { if (file.Extension == ".vpp_pc" || file.Extension == ".str2_pc") { string inputPath = file.FullName; string outputPath = file.DirectoryName + "\\Unpack\\" + file.Name + "\\"; //Extract packfile try { Packfile packfile = new Packfile(options.Verbose); packfile.ReadMetadata(inputPath); packfile.ExtractFileData(outputPath); } catch (Exception ex) { //If encounter error, move to next file error.WriteLine($"Exception caught while unpacking {file.Name}: {ex.Message} ... Skipping to next file."); continue; } //Extract contents of file if recursive extracting if (options.Recursive) { foreach (FileInfo subfile in new DirectoryInfo(outputPath).GetFiles()) { if (subfile.Extension == ".vpp_pc" || subfile.Extension == ".str2_pc") { try { string subInputPath = subfile.FullName; string subOutputPath = subfile.DirectoryName + "\\Subfiles\\" + subfile.Name + "\\"; Packfile packfile2 = new Packfile(options.Verbose); packfile2.ReadMetadata(subInputPath); packfile2.ExtractFileData(subOutputPath); } catch (Exception ex2) { //If encounter error, move to next file error.WriteLine($"Exception caught while unpacking {subfile.Name}: {ex2.Message} ... Skipping to next file."); continue; } } } } } } } else if (File.Exists(input)) //Handle path being a file path { Console.WriteLine("Input exists and is a file!"); FileInfo PackfileInfo = new FileInfo(input); string InputPath = input; string OutputPath = PackfileInfo.DirectoryName + "\\Unpack\\" + PackfileInfo.Name + "\\"; //Extract file try { Packfile packfile3 = new Packfile(options.Verbose); packfile3.ReadMetadata(InputPath); packfile3.ExtractFileData(OutputPath); } catch (Exception ex3) { //If encounter error, move to next file error.WriteLine($"Exception caught while unpacking {PackfileInfo.Name}: {ex3.Message} ... Skipping to next file."); continue; } //Extract contents of file if recursive extracting if (options.Recursive) { foreach (FileInfo file2 in new DirectoryInfo(OutputPath).GetFiles()) { if (file2.Extension == ".vpp_pc" || file2.Extension == ".str2_pc") { try { string subInputPath2 = file2.FullName; string subOutputPath2 = file2.DirectoryName + "\\Subfiles\\" + file2.Name + "\\"; Packfile packfile4 = new Packfile(options.Verbose); packfile4.ReadMetadata(subInputPath2); packfile4.ExtractFileData(subOutputPath2); } catch (Exception ex4) { //If encounter error, move to next file error.WriteLine($"Exception caught while unpacking {file2.Name}: {ex4.Message} ... Skipping to next file."); continue; } } } } } } }); Console.WriteLine("Done!"); }
static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse <Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); #if DEBUG Console.ReadLine(); #endif return; } Directory.CreateDirectory(options.Output); string[] files = Directory.GetFiles(options.Source); Dictionary <string, IPackfile> packfiles = new Dictionary <string, IPackfile>(); int totalFiles = 0; Console.Write("Looking for packfiles... "); foreach (string file in files) { if (Path.GetExtension(file) == ".vpp_pc") { var packfile = Packfile.FromStream(File.OpenRead(file), false); totalFiles += packfile.Files.Count; packfiles.Add(Path.GetFileName(file), packfile); } } Console.WriteLine("found {0} packfiles, containing {1} files.", packfiles.Count, totalFiles); int currentFile = 0; foreach (var packfilePair in packfiles) { Console.WriteLine("{0} Compressed: {1} Condensed: {2}", packfilePair.Key, packfilePair.Value.IsCompressed, packfilePair.Value.IsCondensed); Directory.CreateDirectory(Path.Combine(options.Output, packfilePair.Key)); foreach (var file in packfilePair.Value.Files) { currentFile++; if (Path.GetExtension(file.Name) == ".str2_pc") { string strOutputFolder = Path.Combine(options.Output, packfilePair.Key, file.Name); Directory.CreateDirectory(strOutputFolder); Console.WriteLine("[{0}/{1}] Extracting {2}: packfile {3} to {4}:", currentFile, totalFiles, packfilePair.Key, file.Name, strOutputFolder); using (Stream strStream = file.GetStream()) { using (var strPackfile = Packfile.FromStream(strStream, true)) { int strCurrentFile = 0; foreach (var strFile in strPackfile.Files) { strCurrentFile++; Console.Write("[{0}/{1}] [{2}/{3}] Extracting {4}\\{5}: {6}", currentFile, totalFiles, strCurrentFile, strPackfile.Files.Count, packfilePair.Key, file.Name, strFile.Name); using (Stream outputStream = File.Create(Path.Combine(strOutputFolder, strFile.Name))) { using (Stream inputStream = strFile.GetStream()) { inputStream.CopyTo(outputStream); } outputStream.Flush(); } Console.WriteLine("done."); } } } } else { Console.Write("[{0}/{1}] Extracting {2}: {3}... ", currentFile, totalFiles, packfilePair.Key, file.Name); using (Stream outputStream = File.Create(Path.Combine(options.Output, packfilePair.Key, file.Name))) { using (Stream inputStream = file.GetStream()) { inputStream.CopyTo(outputStream); } outputStream.Flush(); } Console.WriteLine("done."); } } } #if DEBUG Console.ReadLine(); #endif }
public static string EnsureExt(string file) { return(Packfile.EnsureExt(file, false)); }
static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse <Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); Console.ReadLine(); return; } if (options.Source == null) { string sriv = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowIV); string srgooh = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowGatOutOfHell); int gameCount = 0, srivNum = 0, srgoohNum = 0; Console.WriteLine("Detected the following games:"); if (sriv != null) { gameCount++; srivNum = gameCount; Console.WriteLine("{0}. Saints Row IV: {1}", gameCount, sriv); } if (srgooh != null) { gameCount++; srgoohNum = gameCount; Console.WriteLine("{0}. Saints Row Gat Out Of Hell: {1}", gameCount, srgooh); } Console.WriteLine(); while (true) { Console.Write("Which game do you want to update? (enter the number) "); ConsoleKeyInfo input = Console.ReadKey(); Console.WriteLine(); Console.WriteLine(); if (input.Key == ConsoleKey.D1 || input.Key == ConsoleKey.NumPad1) { if (srivNum == 1) { options.Source = sriv; Console.WriteLine("Updating Saints Row IV files."); } else if (srgoohNum == 1) { options.Source = srgooh; Console.WriteLine("Updating Saints Row: Gat Out Of Hell files."); } } else if (input.Key == ConsoleKey.D2 || input.Key == ConsoleKey.NumPad2) { if (srivNum == 2) { options.Source = sriv; Console.WriteLine("Updating Saints Row IV files."); } else if (srgoohNum == 2) { options.Source = srgooh; Console.WriteLine("Updating Saints Row: Gat Out Of Hell files."); } } if (options.Source != null) { break; } } } if (options.Source == null) { Console.WriteLine("Couldn't find the Saints Row IV folder?"); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); return; } string str2Dir = options.Source; //if (Directory.Exists(Path.Combine(options.Source, "mods"))) //str2Dir = Path.Combine(options.Source, "mods"); string[] str2Paths = Directory.GetFiles(str2Dir, "*.str2_pc"); List <string> str2Files = new List <string>(); foreach (string str2Path in str2Paths) { str2Files.Add(Path.GetFileName(str2Path)); } if (str2Files.Count == 0) { Console.WriteLine("No str2_pc files found - no update needed."); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); return; } string packfileCache = Path.Combine(options.Source, "packfiles", "pc", "cache"); Dictionary <string, Stream2File> asmsToSave = new Dictionary <string, Stream2File>(); string[] packfiles = Directory.GetFiles(packfileCache, "*.vpp_pc"); int vppCount = 0; foreach (string packfilePath in packfiles) { vppCount++; Console.WriteLine("[{0}/{1}] Checking {2}...", vppCount, packfiles.Length, Path.GetFileName(packfilePath)); using (Stream stream = File.OpenRead(packfilePath)) { using (IPackfile packfile = Packfile.FromStream(stream, false)) { foreach (var packedFile in packfile.Files) { if (Path.GetExtension(packedFile.Name) != ".asm_pc") { continue; } using (Stream asmStream = packedFile.GetStream()) { Stream2File asm = new Stream2File(asmStream); foreach (var container in asm.Containers) { string containerName = Path.ChangeExtension(container.Name, ".str2_pc"); if (str2Files.Contains(containerName)) { if (!asmsToSave.ContainsKey(packedFile.Name)) { asmsToSave.Add(packedFile.Name, asm); } Console.Write(" - Updating {0} - {1}...", packedFile.Name, containerName); using (Stream str2Stream = File.OpenRead(Path.Combine(str2Dir, containerName))) { using (IPackfile str2 = Packfile.FromStream(str2Stream, true)) { str2.Update(container); } } Console.WriteLine(" done."); } } } } } } } Console.WriteLine(); Console.WriteLine("Writing updated asm_pc files..."); int count = 0; foreach (var asmPair in asmsToSave) { count++; Console.Write("[{0}/{1}] Saving {2}...", count, asmsToSave.Count, asmPair.Key); string outPath = Path.Combine(str2Dir, asmPair.Key); using (Stream outStream = File.Create(outPath)) { asmPair.Value.Save(outStream); } Console.WriteLine(" done."); } Console.WriteLine("Done."); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); }
static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse <Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); #if DEBUG Console.ReadLine(); #endif return; } switch (options.Action) { case "toxml": { using (Stream stream = File.OpenRead(options.Source)) { IAssetAssemblerFile file = AssetAssemblerFile.FromStream(stream); if (options.Output == null || options.Output == "") { options.Output = Path.ChangeExtension(options.Source, "xml"); } XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = "\t"; settings.NewLineChars = "\r\n"; using (XmlWriter xml = XmlWriter.Create(options.Output, settings)) { xml.WriteStartDocument(); xml.WriteStartElement("AssetAssembler"); xml.WriteAttributeString("Version", file.Version.ToString()); xml.WriteStartElement("AllocatorTypes"); foreach (var pair in file.AllocatorTypes) { xml.WriteStartElement("AllocatorType"); xml.WriteAttributeString("ID", pair.Key.ToString()); xml.WriteAttributeString("Name", pair.Value); xml.WriteEndElement(); } xml.WriteEndElement(); // AllocatorTypes xml.WriteStartElement("ContainerTypes"); foreach (var pair in file.ContainerTypes) { xml.WriteStartElement("ContainerType"); xml.WriteAttributeString("ID", pair.Key.ToString()); xml.WriteAttributeString("Name", pair.Value); xml.WriteEndElement(); } xml.WriteEndElement(); // ContainerTypes xml.WriteStartElement("PrimitiveTypes"); foreach (var pair in file.PrimitiveTypes) { xml.WriteStartElement("PrimitiveType"); xml.WriteAttributeString("ID", pair.Key.ToString()); xml.WriteAttributeString("Name", pair.Value); xml.WriteEndElement(); } xml.WriteEndElement(); // PrimitiveTypes xml.WriteStartElement("Containers"); foreach (var container in file.Containers) { xml.WriteStartElement("Container"); xml.WriteAttributeString("Name", container.Name); xml.WriteAttributeString("Type", file.ContainerTypes[container.ContainerType]); xml.WriteAttributeString("Flags", container.Flags.ToString()); xml.WriteAttributeString("PackfileBaseOffset", container.PackfileBaseOffset.ToString()); xml.WriteAttributeString("CompressionType", container.CompressionType.ToString()); xml.WriteAttributeString("StubContainerParentName", container.StubContainerParentName); xml.WriteAttributeString("TotalCompressedPackfileReadSize", container.TotalCompressedPackfileReadSize.ToString()); if (container.AuxData.Length > 0) { xml.WriteStartElement("AuxData"); xml.WriteString(Convert.ToBase64String(container.AuxData, Base64FormattingOptions.None)); xml.WriteEndElement(); // AuxData } for (int i = 0; i < container.PrimitiveCount; i++) { var primitive = container.Primitives[i]; //var sizes = container.PrimitiveSizes[i]; xml.WriteStartElement("Primitive"); xml.WriteAttributeString("Name", primitive.Name); xml.WriteAttributeString("Type", file.PrimitiveTypes[primitive.Type]); xml.WriteAttributeString("Allocator", file.AllocatorTypes.ContainsKey(primitive.Allocator) ? file.AllocatorTypes[primitive.Allocator] : primitive.Allocator.ToString()); xml.WriteAttributeString("Flags", primitive.Flags.ToString()); xml.WriteAttributeString("ExtensionIndex", primitive.ExtensionIndex.ToString()); xml.WriteAttributeString("CPUSize", primitive.CPUSize.ToString()); xml.WriteAttributeString("GPUSize", primitive.GPUSize.ToString()); xml.WriteAttributeString("AllocationGroup", primitive.AllocationGroup.ToString()); //xml.WriteAttributeString("WriteTimeCPUSize", sizes.CPUSize.ToString()); //xml.WriteAttributeString("WriteTimeGPUSize", sizes.GPUSize.ToString()); xml.WriteEndElement(); // Primitive } xml.WriteEndElement(); // Container } xml.WriteEndElement(); // Containers xml.WriteEndElement(); // AssetAssembler xml.WriteEndDocument(); } } break; } case "toasm": { using (Stream stream = File.OpenRead(options.Source)) { XDocument xml = XDocument.Load(stream); var asmNode = xml.Element("AssetAssembler"); uint version = uint.Parse(asmNode.Attribute("Version").Value); IAssetAssemblerFile file = AssetAssemblerFile.Create(version); if (options.Output == null || options.Output == "") { options.Output = Path.ChangeExtension(options.Source, "asm_pc"); } Dictionary <string, byte> allocatorTypesLookup = new Dictionary <string, byte>(); Dictionary <string, byte> containerTypesLookup = new Dictionary <string, byte>(); Dictionary <string, byte> primitiveTypesLookup = new Dictionary <string, byte>(); foreach (var node in xml.Descendants("AllocatorType")) { byte id = byte.Parse(node.Attribute("ID").Value); string name = node.Attribute("Name").Value; allocatorTypesLookup.Add(name, id); file.AllocatorTypes.Add(id, name); } foreach (var node in xml.Descendants("ContainerType")) { byte id = byte.Parse(node.Attribute("ID").Value); string name = node.Attribute("Name").Value; containerTypesLookup.Add(name, id); file.ContainerTypes.Add(id, name); } foreach (var node in xml.Descendants("PrimitiveType")) { byte id = byte.Parse(node.Attribute("ID").Value); string name = node.Attribute("Name").Value; primitiveTypesLookup.Add(name, id); file.PrimitiveTypes.Add(id, name); } foreach (var cNode in xml.Descendants("Container")) { IContainer container = file.CreateContainer(); container.Name = cNode.Attribute("Name").Value; container.ContainerType = containerTypesLookup[cNode.Attribute("Type").Value]; container.Flags = (ContainerFlags)ushort.Parse(cNode.Attribute("Flags").Value); container.PackfileBaseOffset = uint.Parse(cNode.Attribute("PackfileBaseOffset").Value); container.CompressionType = byte.Parse(cNode.Attribute("CompressionType").Value); container.StubContainerParentName = cNode.Attribute("StubContainerParentName").Value; container.TotalCompressedPackfileReadSize = int.Parse(cNode.Attribute("TotalCompressedPackfileReadSize").Value); var auxData = cNode.Element("AuxData"); if (auxData != null) { container.AuxData = Convert.FromBase64String(auxData.Value); } else { container.AuxData = new byte[0]; } foreach (var pNode in cNode.Descendants("Primitive")) { IPrimitive p = container.CreatePrimitive(); p.Name = pNode.Attribute("Name").Value; p.Type = primitiveTypesLookup[pNode.Attribute("Type").Value]; byte allocatorType = 0; if (byte.TryParse(pNode.Attribute("Allocator").Value, out allocatorType)) { p.Allocator = allocatorType; } else { p.Allocator = allocatorTypesLookup[pNode.Attribute("Allocator").Value]; } p.Flags = byte.Parse(pNode.Attribute("Flags").Value); p.ExtensionIndex = byte.Parse(pNode.Attribute("ExtensionIndex").Value); p.CPUSize = uint.Parse(pNode.Attribute("CPUSize").Value); p.GPUSize = uint.Parse(pNode.Attribute("GPUSize").Value); p.AllocationGroup = byte.Parse(pNode.Attribute("AllocationGroup").Value); container.Primitives.Add(p); } container.PrimitiveCount = (short)container.Primitives.Count; file.Containers.Add(container); } using (Stream outputStream = File.Create(options.Output)) { file.Save(outputStream); } } break; } case "update": { IAssetAssemblerFile file = null; using (Stream stream = File.OpenRead(options.Source)) { file = AssetAssemblerFile.FromStream(stream); string folder = Path.GetDirectoryName(options.Source); foreach (var container in file.Containers) { string str2File = Path.ChangeExtension(container.Name, ".str2_pc"); string filename = Path.Combine(folder, str2File); if (File.Exists(filename)) { Console.Write("Found {0}, updating... ", str2File); using (Stream str2Stream = File.OpenRead(filename)) { IPackfile packfile = Packfile.FromStream(str2Stream, true); packfile.Update(container); } Console.WriteLine("done."); } else { Console.WriteLine("Could not find {0}.", str2File); } } } using (Stream stream = File.Create(options.Source)) { file.Save(stream); } break; } default: { Console.WriteLine("Unrecogised action!"); break; } } #if DEBUG Console.ReadLine(); #endif }