// Copyright (c) 2020 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.IO; using System.Linq; using System.Reflection.PortableExecutable; using System.Xml; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler { /// /// A implementation that creates the projects in the default format. /// sealed class ProjectFileWriterDefault : IProjectFileWriter { /// /// Creates a new instance of the class. /// /// A new instance of the class. public static IProjectFileWriter Create() => new ProjectFileWriterDefault(); /// public void Write( TextWriter target, IProjectInfoProvider project, IEnumerable files, MetadataFile module) { const string ns = "http://schemas.microsoft.com/developer/msbuild/2003"; string platformName = module is PEFile peFile ? TargetServices.GetPlatformName(peFile) : "AnyCPU"; var targetFramework = TargetServices.DetectTargetFramework(module); if (targetFramework.Identifier == ".NETFramework" && targetFramework.VersionNumber == 200) targetFramework = TargetServices.DetectTargetFrameworkNET20(module, project.AssemblyResolver, targetFramework); List typeGuids = new List(); if (targetFramework.IsPortableClassLibrary) typeGuids.Add(ProjectTypeGuids.PortableLibrary); typeGuids.Add(ProjectTypeGuids.CSharpWindows); using (XmlTextWriter w = new XmlTextWriter(target)) { w.Formatting = Formatting.Indented; w.WriteStartDocument(); w.WriteStartElement("Project", ns); w.WriteAttributeString("ToolsVersion", "4.0"); w.WriteAttributeString("DefaultTargets", "Build"); w.WriteStartElement("PropertyGroup"); w.WriteElementString("ProjectGuid", project.ProjectGuid.ToString("B").ToUpperInvariant()); w.WriteElementString("ProjectTypeGuids", string.Join(";", typeGuids.Select(g => g.ToString("B").ToUpperInvariant()))); w.WriteStartElement("Configuration"); w.WriteAttributeString("Condition", " '$(Configuration)' == '' "); w.WriteValue("Debug"); w.WriteEndElement(); // w.WriteStartElement("Platform"); w.WriteAttributeString("Condition", " '$(Platform)' == '' "); w.WriteValue(platformName); w.WriteEndElement(); // string outputType; PEHeaders headers = (module as PEFile)?.Reader.PEHeaders; switch (headers?.PEHeader.Subsystem) { case Subsystem.WindowsGui when !headers.IsDll: outputType = "WinExe"; break; case Subsystem.WindowsCui when !headers.IsDll: outputType = "Exe"; break; default: outputType = "Library"; break; } w.WriteElementString("OutputType", outputType); w.WriteElementString("LangVersion", project.LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.')); w.WriteElementString("AssemblyName", module.Name); if (targetFramework.Identifier != null) w.WriteElementString("TargetFrameworkIdentifier", targetFramework.Identifier); if (targetFramework.VersionString != null) w.WriteElementString("TargetFrameworkVersion", targetFramework.VersionString); if (targetFramework.Profile != null) w.WriteElementString("TargetFrameworkProfile", targetFramework.Profile); w.WriteElementString("WarningLevel", "4"); w.WriteElementString("AllowUnsafeBlocks", "True"); if (project.StrongNameKeyFile != null) { w.WriteElementString("SignAssembly", "True"); w.WriteElementString("AssemblyOriginatorKeyFile", Path.GetFileName(project.StrongNameKeyFile)); } w.WriteEndElement(); // w.WriteStartElement("PropertyGroup"); // platform-specific w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' "); w.WriteElementString("PlatformTarget", platformName); if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU" && ((module as PEFile)?.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0) { w.WriteElementString("Prefer32Bit", "false"); } w.WriteEndElement(); // (platform-specific) w.WriteStartElement("PropertyGroup"); // Debug w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' "); w.WriteElementString("OutputPath", "bin\\Debug\\"); w.WriteElementString("DebugSymbols", "true"); w.WriteElementString("DebugType", "full"); w.WriteElementString("Optimize", "false"); w.WriteEndElement(); // (Debug) w.WriteStartElement("PropertyGroup"); // Release w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' "); w.WriteElementString("OutputPath", "bin\\Release\\"); w.WriteElementString("DebugSymbols", "true"); w.WriteElementString("DebugType", "pdbonly"); w.WriteElementString("Optimize", "true"); w.WriteEndElement(); // (Release) w.WriteStartElement("ItemGroup"); // References foreach (var r in module.AssemblyReferences) { if (r.Name != "mscorlib") { w.WriteStartElement("Reference"); w.WriteAttributeString("Include", r.Name); var asm = project.AssemblyResolver.Resolve(r); if (asm != null && !project.AssemblyReferenceClassifier.IsGacAssembly(r)) { w.WriteElementString("HintPath", asm.FileName); } w.WriteEndElement(); } } w.WriteEndElement(); // (References) foreach (IGrouping gr in files.GroupBy(f => f.ItemType).OrderBy(g => g.Key)) { w.WriteStartElement("ItemGroup"); foreach (var item in gr.OrderBy(f => f.FileName, StringComparer.OrdinalIgnoreCase)) { w.WriteStartElement(gr.Key); w.WriteAttributeString("Include", item.FileName); if (item.AdditionalProperties != null) { foreach (var (key, value) in item.AdditionalProperties) w.WriteAttributeString(key, value); } w.WriteEndElement(); } w.WriteEndElement(); } if (targetFramework.IsPortableClassLibrary) { w.WriteStartElement("Import"); w.WriteAttributeString("Project", "$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets"); w.WriteEndElement(); } else { w.WriteStartElement("Import"); w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"); w.WriteEndElement(); } w.WriteEndDocument(); } } } }