|
|
|
@ -7,250 +7,249 @@ using System.Reflection; |
|
|
|
using Avalonia.Platform.Internal; |
|
|
|
using Avalonia.Utilities; |
|
|
|
|
|
|
|
namespace Avalonia.Platform |
|
|
|
namespace Avalonia.Platform; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Loads assets compiled into the application binary.
|
|
|
|
/// </summary>
|
|
|
|
internal class StandardAssetLoader : IAssetLoader |
|
|
|
{ |
|
|
|
private readonly IAssemblyDescriptorResolver _assemblyDescriptorResolver; |
|
|
|
private AssemblyDescriptor? _defaultResmAssembly; |
|
|
|
|
|
|
|
public StandardAssetLoader(IAssemblyDescriptorResolver resolver, Assembly? assembly = null) |
|
|
|
{ |
|
|
|
if (assembly == null) |
|
|
|
assembly = Assembly.GetEntryAssembly(); |
|
|
|
if (assembly != null) |
|
|
|
_defaultResmAssembly = new AssemblyDescriptor(assembly); |
|
|
|
_assemblyDescriptorResolver = resolver; |
|
|
|
} |
|
|
|
|
|
|
|
public StandardAssetLoader(Assembly? assembly = null) : this(new AssemblyDescriptorResolver(), assembly) |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Loads assets compiled into the application binary.
|
|
|
|
/// Sets the default assembly from which to load assets for which no assembly is specified.
|
|
|
|
/// </summary>
|
|
|
|
internal class StandardAssetLoader : IAssetLoader |
|
|
|
/// <param name="assembly">The default assembly.</param>
|
|
|
|
public void SetDefaultAssembly(Assembly assembly) |
|
|
|
{ |
|
|
|
private readonly IAssemblyDescriptorResolver _assemblyDescriptorResolver; |
|
|
|
private AssemblyDescriptor? _defaultResmAssembly; |
|
|
|
_defaultResmAssembly = new AssemblyDescriptor(assembly); |
|
|
|
} |
|
|
|
|
|
|
|
public StandardAssetLoader(IAssemblyDescriptorResolver resolver, Assembly? assembly = null) |
|
|
|
{ |
|
|
|
if (assembly == null) |
|
|
|
assembly = Assembly.GetEntryAssembly(); |
|
|
|
if (assembly != null) |
|
|
|
_defaultResmAssembly = new AssemblyDescriptor(assembly); |
|
|
|
_assemblyDescriptorResolver = resolver; |
|
|
|
} |
|
|
|
/// <summary>
|
|
|
|
/// Checks if an asset with the specified URI exists.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">
|
|
|
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
|
|
/// </param>
|
|
|
|
/// <returns>True if the asset could be found; otherwise false.</returns>
|
|
|
|
public bool Exists(Uri uri, Uri? baseUri = null) |
|
|
|
{ |
|
|
|
return TryGetAsset(uri, baseUri, out _); |
|
|
|
} |
|
|
|
|
|
|
|
public StandardAssetLoader(Assembly? assembly = null) : this(new AssemblyDescriptorResolver(), assembly) |
|
|
|
/// <summary>
|
|
|
|
/// Opens the asset with the requested URI.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">
|
|
|
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
|
|
/// </param>
|
|
|
|
/// <returns>A stream containing the asset contents.</returns>
|
|
|
|
/// <exception cref="FileNotFoundException">
|
|
|
|
/// The asset could not be found.
|
|
|
|
/// </exception>
|
|
|
|
public Stream Open(Uri uri, Uri? baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Opens the asset with the requested URI and returns the asset stream and the
|
|
|
|
/// assembly containing the asset.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">
|
|
|
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
|
|
/// </param>
|
|
|
|
/// <returns>
|
|
|
|
/// The stream containing the resource contents together with the assembly.
|
|
|
|
/// </returns>
|
|
|
|
/// <exception cref="FileNotFoundException">
|
|
|
|
/// The asset could not be found.
|
|
|
|
/// </exception>
|
|
|
|
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri? baseUri = null) |
|
|
|
{ |
|
|
|
if (TryGetAsset(uri, baseUri, out var assetDescriptor)) |
|
|
|
{ |
|
|
|
|
|
|
|
return (assetDescriptor.GetStream(), assetDescriptor.Assembly); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sets the default assembly from which to load assets for which no assembly is specified.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="assembly">The default assembly.</param>
|
|
|
|
public void SetDefaultAssembly(Assembly assembly) |
|
|
|
throw new FileNotFoundException($"The resource {uri} could not be found."); |
|
|
|
} |
|
|
|
|
|
|
|
public Assembly? GetAssembly(Uri uri, Uri? baseUri) |
|
|
|
{ |
|
|
|
if (!uri.IsAbsoluteUri && baseUri != null) |
|
|
|
{ |
|
|
|
_defaultResmAssembly = new AssemblyDescriptor(assembly); |
|
|
|
uri = new Uri(baseUri, uri); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Checks if an asset with the specified URI exists.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">
|
|
|
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
|
|
/// </param>
|
|
|
|
/// <returns>True if the asset could be found; otherwise false.</returns>
|
|
|
|
public bool Exists(Uri uri, Uri? baseUri = null) |
|
|
|
if (TryGetAssembly(uri, out var assemblyDescriptor)) |
|
|
|
{ |
|
|
|
return TryGetAsset(uri, baseUri, out _); |
|
|
|
return assemblyDescriptor.Assembly; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Opens the asset with the requested URI.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">
|
|
|
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
|
|
/// </param>
|
|
|
|
/// <returns>A stream containing the asset contents.</returns>
|
|
|
|
/// <exception cref="FileNotFoundException">
|
|
|
|
/// The asset could not be found.
|
|
|
|
/// </exception>
|
|
|
|
public Stream Open(Uri uri, Uri? baseUri = null) => OpenAndGetAssembly(uri, baseUri).Item1; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Opens the asset with the requested URI and returns the asset stream and the
|
|
|
|
/// assembly containing the asset.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">
|
|
|
|
/// A base URI to use if <paramref name="uri"/> is relative.
|
|
|
|
/// </param>
|
|
|
|
/// <returns>
|
|
|
|
/// The stream containing the resource contents together with the assembly.
|
|
|
|
/// </returns>
|
|
|
|
/// <exception cref="FileNotFoundException">
|
|
|
|
/// The asset could not be found.
|
|
|
|
/// </exception>
|
|
|
|
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri? baseUri = null) |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets all assets of a folder and subfolders that match specified uri.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">Base URI that is used if <paramref name="uri"/> is relative.</param>
|
|
|
|
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
|
|
|
|
public IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri) |
|
|
|
{ |
|
|
|
if (uri.IsAbsoluteResm()) |
|
|
|
{ |
|
|
|
if (TryGetAsset(uri, baseUri, out var assetDescriptor)) |
|
|
|
if (!TryGetAssembly(uri, out var assembly)) |
|
|
|
{ |
|
|
|
return (assetDescriptor.GetStream(), assetDescriptor.Assembly); |
|
|
|
assembly = _defaultResmAssembly; |
|
|
|
} |
|
|
|
|
|
|
|
throw new FileNotFoundException($"The resource {uri} could not be found."); |
|
|
|
return assembly?.Resources? |
|
|
|
.Where(x => x.Key.Contains(uri.GetUnescapeAbsolutePath())) |
|
|
|
.Select(x => new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ?? |
|
|
|
Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
|
|
|
|
public Assembly? GetAssembly(Uri uri, Uri? baseUri) |
|
|
|
uri = uri.EnsureAbsolute(baseUri); |
|
|
|
|
|
|
|
if (uri.IsAvares()) |
|
|
|
{ |
|
|
|
if (!uri.IsAbsoluteUri && baseUri != null) |
|
|
|
if (!TryGetResAsmAndPath(uri, out var assembly, out var path)) |
|
|
|
{ |
|
|
|
uri = new Uri(baseUri, uri); |
|
|
|
return Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
|
|
|
|
if (TryGetAssembly(uri, out var assemblyDescriptor)) |
|
|
|
if (assembly?.AvaloniaResources == null) |
|
|
|
{ |
|
|
|
return assemblyDescriptor.Assembly; |
|
|
|
return Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
if (path.Length > 0 && path[path.Length - 1] != '/') |
|
|
|
{ |
|
|
|
path += '/'; |
|
|
|
} |
|
|
|
|
|
|
|
return assembly.AvaloniaResources |
|
|
|
.Where(r => r.Key.StartsWith(path, StringComparison.Ordinal)) |
|
|
|
.Select(x => new Uri($"avares://{assembly.Name}{x.Key}")); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets all assets of a folder and subfolders that match specified uri.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="uri">The URI.</param>
|
|
|
|
/// <param name="baseUri">Base URI that is used if <paramref name="uri"/> is relative.</param>
|
|
|
|
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
|
|
|
|
public IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri) |
|
|
|
return Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetAsset(Uri uri, Uri? baseUri, [NotNullWhen(true)] out IAssetDescriptor? assetDescriptor) |
|
|
|
{ |
|
|
|
assetDescriptor = null; |
|
|
|
|
|
|
|
if (uri.IsAbsoluteResm()) |
|
|
|
{ |
|
|
|
if (uri.IsAbsoluteResm()) |
|
|
|
if (!TryGetAssembly(uri, out var assembly) && !TryGetAssembly(baseUri, out assembly)) |
|
|
|
{ |
|
|
|
if (!TryGetAssembly(uri, out var assembly)) |
|
|
|
{ |
|
|
|
assembly = _defaultResmAssembly; |
|
|
|
} |
|
|
|
|
|
|
|
return assembly?.Resources? |
|
|
|
.Where(x => x.Key.Contains(uri.GetUnescapeAbsolutePath())) |
|
|
|
.Select(x => new Uri($"resm:{x.Key}?assembly={assembly.Name}")) ?? |
|
|
|
Enumerable.Empty<Uri>(); |
|
|
|
assembly = _defaultResmAssembly; |
|
|
|
} |
|
|
|
|
|
|
|
uri = uri.EnsureAbsolute(baseUri); |
|
|
|
|
|
|
|
if (uri.IsAvares()) |
|
|
|
if (assembly?.Resources != null) |
|
|
|
{ |
|
|
|
if (!TryGetResAsmAndPath(uri, out var assembly, out var path)) |
|
|
|
{ |
|
|
|
return Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
|
|
|
|
if (assembly?.AvaloniaResources == null) |
|
|
|
{ |
|
|
|
return Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
var resourceKey = uri.AbsolutePath; |
|
|
|
|
|
|
|
if (path.Length > 0 && path[path.Length - 1] != '/') |
|
|
|
if (assembly.Resources.TryGetValue(resourceKey, out assetDescriptor)) |
|
|
|
{ |
|
|
|
path += '/'; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return assembly.AvaloniaResources |
|
|
|
.Where(r => r.Key.StartsWith(path, StringComparison.Ordinal)) |
|
|
|
.Select(x => new Uri($"avares://{assembly.Name}{x.Key}")); |
|
|
|
} |
|
|
|
|
|
|
|
return Enumerable.Empty<Uri>(); |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetAsset(Uri uri, Uri? baseUri, [NotNullWhen(true)] out IAssetDescriptor? assetDescriptor) |
|
|
|
{ |
|
|
|
assetDescriptor = null; |
|
|
|
uri = uri.EnsureAbsolute(baseUri); |
|
|
|
|
|
|
|
if (uri.IsAbsoluteResm()) |
|
|
|
if (uri.IsAvares()) |
|
|
|
{ |
|
|
|
if (TryGetResAsmAndPath(uri, out var assembly, out var path)) |
|
|
|
{ |
|
|
|
if (!TryGetAssembly(uri, out var assembly) && !TryGetAssembly(baseUri, out assembly)) |
|
|
|
if (assembly.AvaloniaResources == null) |
|
|
|
{ |
|
|
|
assembly = _defaultResmAssembly; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (assembly?.Resources != null) |
|
|
|
if (assembly.AvaloniaResources.TryGetValue(path, out assetDescriptor)) |
|
|
|
{ |
|
|
|
var resourceKey = uri.AbsolutePath; |
|
|
|
|
|
|
|
if (assembly.Resources.TryGetValue(resourceKey, out assetDescriptor)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
uri = uri.EnsureAbsolute(baseUri); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (uri.IsAvares()) |
|
|
|
{ |
|
|
|
if (TryGetResAsmAndPath(uri, out var assembly, out var path)) |
|
|
|
{ |
|
|
|
if (assembly.AvaloniaResources == null) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (assembly.AvaloniaResources.TryGetValue(path, out assetDescriptor)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private bool TryGetResAsmAndPath(Uri uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly, out string path) |
|
|
|
{ |
|
|
|
path = uri.GetUnescapeAbsolutePath(); |
|
|
|
|
|
|
|
return false; |
|
|
|
if (TryLoadAssembly(uri.Authority, out assembly)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetResAsmAndPath(Uri uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly, out string path) |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetAssembly(Uri? uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly) |
|
|
|
{ |
|
|
|
assembly = null; |
|
|
|
|
|
|
|
if (uri != null) |
|
|
|
{ |
|
|
|
path = uri.GetUnescapeAbsolutePath(); |
|
|
|
if (!uri.IsAbsoluteUri) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
if (TryLoadAssembly(uri.Authority, out assembly)) |
|
|
|
if (uri.IsAvares() && TryGetResAsmAndPath(uri, out assembly, out _)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetAssembly(Uri? uri, [NotNullWhen(true)] out IAssemblyDescriptor? assembly) |
|
|
|
{ |
|
|
|
assembly = null; |
|
|
|
|
|
|
|
if (uri != null) |
|
|
|
if (uri.IsResm()) |
|
|
|
{ |
|
|
|
if (!uri.IsAbsoluteUri) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
var assemblyName = uri.GetAssemblyNameFromQuery(); |
|
|
|
|
|
|
|
if (uri.IsAvares() && TryGetResAsmAndPath(uri, out assembly, out _)) |
|
|
|
if (assemblyName.Length > 0 && TryLoadAssembly(assemblyName, out assembly)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
if (uri.IsResm()) |
|
|
|
{ |
|
|
|
var assemblyName = uri.GetAssemblyNameFromQuery(); |
|
|
|
|
|
|
|
if (assemblyName.Length > 0 && TryLoadAssembly(assemblyName, out assembly)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryLoadAssembly(string assemblyName, [NotNullWhen(true)] out IAssemblyDescriptor? assembly) |
|
|
|
{ |
|
|
|
assembly = null; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
assembly = _assemblyDescriptorResolver.GetAssembly(assemblyName); |
|
|
|
private bool TryLoadAssembly(string assemblyName, [NotNullWhen(true)] out IAssemblyDescriptor? assembly) |
|
|
|
{ |
|
|
|
assembly = null; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
catch (Exception) { } |
|
|
|
try |
|
|
|
{ |
|
|
|
assembly = _assemblyDescriptorResolver.GetAssembly(assemblyName); |
|
|
|
|
|
|
|
return false; |
|
|
|
return true; |
|
|
|
} |
|
|
|
catch (Exception) { } |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|