Skip to content

Commit 53e27d0

Browse files
committed
Improve info and extract commands
- You can now choose to either specify regions to download or regions to skip - You can now display more than 4096 files by using the '-a' ('--show-all-files') option with the info command.
1 parent 066715a commit 53e27d0

2 files changed

Lines changed: 63 additions & 17 deletions

File tree

XvdTool.Streaming/Program.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ public sealed class Settings : XvdCommandSettings
150150
[Description("File path to save the output into.")]
151151
[CommandOption("-o|--output")]
152152
public string? OutputPath { get; init; }
153+
154+
[Description("If all files should be printed.\nIf unset, only the first 4096 files will be printed.")]
155+
[CommandOption(("-a|--show-all-files"))]
156+
public bool ShowAllFiles { get; set; }
153157
}
154158

155159
public override int Execute(CommandContext context, Settings settings)
@@ -160,7 +164,7 @@ public override int Execute(CommandContext context, Settings settings)
160164

161165
using (XvdFile)
162166
{
163-
var infoOutput = XvdFile.PrintInfo();
167+
var infoOutput = XvdFile.PrintInfo(settings.ShowAllFiles);
164168
if (settings.OutputPath != null)
165169
{
166170
var directory = Path.GetDirectoryName(settings.OutputPath);
@@ -185,8 +189,12 @@ public sealed class Settings : CryptoCommandSettings
185189
public string? OutputDirectory { get; init; }
186190

187191
[Description("List of regions to skip downloading. Defaults to none.")]
188-
[CommandOption("-r|--skip-region")]
189-
public uint[]? SkippedRegions { get; init; }
192+
[CommandOption("-b|--skip-region")]
193+
public uint[]? SkipRegions { get; init; }
194+
195+
[Description("List of regions to download. Defaults to all.")]
196+
[CommandOption("-w|--download-region")]
197+
public uint[]? DownloadRegions { get; init; }
190198

191199
[Description("Skips performing hash verification on the pages prior to decryption.\nMassively improves performance at the cost of integrity.\nOnly use this if you know the file is not corrupt!")]
192200
[CommandOption("-n|--no-hash-check")]
@@ -210,13 +218,21 @@ public override int Execute(CommandContext context, Settings settings)
210218

211219
using (XvdFile)
212220
{
213-
XvdFile.ExtractFiles(outputPath, keyEntry, settings.SkipHashCheck, settings.SkippedRegions);
221+
XvdFile.ExtractFiles(outputPath, keyEntry, settings.SkipHashCheck, settings.SkipRegions, settings.DownloadRegions);
214222
}
215223

216224
ConsoleLogger.WriteInfoLine("[green bold]Successfully[/] extracted files.");
217225

218226
return 0;
219227
}
228+
229+
public override ValidationResult Validate(CommandContext context, Settings settings)
230+
{
231+
if (settings is {DownloadRegions: not null, SkipRegions: not null})
232+
return ValidationResult.Error("'--skip-region' and '--download-region' cannot be used together.");
233+
234+
return ValidationResult.Success();
235+
}
220236
}
221237

222238
internal sealed class VerifyCommand : XvdCommand<VerifyCommand.Settings>

XvdTool.Streaming/StreamedXvdFile.cs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ public bool VerifyDataHashes()
302302
return LocalVerifyDataHashes();
303303
}
304304

305-
public void ExtractFiles(string outputPath, in KeyEntry key, bool skipHashCheck = false, uint[]? skippedRegionList = null)
305+
public void ExtractFiles(string outputPath, in KeyEntry key, bool skipHashCheck = false, uint[]? skippedRegionList = null, uint[]? downloadRegionList = null)
306306
{
307307
if (!_hasXvcInfo)
308308
{
@@ -340,12 +340,24 @@ public void ExtractFiles(string outputPath, in KeyEntry key, bool skipHashCheck
340340

341341
var firstSegmentOffset = XvdMath.PageNumberToOffset(_xvcUpdateSegments[0].PageNum);
342342

343-
var extractableRegionList =
344-
_xvcRegions
345-
.Where(region =>
346-
(skippedRegionList == null || !skippedRegionList.Contains((uint)region.Id))
343+
XvcRegionHeader[] extractableRegionList;
344+
345+
if (downloadRegionList != null)
346+
{
347+
extractableRegionList = _xvcRegions
348+
.Where(region => downloadRegionList.Contains((uint)region.Id)
347349
&& (region.FirstSegmentIndex != 0 || firstSegmentOffset == region.Offset))
348-
.ToArray();
350+
.ToArray();
351+
}
352+
else
353+
{
354+
extractableRegionList =
355+
_xvcRegions
356+
.Where(region =>
357+
(skippedRegionList == null || !skippedRegionList.Contains((uint)region.Id))
358+
&& (region.FirstSegmentIndex != 0 || firstSegmentOffset == region.Offset))
359+
.ToArray();
360+
}
349361

350362
// Fancy console version
351363
AnsiConsole.Progress()
@@ -553,7 +565,7 @@ private void ExtractRegion(
553565
}
554566
}
555567

556-
public string PrintInfo()
568+
public string PrintInfo(bool showAllFiles = false)
557569
{
558570
AnsiConsole.Record();
559571

@@ -665,6 +677,7 @@ static Rows StringToRows(string text)
665677
.AddColumns(
666678
new TableColumn("Offset"),
667679
new TableColumn("Size"),
680+
new TableColumn("Size in Bytes"),
668681
new TableColumn("File Path")
669682
)
670683
.RoundedBorder()
@@ -675,6 +688,7 @@ static Rows StringToRows(string text)
675688
packageFilesTable.AddRow(
676689
new Markup($"[green bold]0x{entry.Offset:x8}[/]"),
677690
new Markup($"[green bold]0x{entry.Size:x8}[/]"),
691+
new Markup($"[green bold]{ToFileSize(entry.Size)}[/]"),
678692
new Markup($"[aqua underline]{entry.FilePath}[/]")
679693
);
680694
}
@@ -701,38 +715,54 @@ static Rows StringToRows(string text)
701715
.AddColumns(
702716
new TableColumn("Start Page"),
703717
new TableColumn("File Size"),
718+
new TableColumn("Size in Bytes"),
704719
new TableColumn("Hash"),
705720
new TableColumn("Flags"),
706721
new TableColumn("File Path")
707722
)
708723
.RoundedBorder()
709724
.Expand();
710725

711-
for (int i = 0; i < Math.Min(_segments.Length, 0x1000); i++)
726+
for (int i = 0; i < (showAllFiles ? _segments.Length : Math.Min(_segments.Length, 0x1000)); i++)
712727
{
713728
var segment = _segments[i];
714729
var updateSegment = _xvcUpdateSegments[i];
715730

716731
segmentTable.AddRow(
717732
new Markup($"[green]0x{updateSegment.PageNum:x8}[/]"),
718733
new Markup($"[green]0x{segment.FileSize:x16}[/]"),
734+
new Markup($"[green]{ToFileSize(segment.FileSize)}[/]"),
719735
new Markup($"[green]0x{updateSegment.Hash:x16}[/]"),
720736
new Markup(segment.Flags != 0x0 ? $"[fuchsia]0x{(byte)segment.Flags:x2}[/]" : $"0x{segment.Flags}"),
721737
new Markup($"[aqua underline]{_segmentPaths[i]}[/]")
722738
);
739+
}
723740

724-
if (_segments.Length > 0x1000)
725-
{
726-
segmentTable.AddEmptyRow();
727-
segmentTable.AddRow(new Markup("[red bold]<Too many segment files to print>[/]"));
728-
}
741+
if (!showAllFiles && _segments.Length > 0x1000)
742+
{
743+
segmentTable.AddEmptyRow();
744+
segmentTable.AddRow(new Markup("[red bold]<Too many segment files to print>[/]"));
729745
}
730746

731747
AnsiConsole.Write(segmentTable);
732748
}
733749
}
734750

735751
return AnsiConsole.ExportText();
752+
753+
string ToFileSize(ulong size)
754+
{
755+
if (size < 1024)
756+
return $"{size} B";
757+
758+
if (size < 1024 * 1024)
759+
return $"{Math.Round(size / 1024.0, 2)} KB";
760+
761+
if (size < 1024 * 1024 * 1024)
762+
return $"{Math.Round(size / (1024.0 * 1024.0), 2)} MB";
763+
764+
return $"{Math.Round(size / (1024.0 * 1024.0 * 1024.0), 2)} KB";
765+
}
736766
}
737767

738768
public void Dispose()

0 commit comments

Comments
 (0)