updated to accept only .tar.zstd uploads
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using System.Formats.Tar;
|
||||
using System.IO;
|
||||
using ZstdSharp;
|
||||
|
||||
namespace ParadoxSaveParser.WebAPI;
|
||||
|
||||
/// <summary>
|
||||
/// Uploaded save is a zstd-compressed tar with files of the original save inside.
|
||||
/// Game data is stored in entry with name from <see cref="GameSaveEntryNames"/>.
|
||||
/// </summary>
|
||||
public static class SaveArchive
|
||||
{
|
||||
public static Task<long> GetGameDataSize(IOPath archivePath, Game game, CancellationToken ct)
|
||||
{
|
||||
return WithGameDataEntry(archivePath, game, ct,
|
||||
entry => Task.FromResult(entry.Length));
|
||||
}
|
||||
|
||||
public static Task ExtractGameData(IOPath archivePath, Game game, Stream dest, long maxBytes,
|
||||
CancellationToken ct)
|
||||
{
|
||||
return WithGameDataEntry(archivePath, game, ct, async entry =>
|
||||
{
|
||||
if (entry.Length > maxBytes)
|
||||
throw new InvalidDataException(
|
||||
$"Game data size ({entry.Length} bytes) exceeds limit ({maxBytes} bytes)");
|
||||
if (entry.DataStream is not null)
|
||||
await entry.DataStream.CopyToAsync(dest, ct);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task<T> WithGameDataEntry<T>(IOPath archivePath, Game game, CancellationToken ct,
|
||||
Func<TarEntry, Task<T>> action)
|
||||
{
|
||||
if (!GameSaveEntryNames.Map.TryGetValue(game, out string? entryName))
|
||||
throw new ArgumentOutOfRangeException(nameof(game), game, "No game data entry name for game");
|
||||
|
||||
await using var file = File.OpenRead(archivePath);
|
||||
await using var zstd = new DecompressionStream(file);
|
||||
await using var tar = new TarReader(zstd);
|
||||
while (await tar.GetNextEntryAsync(copyData: false, ct) is { } entry)
|
||||
{
|
||||
if (entry.EntryType is not (TarEntryType.RegularFile or TarEntryType.V7RegularFile))
|
||||
continue;
|
||||
if (System.IO.Path.GetFileName(entry.Name) == entryName)
|
||||
return await action(entry);
|
||||
}
|
||||
|
||||
throw new InvalidDataException($"Invalid save format: no '{entryName}' entry found");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user