/// <summary> /// Extract all files from PBO. /// Will extract to extractionDir if specified. /// If not will output in the current Dir of the PBO /// </summary> /// <param name="pbo"></param> /// <param name="path"></param> public void ExtractAll(PBO pbo, string extractionDir = null) { try { PushOnEvent($"Starting full extraction of {pbo.LongName}", EventType.Debug); //Get outoput dir depending on if extractionDir was passed string outputDir = extractionDir ?? Path.GetDirectoryName(pbo.LongName); //Run through each file in the PBO and write to disk foreach (PBOFile file in pbo.Files) { //Calculate file name string fileName = Path.Combine(outputDir, file.FileName); //Write to disk WriteToFile(fileName, ExtractFileData(file)); } PushOnEvent($"Successfully extracted {pbo.LongName}", EventType.Debug); } catch (Exception ex) { PushOnEvent($"Failed to extract {pbo.LongName}\n{ex.Message}", EventType.Error); } }
internal void ReadHeader(PBO pbo) { try { _client.PushOnEvent($"Starting Header Read for {pbo.LongName}", EventType.Debug); //Get the signature PBOFile sig = ReadDatablock(); //_client.PushOnEvent($"Signature read Packing Method: {sig.PackingMethod}", EventType.Debug); //Look for a prefix if (sig.PackingMethod == PackingMethod.Product) { string possiblePrefix; do { possiblePrefix = ReadString(); if (possiblePrefix != string.Empty) { pbo.Prefix = new PBOPrefix(possiblePrefix, ReadString()); } } while (possiblePrefix != string.Empty); } //Read all file header structs PBOFile file; do { file = ReadDatablock(); if (file.FileName != string.Empty) { pbo.Files.Add(file); _client.PushOnEvent($"File found: {file.FileName}", EventType.Info); } } while (file.FileName != string.Empty); //Update the file offsets for each file foreach (PBOFile pbofile in pbo.Files) { pbofile.Offset = BaseStream.Position; BaseStream.Position += pbofile.DataSize; } _client.PushOnEvent($"Header read successfully from {pbo.LongName}", EventType.Debug); } catch (Exception ex) { _client.PushOnEvent($"Failed to read header for {pbo.LongName}\n {ex.Message}", EventType.Error); } }
private static void ExtractPbo(string pboFile, string outputFolder, IEnumerable <string> ignorePrefixes, bool minify) { var pboArchive = new PBO(pboFile, true); if (pboArchive.Prefix == null) { Console.WriteLine($"{pboArchive.FileName} has no prefix"); return; } foreach (var ignorePrefix in ignorePrefixes) { if (pboArchive.Prefix.Contains(ignorePrefix)) { return; } } Console.WriteLine($"Extracting {pboArchive.FileName}"); var pboDirectoryPath = Path.Join(outputFolder, ConvertPathSeparator(pboArchive.Prefix)); if (!minify) { pboArchive.ExtractFiles(pboArchive.FileEntries, outputFolder); return; } var allowedEntries = pboArchive.FileEntries.Where(IsAllowedFile); var minifiedEntries = pboArchive.FileEntries.Except(allowedEntries); pboArchive.ExtractFiles(allowedEntries, pboDirectoryPath); foreach (var ignoredEntry in minifiedEntries) { var filename = Path.Join(pboDirectoryPath, ConvertPathSeparator(ignoredEntry.FileName)); Directory.CreateDirectory(Path.GetDirectoryName(filename)); File.Create(filename).Dispose(); } }
/// <summary> /// Extract all files from PBO. /// Will extract to extractionDir if specified. /// If not will output in the current Dir of the PBO /// </summary> /// <param name="pbo"></param> /// <param name="path"></param> public void ExtractAll(string filePath, string extractionDir = null) { if (!File.Exists(filePath)) { PushOnEvent($"File {filePath} does not exist", EventType.Error); return; } PBO pbo = AnalyzePBO(filePath); try { PushOnEvent($"Starting full extraction of {pbo.LongName}", EventType.Debug); //Get outoput dir depending on if extractionDir was passed string outputDir = extractionDir ?? Path.GetDirectoryName(pbo.LongName); if (pbo.Prefix != null) { WriteToFile($"{outputDir}\\${pbo.Prefix.PrefixName.ToUpper()}$", Encoding.ASCII.GetBytes(pbo.Prefix.PrefixValue)); } //Run through each file in the PBO and write to disk foreach (PBOFile file in pbo.Files) { //Calculate file name string fileName = Path.Combine(outputDir, file.FileName); //Write to disk WriteToFile(fileName, ExtractFileData(file)); } PushOnEvent($"Successfully extracted {pbo.LongName}", EventType.Debug); } catch (Exception ex) { PushOnEvent($"Failed to extract {pbo.LongName}\n{ex.Message}", EventType.Error); } }
/// <summary> /// Analyzes the contents of the PBO File and returns it as a PBO object /// </summary> /// <param name="File"></param> public PBO AnalyzePBO(string file) { try { PushOnEvent("AnalyzePBO Started", EventType.Debug); //Create A PBO object to store all the PBO's attributes PBO pbo = new PBO(); pbo.LongName = file; pbo.ShortName = Path.GetFileName(file); //Open FileStream FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read); //Create new instance of PBOReader PBOReader _reader = new PBOReader(stream, this); //Assign Reader pbo.Reader = _reader; //Read the header _reader.ReadHeader(pbo); //Set analysed flag pbo.PBOAnalysed = true; PushOnEvent("AnalyzePBO Finished", EventType.Debug); //Return object return(pbo); } catch (Exception ex) { PushOnEvent(ex.Message, EventType.Error); return(null); } }
static void Main(string[] args) { //New PBOToolsClient instance PBOSharpClient client = new PBOSharpClient(); //Assign EH client.onEvent += Client_onEvent; //AnalyzePBO PBO pbo = client.AnalyzePBO($"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\Workspace\\MyMission.Altis.pbo"); //Extract with PBO object //client.ExtractAll(pbo, $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\PBOOutput"); //Extract with file path //client.ExtractAll($"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\Workspace\\MyMission.Altis.pbo"); //client.PackPBO( // $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\PBOOutput\\MyMission.Altis", // $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\PBOOutput", // "MyMission.Altis.pbo"); //Extract specific files data //byte[] fileData = client.ExtractFileData(pbo.Files[0]); //Access list of all files within the pbo //pbo.Files //Access file data attributes //pbo.Files[0].FileName //pbo.Files[0].FileNameShort //pbo.Files[0].PackingMethod //pbo.Files[0].OriginalSize //pbo.Files[0].Reserved //pbo.Files[0].Timestamp //pbo.Files[0].DataSize //pbo.Files[0].Offset }
private static int Dependencies(DependenciesOptions opts) { if (string.IsNullOrEmpty(opts.ModsBasePath)) { opts.ModsBasePath = @"C:\Program Files (x86)\Steam\steamapps\common\Arma 3\!Workshop"; } Console.WriteLine($"Build index of mods pbo and files from '{opts.ModsBasePath}'"); var mods = Directory.GetDirectories(opts.ModsBasePath); var modsData = new List <ModInfo>(); foreach (var mod in mods) { var path = Path.Combine(mod, "addons"); if (Directory.Exists(path)) { var infos = new ModInfo(); infos.Path = mod; infos.Pbos = new List <PboInfo>(); var allPBOs = Directory.GetFiles(Path.Combine(mod, "addons"), "*.pbo"); foreach (var pboPath in allPBOs) { var pbo = new PBO(pboPath); var pboInfos = new PboInfo(); pboInfos.Mod = infos; pboInfos.Path = pboPath; pboInfos.Files = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var entry in pbo.FileEntries) { if (string.Equals(Path.GetExtension(entry.FileName), ".p3d", StringComparison.OrdinalIgnoreCase)) { pboInfos.Files.Add(Path.Combine(pbo.Prefix, entry.FileName)); } } if (pboInfos.Files.Count > 0) { infos.Pbos.Add(pboInfos); } } if (infos.Pbos.Count > 0) { infos.WorkshopId = GetWorkshopId(mod); modsData.Add(infos); } } } var allPbos = modsData.SelectMany(m => m.Pbos); Console.WriteLine($"Read WRP from '{opts.Source}'"); var source = StreamHelper.Read <AnyWrp>(opts.Source); Console.WriteLine("Compute model list"); var models = source.GetEditableWrp().GetNonDummyObjects().Select(e => e.Model).Distinct().ToHashSet(StringComparer.OrdinalIgnoreCase); var usedPbo = new HashSet <PboInfo>(); foreach (var model in models) { if (!model.StartsWith("a3\\")) { var pbo = allPbos.FirstOrDefault(p => p.Files.Contains(model)); if (pbo != null) { usedPbo.Add(pbo); } else { Console.Error.WriteLine($"Model '{model}' was not found."); } } } var usedMods = usedPbo.GroupBy(p => p.Mod).Select(m => new ModInfo() { Path = m.Key.Path, WorkshopId = m.Key.WorkshopId, Pbos = m.Select(p => new PboInfo() { Path = p.Path, Files = p.Files.Where(f => models.Contains(f)).ToHashSet(StringComparer.OrdinalIgnoreCase) }).ToList() }).ToList(); if (string.IsNullOrEmpty(opts.ReportFile)) { opts.ReportFile = Path.ChangeExtension(opts.Source, ".txt"); } Console.WriteLine($"Write full report to '{opts.ReportFile}'"); using (var writer = new StreamWriter(opts.ReportFile, false)) { foreach (var mod in usedMods) { Console.WriteLine($" Depends on '{Path.GetFileName(mod.Path)}' (Workshop #{mod.WorkshopId})"); writer.WriteLine($"Depends on '{Path.GetFileName(mod.Path)}'"); writer.WriteLine($" Workshop #{mod.WorkshopId}"); writer.WriteLine($" '{mod.Path}')"); foreach (var pbo in mod.Pbos) { writer.WriteLine($" Content from '{Path.GetFileName(pbo.Path)}'"); foreach (var file in pbo.Files) { writer.WriteLine($" '{file}'"); } writer.WriteLine(); } writer.WriteLine(); writer.WriteLine(); } writer.WriteLine($"Project drive minimal setup (using bankrev)"); foreach (var mod in usedMods) { foreach (var pbo in mod.Pbos) { writer.WriteLine($@" bankrev -f ""P:"" -prefix ""{pbo.Path}"" "); } } } Console.WriteLine("Done"); return(0); }