Browse Source

Fix #2337: Expose simple public XamlDecompiler API.

pull/2491/head
Siegfried Pammer 4 years ago
parent
commit
113e00505d
  1. 6
      ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs
  2. 36
      ILSpy.BamlDecompiler/BamlDecompilationResult.cs
  3. 50
      ILSpy.BamlDecompiler/BamlDecompilerSettings.cs
  4. 144
      ILSpy.BamlDecompiler/BamlDecompilerTypeSystem.cs
  5. 140
      ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
  6. 9
      ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
  7. 6
      ILSpy.BamlDecompiler/XamlContext.cs
  8. 81
      ILSpy.BamlDecompiler/XamlDecompiler.cs

6
ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs

@ -168,7 +168,11 @@ namespace ILSpy.BamlDecompiler.Tests @@ -168,7 +168,11 @@ namespace ILSpy.BamlDecompiler.Tests
var res = module.Resources.First();
Stream bamlStream = LoadBaml(res, name + ".baml");
Assert.IsNotNull(bamlStream);
XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, resolver, bamlStream, CancellationToken.None);
BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(module, resolver);
var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings());
XDocument document = decompiler.Decompile(bamlStream).Xaml;
XamlIsEqual(File.ReadAllText(sourcePath), document.ToString());
}

36
ILSpy.BamlDecompiler/BamlDecompilationResult.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// Copyright (c) 2021 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.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace ILSpy.BamlDecompiler
{
public class BamlDecompilationResult
{
public XDocument Xaml { get; }
public List<string> AssemblyReferences { get; }
public BamlDecompilationResult(XDocument xaml, IEnumerable<string> assemblyReferences)
{
this.Xaml = xaml;
this.AssemblyReferences = assemblyReferences.ToList();
}
}
}

50
ILSpy.BamlDecompiler/BamlDecompilerSettings.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// Copyright (c) 2021 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.ComponentModel;
using System.Runtime.CompilerServices;
namespace ILSpy.BamlDecompiler
{
public class BamlDecompilerSettings : INotifyPropertyChanged
{
bool throwOnAssemblyResolveErrors = true;
[Browsable(false)]
public bool ThrowOnAssemblyResolveErrors {
get { return throwOnAssemblyResolveErrors; }
set {
if (throwOnAssemblyResolveErrors != value)
{
throwOnAssemblyResolveErrors = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

144
ILSpy.BamlDecompiler/BamlDecompilerTypeSystem.cs

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
// Copyright (c) 2021 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;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
namespace ILSpy.BamlDecompiler
{
class BamlDecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
{
string[] defaultBamlReferences = new[] {
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"PresentationUI, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
};
public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
{
if (mainModule == null)
throw new ArgumentNullException(nameof(mainModule));
if (assemblyResolver == null)
throw new ArgumentNullException(nameof(assemblyResolver));
// Load referenced assemblies and type-forwarder references.
// This is necessary to make .NET Core/PCL binaries work better.
var referencedAssemblies = new List<PEFile>();
var assemblyReferenceQueue = new Queue<(bool IsAssembly, PEFile MainModule, object Reference)>();
var mainMetadata = mainModule.Metadata;
foreach (var h in mainMetadata.GetModuleReferences())
{
var moduleRef = mainMetadata.GetModuleReference(h);
var moduleName = mainMetadata.GetString(moduleRef.Name);
foreach (var fileHandle in mainMetadata.AssemblyFiles)
{
var file = mainMetadata.GetAssemblyFile(fileHandle);
if (mainMetadata.StringComparer.Equals(file.Name, moduleName) && file.ContainsMetadata)
{
assemblyReferenceQueue.Enqueue((false, mainModule, moduleName));
break;
}
}
}
foreach (var refs in mainModule.AssemblyReferences)
{
assemblyReferenceQueue.Enqueue((true, mainModule, refs));
}
foreach (var bamlReference in defaultBamlReferences)
{
assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference)));
}
var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference) reference) =>
reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName :
"M:" + reference.Reference);
var processedAssemblyReferences = new HashSet<(bool IsAssembly, PEFile Parent, object Reference)>(comparer);
while (assemblyReferenceQueue.Count > 0)
{
var asmRef = assemblyReferenceQueue.Dequeue();
if (!processedAssemblyReferences.Add(asmRef))
continue;
PEFile asm;
if (asmRef.IsAssembly)
{
asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference);
}
else
{
asm = assemblyResolver.ResolveModule(asmRef.MainModule, (string)asmRef.Reference);
}
if (asm != null)
{
referencedAssemblies.Add(asm);
var metadata = asm.Metadata;
foreach (var h in metadata.ExportedTypes)
{
var exportedType = metadata.GetExportedType(h);
switch (exportedType.Implementation.Kind)
{
case HandleKind.AssemblyReference:
assemblyReferenceQueue.Enqueue((true, asm, new ICSharpCode.Decompiler.Metadata.AssemblyReference(asm, (AssemblyReferenceHandle)exportedType.Implementation)));
break;
case HandleKind.AssemblyFile:
var file = metadata.GetAssemblyFile((AssemblyFileHandle)exportedType.Implementation);
assemblyReferenceQueue.Enqueue((false, asm, metadata.GetString(file.Name)));
break;
}
}
}
}
var mainModuleWithOptions = mainModule.WithOptions(TypeSystemOptions.Default);
var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(TypeSystemOptions.Default));
// Primitive types are necessary to avoid assertions in ILReader.
// Fallback to MinimalCorlib to provide the primitive types.
if (!HasType(KnownTypeCode.Void) || !HasType(KnownTypeCode.Int32))
{
Init(mainModule.WithOptions(TypeSystemOptions.Default), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.Instance }));
}
else
{
Init(mainModuleWithOptions, referencedAssembliesWithOptions);
}
this.MainModule = (MetadataModule)base.MainModule;
bool HasType(KnownTypeCode code)
{
TopLevelTypeName name = KnownTypeReference.Get(code).TypeName;
if (mainModule.GetTypeDefinition(name) != null)
return true;
foreach (var file in referencedAssemblies)
{
if (file.GetTypeDefinition(name) != null)
return true;
}
return false;
}
}
public new MetadataModule MainModule { get; }
}
}

140
ILSpy.BamlDecompiler/BamlResourceEntryNode.cs

@ -17,27 +17,17 @@ @@ -17,27 +17,17 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
using ILSpy.BamlDecompiler.Baml;
using SRM = System.Reflection.Metadata;
namespace ILSpy.BamlDecompiler
{
public sealed class BamlResourceEntryNode : ResourceEntryNode
@ -75,131 +65,11 @@ namespace ILSpy.BamlDecompiler @@ -75,131 +65,11 @@ namespace ILSpy.BamlDecompiler
{
var asm = this.Ancestors().OfType<AssemblyTreeNode>().First().LoadedAssembly;
using var data = OpenStream();
XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), asm.GetAssemblyResolver(), data, cancellationToken);
output.Write(xamlDocument.ToString());
}
internal static XDocument LoadIntoDocument(PEFile module, IAssemblyResolver assemblyResolver,
Stream stream, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var document = BamlReader.ReadDocument(stream, cancellationToken);
var xaml = new XamlDecompiler().Decompile(new BamlDecompilerTypeSystem(module, assemblyResolver), document, cancellationToken, new BamlDecompilerOptions(), null);
return xaml;
}
class BamlDecompilerTypeSystem : SimpleCompilation, IDecompilerTypeSystem
{
string[] defaultBamlReferences = new[] {
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"PresentationUI, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
};
public BamlDecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver)
{
if (mainModule == null)
throw new ArgumentNullException(nameof(mainModule));
if (assemblyResolver == null)
throw new ArgumentNullException(nameof(assemblyResolver));
// Load referenced assemblies and type-forwarder references.
// This is necessary to make .NET Core/PCL binaries work better.
var referencedAssemblies = new List<PEFile>();
var assemblyReferenceQueue = new Queue<(bool IsAssembly, PEFile MainModule, object Reference)>();
var mainMetadata = mainModule.Metadata;
foreach (var h in mainMetadata.GetModuleReferences())
{
var moduleRef = mainMetadata.GetModuleReference(h);
var moduleName = mainMetadata.GetString(moduleRef.Name);
foreach (var fileHandle in mainMetadata.AssemblyFiles)
{
var file = mainMetadata.GetAssemblyFile(fileHandle);
if (mainMetadata.StringComparer.Equals(file.Name, moduleName) && file.ContainsMetadata)
{
assemblyReferenceQueue.Enqueue((false, mainModule, moduleName));
break;
}
}
}
foreach (var refs in mainModule.AssemblyReferences)
{
assemblyReferenceQueue.Enqueue((true, mainModule, refs));
}
foreach (var bamlReference in defaultBamlReferences)
{
assemblyReferenceQueue.Enqueue((true, mainModule, AssemblyNameReference.Parse(bamlReference)));
}
var comparer = KeyComparer.Create(((bool IsAssembly, PEFile MainModule, object Reference) reference) =>
reference.IsAssembly ? "A:" + ((IAssemblyReference)reference.Reference).FullName :
"M:" + reference.Reference);
var processedAssemblyReferences = new HashSet<(bool IsAssembly, PEFile Parent, object Reference)>(comparer);
while (assemblyReferenceQueue.Count > 0)
{
var asmRef = assemblyReferenceQueue.Dequeue();
if (!processedAssemblyReferences.Add(asmRef))
continue;
PEFile asm;
if (asmRef.IsAssembly)
{
asm = assemblyResolver.Resolve((IAssemblyReference)asmRef.Reference);
}
else
{
asm = assemblyResolver.ResolveModule(asmRef.MainModule, (string)asmRef.Reference);
}
if (asm != null)
{
referencedAssemblies.Add(asm);
var metadata = asm.Metadata;
foreach (var h in metadata.ExportedTypes)
{
var exportedType = metadata.GetExportedType(h);
switch (exportedType.Implementation.Kind)
{
case SRM.HandleKind.AssemblyReference:
assemblyReferenceQueue.Enqueue((true, asm, new AssemblyReference(asm, (SRM.AssemblyReferenceHandle)exportedType.Implementation)));
break;
case SRM.HandleKind.AssemblyFile:
var file = metadata.GetAssemblyFile((SRM.AssemblyFileHandle)exportedType.Implementation);
assemblyReferenceQueue.Enqueue((false, asm, metadata.GetString(file.Name)));
break;
}
}
}
}
var mainModuleWithOptions = mainModule.WithOptions(TypeSystemOptions.Default);
var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(TypeSystemOptions.Default));
// Primitive types are necessary to avoid assertions in ILReader.
// Fallback to MinimalCorlib to provide the primitive types.
if (!HasType(KnownTypeCode.Void) || !HasType(KnownTypeCode.Int32))
{
Init(mainModule.WithOptions(TypeSystemOptions.Default), referencedAssembliesWithOptions.Concat(new[] { MinimalCorlib.Instance }));
}
else
{
Init(mainModuleWithOptions, referencedAssembliesWithOptions);
}
this.MainModule = (MetadataModule)base.MainModule;
bool HasType(KnownTypeCode code)
{
TopLevelTypeName name = KnownTypeReference.Get(code).TypeName;
if (mainModule.GetTypeDefinition(name) != null)
return true;
foreach (var file in referencedAssemblies)
{
if (file.GetTypeDefinition(name) != null)
return true;
}
return false;
}
}
public new MetadataModule MainModule { get; }
BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(asm.GetPEFileOrNull(), asm.GetAssemblyResolver());
var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings());
decompiler.CancellationToken = cancellationToken;
var result = decompiler.Decompile(data);
output.Write(result.Xaml.ToString());
}
}
}

9
ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs

@ -46,9 +46,14 @@ namespace ILSpy.BamlDecompiler @@ -46,9 +46,14 @@ namespace ILSpy.BamlDecompiler
public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options)
{
var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver(), stream, options.CancellationToken);
BamlDecompilerTypeSystem typeSystem = new BamlDecompilerTypeSystem(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver());
var decompiler = new XamlDecompiler(typeSystem, new BamlDecompilerSettings() {
ThrowOnAssemblyResolveErrors = options.DecompilerSettings.ThrowOnAssemblyResolveErrors
});
decompiler.CancellationToken = options.CancellationToken;
fileName = Path.ChangeExtension(fileName, ".xaml");
document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName));
var result = decompiler.Decompile(stream);
result.Xaml.Save(Path.Combine(options.SaveAsProjectDirectory, fileName));
return fileName;
}
}

6
ILSpy.BamlDecompiler/XamlContext.cs

@ -48,7 +48,7 @@ namespace ILSpy.BamlDecompiler @@ -48,7 +48,7 @@ namespace ILSpy.BamlDecompiler
public IDecompilerTypeSystem TypeSystem { get; }
public CancellationToken CancellationToken { get; private set; }
public BamlDecompilerOptions BamlDecompilerOptions { get; private set; }
public BamlDecompilerSettings Settings { get; private set; }
public BamlContext Baml { get; private set; }
public BamlNode RootNode { get; private set; }
@ -56,11 +56,11 @@ namespace ILSpy.BamlDecompiler @@ -56,11 +56,11 @@ namespace ILSpy.BamlDecompiler
public XmlnsDictionary XmlNs { get; }
public static XamlContext Construct(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerOptions bamlDecompilerOptions)
public static XamlContext Construct(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerSettings bamlDecompilerOptions)
{
var ctx = new XamlContext(typeSystem);
ctx.CancellationToken = token;
ctx.BamlDecompilerOptions = bamlDecompilerOptions ?? new BamlDecompilerOptions();
ctx.Settings = bamlDecompilerOptions ?? new BamlDecompilerSettings();
ctx.Baml = BamlContext.ConstructContext(typeSystem, document, token);
ctx.RootNode = BamlNode.Parse(document, token);

81
ILSpy.BamlDecompiler/XamlDecompiler.cs

@ -20,11 +20,15 @@ @@ -20,11 +20,15 @@
THE SOFTWARE.
*/
using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Threading;
using System.Xml.Linq;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ILSpy.BamlDecompiler.Baml;
@ -32,7 +36,7 @@ using ILSpy.BamlDecompiler.Rewrite; @@ -32,7 +36,7 @@ using ILSpy.BamlDecompiler.Rewrite;
namespace ILSpy.BamlDecompiler
{
internal class XamlDecompiler
public class XamlDecompiler
{
static readonly IRewritePass[] rewritePasses = new IRewritePass[] {
new XClassRewritePass(),
@ -42,9 +46,66 @@ namespace ILSpy.BamlDecompiler @@ -42,9 +46,66 @@ namespace ILSpy.BamlDecompiler
new DocumentRewritePass(),
};
public XDocument Decompile(IDecompilerTypeSystem typeSystem, BamlDocument document, CancellationToken token, BamlDecompilerOptions bamlDecompilerOptions, List<string> assemblyReferences)
private BamlDecompilerTypeSystem typeSystem;
private BamlDecompilerSettings settings;
private MetadataModule module;
public BamlDecompilerSettings Settings {
get { return settings; }
set { settings = value; }
}
public CancellationToken CancellationToken { get; set; }
public XamlDecompiler(string fileName, BamlDecompilerSettings settings)
: this(CreateTypeSystemFromFile(fileName, settings), settings)
{
}
public XamlDecompiler(string fileName, IAssemblyResolver assemblyResolver, BamlDecompilerSettings settings)
: this(LoadPEFile(fileName, settings), assemblyResolver, settings)
{
}
public XamlDecompiler(PEFile module, IAssemblyResolver assemblyResolver, BamlDecompilerSettings settings)
: this(new BamlDecompilerTypeSystem(module, assemblyResolver), settings)
{
}
internal XamlDecompiler(BamlDecompilerTypeSystem typeSystem, BamlDecompilerSettings settings)
{
var ctx = XamlContext.Construct(typeSystem, document, token, bamlDecompilerOptions);
this.typeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem));
this.settings = settings;
this.module = typeSystem.MainModule;
if (module.TypeSystemOptions.HasFlag(TypeSystemOptions.Uncached))
throw new ArgumentException("Cannot use an uncached type system in the decompiler.");
}
static PEFile LoadPEFile(string fileName, BamlDecompilerSettings settings)
{
return new PEFile(
fileName,
new FileStream(fileName, FileMode.Open, FileAccess.Read),
streamOptions: PEStreamOptions.PrefetchEntireImage,
metadataOptions: MetadataReaderOptions.None
);
}
static BamlDecompilerTypeSystem CreateTypeSystemFromFile(string fileName, BamlDecompilerSettings settings)
{
var file = LoadPEFile(fileName, settings);
var resolver = new UniversalAssemblyResolver(fileName, settings.ThrowOnAssemblyResolveErrors,
file.DetectTargetFrameworkId(), file.DetectRuntimePack(),
PEStreamOptions.PrefetchMetadata,
MetadataReaderOptions.None);
return new BamlDecompilerTypeSystem(file, resolver);
}
public BamlDecompilationResult Decompile(Stream stream)
{
var ct = CancellationToken;
var document = BamlReader.ReadDocument(stream, ct);
var ctx = XamlContext.Construct(typeSystem, document, ct, settings);
var handler = HandlerMap.LookupHandler(ctx.RootNode.Type);
var elem = handler.Translate(ctx, ctx.RootNode, null);
@ -54,18 +115,12 @@ namespace ILSpy.BamlDecompiler @@ -54,18 +115,12 @@ namespace ILSpy.BamlDecompiler
foreach (var pass in rewritePasses)
{
token.ThrowIfCancellationRequested();
ct.ThrowIfCancellationRequested();
pass.Run(ctx, xaml);
}
if (assemblyReferences != null)
assemblyReferences.AddRange(ctx.Baml.AssemblyIdMap.Select(a => a.Value.AssemblyFullName));
return xaml;
var assemblyReferences = ctx.Baml.AssemblyIdMap.Select(a => a.Value.AssemblyFullName);
return new BamlDecompilationResult(xaml, assemblyReferences);
}
}
public class BamlDecompilerOptions
{
}
}
Loading…
Cancel
Save