Skip to content

Commit ace64fb

Browse files
authored
Added support for more archive types using 7zip (#9633)
1 parent 2f1ebf0 commit ace64fb

30 files changed

+612
-404
lines changed

src/Files.FullTrust/MessageHandlers/Win32MessageHandler.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ public async Task ParseArgumentsAsync(PipeStream connection, Dictionary<string,
8181
var fileIconPath = (string)message["filePath"];
8282
var thumbnailSize = (int)(long)message["thumbnailSize"];
8383
var isOverlayOnly = (bool)message["isOverlayOnly"];
84-
var (icon, overlay) = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath, thumbnailSize, true, isOverlayOnly));
84+
var isFolder = (bool)message["isFolder"];
85+
var (icon, overlay) = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath, thumbnailSize, isFolder, true, isOverlayOnly));
8586
await Win32API.SendMessageAsync(connection, new ValueSet()
8687
{
8788
{ "Icon", icon },
@@ -92,7 +93,8 @@ public async Task ParseArgumentsAsync(PipeStream connection, Dictionary<string,
9293
case "GetIconWithoutOverlay":
9394
var fileIconPath2 = (string)message["filePath"];
9495
var thumbnailSize2 = (int)(long)message["thumbnailSize"];
95-
var icon2 = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath2, thumbnailSize2, false));
96+
var isFolder2 = (bool)message["isFolder"];
97+
var icon2 = await Win32API.StartSTATask(() => Win32API.GetFileIconAndOverlay(fileIconPath2, thumbnailSize2, isFolder2, false));
9698
await Win32API.SendMessageAsync(connection, new ValueSet()
9799
{
98100
{ "Icon", icon2.icon },

src/Files.FullTrust/Win32API.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public static string[] CommandLineToArgs(string commandLine)
163163

164164
private static readonly object lockObject = new object();
165165

166-
public static (string icon, string overlay) GetFileIconAndOverlay(string path, int thumbnailSize, bool getOverlay = true, bool onlyGetOverlay = false)
166+
public static (string icon, string overlay) GetFileIconAndOverlay(string path, int thumbnailSize, bool isFolder, bool getOverlay = true, bool onlyGetOverlay = false)
167167
{
168168
string iconStr = null, overlayStr = null;
169169

@@ -195,8 +195,7 @@ public static (string icon, string overlay) GetFileIconAndOverlay(string path, i
195195
var useFileAttibutes = !onlyGetOverlay && iconStr == null; // Cannot access file, use file attributes
196196
var ret = ShellFolderExtensions.GetStringAsPidl(path, out var pidl) ?
197197
Shell32.SHGetFileInfo(pidl, 0, ref shfi, Shell32.SHFILEINFO.Size, Shell32.SHGFI.SHGFI_PIDL | flags) :
198-
// TODO: pass FileAttributes.Directory for folders (add "isFolder" parameter)
199-
Shell32.SHGetFileInfo(path, 0, ref shfi, Shell32.SHFILEINFO.Size, flags | (useFileAttibutes ? Shell32.SHGFI.SHGFI_USEFILEATTRIBUTES : 0));
198+
Shell32.SHGetFileInfo(path, isFolder ? FileAttributes.Directory : 0, ref shfi, Shell32.SHFILEINFO.Size, flags | (useFileAttibutes ? Shell32.SHGFI.SHGFI_USEFILEATTRIBUTES : 0));
200199
if (ret == IntPtr.Zero)
201200
{
202201
return (iconStr, null);
@@ -235,6 +234,13 @@ public static (string icon, string overlay) GetFileIconAndOverlay(string path, i
235234
}
236235
}
237236
}
237+
else if (isFolder)
238+
{
239+
// Could not icon, load generic icon
240+
var icons = ExtractSelectedIconsFromDLL(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "imageres.dll"), new[] { 2 }, thumbnailSize);
241+
var generic = icons.SingleOrDefault(x => x.Index == 2);
242+
iconStr = generic?.IconData;
243+
}
238244
else
239245
{
240246
// Could not icon, load generic icon

src/Files.Package/7z.dll

1.1 MB
Binary file not shown.

src/Files.Package/7z64.dll

1.61 MB
Binary file not shown.

src/Files.Package/Files.Package.wapproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@
100100
<ProjectReference Include="..\Files.FullTrust\Files.FullTrust.csproj" />
101101
</ItemGroup>
102102
<ItemGroup>
103+
<Content Include="7z.dll">
104+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
105+
</Content>
106+
<Content Include="7z64.dll">
107+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
108+
</Content>
103109
<Content Include="Assets\AppTilesDev\BadgeLogo.scale-100.png" />
104110
<Content Include="Assets\AppTilesDev\BadgeLogo.scale-125.png" />
105111
<Content Include="Assets\AppTilesDev\BadgeLogo.scale-150.png" />
@@ -482,11 +488,11 @@
482488
<Content Include="Assets\AppTilesDev\Wide310x150Logo.scale-150.png" />
483489
<Content Include="Assets\AppTilesDev\Wide310x150Logo.scale-200.png" />
484490
<Content Include="Assets\AppTilesDev\Wide310x150Logo.scale-400.png" />
491+
<None Include="nupkgs\SevenZipSharp.1.0.0.nupkg" />
485492
<Content Include="Package.appinstaller" />
486493
</ItemGroup>
487494
<ItemGroup>
488495
<None Include="nupkgs\microsoft.management.infrastructure.runtime.win.2.0.1.nupkg" />
489-
<None Include="nupkgs\SharpZipLib.1.3.4.nupkg" />
490496
</ItemGroup>
491497
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
492498
</Project>

src/Files.Package/Package.appxmanifest

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@
6969
</uap5:Extension>
7070
<Extension Category="windows.updateTask" EntryPoint="BackgroundTasks.UpdateTask" />
7171
<uap:Extension Category="windows.fileTypeAssociation">
72-
<uap:FileTypeAssociation Name="zip">
72+
<uap:FileTypeAssociation Name="archives">
7373
<uap:SupportedFileTypes>
7474
<uap:FileType>.zip</uap:FileType>
75+
<uap:FileType>.7z</uap:FileType>
76+
<uap:FileType>.rar</uap:FileType>
77+
<uap:FileType>.tar</uap:FileType>
7578
</uap:SupportedFileTypes>
7679
</uap:FileTypeAssociation>
7780
</uap:Extension>
Binary file not shown.
-651 KB
Binary file not shown.

src/Files.Shared/Extensions/LinqExtensions.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ public static class LinqExtensions
4242
return defaultValue;
4343
}
4444

45+
public static async Task<TValue?> GetAsync<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<Task<TValue?>> defaultValueFunc)
46+
{
47+
if (dictionary is null || key is null)
48+
{
49+
return await defaultValueFunc();
50+
}
51+
if (!dictionary.ContainsKey(key))
52+
{
53+
var defaultValue = await defaultValueFunc();
54+
if (defaultValue is TValue value)
55+
{
56+
dictionary.Add(key, value);
57+
}
58+
return defaultValue;
59+
}
60+
return dictionary[key];
61+
}
62+
4563
public static async Task<IEnumerable<T>> WhereAsync<T>(this IEnumerable<T> source, Func<T, Task<bool>> predicate)
4664
{
4765
var results = await Task.WhenAll(source.Select(async x => (x, await predicate(x))));

src/Files.Uwp/Files.Uwp.csproj

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,15 +1595,12 @@
15951595
<PackageReference Include="Newtonsoft.Json">
15961596
<Version>13.0.1</Version>
15971597
</PackageReference>
1598-
<PackageReference Include="SharpZipLib">
1599-
<Version>1.3.4</Version>
1598+
<PackageReference Include="SevenZipSharp">
1599+
<Version>1.0.0</Version>
16001600
</PackageReference>
16011601
<PackageReference Include="SQLitePCLRaw.bundle_green">
16021602
<Version>2.1.0</Version>
16031603
</PackageReference>
1604-
<PackageReference Include="Ude.NetStandard">
1605-
<Version>1.2.0</Version>
1606-
</PackageReference>
16071604
</ItemGroup>
16081605
<ItemGroup>
16091606
<AppxManifest Include="..\Files.Package\Package.appxmanifest">
@@ -1629,7 +1626,6 @@
16291626
<Name>Windows Desktop Extensions for the UWP</Name>
16301627
</SDKReference>
16311628
</ItemGroup>
1632-
<ItemGroup />
16331629
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '17.0' ">
16341630
<VisualStudioVersion>17.0</VisualStudioVersion>
16351631
</PropertyGroup>

src/Files.Uwp/Filesystem/BaseStorage/BaseStorageFile.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public static IAsyncOperation<BaseStorageFile> GetFileFromPathAsync(string path)
9595

9696
public async Task<string> ReadTextAsync(int maxLength = -1)
9797
{
98-
using var inputStream = await OpenSequentialReadAsync();
98+
using var inputStream = await OpenReadAsync();
9999
using var dataReader = new DataReader(inputStream);
100100
StringBuilder builder = new();
101101
uint bytesRead, bytesToRead;
@@ -104,7 +104,7 @@ public async Task<string> ReadTextAsync(int maxLength = -1)
104104
bytesToRead = maxLength < 0 ? 4096 : (uint)Math.Min(maxLength, 4096);
105105
bytesRead = await dataReader.LoadAsync(bytesToRead);
106106
builder.Append(dataReader.ReadString(bytesRead));
107-
} while (bytesRead > 0);
107+
} while (bytesRead > 0 && inputStream.Position < inputStream.Size);
108108
return builder.ToString();
109109
}
110110

src/Files.Uwp/Filesystem/BaseStorage/IBaseStorageFolder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.IO;
23
using Windows.Foundation;
34
using Windows.Storage;
45
using Windows.Storage.FileProperties;
@@ -38,4 +39,11 @@ public interface IBaseStorageFolder : IStorageItem2, IStorageFolder, IStorageFol
3839
new BaseStorageFileQueryResult CreateFileQueryWithOptions(QueryOptions queryOptions);
3940
new BaseStorageFolderQueryResult CreateFolderQueryWithOptions(QueryOptions queryOptions);
4041
}
42+
43+
public interface ICreateFileWithStream
44+
{
45+
IAsyncOperation<BaseStorageFile> CreateFileAsync(Stream contents, string desiredName);
46+
47+
IAsyncOperation<BaseStorageFile> CreateFileAsync(Stream contents, string desiredName, CreationCollisionOption options);
48+
}
4149
}

src/Files.Uwp/Filesystem/Search/FolderSearch.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,8 @@ private ListedItem GetListedItemAsync(string itemPath, WIN32_FIND_DATA findData)
349349
{
350350
ListedItem listedItem = null;
351351
var isHidden = ((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden;
352-
if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) != FileAttributes.Directory)
352+
var isFolder = ((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory;
353+
if (!isFolder)
353354
{
354355
string itemFileExtension = null;
355356
string itemType = null;
@@ -371,7 +372,7 @@ private ListedItem GetListedItemAsync(string itemPath, WIN32_FIND_DATA findData)
371372
Opacity = isHidden ? Constants.UI.DimItemOpacity : 1
372373
};
373374
}
374-
else if (((FileAttributes)findData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
375+
else
375376
{
376377
if (findData.cFileName != "." && findData.cFileName != "..")
377378
{
@@ -388,7 +389,7 @@ private ListedItem GetListedItemAsync(string itemPath, WIN32_FIND_DATA findData)
388389
}
389390
if (listedItem != null && MaxItemCount > 0) // Only load icon for searchbox suggestions
390391
{
391-
_ = FileThumbnailHelper.LoadIconFromPathAsync(listedItem.ItemPath, ThumbnailSize, ThumbnailMode.ListView)
392+
_ = FileThumbnailHelper.LoadIconFromPathAsync(listedItem.ItemPath, ThumbnailSize, ThumbnailMode.ListView, isFolder)
392393
.ContinueWith((t) =>
393394
{
394395
if (t.IsCompletedSuccessfully && t.Result != null)

src/Files.Uwp/Filesystem/StorageEnumerators/Win32StorageEnumerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ CancellationToken cancellationToken
368368
}
369369
else
370370
{
371-
if (".zip".Equals(itemFileExtension, StringComparison.OrdinalIgnoreCase) && await ZipStorageFolder.CheckDefaultZipApp(itemPath))
371+
if (ZipStorageFolder.IsZipPath(itemPath) && await ZipStorageFolder.CheckDefaultZipApp(itemPath))
372372
{
373373
return new ZipItem(null)
374374
{

src/Files.Uwp/Filesystem/StorageItems/FtpStorageFile.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,18 @@ public override IAsyncOperation<BaseStorageFile> CopyAsync(IStorageFolder destin
165165
}
166166

167167
BaseStorageFolder destFolder = destinationFolder.AsBaseStorageFolder();
168-
BaseStorageFile file = await destFolder.CreateFileAsync(desiredNewName, option.Convert());
169168

170-
var stream = await file.OpenStreamForWriteAsync();
171-
return await ftpClient.DownloadAsync(stream, FtpPath, token: cancellationToken) ? file : null;
169+
if (destFolder is ICreateFileWithStream cwsf)
170+
{
171+
using var inStream = await ftpClient.OpenReadAsync(FtpPath, cancellationToken);
172+
return await cwsf.CreateFileAsync(inStream, desiredNewName, option.Convert());
173+
}
174+
else
175+
{
176+
BaseStorageFile file = await destFolder.CreateFileAsync(desiredNewName, option.Convert());
177+
using var stream = await file.OpenStreamForWriteAsync();
178+
return await ftpClient.DownloadAsync(stream, FtpPath, token: cancellationToken) ? file : null;
179+
}
172180
});
173181
}
174182

src/Files.Uwp/Filesystem/StorageItems/SystemStorageFile.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,22 @@ public override IAsyncOperation<BaseStorageFile> CopyAsync(IStorageFolder destin
6969
// File created by CreateFileAsync will get immediately deleted on MTP?! (#7206)
7070
return await File.CopyAsync(sysFolder.Folder, desiredNewName, option);
7171
}
72-
var destFile = await destFolder.CreateFileAsync(desiredNewName, option.Convert());
73-
using (var inStream = await this.OpenStreamForReadAsync())
74-
using (var outStream = await destFile.OpenStreamForWriteAsync())
72+
else if (destFolder is ICreateFileWithStream cwsf)
7573
{
76-
await inStream.CopyToAsync(outStream);
77-
await outStream.FlushAsync();
74+
using var inStream = await this.OpenStreamForReadAsync();
75+
return await cwsf.CreateFileAsync(inStream, desiredNewName, option.Convert());
76+
}
77+
else
78+
{
79+
var destFile = await destFolder.CreateFileAsync(desiredNewName, option.Convert());
80+
using (var inStream = await this.OpenStreamForReadAsync())
81+
using (var outStream = await destFile.OpenStreamForWriteAsync())
82+
{
83+
await inStream.CopyToAsync(outStream);
84+
await outStream.FlushAsync();
85+
}
86+
return destFile;
7887
}
79-
return destFile;
8088
}
8189
catch (UnauthorizedAccessException ex) // shortcuts & .url
8290
{

0 commit comments

Comments
 (0)