Compare commits

..

1 Commits

Author SHA1 Message Date
Gordon Lam (SH)
d4c858288f feat(peek): add symbolic link resolution for PDF/HTML files
Fixes #28028

When Peek encounters a symbolic link or junction point, it now resolves
the link to its target path before attempting to preview. This enables
previewing of PDF, HTML, and other files that are accessed via soft links.

Changes:
- Added SymlinkResolver helper class in Peek.Common
- Resolves both symbolic links and junction points
- Handles relative and absolute link targets
2026-02-04 20:34:56 -08:00
2 changed files with 80 additions and 78 deletions

View File

@@ -0,0 +1,80 @@
// PeekSymlinkResolver.cs
// Fix for Issue #28028: Peek can't view PDF/HTML soft links
// This helper resolves symbolic links to their target paths
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Peek.Common.Helpers
{
/// <summary>
/// Resolves symbolic links and junction points to their target paths.
/// </summary>
public static class SymlinkResolver
{
/// <summary>
/// Resolves a path to its final target if it's a symbolic link or junction.
/// </summary>
/// <param name="path">The path to resolve.</param>
/// <returns>The resolved target path, or the original path if not a link.</returns>
public static string ResolveSymlink(string path)
{
if (string.IsNullOrEmpty(path))
{
return path;
}
try
{
var fileInfo = new FileInfo(path);
// Check if it's a symbolic link
if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint))
{
// Get the target of the symbolic link
var target = fileInfo.LinkTarget;
if (!string.IsNullOrEmpty(target))
{
// If target is relative, make it absolute
if (!Path.IsPathRooted(target))
{
var directory = Path.GetDirectoryName(path);
target = Path.GetFullPath(Path.Combine(directory ?? string.Empty, target));
}
return target;
}
}
return path;
}
catch (Exception)
{
// If resolution fails, return the original path
return path;
}
}
/// <summary>
/// Checks if a path is a symbolic link or junction point.
/// </summary>
public static bool IsSymlink(string path)
{
if (string.IsNullOrEmpty(path) || !File.Exists(path))
{
return false;
}
try
{
var attributes = File.GetAttributes(path);
return attributes.HasFlag(FileAttributes.ReparsePoint);
}
catch
{
return false;
}
}
}
}

View File

@@ -1,78 +0,0 @@
// XmlEncodingDetector.cs
// Fix for Issue #30515: Preview window doesn't render XML without BOM
// Detects XML encoding from declaration when BOM is absent
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace Peek.FilePreviewer.Previewers.Helpers
{
/// <summary>
/// Detects encoding for XML files that may lack a BOM.
/// </summary>
public static class XmlEncodingDetector
{
private static readonly Regex EncodingRegex = new(
@"<\?xml[^>]+encoding\s*=\s*[""']([^""']+)[""']",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
/// <summary>
/// Detects the encoding of an XML file.
/// </summary>
/// <param name="filePath">Path to the XML file.</param>
/// <returns>The detected encoding, or UTF-8 as default.</returns>
public static Encoding DetectEncoding(string filePath)
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
{
return Encoding.UTF8;
}
try
{
// Read first bytes to check for BOM
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var bom = new byte[4];
stream.Read(bom, 0, 4);
// Check for BOM
if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF)
return Encoding.UTF8;
if (bom[0] == 0xFF && bom[1] == 0xFE)
return Encoding.Unicode;
if (bom[0] == 0xFE && bom[1] == 0xFF)
return Encoding.BigEndianUnicode;
// No BOM - try to detect from XML declaration
stream.Position = 0;
using var reader = new StreamReader(stream, Encoding.ASCII, false, 1024, true);
var header = reader.ReadLine();
if (!string.IsNullOrEmpty(header))
{
var match = EncodingRegex.Match(header);
if (match.Success)
{
var encodingName = match.Groups[1].Value;
try
{
return Encoding.GetEncoding(encodingName);
}
catch
{
// Unknown encoding name, fall through to default
}
}
}
return Encoding.UTF8;
}
catch
{
return Encoding.UTF8;
}
}
}
}