1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Globalization;
5 using System.IO;
6 using System.Reflection;
7 using System.Text;
8
9 namespace MS.StrongName.ManagedSN
10 {
11 /// <summary>
12 /// Entry point for the ManagedSN tool. Handles the first level of command line parsing
13 /// and dispatching to appropriate methods for each option.
14 /// </summary>
15 public static class ManagedStrongName
16 {
17 /// <summary>
18 /// Return code for successfully completion
19 /// </summary>
20 public const int SuccessCode = 0;
21
22 /// <summary>
23 /// Return code when an error occurs or a failed completion
24 /// </summary>
25 public const int ErrorCode = 101;
26
27 private static IDictionary<string, Command> commands = null;
28
29 /// <summary>
30 /// Table of available commands
31 /// </summary>
32 internal static IDictionary<string, Command> CommandTable
33 {
34 get
35 {
36 if(commands == null)
37 commands = CreateCommandTable();
38
39 return commands;
40 }
41 }
42
43 /// <summary>
44 /// Managed tool that provides the same services as the .NET SDK's sn.exe tool
45 /// </summary>
46 public static int Main(string[] args)
47 {
48 Log.Message(String.Format(
49 CultureInfo.CurrentCulture,
50 Resources.Header,
51 FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion));
52 Log.Message(String.Empty);
53
54 // make sure we hook all unexpected errors to fail more gracefully
55 AppDomain.CurrentDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs e)
56 {
57 Log.Error(Resources.InternalError);
58 Log.Error(e.ExceptionObject.ToString());
59 return;
60 };
61
62 // get the first command line option
63 string option;
64 if(args.Length >= 1)
65 {
66 option = args[0].Trim();
67 if(String.IsNullOrEmpty(option))
68 option = "?"; // empty means get help
69
70 // get the - or / off the front of the option
71 if(option[0] == '-' || option[0] == '/')
72 option = option.Substring(1, option.Length - 1);
73 }
74 else
75 option = "?"; // no options means get help
76
77 // go do what's requested of us
78 OptionHandler handler;
79 Command command = CommandTable[option];
80
81 // null means we had an invalid option
82 if(command == null)
83 handler = new OptionHandler(InvalidOption);
84 else
85 handler = command.Handler;
86
87 return handler(args);
88 }
89
90 /// <summary>
91 /// Setup the table of options -> SN commands
92 /// </summary>
93 /// <returns>A dictionary mapping option names to Command objects</returns>
94 private static IDictionary<string, Command> CreateCommandTable()
95 {
96 Command[] commandList = new Command[]
97 {
98 new Command("d", new OptionHandler(Commands.DeleteKeyPair), Resources.DeleteKeyPairArguments, Resources.DeleteKeyPairHelp),
99 new Command("e", new OptionHandler(Commands.ExtractAssemblyPublicKey), Resources.ExtractAssemblyPublicKeyArguments, Resources.ExtractAssemblyPublicKeyHelp),
100 new Command("h", new OptionHandler(Commands.Help), null, Resources.HelpHelp),
101 new Command("?", new OptionHandler(Commands.Help), null, Resources.HelpHelp),
102 new Command("i", new OptionHandler(Commands.InstallKeyPair), Resources.InstallKeyPairArguments, Resources.InstallKeyPairHelp),
103 new Command("k", new OptionHandler(Commands.GenerateKey), Resources.GenerateKeyArguments, Resources.GenerateKeyHelp),
104 new Command("m", new OptionHandler(Commands.MachineKeyStore), Resources.MachineKeyStoreArguments, Resources.MachineKeyStoreHelp),
105 new Command("p", new OptionHandler(Commands.ExtractPublicKeyFromKeyPair), Resources.ExtractPublicKeyFromKeyPairArguments, Resources.ExtractPublicKeyFromKeyPairHelp),
106 new Command("pc", new OptionHandler(Commands.ExtractPublicKeyFromKeyContainer), Resources.ExtractPublicKeyFromKeyContainerArguments, Resources.ExtractPublicKeyFromKeyContainerHelp),
107 new Command("t", new OptionHandler(Commands.DisplayPublicKeyTokenFromFile), Resources.DisplayPublicKeyTokenFromFileArguments, Resources.DisplayPublicKeyTokenFromFileHelp),
108 new Command("tp", new OptionHandler(Commands.DisplayPublicKeyTokenWithKeyFromFile), Resources.DisplayPublicKeyTokenWithKeyFromFileArguments, Resources.DisplayPublicKeyTokenWithKeyFromFileHelp),
109 new Command("T", new OptionHandler(Commands.DisplayPublicKeyTokenFromAssembly), Resources.DisplayPublicKeyTokenFromAssemblyArguments, Resources.DisplayPublicKeyTokenFromAssemblyHelp),
110 new Command("Tp", new OptionHandler(Commands.DisplayPublicKeyTokenWithKeyFromAssembly), Resources.DisplayPublicKeyTokenWithKeyFromAssemblyArguments, Resources.DisplayPublicKeyTokenWithKeyFromAssemblyHelp),
111 new Command("v", new OptionHandler(Commands.Verify), Resources.VerifyArguments, Resources.VerifyHelp),
112 new Command("vf", new OptionHandler(Commands.ForceVerify), Resources.ForceVerifyArguments, Resources.ForceVerifyHelp)
113 };
114
115 // set the commands up in a dictionary
116 Dictionary<string, Command> commandTable = new Dictionary<string, Command>(commandList.Length);
117 foreach(Command command in commandList)
118 commandTable[command.Option] = command;
119
120 return commandTable;
121 }
122
123 /// <summary>
124 /// Display help for an invalid option
125 /// </summary>
126 private static int InvalidOption(string[] arguments)
127 {
128 Debug.Assert(arguments.Length > 0);
129
130 Log.Error(String.Format(
131 CultureInfo.InvariantCulture,
132 Resources.InvalidOption,
133 arguments[0]));
134 Log.Error(String.Empty);
135
136 return Commands.Help(arguments);
137 }
138
139 /// <summary>
140 /// Format a help string to be displayed on multiple lines
141 /// </summary>
142 /// <param name="help">help string to format</param>
143 /// <param name="padding">number of spaces to add to the beginning of each line</param>
144 public static string[] FormatHelp(string help, int padding)
145 {
146 Debug.Assert(help != null, "Null help string");
147 Debug.Assert(padding >= 0, "Invalid padding value");
148
149 int consoleSize = Console.WindowWidth;
150 List<string> lines = new List<string>((help.Length / consoleSize) + 1);
151
152 // split on whitespace
153 string[] words = help.Split(new char[] {' ', '\t', '\n'});
154
155 // setup the first line
156 StringBuilder currentLine = new StringBuilder(consoleSize);
157 currentLine.Append(' ', (int)padding);
158
159 // add each word in the help text
160 foreach(string word in words)
161 {
162 // if this word will make the line too big, start a new line
163 // allow an exception for the first word of a line, to prevent
164 // infinite looping when one word is bigger than the console
165 if(currentLine.Length != padding && currentLine.Length + word.Length >= consoleSize)
166 {
167 lines.Add(currentLine.ToString());
168
169 currentLine = new StringBuilder(consoleSize);
170 currentLine.Append(' ', (int)padding);
171 }
172
173 currentLine.Append(word);
174 currentLine.Append(' ');
175 }
176
177 // finish the last line
178 lines.Add(currentLine.ToString());
179 return lines.ToArray();
180 }
181 }
182 }