Skip to content

Commit

Permalink
Add IFileLoader API
Browse files Browse the repository at this point in the history
  • Loading branch information
siegfriedpammer committed Mar 31, 2024
1 parent 02eb6b7 commit 65e30c0
Show file tree
Hide file tree
Showing 14 changed files with 418 additions and 155 deletions.
7 changes: 6 additions & 1 deletion ICSharpCode.ILSpyX/AssemblyList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
using System.Xml.Linq;

using ICSharpCode.ILSpyX.Extensions;
using ICSharpCode.ILSpyX.FileLoaders;

namespace ICSharpCode.ILSpyX
{
Expand Down Expand Up @@ -128,6 +129,7 @@ public event NotifyCollectionChangedEventHandler CollectionChanged {

public bool ApplyWinRTProjections { get; set; }
public bool UseDebugSymbols { get; set; }
public FileLoaderRegistry LoaderRegistry => this.manager.LoaderRegistry;

/// <summary>
/// Gets the loaded assemblies. This method is thread-safe.
Expand Down Expand Up @@ -279,7 +281,7 @@ public LoadedAssembly OpenAssembly(string file, bool isAutoLoaded = false)
{
file = Path.GetFullPath(file);
return OpenAssembly(file, () => {
var newAsm = new LoadedAssembly(this, file, applyWinRTProjections: ApplyWinRTProjections, useDebugSymbols: UseDebugSymbols);
var newAsm = new LoadedAssembly(this, file, fileLoaders: manager?.LoaderRegistry, applyWinRTProjections: ApplyWinRTProjections, useDebugSymbols: UseDebugSymbols);
newAsm.IsAutoLoaded = isAutoLoaded;
return newAsm;
});
Expand All @@ -293,6 +295,7 @@ public LoadedAssembly OpenAssembly(string file, Stream? stream, bool isAutoLoade
file = Path.GetFullPath(file);
return OpenAssembly(file, () => {
var newAsm = new LoadedAssembly(this, file, stream: Task.FromResult(stream),
fileLoaders: manager?.LoaderRegistry,
applyWinRTProjections: ApplyWinRTProjections, useDebugSymbols: UseDebugSymbols);
newAsm.IsAutoLoaded = isAutoLoaded;
return newAsm;
Expand Down Expand Up @@ -345,6 +348,7 @@ LoadedAssembly OpenAssembly(string file, Func<LoadedAssembly> load)
return null;

var newAsm = new LoadedAssembly(this, file, stream: Task.FromResult<Stream?>(stream),
fileLoaders: manager?.LoaderRegistry,
applyWinRTProjections: ApplyWinRTProjections, useDebugSymbols: UseDebugSymbols);
newAsm.IsAutoLoaded = target.IsAutoLoaded;

Expand Down Expand Up @@ -374,6 +378,7 @@ LoadedAssembly OpenAssembly(string file, Func<LoadedAssembly> load)
if (index < 0)
return null;
var newAsm = new LoadedAssembly(this, target.FileName, pdbFileName: target.PdbFileName,
fileLoaders: manager?.LoaderRegistry,
applyWinRTProjections: ApplyWinRTProjections, useDebugSymbols: UseDebugSymbols);
newAsm.IsAutoLoaded = target.IsAutoLoaded;
lock (lockObj)
Expand Down
3 changes: 3 additions & 0 deletions ICSharpCode.ILSpyX/AssemblyListManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using System.Xml.Linq;

using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpyX.FileLoaders;
using ICSharpCode.ILSpyX.Settings;

namespace ICSharpCode.ILSpyX
Expand Down Expand Up @@ -59,6 +60,8 @@ public AssemblyListManager(ISettingsProvider settingsProvider)

public ObservableCollection<string> AssemblyLists { get; } = new ObservableCollection<string>();

public FileLoaderRegistry LoaderRegistry { get; } = new FileLoaderRegistry();

/// <summary>
/// Loads an assembly list from the ILSpySettings.
/// If no list with the specified name is found, the default list is loaded instead.
Expand Down
3 changes: 2 additions & 1 deletion ICSharpCode.ILSpyX/AssemblyListSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpyX.Extensions;
using ICSharpCode.ILSpyX.FileLoaders;

namespace ICSharpCode.ILSpyX
{
Expand Down Expand Up @@ -156,7 +157,7 @@ public async Task<IList<LoadedAssembly>> GetAllAssembliesAsync()

foreach (var asm in assemblies)
{
LoadedAssembly.LoadResult result;
LoadResult result;
try
{
result = await asm.GetLoadResultAsync().ConfigureAwait(false);
Expand Down
40 changes: 40 additions & 0 deletions ICSharpCode.ILSpyX/FileLoaders/ArchiveFileLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2024 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.IO;
using System.Threading.Tasks;

namespace ICSharpCode.ILSpyX.FileLoaders
{
public sealed class ArchiveFileLoader : IFileLoader
{
public Task<LoadResult?> Load(string fileName, Stream stream, FileLoadSettings settings)
{
try
{
var zip = LoadedPackage.FromZipFile(fileName);
var result = zip != null ? new LoadResult { Package = zip } : null;
return Task.FromResult(result);
}
catch (InvalidDataException)
{
return Task.FromResult<LoadResult?>(null);
}
}
}
}
33 changes: 33 additions & 0 deletions ICSharpCode.ILSpyX/FileLoaders/BundleFileLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) 2024 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.IO;
using System.Threading.Tasks;

namespace ICSharpCode.ILSpyX.FileLoaders
{
public sealed class BundleFileLoader : IFileLoader
{
public Task<LoadResult?> Load(string fileName, Stream stream, FileLoadSettings settings)
{
var bundle = LoadedPackage.FromBundle(fileName);
var result = bundle != null ? new LoadResult { Package = bundle } : null;
return Task.FromResult(result);
}
}
}
49 changes: 49 additions & 0 deletions ICSharpCode.ILSpyX/FileLoaders/FileLoaderRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2024 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;

namespace ICSharpCode.ILSpyX.FileLoaders
{
public sealed class FileLoaderRegistry
{
readonly List<IFileLoader> registeredLoaders = new List<IFileLoader>();

public IReadOnlyList<IFileLoader> RegisteredLoaders => registeredLoaders;

public void Register(IFileLoader loader)
{
if (loader is null)
{
throw new ArgumentNullException(nameof(loader));
}

registeredLoaders.Add(loader);
}

public FileLoaderRegistry()
{
Register(new XamarinCompressedFileLoader());
Register(new WebCilFileLoader());
Register(new MetadataFileLoader());
Register(new BundleFileLoader());
Register(new ArchiveFileLoader());
}
}
}
40 changes: 40 additions & 0 deletions ICSharpCode.ILSpyX/FileLoaders/LoadResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2024 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.IO;
using System.Threading.Tasks;

using ICSharpCode.Decompiler.Metadata;

namespace ICSharpCode.ILSpyX.FileLoaders
{
public sealed class LoadResult
{
public MetadataFile? MetadataFile { get; init; }
public Exception? FileLoadException { get; init; }
public LoadedPackage? Package { get; init; }
}

public record FileLoadSettings(bool ApplyWinRTProjections);

public interface IFileLoader
{
Task<LoadResult?> Load(string fileName, Stream stream, FileLoadSettings settings);
}
}
48 changes: 48 additions & 0 deletions ICSharpCode.ILSpyX/FileLoaders/MetadataFileLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2024 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.IO;
using System.Reflection.Metadata;
using System.Threading.Tasks;

using ICSharpCode.Decompiler.Metadata;

using static ICSharpCode.Decompiler.Metadata.MetadataFile;

namespace ICSharpCode.ILSpyX.FileLoaders
{
public sealed class MetadataFileLoader : IFileLoader
{
public Task<LoadResult?> Load(string fileName, Stream stream, FileLoadSettings settings)
{
try
{
var kind = Path.GetExtension(fileName).Equals(".pdb", StringComparison.OrdinalIgnoreCase)
? MetadataFileKind.ProgramDebugDatabase : MetadataFileKind.Metadata;
var metadata = MetadataReaderProvider.FromMetadataStream(stream, MetadataStreamOptions.PrefetchMetadata | MetadataStreamOptions.LeaveOpen);
var metadataFile = new MetadataFile(kind, fileName, metadata);
return Task.FromResult<LoadResult?>(new LoadResult { MetadataFile = metadataFile });
}
catch (BadImageFormatException)
{
return Task.FromResult<LoadResult?>(null);
}
}
}
}
40 changes: 40 additions & 0 deletions ICSharpCode.ILSpyX/FileLoaders/WebCilFileLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2024 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System.IO;
using System.Reflection.Metadata;
using System.Threading.Tasks;

using ICSharpCode.Decompiler.Metadata;

namespace ICSharpCode.ILSpyX.FileLoaders
{
public sealed class WebCilFileLoader : IFileLoader
{
public Task<LoadResult?> Load(string fileName, Stream stream, FileLoadSettings settings)
{
MetadataReaderOptions options = settings.ApplyWinRTProjections
? MetadataReaderOptions.ApplyWindowsRuntimeProjections
: MetadataReaderOptions.None;

var wasm = WebCilFile.FromStream(fileName, options);
var result = wasm != null ? new LoadResult { MetadataFile = wasm } : null;
return Task.FromResult(result);
}
}
}
Loading

0 comments on commit 65e30c0

Please sign in to comment.