diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs index 21ea662a6..76ecae963 100644 --- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs +++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs @@ -7,6 +7,10 @@ using System.ComponentModel.Composition; using System.IO; using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy; +using System.Resources; +using System.Collections; +using System.Linq; namespace ILSpy.BamlDecompiler { @@ -26,4 +30,19 @@ namespace ILSpy.BamlDecompiler return null; } } + + [Export(typeof(IResourceFileHandler))] + public sealed class BamlResourceFileHandler : IResourceFileHandler + { + public string EntryType => "Page"; + public bool CanHandle(string name, DecompilationOptions options) => name.EndsWith(".baml", StringComparison.OrdinalIgnoreCase); + + public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options) + { + var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetAssemblyResolver(), assembly.AssemblyDefinition, stream); + fileName = Path.ChangeExtension(fileName, ".xaml"); + document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName)); + return fileName; + } + } } diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 5c6e84f5d..243e2275a 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -137,6 +137,7 @@ + diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 031fa4247..51e81a9b4 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -511,63 +511,46 @@ namespace ICSharpCode.ILSpy #region WriteResourceFilesInProject IEnumerable> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet directories) { - //AppDomain bamlDecompilerAppDomain = null; - //try { - foreach (EmbeddedResource r in assembly.ModuleDefinition.Resources.OfType()) { - string fileName; - Stream s = r.GetResourceStream(); - s.Position = 0; - if (r.Name.EndsWith(".g.resources", StringComparison.OrdinalIgnoreCase)) { - IEnumerable rs = null; - try { - rs = new ResourceSet(s).Cast(); + foreach (EmbeddedResource r in assembly.ModuleDefinition.Resources.OfType()) { + Stream stream = r.GetResourceStream(); + stream.Position = 0; + + IEnumerable entries; + if (r.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase) && GetEntries(stream, out entries) && entries.All(e => e.Value is Stream)) { + foreach (var pair in entries) { + string fileName = Path.Combine(((string)pair.Key).Split('/').Select(p => TextView.DecompilerTextView.CleanUpName(p)).ToArray()); + string dirName = Path.GetDirectoryName(fileName); + if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName)) { + Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dirName)); } - catch (ArgumentException) { + Stream entryStream = (Stream)pair.Value; + bool handled = false; + foreach (var handler in App.CompositionContainer.GetExportedValues()) { + if (handler.CanHandle(fileName, options)) { + handled = true; + entryStream.Position = 0; + yield return Tuple.Create(handler.EntryType, handler.WriteResourceToFile(assembly, fileName, entryStream, options)); + break; + } } - if (rs != null && rs.All(e => e.Value is Stream)) { - foreach (var pair in rs) { - fileName = Path.Combine(((string)pair.Key).Split('/').Select(p => TextView.DecompilerTextView.CleanUpName(p)).ToArray()); - string dirName = Path.GetDirectoryName(fileName); - if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName)) { - Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dirName)); - } - Stream entryStream = (Stream)pair.Value; + if (!handled) { + using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) + { entryStream.Position = 0; - if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) { -// MemoryStream ms = new MemoryStream(); -// entryStream.CopyTo(ms); - // TODO implement extension point -// var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assembly.FileName); -// string xaml = null; -// try { -// xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly)); -// } -// catch (XamlXmlWriterException) { } // ignore XAML writer exceptions -// if (xaml != null) { -// File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml); -// yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml")); -// continue; -// } - } - using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { - entryStream.CopyTo(fs); - } - yield return Tuple.Create("Resource", fileName); + entryStream.CopyTo(fs); } - continue; + yield return Tuple.Create("EmbeddedResource", fileName); } } - fileName = GetFileNameForResource(r.Name, directories); - using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { - s.CopyTo(fs); + } else { + string fileName = GetFileNameForResource(r.Name, directories); + using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) + { + stream.CopyTo(fs); } yield return Tuple.Create("EmbeddedResource", fileName); } - //} - //finally { - // if (bamlDecompilerAppDomain != null) - // AppDomain.Unload(bamlDecompilerAppDomain); - //} + } } string GetFileNameForResource(string fullName, HashSet directories) @@ -584,6 +567,17 @@ namespace ICSharpCode.ILSpy } return fileName; } + + bool GetEntries(Stream stream, out IEnumerable entries) + { + try { + entries = new ResourceSet(stream).Cast(); + return true; + } catch (ArgumentException) { + entries = null; + return false; + } + } #endregion AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null, bool isSingleMember = false) diff --git a/ILSpy/Languages/IResourceFileHandler.cs b/ILSpy/Languages/IResourceFileHandler.cs new file mode 100644 index 000000000..fd040b1a1 --- /dev/null +++ b/ILSpy/Languages/IResourceFileHandler.cs @@ -0,0 +1,12 @@ +using System; +using System.IO; + +namespace ICSharpCode.ILSpy +{ + public interface IResourceFileHandler + { + string EntryType { get; } + bool CanHandle(string name, DecompilationOptions options); + string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options); + } +} diff --git a/ILSpy/VB/VBLanguage.cs b/ILSpy/VB/VBLanguage.cs index 4aad4a870..d9e9801e2 100644 --- a/ILSpy/VB/VBLanguage.cs +++ b/ILSpy/VB/VBLanguage.cs @@ -324,72 +324,59 @@ namespace ICSharpCode.ILSpy.VB #region WriteResourceFilesInProject IEnumerable> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet directories) { - //AppDomain bamlDecompilerAppDomain = null; - //try { - foreach (EmbeddedResource r in assembly.ModuleDefinition.Resources.OfType()) { - string fileName; - Stream s = r.GetResourceStream(); - s.Position = 0; - if (r.Name.EndsWith(".g.resources", StringComparison.OrdinalIgnoreCase)) { - IEnumerable rs = null; - try { - rs = new ResourceSet(s).Cast(); + foreach (EmbeddedResource r in assembly.ModuleDefinition.Resources.OfType()) { + Stream stream = r.GetResourceStream(); + stream.Position = 0; + + IEnumerable entries; + if (r.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase) && GetEntries(stream, out entries) && entries.All(e => e.Value is Stream)) { + foreach (var pair in entries) { + string fileName = Path.Combine(((string)pair.Key).Split('/').Select(p => TextView.DecompilerTextView.CleanUpName(p)).ToArray()); + string dirName = Path.GetDirectoryName(fileName); + if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName)) + { + Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dirName)); } - catch (ArgumentException) { + Stream entryStream = (Stream)pair.Value; + bool handled = false; + foreach (var handler in App.CompositionContainer.GetExportedValues()) + { + if (handler.CanHandle(fileName, options)) { + handled = true; + entryStream.Position = 0; + yield return Tuple.Create(handler.EntryType, handler.WriteResourceToFile(assembly, fileName, entryStream, options)); + break; + } } - if (rs != null && rs.All(e => e.Value is Stream)) { - foreach (var pair in rs) { - fileName = Path.Combine(((string)pair.Key).Split('/').Select(p => TextView.DecompilerTextView.CleanUpName(p)).ToArray()); - string dirName = Path.GetDirectoryName(fileName); - if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName)) { - Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dirName)); - } - Stream entryStream = (Stream)pair.Value; + if (!handled) { + using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) + { entryStream.Position = 0; - if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) { - //MemoryStream ms = new MemoryStream(); - //entryStream.CopyTo(ms); - // TODO implement extension point -// var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assembly.FileName); -// string xaml = null; -// try { -// xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly)); -// } -// catch (XamlXmlWriterException) { } // ignore XAML writer exceptions -// if (xaml != null) { -// File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml); -// yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml")); -// continue; -// } - } - using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { - entryStream.CopyTo(fs); - } - yield return Tuple.Create("Resource", fileName); + entryStream.CopyTo(fs); } - continue; + yield return Tuple.Create("EmbeddedResource", fileName); } } - fileName = GetFileNameForResource(r.Name, directories); - using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { - s.CopyTo(fs); + } else { + string fileName = GetFileNameForResource(r.Name, directories); + using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) + { + stream.CopyTo(fs); } yield return Tuple.Create("EmbeddedResource", fileName); } - //} - //finally { - // if (bamlDecompilerAppDomain != null) - // AppDomain.Unload(bamlDecompilerAppDomain); - //} + } } string GetFileNameForResource(string fullName, HashSet directories) { string[] splitName = fullName.Split('.'); string fileName = TextView.DecompilerTextView.CleanUpName(fullName); - for (int i = splitName.Length - 1; i > 0; i--) { + for (int i = splitName.Length - 1; i > 0; i--) + { string ns = string.Join(".", splitName, 0, i); - if (directories.Contains(ns)) { + if (directories.Contains(ns)) + { string name = string.Join(".", splitName, i, splitName.Length - i); fileName = Path.Combine(ns, TextView.DecompilerTextView.CleanUpName(name)); break; @@ -397,8 +384,22 @@ namespace ICSharpCode.ILSpy.VB } return fileName; } + + bool GetEntries(Stream stream, out IEnumerable entries) + { + try + { + entries = new ResourceSet(stream).Cast(); + return true; + } + catch (ArgumentException) + { + entries = null; + return false; + } + } #endregion - + public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));