mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-18 22:52:37 +00:00
Restruct AppViewer codes
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer.PackageParsers.Appx;
|
||||
|
||||
public class AppxBundleReader : IDisposable
|
||||
{
|
||||
private ZipFile zip;
|
||||
private AppxReader appxReader = null;
|
||||
|
||||
private string name;
|
||||
private string publisher;
|
||||
private string version;
|
||||
|
||||
public string Name => name ?? appxReader?.Name;
|
||||
public string Publisher => publisher ?? appxReader?.Publisher;
|
||||
public string Version => version ?? appxReader?.Version;
|
||||
public string DisplayName => appxReader?.DisplayName;
|
||||
public string PublisherDisplayName => appxReader?.PublisherDisplayName;
|
||||
public string Description => appxReader?.Description;
|
||||
public string Logo => appxReader?.Logo;
|
||||
public string[] Capabilities => appxReader?.Capabilities;
|
||||
public Bitmap Icon => appxReader?.Icon;
|
||||
|
||||
public AppxBundleReader(Stream stream)
|
||||
{
|
||||
Open(stream);
|
||||
}
|
||||
|
||||
public AppxBundleReader(string path)
|
||||
{
|
||||
Open(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
appxReader?.Dispose();
|
||||
appxReader = null;
|
||||
zip?.Close();
|
||||
zip = null;
|
||||
}
|
||||
|
||||
private void Open(Stream stream)
|
||||
{
|
||||
zip = new ZipFile(stream);
|
||||
ZipEntry entry = zip.GetEntry("AppxMetadata/AppxBundleManifest.xml")
|
||||
?? throw new InvalidDataException("AppxMetadata/AppxBundleManifest.xml not found");
|
||||
|
||||
XmlDocument xml = new() { XmlResolver = null };
|
||||
xml.Load(zip.GetInputStream(entry));
|
||||
|
||||
XmlElement bundleNode = xml.DocumentElement;
|
||||
|
||||
// Identity
|
||||
{
|
||||
XmlElement identityNode = bundleNode["Identity"];
|
||||
|
||||
if (identityNode != null)
|
||||
{
|
||||
name = identityNode.Attributes["Name"]?.Value;
|
||||
version = identityNode.Attributes["Version"]?.Value;
|
||||
publisher = identityNode.Attributes["Publisher"]?.Value;
|
||||
|
||||
Match m = Regex.Match(Publisher, @"CN=([^,]*),?");
|
||||
if (m.Success) publisher = m.Groups[1].Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Packages
|
||||
{
|
||||
XmlElement packagesNode = bundleNode["Packages"];
|
||||
|
||||
if (packagesNode != null)
|
||||
{
|
||||
string arch = RuntimeInformation.OSArchitecture == Architecture.Arm64
|
||||
? "arm64"
|
||||
: Environment.Is64BitProcess ? "x64" : "x86";
|
||||
|
||||
var packages = packagesNode.ChildNodes.Select(package =>
|
||||
{
|
||||
return new
|
||||
{
|
||||
Type = package.Attributes["Type"]?.Value,
|
||||
Architecture = package.Attributes["Architecture"]?.Value,
|
||||
FileName = package.Attributes["FileName"]?.Value,
|
||||
Version = package.Attributes["Version"]?.Value
|
||||
};
|
||||
});
|
||||
|
||||
var package = packages
|
||||
.Where(p => p.Type == "application" && p.Architecture == arch)
|
||||
.FirstOrDefault() ?? packages.FirstOrDefault();
|
||||
|
||||
if (package != null)
|
||||
{
|
||||
appxReader = new AppxReader(zip.GetInputStream(zip.GetEntry(package.FileName)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file static class LinqExtension
|
||||
{
|
||||
public static IEnumerable<dynamic> Select(this XmlNodeList nodes, Func<XmlNode, dynamic> selector)
|
||||
{
|
||||
foreach (XmlNode node in nodes)
|
||||
{
|
||||
yield return selector(node);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Drawing;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer.PackageParsers.Appx;
|
||||
|
||||
public class AppxInfo
|
||||
{
|
||||
public string ProductName { get; set; }
|
||||
|
||||
public string ProductVersion { get; set; }
|
||||
|
||||
public string Publisher { get; set; }
|
||||
|
||||
public Bitmap Logo { get; set; }
|
||||
|
||||
public string[] Capabilities { get; set; }
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer.PackageParsers.Appx;
|
||||
|
||||
public static class AppxParser
|
||||
{
|
||||
public static AppxInfo Parse(string path)
|
||||
{
|
||||
bool isBundle = Path.GetExtension(path).ToLower() switch
|
||||
{
|
||||
".msixbundle" or ".appxbundle" => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if (isBundle)
|
||||
{
|
||||
AppxBundleReader appxReader = new(path);
|
||||
|
||||
return new AppxInfo
|
||||
{
|
||||
ProductName = appxReader.DisplayName,
|
||||
ProductVersion = appxReader.Version,
|
||||
Publisher = appxReader.Publisher,
|
||||
Logo = appxReader.Icon,
|
||||
Capabilities = appxReader.Capabilities,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
AppxReader appxReader = new(path);
|
||||
|
||||
return new AppxInfo
|
||||
{
|
||||
ProductName = appxReader.DisplayName,
|
||||
ProductVersion = appxReader.Version,
|
||||
Publisher = appxReader.Publisher,
|
||||
Logo = appxReader.Icon,
|
||||
Capabilities = appxReader.Capabilities,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,155 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer.PackageParsers.Appx;
|
||||
|
||||
public class AppxReader : IDisposable
|
||||
{
|
||||
private ZipFile zip;
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Publisher { get; set; }
|
||||
public string Version { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string PublisherDisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Logo { get; set; }
|
||||
public string[] Capabilities { get; set; }
|
||||
|
||||
public Bitmap Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Logo)) return null;
|
||||
|
||||
string extension = Path.GetExtension(Logo);
|
||||
string name = Logo.Substring(0, Logo.Length - extension.Length);
|
||||
|
||||
ZipEntry logoEntry = null;
|
||||
int logoScale = 0;
|
||||
|
||||
foreach (ZipEntry entry in zip)
|
||||
{
|
||||
Match m = Regex.Match(entry.Name, @$"{name}(\.scale\-(\d+))?{extension}");
|
||||
|
||||
if (m.Success)
|
||||
{
|
||||
if (int.TryParse(m.Groups[2].Value, out int currentScale))
|
||||
{
|
||||
if (currentScale > logoScale)
|
||||
{
|
||||
logoEntry = entry;
|
||||
logoScale = currentScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (logoEntry != null)
|
||||
{
|
||||
return new Bitmap(zip.GetInputStream(logoEntry));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public AppxReader(Stream stream)
|
||||
{
|
||||
zip = new ZipFile(stream);
|
||||
Open();
|
||||
}
|
||||
|
||||
public AppxReader(string path)
|
||||
{
|
||||
zip = new ZipFile(path);
|
||||
Open();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
zip?.Close();
|
||||
zip = null;
|
||||
}
|
||||
|
||||
private void Open()
|
||||
{
|
||||
ZipEntry entry = zip.GetEntry("AppxManifest.xml")
|
||||
?? throw new InvalidDataException("AppxManifest.xml not found");
|
||||
|
||||
XmlDocument xml = new() { XmlResolver = null };
|
||||
xml.Load(zip.GetInputStream(entry));
|
||||
|
||||
XmlElement packageNode = xml.DocumentElement;
|
||||
|
||||
// Identity
|
||||
{
|
||||
XmlElement identityNode = packageNode["Identity"];
|
||||
|
||||
if (identityNode != null)
|
||||
{
|
||||
Name = identityNode.Attributes["Name"]?.Value;
|
||||
Version = identityNode.Attributes["Version"]?.Value;
|
||||
Publisher = identityNode.Attributes["Publisher"]?.Value;
|
||||
|
||||
Match m = Regex.Match(Publisher, @"CN=([^,]*),?");
|
||||
if (m.Success) Publisher = m.Groups[1].Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Properties
|
||||
{
|
||||
XmlElement propertiesNode = packageNode["Properties"];
|
||||
|
||||
if (propertiesNode != null)
|
||||
{
|
||||
DisplayName = propertiesNode["DisplayName"]?.FirstChild?.Value;
|
||||
PublisherDisplayName = propertiesNode["PublisherDisplayName"]?.FirstChild?.Value;
|
||||
Description = propertiesNode["Description"]?.FirstChild?.Value;
|
||||
Logo = propertiesNode["Logo"]?.FirstChild?.Value.Replace(@"\", "/");
|
||||
}
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
{
|
||||
XmlElement capabilitiesNode = packageNode["Capabilities"];
|
||||
|
||||
if (capabilitiesNode != null)
|
||||
{
|
||||
Capabilities = [.. capabilitiesNode.ChildNodes.Select(capability => capability.Attributes["Name"]?.Value)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file static class LinqExtension
|
||||
{
|
||||
public static IEnumerable<dynamic> Select(this XmlNodeList nodes, Func<XmlNode, dynamic> selector)
|
||||
{
|
||||
foreach (XmlNode node in nodes)
|
||||
{
|
||||
yield return selector(node);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user