Skip to content

Commit bfdb87b

Browse files
author
mahoshojoHCG
committed
gui: add compress and decompress for lz4 and zst, decompress for xz
1 parent 59a16db commit bfdb87b

14 files changed

+204
-35
lines changed

WinPartFlash.Gui/Compression/CompressionStreamCopierExtension.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ public static IServiceCollection AddCompressionStreamCopier(this IServiceCollect
88
{
99
services.AddSingleton<RawStreamCopier>();
1010
services.AddSingleton<GzipCompressionStreamCopier>();
11-
services.AddSingleton<GzipDeCompressionStreamCopier>();
11+
services.AddSingleton<GzipDecompressionStreamCopier>();
12+
services.AddSingleton<XzDecompressionStreamCopier>();
13+
services.AddSingleton<ZstandardCompressionStreamCopier>();
14+
services.AddSingleton<ZstandardDecompressionStreamCopier>();
15+
services.AddSingleton<Lz4CompressionStreamCopier>();
16+
services.AddSingleton<Lz4DecompressionStreamCopier>();
1217
services.AddSingleton<ICompressionStreamCopierFactory, CompressionStreamCopierFactory>();
1318
return services;
1419
}

WinPartFlash.Gui/Compression/CompressionStreamCopierFactory.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ public ICompressionStreamCopier GetCopier(CompressionType compressionType)
1111
{
1212
CompressionType.Raw => serviceProvider.GetRequiredService<RawStreamCopier>(),
1313
CompressionType.GzipCompress => serviceProvider.GetRequiredService<GzipCompressionStreamCopier>(),
14-
CompressionType.GzipDecompress => serviceProvider.GetRequiredService<GzipDeCompressionStreamCopier>(),
15-
// TODO: Support following methods
16-
CompressionType.Lz4Compress => throw new NotSupportedException(),
17-
CompressionType.Lz4Decompress => throw new NotSupportedException(),
14+
CompressionType.GzipDecompress => serviceProvider.GetRequiredService<GzipDecompressionStreamCopier>(),
15+
CompressionType.Lz4Compress => serviceProvider.GetRequiredService<Lz4CompressionStreamCopier>(),
16+
CompressionType.Lz4Decompress => serviceProvider.GetRequiredService<Lz4DecompressionStreamCopier>(),
17+
CompressionType.XzDecompress => serviceProvider.GetRequiredService<XzDecompressionStreamCopier>(),
18+
CompressionType.ZstandardCompress => serviceProvider.GetRequiredService<ZstandardCompressionStreamCopier>(),
19+
CompressionType.ZstandardDecompress => serviceProvider
20+
.GetRequiredService<ZstandardDecompressionStreamCopier>(),
1821
_ => throw new ArgumentOutOfRangeException(nameof(compressionType), compressionType, null)
1922
};
2023
}

WinPartFlash.Gui/Compression/CompressionType.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@ public enum CompressionType
66
GzipCompress,
77
GzipDecompress,
88
Lz4Compress,
9-
Lz4Decompress
9+
Lz4Decompress,
10+
ZstandardCompress,
11+
ZstandardDecompress,
12+
XzDecompress
1013
}

WinPartFlash.Gui/Compression/GzipDecompressionStreamCopier.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
namespace WinPartFlash.Gui.Compression;
66

7-
public class GzipDeCompressionStreamCopier : ICompressionStreamCopier
7+
public class GzipDecompressionStreamCopier : ICompressionStreamCopier
88
{
99
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
1010
{
11-
await using var compressionStream = new GZipStream(outputStream, CompressionMode.Decompress);
12-
await compressionStream.CopyToAsync(sourceStream);
11+
await using var decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress);
12+
await decompressionStream.CopyToAsync(outputStream);
1313
}
1414
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.IO;
2+
using System.Threading.Tasks;
3+
using K4os.Compression.LZ4.Streams;
4+
5+
namespace WinPartFlash.Gui.Compression;
6+
7+
public class Lz4CompressionStreamCopier : ICompressionStreamCopier
8+
{
9+
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
10+
{
11+
await using var compressionStream = LZ4Stream.Encode(outputStream);
12+
await sourceStream.CopyToAsync(compressionStream);
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.IO;
2+
using System.Threading.Tasks;
3+
using K4os.Compression.LZ4.Streams;
4+
5+
namespace WinPartFlash.Gui.Compression;
6+
7+
public class Lz4DecompressionStreamCopier : ICompressionStreamCopier
8+
{
9+
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
10+
{
11+
await using var decompressionStream = LZ4Stream.Decode(sourceStream);
12+
await decompressionStream.CopyToAsync(outputStream);
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.IO;
2+
using System.Threading.Tasks;
3+
using SharpCompress.Compressors.Xz;
4+
5+
namespace WinPartFlash.Gui.Compression;
6+
7+
public class XzDecompressionStreamCopier : ICompressionStreamCopier
8+
{
9+
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
10+
{
11+
await using var decompressionStream = new XZStream(sourceStream);
12+
await decompressionStream.CopyToAsync(outputStream);
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.IO;
2+
using System.Threading.Tasks;
3+
using ZstdSharp;
4+
5+
namespace WinPartFlash.Gui.Compression;
6+
7+
public class ZstandardCompressionStreamCopier : ICompressionStreamCopier
8+
{
9+
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
10+
{
11+
await using var compressionStream = new CompressionStream(outputStream);
12+
await sourceStream.CopyToAsync(compressionStream);
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.IO;
2+
using System.Threading.Tasks;
3+
using ZstdSharp;
4+
5+
namespace WinPartFlash.Gui.Compression;
6+
7+
public class ZstandardDecompressionStreamCopier : ICompressionStreamCopier
8+
{
9+
public async ValueTask CopyToStreamAsync(Stream sourceStream, Stream outputStream)
10+
{
11+
await using var decompressionStream = new DecompressionStream(sourceStream);
12+
await decompressionStream.CopyToAsync(outputStream);
13+
}
14+
}

WinPartFlash.Gui/FileOpenHelper/FileOpenHelper.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Net.Http;
66
using System.Threading.Tasks;
77
using WinPartFlash.Gui.Compression;
8+
using WinPartFlash.Gui.Utils;
89

910
namespace WinPartFlash.Gui.FileOpenHelper;
1011

@@ -13,8 +14,11 @@ public class FileOpenHelper(IHttpClientFactory clientFactory) : IFileOpenHelper
1314
private static readonly Dictionary<string, CompressionType> ContentTypeMapping =
1415
new()
1516
{
16-
{ "application/gzip", CompressionType.GzipDecompress },
17-
{ "application/x-gzip", CompressionType.GzipDecompress }
17+
{ FileNameHelpers.ContentTypeGzip, CompressionType.GzipDecompress },
18+
{ FileNameHelpers.ContentTypeGzipDeprecated, CompressionType.GzipDecompress },
19+
{ FileNameHelpers.ContentTypeXz, CompressionType.XzDecompress },
20+
{ FileNameHelpers.ContentTypeLz4, CompressionType.Lz4Compress },
21+
{ FileNameHelpers.ContentTypeZstandard, CompressionType.ZstandardDecompress }
1822
};
1923

2024
private readonly IReadOnlyList<IFileOpenHelper> _helpers =
@@ -26,10 +30,16 @@ public class FileOpenHelper(IHttpClientFactory clientFactory) : IFileOpenHelper
2630
private static CompressionType DetectFromFileName(string fileName)
2731
{
2832
fileName = fileName.Trim('\"');
29-
if (fileName.EndsWith(".gz"))
33+
if (fileName.EndsWith(FileNameHelpers.FileExtensionGzip))
3034
return CompressionType.GzipDecompress;
31-
if (fileName.EndsWith(".lz4"))
35+
if (fileName.EndsWith(FileNameHelpers.FileExtensionLz4))
3236
return CompressionType.Lz4Decompress;
37+
if (fileName.EndsWith(FileNameHelpers.FileExtensionXz))
38+
return CompressionType.XzDecompress;
39+
if (fileName.EndsWith(FileNameHelpers.FileExtensionLz4))
40+
return CompressionType.Lz4Decompress;
41+
if (fileName.EndsWith(FileNameHelpers.FileExtensionZstandard))
42+
return CompressionType.ZstandardDecompress;
3343

3444
return CompressionType.Raw;
3545
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace WinPartFlash.Gui.Utils;
2+
3+
public static class FileNameHelpers
4+
{
5+
public const string FileExtensionGzip = ".gz";
6+
public const string FileExtensionXz = ".xz";
7+
public const string FileExtensionLz4 = ".lz4";
8+
public const string FileExtensionZstandard = ".zst";
9+
10+
public const string FileExtensionImage = ".img";
11+
12+
13+
public const string ContentTypeGzip = "application/gzip";
14+
public const string ContentTypeGzipDeprecated = "application/x-gzip";
15+
public const string ContentTypeXz = "application/x-xz";
16+
public const string ContentTypeLz4 = "application/x-lz4";
17+
public const string ContentTypeZstandard = "application/x-zstd";
18+
}

WinPartFlash.Gui/ViewModels/MainWindowViewModel.cs

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,38 @@ namespace WinPartFlash.Gui.ViewModels;
2121

2222
public class MainWindowViewModel : ViewModelBase
2323
{
24-
private static readonly List<string> RawTrimEndings = [".gz", ".lz4"];
24+
private static readonly List<string> RawTrimEndings =
25+
[
26+
FileNameHelpers.FileExtensionGzip,
27+
FileNameHelpers.FileExtensionLz4,
28+
FileNameHelpers.FileExtensionZstandard
29+
];
2530

2631
private static readonly FilePickerFileType DiskImage = new(Strings.FileTypeNameDiskImages)
2732
{
28-
Patterns = ["*.img", "*.img.gz"]
33+
Patterns =
34+
[
35+
"*" + FileNameHelpers.FileExtensionImage,
36+
"*" + FileNameHelpers.FileExtensionImage + FileNameHelpers.FileExtensionGzip,
37+
"*" + FileNameHelpers.FileExtensionImage + FileNameHelpers.FileExtensionLz4,
38+
"*" + FileNameHelpers.FileExtensionImage + FileNameHelpers.FileExtensionZstandard
39+
]
2940
};
3041

3142
private readonly IPartitionDetector _partitionDetector;
3243
private readonly ICompressionStreamCopierFactory _streamCopierFactory;
3344
private readonly IFileOpenHelper _fileOpenHelper;
3445

35-
private readonly ObservableAsPropertyHelper<CompressionType> _compressionType;
3646
private readonly ObservableAsPropertyHelper<bool> _isMainWindowEnabled;
3747
private readonly ObservableAsPropertyHelper<bool> _isSaveButtonEnabled;
3848
private readonly ObservableAsPropertyHelper<bool> _isFlashButtonEnabled;
3949

50+
private CompressionType _compressionType;
51+
4052
private bool _isSaveGzipFileChecked;
4153
private bool _isSaveRawFileChecked = true;
54+
private bool _isSaveZstandardFileChecked;
55+
private bool _isSaveLz4FileChecked;
4256
private bool _isBackgroundTaskRunning;
4357

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

67-
_compressionType = this
68-
.WhenAnyValue(vm => vm.IsSaveRawFileChecked,
69-
vm => vm.IsSaveGzipFileChecked)
70-
.Select(tuple =>
81+
// Subscribe to update compression type by clicking button
82+
this
83+
.WhenAnyValue(vm => vm.IsSaveRawFileChecked)
84+
.Subscribe(enabled =>
7185
{
72-
var (rawChecked, gzipChecked) = tuple;
73-
if (rawChecked)
74-
return CompressionType.Raw;
75-
if (gzipChecked)
76-
return CompressionType.GzipCompress;
77-
return CompressionType.Raw;
78-
})
79-
.ToProperty(this, vm => vm.CompressionType);
86+
if (enabled) CompressionType = CompressionType.Raw;
87+
});
88+
89+
this
90+
.WhenAnyValue(vm => vm.IsSaveGzipFileChecked)
91+
.Subscribe(enabled =>
92+
{
93+
if (enabled) CompressionType = CompressionType.GzipCompress;
94+
});
8095

96+
this
97+
.WhenAnyValue(vm => vm.IsSaveLz4FileChecked)
98+
.Subscribe(enabled =>
99+
{
100+
if (enabled) CompressionType = CompressionType.Lz4Compress;
101+
});
102+
103+
this
104+
.WhenAnyValue(vm => vm.IsSaveZstandardFileChecked)
105+
.Subscribe(enabled =>
106+
{
107+
if (enabled) CompressionType = CompressionType.ZstandardCompress;
108+
});
109+
110+
//Subscribe to update file name after compression type updated
81111
this
82112
.WhenAnyValue(vm => vm.CompressionType)
83113
.Subscribe(type =>
84114
{
85115
var ending = RawTrimEndings.FirstOrDefault(e => SavePartitionFileName.EndsWith(e));
86116
var rawFileName = ending == null ? SavePartitionFileName : SavePartitionFileName[..^ending.Length];
87-
switch (CompressionType)
117+
switch (type)
88118
{
89119
case CompressionType.Raw:
90120
if (!string.IsNullOrWhiteSpace(rawFileName))
91121
SavePartitionFileName = rawFileName;
92122
break;
93123
case CompressionType.GzipCompress:
94124
if (!string.IsNullOrWhiteSpace(rawFileName))
95-
SavePartitionFileName = rawFileName + ".gz";
125+
SavePartitionFileName = rawFileName + FileNameHelpers.FileExtensionGzip;
96126
break;
97127
case CompressionType.Lz4Compress:
98128
if (!string.IsNullOrWhiteSpace(rawFileName))
99-
SavePartitionFileName = rawFileName + ".lz4";
129+
SavePartitionFileName = rawFileName + FileNameHelpers.FileExtensionLz4;
130+
break;
131+
case CompressionType.ZstandardCompress:
132+
if (!string.IsNullOrWhiteSpace(rawFileName))
133+
SavePartitionFileName = rawFileName + FileNameHelpers.FileExtensionZstandard;
100134
break;
101135
default:
102136
throw new ArgumentOutOfRangeException();
103137
}
104138
});
105139

140+
// Subscribe to update button status after file name updated
106141
this
107142
.WhenAnyValue(vm => vm.SavePartitionFileName)
108143
.Subscribe(name =>
109144
{
110-
if (name.EndsWith(".gz"))
145+
if (name.EndsWith(FileNameHelpers.FileExtensionGzip))
111146
IsSaveGzipFileChecked = true;
147+
else if (name.EndsWith(FileNameHelpers.FileExtensionLz4))
148+
IsSaveLz4FileChecked = true;
149+
else if (name.EndsWith(FileNameHelpers.FileExtensionZstandard))
150+
IsSaveZstandardFileChecked = true;
112151
else
113152
IsSaveRawFileChecked = true;
114153
});
@@ -139,6 +178,18 @@ public MainWindowViewModel(
139178
.ToProperty(this, vm => vm.IsFlashButtonEnabled);
140179
}
141180

181+
public bool IsSaveZstandardFileChecked
182+
{
183+
get => _isSaveZstandardFileChecked;
184+
set => this.RaiseAndSetIfChanged(ref _isSaveZstandardFileChecked, value);
185+
}
186+
187+
public bool IsSaveLz4FileChecked
188+
{
189+
get => _isSaveLz4FileChecked;
190+
set => this.RaiseAndSetIfChanged(ref _isSaveLz4FileChecked, value);
191+
}
192+
142193
public bool IsFlashButtonEnabled => _isFlashButtonEnabled.Value;
143194

144195
public int Progress
@@ -198,7 +249,11 @@ public List<PartitionItemViewModel> PartitionItems
198249
public ReactiveCommand<Visual?, Unit> SavePartitionCommand { get; }
199250
public ReactiveCommand<Visual?, Unit> FlashPartitionCommand { get; }
200251

201-
private CompressionType CompressionType => _compressionType.Value;
252+
private CompressionType CompressionType
253+
{
254+
get => _compressionType;
255+
set => this.RaiseAndSetIfChanged(ref _compressionType, value);
256+
}
202257

203258
private static Window? GetVisualTopWindow(Visual? visual)
204259
{

WinPartFlash.Gui/Views/MainWindow.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
<!-- Below are image file types and should not localize. -->
6060
<RadioButton Content="raw" IsChecked="{Binding IsSaveRawFileChecked}" />
6161
<RadioButton Content="gz" IsChecked="{Binding IsSaveGzipFileChecked}" />
62-
<RadioButton Content="lz4" IsEnabled="False" />
62+
<RadioButton Content="lz4" IsChecked="{Binding IsSaveLz4FileChecked}" />
63+
<RadioButton Content="zst" IsChecked="{Binding IsSaveZstandardFileChecked}" />
6364
</StackPanel>
6465

6566
<ProgressBar Margin="0 0 0 10"

0 commit comments

Comments
 (0)