// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixBuildTools.MsgGen { using Microsoft.CSharp; using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; using System.Xml; using System.Xml.Schema; /// /// The main entry point for MsgGen. /// public class MsgGen { /// /// The main entry point for MsgGen. /// /// Commandline arguments for the application. /// Returns the application error code. [STAThread] public static int Main(string[] args) { try { MsgGenMain msgGen = new MsgGenMain(args); } catch (Exception e) { Console.WriteLine("MsgGen.exe : fatal error MSGG0000: {0}\r\n\r\nStack Trace:\r\n{1}", e.Message, e.StackTrace); if (e is NullReferenceException || e is SEHException) { throw; } return 2; } return 0; } /// /// Main class for MsgGen. /// private class MsgGenMain { private bool showLogo; private bool showHelp; private string sourceFile; private string destClassFile; private string destResourcesFile; /// /// Main method for the MsgGen application within the MsgGenMain class. /// /// Commandline arguments to the application. public MsgGenMain(string[] args) { this.showLogo = true; this.showHelp = false; this.sourceFile = null; this.destClassFile = null; this.destResourcesFile = null; // parse the command line this.ParseCommandLine(args); if (null == this.sourceFile || null == this.destClassFile) { this.showHelp = true; } if (null == this.destResourcesFile) { this.destResourcesFile = Path.ChangeExtension(this.destClassFile, ".resources"); } // get the assemblies Assembly msgGenAssembly = Assembly.GetExecutingAssembly(); if (this.showLogo) { Console.WriteLine("Microsoft (R) Message Generation Tool version {0}", msgGenAssembly.GetName().Version.ToString()); Console.WriteLine("Copyright (C) Microsoft Corporation 2004. All rights reserved."); Console.WriteLine(); } if (this.showHelp) { Console.WriteLine(" usage: MsgGen.exe [-?] [-nologo] sourceFile destClassFile [destResourcesFile]"); Console.WriteLine(); Console.WriteLine(" -? this help information"); Console.WriteLine(); Console.WriteLine("For more information see: http://wix.sourceforge.net"); return; // exit } // load the schema XmlReader reader = null; XmlSchemaCollection schemaCollection = null; try { reader = new XmlTextReader(msgGenAssembly.GetManifestResourceStream("WixBuildTools.MsgGen.Xsd.messages.xsd")); schemaCollection = new XmlSchemaCollection(); schemaCollection.Add("http://schemas.microsoft.com/genmsgs/2004/07/messages", reader); } finally { reader.Close(); } // load the source file and process it using (StreamReader sr = new StreamReader(this.sourceFile)) { XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.None); XmlValidatingReader validatingReader = new XmlValidatingReader(sr.BaseStream, XmlNodeType.Document, context); validatingReader.Schemas.Add(schemaCollection); XmlDocument errorsDoc = new XmlDocument(); errorsDoc.Load(validatingReader); CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); using (ResourceWriter resourceWriter = new ResourceWriter(this.destResourcesFile)) { GenerateMessageFiles.Generate(errorsDoc, codeCompileUnit, resourceWriter); GenerateCSharpCode(codeCompileUnit, this.destClassFile); } } } /// /// Generate the actual C# code. /// /// The code DOM. /// Destination C# source file. public static void GenerateCSharpCode(CodeCompileUnit codeCompileUnit, string destClassFile) { // generate the code with the C# code provider CSharpCodeProvider provider = new CSharpCodeProvider(); // obtain an ICodeGenerator from the CodeDomProvider class ICodeGenerator gen = provider.CreateGenerator(); // create a TextWriter to a StreamWriter to the output file using (StreamWriter sw = new StreamWriter(destClassFile)) { using (IndentedTextWriter tw = new IndentedTextWriter(sw, " ")) { CodeGeneratorOptions options = new CodeGeneratorOptions(); // code generation options options.BlankLinesBetweenMembers = true; options.BracingStyle = "C"; // generate source code using the code generator gen.GenerateCodeFromCompileUnit(codeCompileUnit, tw, options); } } } /// /// Parse the commandline arguments. /// /// Commandline arguments. private void ParseCommandLine(string[] args) { for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (null == arg || "" == arg) // skip blank arguments { continue; } if ('-' == arg[0] || '/' == arg[0]) { string parameter = arg.Substring(1); if ("nologo" == parameter) { this.showLogo = false; } else if ("?" == parameter || "help" == parameter) { this.showHelp = true; } } else if ('@' == arg[0]) { using (StreamReader reader = new StreamReader(arg.Substring(1))) { string line; ArrayList newArgs = new ArrayList(); while (null != (line = reader.ReadLine())) { string newArg = ""; bool betweenQuotes = false; for (int j = 0; j < line.Length; ++j) { // skip whitespace if (!betweenQuotes && (' ' == line[j] || '\t' == line[j])) { if ("" != newArg) { newArgs.Add(newArg); newArg = null; } continue; } // if we're escaping a quote if ('\\' == line[j] && '"' == line[j]) { ++j; } else if ('"' == line[j]) // if we've hit a new quote { betweenQuotes = !betweenQuotes; continue; } newArg = String.Concat(newArg, line[j]); } if ("" != newArg) { newArgs.Add(newArg); } } string[] ar = (string[])newArgs.ToArray(typeof(string)); this.ParseCommandLine(ar); } } else if (null == this.sourceFile) { this.sourceFile = arg; } else if (null == this.destClassFile) { this.destClassFile = arg; } else if (null == this.destResourcesFile) { this.destResourcesFile = arg; } else { throw new ArgumentException(String.Format("Unknown argument '{0}'.", arg)); } } } } } }