vendor: import KillerPDF 1.7.5 source (GPL-3.0) as the base for MMD PDF

This commit is contained in:
2026-08-27 06:58:22 +02:00
commit 532485a830
577 changed files with 149058 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
using System;
using System.Diagnostics;
using Microsoft.Win32;
namespace KillerPDF.Services
{
internal static class ProtocolRegistrar
{
internal const string Scheme = "killerpdf";
private const string RegistryPath = @"Software\Classes\killerpdf";
internal static void Register() => Register(Registry.CurrentUser, null);
// #183: machine-wide installs must register under HKLM so every user gets the handler,
// not just whoever ran the installer. Root is chosen by the caller; appPath defaults to
// the running executable (the per-user refresh path) but the elevated installer passes
// the Program Files copy explicitly since IT is the source exe at that moment.
internal static void Register(RegistryKey root, string? appPath)
{
try
{
appPath ??= Process.GetCurrentProcess().MainModule!.FileName;
using var protocol = root.CreateSubKey(RegistryPath);
if (protocol == null) return;
protocol.SetValue("", "URL:KillerPDF Protocol");
protocol.SetValue("URL Protocol", "");
using (var icon = protocol.CreateSubKey("DefaultIcon"))
icon?.SetValue("", $"\"{appPath}\",0");
using (var command = protocol.CreateSubKey(@"shell\open\command"))
command?.SetValue("", $"\"{appPath}\" \"%1\"");
}
catch (Exception ex) { Debug.WriteLine($"Failed to register KillerPDF protocol: {ex.Message}"); }
}
internal static void Unregister() => Unregister(Registry.CurrentUser);
internal static void Unregister(RegistryKey root)
{
try { root.DeleteSubKeyTree(RegistryPath, false); } catch { }
}
internal static bool TryGetTargetUrl(string? protocolUrl, out Uri? target)
{
target = null;
if (!Uri.TryCreate(protocolUrl, UriKind.Absolute, out var launch) ||
!launch.Scheme.Equals(Scheme, StringComparison.OrdinalIgnoreCase) ||
!launch.Host.Equals("open", StringComparison.OrdinalIgnoreCase)) return false;
string query = launch.Query.TrimStart('?');
foreach (string pair in query.Split('&'))
{
int equals = pair.IndexOf('=');
if (equals < 0) continue;
string name = Uri.UnescapeDataString(pair.Substring(0, equals).Replace("+", " "));
if (!name.Equals("url", StringComparison.OrdinalIgnoreCase)) continue;
string value = Uri.UnescapeDataString(pair.Substring(equals + 1).Replace("+", " "));
if (!Uri.TryCreate(value, UriKind.Absolute, out var parsed)) return false;
if (!parsed.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) return false;
target = parsed;
return true;
}
return false;
}
}
}