diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/RpmInfoPanel.xaml b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/RpmInfoPanel.xaml
new file mode 100644
index 0000000..1605e82
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/RpmInfoPanel.xaml
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/RpmInfoPanel.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/RpmInfoPanel.xaml.cs
new file mode 100644
index 0000000..79cd9fe
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/RpmInfoPanel.xaml.cs
@@ -0,0 +1,93 @@
+// 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 .
+
+using QuickLook.Common.ExtensionMethods;
+using QuickLook.Common.Helpers;
+using QuickLook.Common.Plugin;
+using QuickLook.Plugin.AppViewer.PackageParsers.AppImage;
+using QuickLook.Plugin.AppViewer.PackageParsers.Rpm;
+using System;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+
+namespace QuickLook.Plugin.AppViewer.InfoPanels;
+
+public partial class RpmInfoPanel : UserControl, IAppInfoPanel
+{
+ private readonly ContextObject _context;
+
+ public RpmInfoPanel(ContextObject context)
+ {
+ _context = context;
+
+ DataContext = this;
+ InitializeComponent();
+
+ string translationFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Translations.config");
+ applicationNameTitle.Text = TranslationHelper.Get("APP_NAME", translationFile);
+ versionTitle.Text = TranslationHelper.Get("APP_VERSION", translationFile);
+ architectureTitle.Text = TranslationHelper.Get("ARCHITECTURE", translationFile);
+ typeTitle.Text = TranslationHelper.Get("TYPE", translationFile);
+ terminalTitle.Text = TranslationHelper.Get("TERMINAL", translationFile);
+ totalSizeTitle.Text = TranslationHelper.Get("TOTAL_SIZE", translationFile);
+ modDateTitle.Text = TranslationHelper.Get("LAST_MODIFIED", translationFile);
+ environmentGroupBox.Header = TranslationHelper.Get("ENVIRONMENT", translationFile);
+ }
+
+ public void DisplayInfo(string path)
+ {
+ var name = Path.GetFileName(path);
+ filename.Text = string.IsNullOrEmpty(name) ? path : name;
+
+ _ = Task.Run(() =>
+ {
+ if (File.Exists(path))
+ {
+ var size = new FileInfo(path).Length;
+ RpmInfo rpmInfo = RpmParser.Parse(path);
+ var last = File.GetLastWriteTime(path);
+
+ Dispatcher.Invoke(() =>
+ {
+ applicationName.Text = rpmInfo.Name;
+ version.Text = rpmInfo.Version;
+ architectureName.Text = rpmInfo.Arch;
+ type.Text = rpmInfo.Type;
+ terminal.Text = rpmInfo.Terminal;
+ totalSize.Text = size.ToPrettySize(2);
+ modDate.Text = last.ToString(CultureInfo.CurrentCulture);
+ permissions.ItemsSource = rpmInfo.Env;
+
+ if (rpmInfo.HasIcon)
+ {
+ image.Source = rpmInfo.Logo.ToBitmapSource();
+ }
+ else
+ {
+ image.Source = new BitmapImage(new Uri("pack://application:,,,/QuickLook.Plugin.AppViewer;component/Resources/rpm.png"));
+ }
+
+ _context.IsBusy = false;
+ });
+ }
+ });
+ }
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmInfo.cs
new file mode 100644
index 0000000..8f65de7
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmInfo.cs
@@ -0,0 +1,43 @@
+// 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 .
+
+using System.Drawing;
+
+namespace QuickLook.Plugin.AppViewer.PackageParsers.Rpm;
+
+public class RpmInfo
+{
+ public string Arch { get; set; }
+
+ public string Version { get; set; }
+
+ public string Name { get; set; }
+
+ public string Exec { get; set; }
+
+ public string Icon { get; set; }
+
+ public Bitmap Logo { get; set; }
+
+ public bool HasIcon => !string.IsNullOrEmpty(Icon) && Logo != null;
+
+ public string Type { get; set; }
+
+ public string Terminal { get; set; }
+
+ public string[] Env { get; set; }
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmParser.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmParser.cs
new file mode 100644
index 0000000..f3a4327
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmParser.cs
@@ -0,0 +1,41 @@
+// 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 .
+
+using QuickLook.Plugin.AppViewer.PackageParsers.AppImage;
+
+namespace QuickLook.Plugin.AppViewer.PackageParsers.Rpm;
+
+public class RpmParser
+{
+ public static RpmInfo Parse(string path)
+ {
+ var reader = new RpmReader(path);
+
+ return new RpmInfo()
+ {
+ Arch = reader.Arch,
+ Version = reader.Version,
+ Name = reader.Name,
+ Exec = reader.Exec,
+ Icon = reader.Icon,
+ Logo = reader.Logo,
+ Type = reader.Type,
+ Terminal = reader.Terminal,
+ Env = reader.Env,
+ };
+ }
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmReader.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmReader.cs
new file mode 100644
index 0000000..0056a96
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Rpm/RpmReader.cs
@@ -0,0 +1,117 @@
+// 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 .
+
+using PureSharpCompress.Common;
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Text;
+
+namespace QuickLook.Plugin.AppViewer.PackageParsers.Rpm;
+
+public class RpmReader
+{
+ public string Arch { get; set; }
+
+ public string Version { get; set; }
+
+ public string Name { get; set; }
+
+ public string Exec { get; set; }
+
+ public string Icon { get; set; }
+
+ public Bitmap Logo { get; set; }
+
+ public string Type { get; set; }
+
+ public string Terminal { get; set; }
+
+ public string[] Env { get; set; }
+
+ public RpmReader(Stream stream)
+ {
+ Open(stream);
+ }
+
+ public RpmReader(string path)
+ {
+ using FileStream fs = File.OpenRead(path);
+ Open(fs);
+ }
+
+ private void Open(Stream stream)
+ {
+ using var br = new BinaryReader(stream);
+
+ // Step 1: Read the lead (96 bytes)
+ byte[] lead = br.ReadBytes(96);
+ Debug.WriteLine($"[lead] 96 bytes read, magic: {BitConverter.ToString(lead, 0, 4)}");
+
+ // Step 2: Read signature header
+ RpmHeader sigHeader = ReadHeader(br);
+ Debug.WriteLine($"[signature header] IndexCount: {sigHeader.IndexCount}, DataSize: {sigHeader.DataSize}");
+
+ // Step 3: Read main header
+ RpmHeader mainHeader = ReadHeader(br);
+ Debug.WriteLine($"[main header] IndexCount: {mainHeader.IndexCount}, DataSize: {mainHeader.DataSize}");
+
+ // Step 4: Remaining is the payload (cpio archive + compression)
+ long payloadSize = stream.Length - stream.Position;
+ Debug.WriteLine($"[payload] Size: {payloadSize} bytes at offset: {stream.Position}");
+
+ // (Optional) Detect compression (e.g. gzip, xz, zstd)
+ byte[] magic = br.ReadBytes(6);
+ string type = magic[0] switch
+ {
+ 0x1F when magic[1] == 0x8B => "gzip",
+ 0xFD when magic[1] == 0x37 => "xz",
+ 0x28 when magic[1] == 0xB5 => "zstd",
+ _ => "unknown"
+ };
+ Debug.WriteLine($"Detected payload compression: {type}");
+ }
+
+ private static RpmHeader ReadHeader(BinaryReader br)
+ {
+ // ed ab ee db 03
+ byte[] magic = br.ReadBytes(3);
+ //if (Encoding.ASCII.GetString(magic) != "\x8e\xad\xe8")
+ //throw new InvalidDataException("Invalid RPM header magic");
+
+ byte version = br.ReadByte(); // Usually 1
+ byte[] reserved = br.ReadBytes(4);
+ int indexCount = ReadBigEndianInt32(br);
+ int dataSize = ReadBigEndianInt32(br);
+ return new RpmHeader { IndexCount = indexCount, DataSize = dataSize };
+ }
+
+ private static int ReadBigEndianInt32(BinaryReader br)
+ {
+ byte[] b = br.ReadBytes(4);
+ if (b.Length < 4) throw new EndOfStreamException();
+ return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+ }
+
+ private class RpmHeader
+ {
+ public int IndexCount { get; set; }
+
+ public int DataSize { get; set; }
+ }
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs
index 9e57119..eb9430e 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs
@@ -51,6 +51,7 @@ public class Plugin : IViewer
// Ubuntu
".deb", // Debian Package
".appimage", // AppImage Format
+ // ".rpm", // Red Hat Package Manager
// Others
".wgt", ".wgtu", // UniApp Widget
@@ -82,6 +83,7 @@ public class Plugin : IViewer
".deb" => new Size { Width = 600, Height = 345 },
".dmg" => new Size { Width = 560, Height = 510 },
".appimage" => new Size { Width = 600, Height = 300 },
+ ".rpm" => new Size { Width = 600, Height = 300 },
".wgt" or ".wgtu" => new Size { Width = 600, Height = 345 },
_ => throw new NotSupportedException("Extension is not supported."),
};
@@ -105,6 +107,7 @@ public class Plugin : IViewer
".deb" => new DebInfoPanel(context),
".dmg" => new DmgInfoPanel(context),
".appimage" => new AppImageInfoPanel(context),
+ ".rpm" => new RpmInfoPanel(context),
".wgt" or ".wgtu" => new WgtInfoPanel(context),
_ => throw new NotSupportedException("Extension is not supported."),
};
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Resources/rpm.png b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Resources/rpm.png
new file mode 100644
index 0000000..b153973
Binary files /dev/null and b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Resources/rpm.png differ