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  }