From e89d10607ef4cc8cb7da7782fabdaeef8c595aa6 Mon Sep 17 00:00:00 2001 From: Samuel Stark Date: Tue, 2 Jan 2024 19:42:28 +0000 Subject: [PATCH 1/3] Add the option to filter extracted and listed files in a GMD by regex. --- ParTool/Options/Extract.cs | 8 +++++++- ParTool/Options/List.cs | 6 ++++++ ParTool/Program.Extract.cs | 15 +++++++++++++-- ParTool/Program.List.cs | 10 ++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/ParTool/Options/Extract.cs b/ParTool/Options/Extract.cs index 6c05e64..5256c7d 100644 --- a/ParTool/Options/Extract.cs +++ b/ParTool/Options/Extract.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------- -// © Kaplas. Licensed under MIT. See LICENSE for details. +// © Kaplas, Samuel W. Stark (TheTurboTurnip). Licensed under MIT. See LICENSE for details. // ------------------------------------------------------- namespace ParTool.Options { @@ -29,5 +29,11 @@ internal class Extract /// [Option('r', "recursive", Default = false, HelpText = "Extract nested PAR archives.")] public bool Recursive { get; set; } + + /// + /// Gets or sets a value used as a Regex filter for which real-files to extract. + /// + [Option("filter", Default = null, HelpText = "Only extract files that match this RegEx (directories will always be extracted)")] + public string FilterRegex { get; set; } } } diff --git a/ParTool/Options/List.cs b/ParTool/Options/List.cs index 19528f9..2dc322b 100644 --- a/ParTool/Options/List.cs +++ b/ParTool/Options/List.cs @@ -23,5 +23,11 @@ internal class List /// [Option('r', "recursive", Default = false, HelpText = "List nested PAR archives.")] public bool Recursive { get; set; } + + /// + /// Gets or sets a value used as a Regex filter for which real-files to extract. + /// + [Option("filter", Default = null, HelpText = "Only extract files that match this RegEx (directories will always be extracted)")] + public string FilterRegex { get; set; } } } diff --git a/ParTool/Program.Extract.cs b/ParTool/Program.Extract.cs index 561a538..d4aa053 100644 --- a/ParTool/Program.Extract.cs +++ b/ParTool/Program.Extract.cs @@ -5,6 +5,7 @@ namespace ParTool { using System; using System.IO; + using System.Text.RegularExpressions; using ParLibrary; using ParLibrary.Converter; using Yarhl.FileSystem; @@ -39,6 +40,9 @@ private static void Extract(Options.Extract opts) Directory.CreateDirectory(opts.OutputDirectory); + // If a FilterRegex was specified (i.e. is not null) then make a new Regex using it. Otherwise, set filterRegex to null. + var filterRegex = (opts.FilterRegex == null) ? null : new Regex(opts.FilterRegex); + var parameters = new ParArchiveReaderParameters { Recursive = opts.Recursive, @@ -47,10 +51,10 @@ private static void Extract(Options.Extract opts) using Node par = NodeFactory.FromFile(opts.ParArchivePath, Yarhl.IO.FileOpenMode.Read); par.TransformWith(parameters); - Extract(par, opts.OutputDirectory); + Extract(par, filterRegex, opts.OutputDirectory); } - private static void Extract(Node parNode, string outputFolder) + private static void Extract(Node parNode, Regex filterRegex, string outputFolder) { foreach (Node node in Navigator.IterateNodes(parNode)) { @@ -65,6 +69,13 @@ private static void Extract(Node parNode, string outputFolder) continue; } + // If the filterRegex exists, skip files that don't match it + if (filterRegex != null && !filterRegex.IsMatch(node.Path)) + { + Console.WriteLine($"Skipping {node.Path} because it doesn't match the filter"); + continue; + } + Console.Write($"Extracting {node.Path}... "); if (file.IsCompressed) diff --git a/ParTool/Program.List.cs b/ParTool/Program.List.cs index 551df0a..9ee1295 100644 --- a/ParTool/Program.List.cs +++ b/ParTool/Program.List.cs @@ -5,6 +5,7 @@ namespace ParTool { using System; using System.IO; + using System.Text.RegularExpressions; using ParLibrary; using ParLibrary.Converter; using Yarhl.FileSystem; @@ -24,6 +25,9 @@ private static void List(Options.List opts) return; } + // If a FilterRegex was specified (i.e. is not null) then make a new Regex using it. Otherwise, set filterRegex to null. + var filterRegex = (opts.FilterRegex == null) ? null : new Regex(opts.FilterRegex); + var parameters = new ParArchiveReaderParameters { Recursive = opts.Recursive, @@ -37,6 +41,12 @@ private static void List(Options.List opts) var file = node.GetFormatAs(); if (file != null) { + // If the filterRegex exists, skip files that don't match it + if (filterRegex != null && !filterRegex.IsMatch(node.Path)) + { + continue; + } + var compression = file.IsCompressed ? "*" : string.Empty; Console.WriteLine($"{node.Path}{compression}\t{file.DecompressedSize} bytes\t{file.FileDate:G}"); } From 221040c38d03609fd776b25e436c4f791da9e91d Mon Sep 17 00:00:00 2001 From: Samuel Stark Date: Tue, 2 Jan 2024 19:49:58 +0000 Subject: [PATCH 2/3] Cleanup, copyright, comments --- ParTool/Options/Extract.cs | 2 +- ParTool/Options/List.cs | 6 +++--- ParTool/Program.Extract.cs | 4 ++-- ParTool/Program.List.cs | 2 +- README.md | 12 ++++++++++-- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ParTool/Options/Extract.cs b/ParTool/Options/Extract.cs index 5256c7d..de46d7e 100644 --- a/ParTool/Options/Extract.cs +++ b/ParTool/Options/Extract.cs @@ -31,7 +31,7 @@ internal class Extract public bool Recursive { get; set; } /// - /// Gets or sets a value used as a Regex filter for which real-files to extract. + /// Gets or sets a value used as a Regex filter for which files to extract. /// [Option("filter", Default = null, HelpText = "Only extract files that match this RegEx (directories will always be extracted)")] public string FilterRegex { get; set; } diff --git a/ParTool/Options/List.cs b/ParTool/Options/List.cs index 2dc322b..81233f7 100644 --- a/ParTool/Options/List.cs +++ b/ParTool/Options/List.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------- -// © Kaplas. Licensed under MIT. See LICENSE for details. +// © Kaplas, Samuel W. Stark (TheTurboTurnip). Licensed under MIT. See LICENSE for details. // ------------------------------------------------------- namespace ParTool.Options { @@ -25,9 +25,9 @@ internal class List public bool Recursive { get; set; } /// - /// Gets or sets a value used as a Regex filter for which real-files to extract. + /// Gets or sets a value used as a Regex filter for which files to list. /// - [Option("filter", Default = null, HelpText = "Only extract files that match this RegEx (directories will always be extracted)")] + [Option("filter", Default = null, HelpText = "Only list files that match this RegEx")] public string FilterRegex { get; set; } } } diff --git a/ParTool/Program.Extract.cs b/ParTool/Program.Extract.cs index d4aa053..892ffdc 100644 --- a/ParTool/Program.Extract.cs +++ b/ParTool/Program.Extract.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------- -// © Kaplas. Licensed under MIT. See LICENSE for details. +// © Kaplas, Samuel W. Stark (TheTurboTurnip). Licensed under MIT. See LICENSE for details. // ------------------------------------------------------- namespace ParTool { @@ -72,7 +72,7 @@ private static void Extract(Node parNode, Regex filterRegex, string outputFolder // If the filterRegex exists, skip files that don't match it if (filterRegex != null && !filterRegex.IsMatch(node.Path)) { - Console.WriteLine($"Skipping {node.Path} because it doesn't match the filter"); + Console.WriteLine($"Skipping {node.Path}"); continue; } diff --git a/ParTool/Program.List.cs b/ParTool/Program.List.cs index 9ee1295..68a2597 100644 --- a/ParTool/Program.List.cs +++ b/ParTool/Program.List.cs @@ -1,5 +1,5 @@ // ------------------------------------------------------- -// © Kaplas. Licensed under MIT. See LICENSE for details. +// © Kaplas, Samuel W. Stark (TheTurboTurnip). Licensed under MIT. See LICENSE for details. // ------------------------------------------------------- namespace ParTool { diff --git a/README.md b/README.md index 36e3591..2765fef 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,27 @@ It supports ***SLLZ*** compression (Including ***SLLZ V2*** used in Yakuza Kiwam ## Usage - **List mode** - `ParTool.exe list [-r]` + `ParTool.exe list [-r] [--filter ""]` Reads a PAR archive and shows it contents. `-r` parameter enables *recursive* mode and shows the contents of nested PAR archives. + + `--filter` parameter filters output lines using a user-provided regular expression. - **Extraction mode** - `ParTool.exe extract [-r]` + `ParTool.exe extract [-r] [--filter ""]` Extracts the PAR archive contents to the specified directory. `-r` parameter enables *recursive* mode and extracts the contents of nested PAR archives. + + `--filter` parameter filters extracted files using a user-provided regular expression. + Files that do not match the filter will not be extracted. + Directories are always extracted. + When combined with `-r`, files matching the filter inside nested PAR archives will be extracted. + - **Creation mode** From 10b5921589569f928fb41fb6a645d0129fca5690 Mon Sep 17 00:00:00 2001 From: Samuel Stark Date: Sun, 7 Jan 2024 19:13:44 +0000 Subject: [PATCH 3/3] Update README to include an example regular expression, resources to learn more about regular expressions, and advice on quoting regular expressions. --- README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2765fef..638edc4 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,23 @@ It supports ***SLLZ*** compression (Including ***SLLZ V2*** used in Yakuza Kiwam ## Usage - **List mode** - `ParTool.exe list [-r] [--filter ""]` + `ParTool.exe list [-r] [--filter '']` Reads a PAR archive and shows it contents. `-r` parameter enables *recursive* mode and shows the contents of nested PAR archives. `--filter` parameter filters output lines using a user-provided regular expression. + + For example, `ParTool.exe list mesh.par -r --filter '\.gmd$'` will only list GMD files (files that end with the characters '.gmd'). + See [https://regexr.com/7q33s] for an explanation of this regular expression, and [the .NET Regular Expression Quick Reference](https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference) for a complete guide to the syntax. + If using Powershell, use single quotes `'` to surround the expression to avoid variable expansion [(see the Powershell docs)](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.4#single-quoted-strings). + If using Command Prompt, use double quotes. + - **Extraction mode** - `ParTool.exe extract [-r] [--filter ""]` + `ParTool.exe extract [-r] [--filter '']` Extracts the PAR archive contents to the specified directory. @@ -31,7 +37,12 @@ It supports ***SLLZ*** compression (Including ***SLLZ V2*** used in Yakuza Kiwam Directories are always extracted. When combined with `-r`, files matching the filter inside nested PAR archives will be extracted. - + For example, `ParTool.exe extract mesh.par -r --filter '\.gmd$'` will only extract GMD files (files that end with the characters '.gmd'). + See [https://regexr.com/7q33s] for an explanation of this regular expression, and [the .NET Regular Expression Quick Reference](https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference) for a complete guide to the syntax. + + If using Powershell, use single quotes `'` to surround the expression to avoid variable expansion [(see the Powershell docs)](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.4#single-quoted-strings). + If using Command Prompt, use double quotes. + - **Creation mode** `ParTool.exe create [-c compression_mode] [--alternative-mode]`