/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Diagnostics; using dnlib.DotNet; using dnSpy.Contracts.Decompiler; namespace dnSpy.Contracts.Text { /// /// Extension methods /// public static class ITextColorWriterExtensions { /// /// Writes a newline /// /// Writer type /// Output /// public static T WriteLine(this T output) where T : ITextColorWriter { output.Write(BoxedTextColor.Text, Environment.NewLine); return output; } /// /// Writes a space /// /// Writer type /// Output /// public static T WriteSpace(this T output) where T : ITextColorWriter { output.Write(BoxedTextColor.Text, " "); return output; } /// /// Writes a comma followed by a space /// /// Writer type /// Output /// public static T WriteCommaSpace(this T output) where T : ITextColorWriter { output.Write(BoxedTextColor.Punctuation, ","); output.WriteSpace(); return output; } /// /// Writes a version /// /// Writer type /// Output /// Version /// public static T Write(this T output, Version? version) where T : ITextColorWriter { if (version is null) output.Write(BoxedTextColor.Error, "?.?.?.?"); else { output.Write(BoxedTextColor.Number, version.Major.ToString()); output.Write(BoxedTextColor.Number, "."); output.Write(BoxedTextColor.Number, version.Minor.ToString()); output.Write(BoxedTextColor.Number, "."); output.Write(BoxedTextColor.Number, version.Build.ToString()); output.Write(BoxedTextColor.Number, "."); output.Write(BoxedTextColor.Number, version.Revision.ToString()); } return output; } /// /// Writes an assembly /// /// Writer type /// Output /// Assembly /// public static T Write(this T output, IAssembly? asm) where T : ITextColorWriter { if (asm is null) return output; var asmDef = asm as AssemblyDef; bool isExe = asmDef is not null && asmDef.ManifestModule is not null && (asmDef.ManifestModule.Characteristics & dnlib.PE.Characteristics.Dll) == 0; output.Write(isExe ? BoxedTextColor.AssemblyExe : BoxedTextColor.Assembly, asm.Name); output.WriteCommaSpace(); output.Write(BoxedTextColor.InstanceProperty, "Version"); output.Write(BoxedTextColor.Operator, "="); output.Write(asm.Version); output.WriteCommaSpace(); output.Write(BoxedTextColor.InstanceProperty, "Culture"); output.Write(BoxedTextColor.Operator, "="); output.Write(BoxedTextColor.EnumField, UTF8String.IsNullOrEmpty(asm.Culture) ? "neutral" : asm.Culture.String); output.WriteCommaSpace(); var publicKey = PublicKeyBase.ToPublicKeyToken(asm.PublicKeyOrToken); output.Write(BoxedTextColor.InstanceProperty, publicKey is null || publicKey is PublicKeyToken ? "PublicKeyToken" : "PublicKey"); output.Write(BoxedTextColor.Operator, "="); if (PublicKeyBase.IsNullOrEmpty2(publicKey)) output.Write(BoxedTextColor.Keyword, "null"); else { Debug2.Assert(publicKey is not null); output.Write(BoxedTextColor.Number, publicKey.ToString()); } if ((asm.Attributes & AssemblyAttributes.Retargetable) != 0) { output.WriteCommaSpace(); output.Write(BoxedTextColor.InstanceProperty, "Retargetable"); output.Write(BoxedTextColor.Operator, "="); output.Write(BoxedTextColor.EnumField, "Yes"); } if ((asm.Attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_WindowsRuntime) { output.WriteCommaSpace(); output.Write(BoxedTextColor.InstanceProperty, "ContentType"); output.Write(BoxedTextColor.Operator, "="); output.Write(BoxedTextColor.EnumField, "WindowsRuntime"); } return output; } /// /// Writes a namespace /// /// Writer type /// Output /// Namespace /// public static T WriteNamespace(this T output, string? @namespace) where T : ITextColorWriter { if (@namespace is null) return output; if (@namespace.Length == 0) output.Write(BoxedTextColor.Punctuation, "-"); else { var parts = @namespace.Split('.'); for (int i = 0; i < parts.Length; i++) { if (i > 0) output.Write(BoxedTextColor.Operator, "."); output.Write(BoxedTextColor.Namespace, IdentifierEscaper.Escape(parts[i])); } } return output; } /// /// Writes a module name /// /// Writer type /// Output /// Module name /// public static T WriteModule(this T output, string name) where T : ITextColorWriter { output.Write(BoxedTextColor.AssemblyModule, NameUtilities.CleanName(name)); return output; } /// /// Writes a filename /// /// Writer type /// Output /// Filename /// public static T WriteFilename(this T output, string? filename) where T : ITextColorWriter { if (filename is null) return output; filename = NameUtilities.CleanName(filename)!; var s = filename.Replace('\\', '/'); var parts = s.Split('/'); int slashIndex = 0; for (int i = 0; i < parts.Length - 1; i++) { output.Write(BoxedTextColor.DirectoryPart, parts[i]); slashIndex += parts[i].Length; output.Write(BoxedTextColor.Text, filename[slashIndex].ToString()); slashIndex++; } var fn = parts[parts.Length - 1]; int index = fn.LastIndexOf('.'); if (index < 0) output.Write(BoxedTextColor.FileNameNoExtension, fn); else { string ext = fn.Substring(index + 1); fn = fn.Substring(0, index); output.Write(BoxedTextColor.FileNameNoExtension, fn); output.Write(BoxedTextColor.Text, "."); output.Write(BoxedTextColor.FileExtension, ext); } return output; } } }