Skip to content

Commit

Permalink
gui: add compress and decompress for lz4 and zst, decompress for xz
Browse files Browse the repository at this point in the history
  • Loading branch information
mahoshojoHCG committed Jun 27, 2024
1 parent 59a16db commit bfdb87b
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ public static IServiceCollection AddCompressionStreamCopier(this IServiceCollect
{
services.AddSingleton<RawStreamCopier>();
services.AddSingleton<GzipCompressionStreamCopier>();
services.AddSingleton<GzipDeCompressionStreamCopier>();
services.AddSingleton<GzipDecompressionStreamCopier>();
services.AddSingleton<XzDecompressionStreamCopier>();
services.AddSingleton<ZstandardCompressionStreamCopier>();
services.AddSingleton<ZstandardDecompressionStreamCopier>();
services.AddSingleton<Lz4CompressionStreamCopier>();
services.AddSingleton<Lz4DecompressionStreamCopier>();
services.AddSingleton<ICompressionStreamCopierFactory, CompressionStreamCopierFactory>();
return services;
}
Expand Down
11 changes: 7 additions & 4 deletions WinPartFlash.Gui/Compression/CompressionStreamCopierFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ public ICompressionStreamCopier GetCopier(CompressionType compressionType)
{
CompressionType.Raw => serviceProvider.GetRequiredService<RawStreamCopier>(),
CompressionType.GzipCompress => serviceProvider.GetRequiredService<GzipCompressionStreamCopier>(),
CompressionType.GzipDecompress => serviceProvider.GetRequiredService<GzipDeCompressionStreamCopier>(),
// TODO: Support following methods
CompressionType.Lz4Compress => throw new NotSupportedException(),
CompressionType.Lz4Decompress => throw new NotSupportedException(),
CompressionType.GzipDecompress => serviceProvider.GetRequiredService<GzipDecompressionStreamCopier>(),
CompressionType.Lz4Compress => serviceProvider.GetRequiredService<Lz4CompressionStreamCopier>(),
CompressionType.Lz4Decompress => serviceProvider.GetRequiredService<Lz4DecompressionStreamCopier>(),
CompressionType.XzDecompress => serviceProvider.GetRequiredService<XzDecompressionStreamCopier>(),
CompressionType.ZstandardCompress => serviceProvider.GetRequiredService<ZstandardCompressionStreamCopier>(),
CompressionType.ZstandardDecompress => serviceProvider
.GetRequiredService<ZstandardDecompressionStreamCopier>(),
_ => throw new ArgumentOutOfRangeException(nameof(compressionType), compressionType, null)
};
}
Expand Down
5 changes: 4 additions & 1 deletion WinPartFlash.Gui/Compression/CompressionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ public enum CompressionType
GzipCompress,
GzipDecompress,
Lz4Compress,
Lz4Decompress
Lz4Decompress,
ZstandardCompress,
ZstandardDecompress,
XzDecompress
}
6 changes: 3 additions & 3 deletions WinPartFlash.Gui/Compression/GzipDecompressionStreamCopier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

namespace WinPartFlash.Gui.Compression;

public class GzipDeCompressionStreamCopier : ICompressionStreamCopier
public class GzipDecompressionStreamCopier : ICompressionStreamCopier
{
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
{
await using var compressionStream = new GZipStream(outputStream, CompressionMode.Decompress);
await compressionStream.CopyToAsync(sourceStream);
await using var decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress);
await decompressionStream.CopyToAsync(outputStream);
}
}
14 changes: 14 additions & 0 deletions WinPartFlash.Gui/Compression/Lz4CompressionStreamCopier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.IO;
using System.Threading.Tasks;
using K4os.Compression.LZ4.Streams;

namespace WinPartFlash.Gui.Compression;

public class Lz4CompressionStreamCopier : ICompressionStreamCopier
{
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
{
await using var compressionStream = LZ4Stream.Encode(outputStream);
await sourceStream.CopyToAsync(compressionStream);
}
}
14 changes: 14 additions & 0 deletions WinPartFlash.Gui/Compression/Lz4DecompressionStreamCopier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.IO;
using System.Threading.Tasks;
using K4os.Compression.LZ4.Streams;

namespace WinPartFlash.Gui.Compression;

public class Lz4DecompressionStreamCopier : ICompressionStreamCopier
{
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
{
await using var decompressionStream = LZ4Stream.Decode(sourceStream);
await decompressionStream.CopyToAsync(outputStream);
}
}
14 changes: 14 additions & 0 deletions WinPartFlash.Gui/Compression/XzDecompressionStreamCopier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.IO;
using System.Threading.Tasks;
using SharpCompress.Compressors.Xz;

namespace WinPartFlash.Gui.Compression;

public class XzDecompressionStreamCopier : ICompressionStreamCopier
{
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
{
await using var decompressionStream = new XZStream(sourceStream);
await decompressionStream.CopyToAsync(outputStream);
}
}
14 changes: 14 additions & 0 deletions WinPartFlash.Gui/Compression/ZstandardCompressionStreamCopier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.IO;
using System.Threading.Tasks;
using ZstdSharp;

namespace WinPartFlash.Gui.Compression;

public class ZstandardCompressionStreamCopier : ICompressionStreamCopier
{
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
{
await using var compressionStream = new CompressionStream(outputStream);
await sourceStream.CopyToAsync(compressionStream);
}
}
14 changes: 14 additions & 0 deletions WinPartFlash.Gui/Compression/ZstandardDecompressionStreamCopier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.IO;
using System.Threading.Tasks;
using ZstdSharp;

namespace WinPartFlash.Gui.Compression;

public class ZstandardDecompressionStreamCopier : ICompressionStreamCopier
{
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
{
await using var decompressionStream = new DecompressionStream(sourceStream);
await decompressionStream.CopyToAsync(outputStream);
}
}
18 changes: 14 additions & 4 deletions WinPartFlash.Gui/FileOpenHelper/FileOpenHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Net.Http;
using System.Threading.Tasks;
using WinPartFlash.Gui.Compression;
using WinPartFlash.Gui.Utils;

namespace WinPartFlash.Gui.FileOpenHelper;

Expand All @@ -13,8 +14,11 @@ public class FileOpenHelper(IHttpClientFactory clientFactory) : IFileOpenHelper
private static readonly Dictionary<string, CompressionType> ContentTypeMapping =
new()
{
{ "application/gzip", CompressionType.GzipDecompress },
{ "application/x-gzip", CompressionType.GzipDecompress }
{ FileNameHelpers.ContentTypeGzip, CompressionType.GzipDecompress },
{ FileNameHelpers.ContentTypeGzipDeprecated, CompressionType.GzipDecompress },
{ FileNameHelpers.ContentTypeXz, CompressionType.XzDecompress },
{ FileNameHelpers.ContentTypeLz4, CompressionType.Lz4Compress },
{ FileNameHelpers.ContentTypeZstandard, CompressionType.ZstandardDecompress }
};

private readonly IReadOnlyList<IFileOpenHelper> _helpers =
Expand All @@ -26,10 +30,16 @@ public class FileOpenHelper(IHttpClientFactory clientFactory) : IFileOpenHelper
private static CompressionType DetectFromFileName(string fileName)
{
fileName = fileName.Trim('\"');
if (fileName.EndsWith(".gz"))
if (fileName.EndsWith(FileNameHelpers.FileExtensionGzip))
return CompressionType.GzipDecompress;
if (fileName.EndsWith(".lz4"))
if (fileName.EndsWith(FileNameHelpers.FileExtensionLz4))
return CompressionType.Lz4Decompress;
if (fileName.EndsWith(FileNameHelpers.FileExtensionXz))
return CompressionType.XzDecompress;
if (fileName.EndsWith(FileNameHelpers.FileExtensionLz4))
return CompressionType.Lz4Decompress;
if (fileName.EndsWith(FileNameHelpers.FileExtensionZstandard))
return CompressionType.ZstandardDecompress;

return CompressionType.Raw;
}
Expand Down
18 changes: 18 additions & 0 deletions WinPartFlash.Gui/Utils/FileNameHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace WinPartFlash.Gui.Utils;

public static class FileNameHelpers
{
public const string FileExtensionGzip = ".gz";
public const string FileExtensionXz = ".xz";
public const string FileExtensionLz4 = ".lz4";
public const string FileExtensionZstandard = ".zst";

public const string FileExtensionImage = ".img";


public const string ContentTypeGzip = "application/gzip";
public const string ContentTypeGzipDeprecated = "application/x-gzip";
public const string ContentTypeXz = "application/x-xz";
public const string ContentTypeLz4 = "application/x-lz4";
public const string ContentTypeZstandard = "application/x-zstd";
}
95 changes: 75 additions & 20 deletions WinPartFlash.Gui/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,38 @@ namespace WinPartFlash.Gui.ViewModels;

public class MainWindowViewModel : ViewModelBase
{
private static readonly List<string> RawTrimEndings = [".gz", ".lz4"];
private static readonly List<string> RawTrimEndings =
[
FileNameHelpers.FileExtensionGzip,
FileNameHelpers.FileExtensionLz4,
FileNameHelpers.FileExtensionZstandard
];

private static readonly FilePickerFileType DiskImage = new(Strings.FileTypeNameDiskImages)
{
Patterns = ["*.img", "*.img.gz"]
Patterns =
[
"*" + FileNameHelpers.FileExtensionImage,
"*" + FileNameHelpers.FileExtensionImage + FileNameHelpers.FileExtensionGzip,
"*" + FileNameHelpers.FileExtensionImage + FileNameHelpers.FileExtensionLz4,
"*" + FileNameHelpers.FileExtensionImage + FileNameHelpers.FileExtensionZstandard
]
};

private readonly IPartitionDetector _partitionDetector;
private readonly ICompressionStreamCopierFactory _streamCopierFactory;
private readonly IFileOpenHelper _fileOpenHelper;

private readonly ObservableAsPropertyHelper<CompressionType> _compressionType;
private readonly ObservableAsPropertyHelper<bool> _isMainWindowEnabled;
private readonly ObservableAsPropertyHelper<bool> _isSaveButtonEnabled;
private readonly ObservableAsPropertyHelper<bool> _isFlashButtonEnabled;

private CompressionType _compressionType;

private bool _isSaveGzipFileChecked;
private bool _isSaveRawFileChecked = true;
private bool _isSaveZstandardFileChecked;
private bool _isSaveLz4FileChecked;
private bool _isBackgroundTaskRunning;

private int _progress;
Expand All @@ -64,51 +78,76 @@ public MainWindowViewModel(
SavePartitionCommand = ReactiveCommand.CreateFromTask<Visual?>(SavePartition);
FlashPartitionCommand = ReactiveCommand.CreateFromTask<Visual?>(FlashPartition);

_compressionType = this
.WhenAnyValue(vm => vm.IsSaveRawFileChecked,
vm => vm.IsSaveGzipFileChecked)
.Select(tuple =>
// Subscribe to update compression type by clicking button
this
.WhenAnyValue(vm => vm.IsSaveRawFileChecked)
.Subscribe(enabled =>
{
var (rawChecked, gzipChecked) = tuple;
if (rawChecked)
return CompressionType.Raw;
if (gzipChecked)
return CompressionType.GzipCompress;
return CompressionType.Raw;
})
.ToProperty(this, vm => vm.CompressionType);
if (enabled) CompressionType = CompressionType.Raw;
});

this
.WhenAnyValue(vm => vm.IsSaveGzipFileChecked)
.Subscribe(enabled =>
{
if (enabled) CompressionType = CompressionType.GzipCompress;
});

this
.WhenAnyValue(vm => vm.IsSaveLz4FileChecked)
.Subscribe(enabled =>
{
if (enabled) CompressionType = CompressionType.Lz4Compress;
});

this
.WhenAnyValue(vm => vm.IsSaveZstandardFileChecked)
.Subscribe(enabled =>
{
if (enabled) CompressionType = CompressionType.ZstandardCompress;
});

//Subscribe to update file name after compression type updated
this
.WhenAnyValue(vm => vm.CompressionType)
.Subscribe(type =>
{
var ending = RawTrimEndings.FirstOrDefault(e => SavePartitionFileName.EndsWith(e));
var rawFileName = ending == null ? SavePartitionFileName : SavePartitionFileName[..^ending.Length];
switch (CompressionType)
switch (type)
{
case CompressionType.Raw:
if (!string.IsNullOrWhiteSpace(rawFileName))
SavePartitionFileName = rawFileName;
break;
case CompressionType.GzipCompress:
if (!string.IsNullOrWhiteSpace(rawFileName))
SavePartitionFileName = rawFileName + ".gz";
SavePartitionFileName = rawFileName + FileNameHelpers.FileExtensionGzip;
break;
case CompressionType.Lz4Compress:
if (!string.IsNullOrWhiteSpace(rawFileName))
SavePartitionFileName = rawFileName + ".lz4";
SavePartitionFileName = rawFileName + FileNameHelpers.FileExtensionLz4;
break;
case CompressionType.ZstandardCompress:
if (!string.IsNullOrWhiteSpace(rawFileName))
SavePartitionFileName = rawFileName + FileNameHelpers.FileExtensionZstandard;
break;
default:
throw new ArgumentOutOfRangeException();
}
});

// Subscribe to update button status after file name updated
this
.WhenAnyValue(vm => vm.SavePartitionFileName)
.Subscribe(name =>
{
if (name.EndsWith(".gz"))
if (name.EndsWith(FileNameHelpers.FileExtensionGzip))
IsSaveGzipFileChecked = true;
else if (name.EndsWith(FileNameHelpers.FileExtensionLz4))
IsSaveLz4FileChecked = true;
else if (name.EndsWith(FileNameHelpers.FileExtensionZstandard))
IsSaveZstandardFileChecked = true;
else
IsSaveRawFileChecked = true;
});
Expand Down Expand Up @@ -139,6 +178,18 @@ public MainWindowViewModel(
.ToProperty(this, vm => vm.IsFlashButtonEnabled);
}

public bool IsSaveZstandardFileChecked
{
get => _isSaveZstandardFileChecked;
set => this.RaiseAndSetIfChanged(ref _isSaveZstandardFileChecked, value);
}

public bool IsSaveLz4FileChecked
{
get => _isSaveLz4FileChecked;
set => this.RaiseAndSetIfChanged(ref _isSaveLz4FileChecked, value);
}

public bool IsFlashButtonEnabled => _isFlashButtonEnabled.Value;

public int Progress
Expand Down Expand Up @@ -198,7 +249,11 @@ public List<PartitionItemViewModel> PartitionItems
public ReactiveCommand<Visual?, Unit> SavePartitionCommand { get; }
public ReactiveCommand<Visual?, Unit> FlashPartitionCommand { get; }

private CompressionType CompressionType => _compressionType.Value;
private CompressionType CompressionType
{
get => _compressionType;
set => this.RaiseAndSetIfChanged(ref _compressionType, value);
}

private static Window? GetVisualTopWindow(Visual? visual)
{
Expand Down
3 changes: 2 additions & 1 deletion WinPartFlash.Gui/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
<!-- Below are image file types and should not localize. -->
<RadioButton Content="raw" IsChecked="{Binding IsSaveRawFileChecked}" />
<RadioButton Content="gz" IsChecked="{Binding IsSaveGzipFileChecked}" />
<RadioButton Content="lz4" IsEnabled="False" />
<RadioButton Content="lz4" IsChecked="{Binding IsSaveLz4FileChecked}" />
<RadioButton Content="zst" IsChecked="{Binding IsSaveZstandardFileChecked}" />
</StackPanel>

<ProgressBar Margin="0 0 0 10"
Expand Down
Loading

0 comments on commit bfdb87b

Please sign in to comment.