diff options
Diffstat (limited to 'tools/Sandcastle/Source/ChmBuilder')
6 files changed, 992 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.config b/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.config new file mode 100644 index 0000000..5c0b7b8 --- /dev/null +++ b/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.config @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8" ?> +<configuration> + <languages> + <language id="1033" codepage="65001" name="0x409 English (United States)" /> + <language id="1028" codepage="950" name="0x404 Chinese (Taiwan)" /> + <language id="1029" codepage="1250" name="0x405 Czech" /> + <language id="1038" codepage="1250" name="0x40e Hungarian" /> + <language id="1041" codepage="932" name="0x411 Japanese" /> + <language id="1042" codepage="949" name="0x412 Korean" /> + <language id="1045" codepage="1250" name="0x415 Polish" /> + <language id="1049" codepage="1251" name="0x419 Russian" /> + <language id="1055" codepage="1254" name="0x41f Turkish" /> + <language id="2052" codepage="936" name="0x804 Chinese (PRC)" /> + </languages> + + + <chmTitles> + <title projectName="Test">Chm Test build</title> + </chmTitles> + + <!-- {0}:projectName, {1}:defaultTopic, {2}:Language, {3}:Title --> + <hhpTemplate> + <line>[OPTIONS]</line> + <!-- + <line>Binary Index=No</line> + --> + <line>Compatibility=1.1 or later</line> + <line>Compiled file={0}.chm</line> + <line>Contents file={0}.hhc</line> + <line>Index file={0}.hhk</line> + <line>Default Topic={1}</line> + <line>Full-text search=Yes</line> + <line>Language={2}</line> + <line>Title={3}</line> + + <line>[FILES]</line> + <line>icons\*.gif</line> + <line>art\*.gif</line> + <line>media\*.gif</line> + <line>scripts\*.js</line> + <line>styles\*.css</line> + <line>html\*.htm</line> + <line>[INFOTYPES]</line> + </hhpTemplate> +</configuration>
\ No newline at end of file diff --git a/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.cs b/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.cs new file mode 100644 index 0000000..1e2aeb2 --- /dev/null +++ b/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.cs @@ -0,0 +1,739 @@ +// Copyright © Microsoft Corporation. +// This source file is subject to the Microsoft Permissive License. +// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. +// All other rights reserved. + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Xml; +using System.Xml.XPath; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; +using System.Reflection; +using Microsoft.Ddue.Tools.CommandLine; + + +namespace Microsoft.Ddue.Tools +{ + + /// <summary> + /// <language id="1033" codepage="65001" name="0x409 English (United States)" /> + /// <language id="2052" codepage="936" name="0x804 Chinese (PRC)" /> + /// </summary> + internal struct LangInfo + { + public int CodePage; + public int ID; + public string Name; + } + + internal struct KKeywordInfo + { + public string File; + public string MainEntry; + public string SubEntry; + } + + public class ChmBuilder + { + + private ChmBuilderArgs _args; + private XPathDocument _config; + //private bool _metadata; + + //defalut topic of chm: get this value when gerenating hhc, save to hhp + private string _defaultTopic = string.Empty; + private bool _hasToc; + + private int _indentCount = 0; + //private string _htmlDirectory; + //private string _tocFile; + //private string _projectName; + //private string _outputDirectory; + private LangInfo _lang; + + //store all "K" type Keywords + List < KKeywordInfo > kkwdTable = new List < KKeywordInfo >(); + + //store all titles from html files + Hashtable titleTable = new Hashtable(); + + + public ChmBuilder(ChmBuilderArgs args) + { + this._args = args; + _args.htmlDirectory = StripEndBackSlash(Path.GetFullPath(_args.htmlDirectory)); + if (String.IsNullOrEmpty(_args.tocFile)) + _hasToc = false; + else + _hasToc = true; + _args.outputDirectory = StripEndBackSlash(Path.GetFullPath(_args.outputDirectory)); + _config = new XPathDocument(args.configFile); + LoadLanginfo(_args.langid); + } + public static int Main(string[] args) + { + ConsoleApplication.WriteBanner(); + + OptionCollection options = new OptionCollection(); + options.Add(new SwitchOption("?", "Show this help page.")); + options.Add(new StringOption("html", "Specify a html directory.", "htmlDirectory")); + options.Add(new StringOption("project", "Specify a project name.", "projectName")); + options.Add(new StringOption("toc", "Specify a toc file.", "tocFile")); + options.Add(new StringOption("lcid", "Specify a language id.If unspecified, 1033 is used.", "languageId")); + options.Add(new StringOption("out", "Specify an output directory. If unspecified, Chm is used.", "outputDirectory")); + options.Add(new BooleanOption("metadata", "Specify whether output metadata or not. Default value is false.")); + options.Add(new StringOption("config", "Specify a configuration file. If unspecified, ChmBuilder.config is used", "configFilePath")); + + ParseArgumentsResult results = options.ParseArguments(args); + if (results.Options["?"].IsPresent) + { + Console.WriteLine("ChmBuilder /html: /project: /toc: /out: /metadata:"); + options.WriteOptionSummary(Console.Out); + return (0); + } + + ChmBuilderArgs cbArgs = new ChmBuilderArgs(); + + // check for invalid options + if (!results.Success) + { + results.WriteParseErrors(Console.Out); + return (1); + } + + // check for missing or extra assembly directories + if (results.UnusedArguments.Count != 0) + { + Console.WriteLine("No non-option arguments are supported."); + return (1); + } + + if (!results.Options["html"].IsPresent) + { + ConsoleApplication.WriteMessage(LogLevel.Error, "You must specify a html directory."); + return (1); + } + cbArgs.htmlDirectory = (string)results.Options["html"].Value; + if (!Directory.Exists(cbArgs.htmlDirectory)) + { + ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("Direcotry: {0} not found.", cbArgs.htmlDirectory)); + return (1); + } + + if (!results.Options["project"].IsPresent) + { + ConsoleApplication.WriteMessage(LogLevel.Error, "You must specify a project name."); + return (1); + } + cbArgs.projectName = (string)results.Options["project"].Value; + + if (results.Options["lcid"].IsPresent) + { + try + { + cbArgs.langid = Convert.ToInt32(results.Options["lcid"].Value); + } + catch + { + ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("{0} is not a valid integer.", results.Options["lcid"].Value)); + return (1); + } + } + + + if (results.Options["toc"].IsPresent) + { + cbArgs.tocFile = (string)results.Options["toc"].Value; + if (!File.Exists(cbArgs.tocFile)) + { + ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("File: {0} not found.", cbArgs.tocFile)); + return (1); + } + } + + if (!results.Options["out"].IsPresent) + cbArgs.outputDirectory = "Chm"; + else + cbArgs.outputDirectory = (string)results.Options["out"].Value; + if (!Directory.Exists(cbArgs.outputDirectory)) + { + Directory.CreateDirectory(cbArgs.outputDirectory); + //ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("Direcotry: {0} not found.", cbArgs.outputDirectory)); + //return (1); + } + + if (results.Options["metadata"].IsPresent && (bool)results.Options["metadata"].Value) + { + cbArgs.metadata = true; + } + + if (results.Options["config"].IsPresent) + { + cbArgs.configFile = (string)results.Options["config"].Value; + } + if (!File.Exists(cbArgs.configFile)) + { + ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("Config file: {0} not found.", cbArgs.configFile)); + return (1); + } + + try + { + ChmBuilder chmBuilder = new ChmBuilder(cbArgs); + chmBuilder.Run(); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + return (1); + } + return 0; + } + + //there are some special characters in hxs html, just convert them to what we want + public static string ReplaceMarks(string input) + { + string ret = input.Replace("%3C", "<"); + ret = ret.Replace("%3E", ">"); + ret = ret.Replace("%2C", ","); + return ret; + } + + /// <summary> + /// eg: "c:\tmp\" to "c:\tmp" + /// </summary> + /// <param name="dir"></param> + /// <returns></returns> + public static string StripEndBackSlash(string dir) + { + if (dir.EndsWith("\\")) + return dir.Substring(0, dir.Length - 1); + else + return dir; + } + + public void Run() + { + WriteHtmls(); + WriteHhk(); + if (_hasToc) WriteHhc(); + WriteHhp(); + } + + private static int CompareKeyword(KKeywordInfo x, KKeywordInfo y) + { + if (x.MainEntry != y.MainEntry) + return (x.MainEntry.CompareTo(y.MainEntry)); + else + { + string s1 = x.SubEntry; + string s2 = y.SubEntry; + if (s1 == null) + s1 = string.Empty; + if (s2 == null) + s2 = string.Empty; + return (s1.CompareTo(s2)); + } + } + + /// <summary> + /// read chmTitle from chmBuilder.config + /// </summary> + /// <returns></returns> + private string GetChmTitle() + { + + XPathNodeIterator iter = _config.CreateNavigator().Select("/configuration/chmTitles/title"); + while (iter.MoveNext()) + { + if (iter.Current.GetAttribute("projectName", string.Empty).ToLower() == _args.projectName.ToLower()) + return iter.Current.Value; + } + + //if no title found, set title to projectname + return _args.projectName; + } + + /// <summary> + /// + /// </summary> + private void InsertSeealsoIndice() + { + kkwdTable.Sort(CompareKeyword); + string lastMainEntry = string.Empty; + for (int i = 0; i < kkwdTable.Count; i++) + { + if (!string.IsNullOrEmpty(kkwdTable[i].SubEntry)) + { + if (i > 0) + lastMainEntry = kkwdTable[i - 1].MainEntry; + if (lastMainEntry != kkwdTable[i].MainEntry) + { + KKeywordInfo seealso = new KKeywordInfo(); + seealso.MainEntry = kkwdTable[i].MainEntry; + kkwdTable.Insert(i, seealso); + } + } + } + } + + /// <summary> + /// load language info from config file + /// </summary> + /// <param name="lcid"></param> + private void LoadLanginfo(int lcid) + { + XPathNavigator node = _config.CreateNavigator().SelectSingleNode(String.Format("/configuration/languages/language[@id='{0}']", lcid.ToString())); + if (node != null) + { + _lang = new LangInfo(); + _lang.ID = lcid; + _lang.CodePage = Convert.ToInt32(node.GetAttribute("codepage", string.Empty)); + _lang.Name = node.GetAttribute("name", string.Empty); + } + else + { + throw new ArgumentException(String.Format("language {0} is not found in config file.", lcid)); + } + } + + private void WriteHhc() + { + XmlReaderSettings settings = new XmlReaderSettings(); + settings.ConformanceLevel = ConformanceLevel.Fragment; + settings.IgnoreWhitespace = true; + settings.IgnoreComments = true; + XmlReader reader = XmlReader.Create(_args.tocFile, settings); + + //<param name="Local" value="Html\15ed547b-455d-808c-259e-1eaa3c86dccc.htm"> + //"html" before GUID + string _localFilePrefix = _args.htmlDirectory.Substring(_args.htmlDirectory.LastIndexOf('\\') + 1); + + string fileAttr; + string titleValue; + using (StreamWriter sw = new StreamWriter(String.Format("{0}\\{1}.hhc", _args.outputDirectory, _args.projectName), false, Encoding.GetEncoding(_lang.CodePage))) + { + sw.WriteLine("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML/EN\">"); + sw.WriteLine("<HTML>"); + sw.WriteLine(" <BODY>"); + + bool bDefaultTopic = true; + while (reader.Read()) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + if (reader.Name == "topic") + { + _indentCount = reader.Depth; + fileAttr = reader.GetAttribute("file") + ".htm"; + if (titleTable.Contains(fileAttr)) + titleValue = (string)titleTable[fileAttr]; + else + titleValue = String.Empty; + + WriteHhcLine(sw, "<UL>"); + WriteHhcLine(sw, " <LI><OBJECT type=\"text/sitemap\">"); + WriteHhcLine(sw, String.Format(" <param name=\"Name\" value=\"{0}\">", titleValue)); + WriteHhcLine(sw, String.Format(" <param name=\"Local\" value=\"{0}\\{1}\">", _localFilePrefix, fileAttr)); + if (bDefaultTopic) + { + _defaultTopic = _localFilePrefix + "\\" + reader.GetAttribute("file") + ".htm"; + bDefaultTopic = false; + } + WriteHhcLine(sw, " </OBJECT></LI>"); + if (reader.IsEmptyElement) + { + WriteHhcLine(sw, "</UL>"); + } + } + break; + + case XmlNodeType.EndElement: + if (reader.Name == "topic") + { + _indentCount = reader.Depth; + WriteHhcLine(sw, "</UL>"); + } + break; + + default: + //Console.WriteLine(reader.Name); + break; + } + } + sw.WriteLine(" </BODY>"); + sw.WriteLine("</HTML>"); + } + } + + private void WriteHhcLine(TextWriter writer, string value) + { + //write correct indent space + writer.WriteLine(); + for (int i = 0; i < _indentCount - 1; i++) + writer.Write(" "); + writer.Write(value); + } + + private void WriteHhk() + { + int iPrefix = _args.outputDirectory.Length + 1; + bool isIndent = false; + + + InsertSeealsoIndice(); + using (StreamWriter sw = new StreamWriter(String.Format("{0}\\{1}.hhk", _args.outputDirectory, _args.projectName), false, Encoding.GetEncoding(_lang.CodePage))) + { + sw.WriteLine("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML/EN\">"); + sw.WriteLine("<HTML>"); + sw.WriteLine(" <BODY>"); + sw.WriteLine(" <UL>"); + + foreach (KKeywordInfo ki in kkwdTable) + { + if (!string.IsNullOrEmpty(ki.MainEntry)) + { + string kwdValue = ki.MainEntry; + if (!string.IsNullOrEmpty(ki.SubEntry)) + { + if (!isIndent) + { + isIndent = true; + sw.WriteLine(" <UL>"); + } + kwdValue = ki.SubEntry; + } + else + { + if (isIndent) + { + isIndent = false; + sw.WriteLine(" </UL>"); + } + } + + sw.WriteLine(" <LI><OBJECT type=\"text/sitemap\">"); + sw.WriteLine(String.Format(" <param name=\"Name\" value=\"{0}\">", kwdValue)); + if (String.IsNullOrEmpty(ki.File)) + sw.WriteLine(String.Format(" <param name=\"See Also\" value=\"{0}\">", kwdValue)); + else + sw.WriteLine(String.Format(" <param name=\"Local\" value=\"{0}\">", ki.File.Substring(iPrefix))); + sw.WriteLine(" </OBJECT><LI>"); + } + } + + sw.WriteLine(" </UL>"); + sw.WriteLine(" </BODY>"); + sw.WriteLine("</HTML>"); + } + } + + + /// <summary> + /// In hhp.template, {0} is projectName, {1} is defalutTopic, {2}:Language, {3}:Title + /// </summary> + private void WriteHhp() + { + string hhpFile = String.Format("{0}\\{1}.hhp", _args.outputDirectory, _args.projectName); + Encoding ei = Encoding.GetEncoding(_lang.CodePage); + + using (FileStream writer = File.OpenWrite(hhpFile)) + { + string var0 = _args.projectName; + string var1 = _defaultTopic; + string var2 = _lang.Name; + string var3 = GetChmTitle(); + + XPathNodeIterator iter = _config.CreateNavigator().Select("/configuration/hhpTemplate/line"); + + while (iter.MoveNext()) + { + String line = iter.Current.Value; + AddText(writer, String.Format(line, var0, var1, var2, var3), ei); + AddText(writer, "\r\n", ei); + } + } + } + + private void AddText(FileStream fs, string value, Encoding ei) + { + byte[] info = ei.GetBytes(value); + fs.Write(info, 0, info.Length); + } + + private void WriteHtmls() + { + string _outhtmldir = _args.outputDirectory + _args.htmlDirectory.Substring(_args.htmlDirectory.LastIndexOf('\\')); + HxsChmConverter converter = new HxsChmConverter(_args.htmlDirectory, _outhtmldir, titleTable, kkwdTable, _args.metadata); + converter.Process(); + } + } + + /// <summary> + /// Convert hxs-ready html page to chm-ready page + /// 1. strip of xmlisland; + /// 2. <mshelp:link> link tiltle </link> ==> <span class="nolink">link title</span> + /// </summary> + internal class HxsChmConverter + { + private string _currentFile; + private string _currentTitle; + private string _htmlDir; + List < KKeywordInfo > _kkeywords; + private bool _metadata; + private string _outputDir; + + Hashtable _titles; + + private int _topicCount = 0; + + public HxsChmConverter(string htmlDir, string outputDir, Hashtable titles, List < KKeywordInfo > kkeywords, bool metadata) + { + _htmlDir = htmlDir; + _outputDir = outputDir; + _titles = titles; + _kkeywords = kkeywords; + _metadata = metadata; + } + + public void Process() + { + _topicCount = 0; + ProcessDirectory(_htmlDir, _outputDir); + Console.WriteLine("Processed {0} files.", _topicCount); + } + + private void ProcessDirectory(string srcDir, string destDir) + { + if (!Directory.Exists(destDir)) + { + Directory.CreateDirectory(destDir); + } + + string[] fileEntries = Directory.GetFiles(srcDir); + foreach (string fileName in fileEntries) + { + string destFile = destDir + fileName.Substring(fileName.LastIndexOf('\\')); + + FileInfo fi = new FileInfo(fileName); + string extion = fi.Extension.ToLower(); + //process .htm and .html files, just copy other files, like css, gif. TFS DCR 318537 + if (extion == ".htm" || extion == ".html") + { + try + { + ProcessFile(fileName, destFile); + } + /* + catch (XmlException ex) + { + ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("Invalid XML file {0}", fileName)); + ConsoleApplication.WriteMessage(LogLevel.Error, ex.Message); + _stop = true; + return; + } + */ + catch (Exception) + { + ConsoleApplication.WriteMessage(LogLevel.Error, String.Format("failed to process file {0}", fileName)); + throw; + } + } + else + File.Copy(fileName, destFile, true); + } + + // Recurse into subdirectories of this directory. + string[] subdirectoryEntries = Directory.GetDirectories(srcDir, "*", SearchOption.TopDirectoryOnly); + foreach (string subdirectory in subdirectoryEntries) + { + DirectoryInfo di = new DirectoryInfo(subdirectory); + string newSubdir = destDir + "\\" + di.Name; + ProcessDirectory(subdirectory, newSubdir); + } + } + + private void ProcessFile(string srcFile, string destFile) + { + //Console.WriteLine("Processing:{0}",srcFile); + + XmlReaderSettings settings = new XmlReaderSettings(); + settings.ConformanceLevel = ConformanceLevel.Fragment; + settings.IgnoreWhitespace = false; + settings.IgnoreComments = true; + XmlReader reader = XmlReader.Create(srcFile, settings); + + XmlWriterSettings settings2 = new XmlWriterSettings(); + settings2.Indent = false; + settings2.IndentChars = "\t"; + settings2.OmitXmlDeclaration = true; + XmlWriter writer = XmlWriter.Create(destFile, settings2); + + _currentTitle = String.Empty; + _currentFile = destFile; + + _topicCount++; + + while (reader.Read()) + { + if (_metadata == false && reader.Name.ToLower() == "xml" && reader.NodeType == XmlNodeType.Element) + { + //skip xml data island + reader.ReadOuterXml(); + } + + switch (reader.NodeType) + { + + case XmlNodeType.Element: + string elementName = reader.Name.ToLower(); + + //skip <mshelp:link> node, + if (elementName == "mshelp:link") + { + writer.WriteStartElement("span"); + writer.WriteAttributeString("class", "nolink"); + reader.MoveToContent(); + } + + else + { + if (!String.IsNullOrEmpty(reader.Prefix)) + writer.WriteStartElement(reader.Prefix, reader.LocalName, null); + else + writer.WriteStartElement(reader.Name); + + if (reader.HasAttributes) + { + while (reader.MoveToNextAttribute()) + { + if (!String.IsNullOrEmpty(reader.Prefix)) + writer.WriteAttributeString(reader.Prefix, reader.LocalName, null, reader.Value); + else + //If we write the following content to output file, we will get xmlexception saying the 2003/5 namespace is redefined. So hard code to skip "xmlns". + //<pre>My.Computer.FileSystem.RenameFile(<span class="literal" xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5"> + if (!(reader.Depth > 2 && reader.Name.StartsWith("xmlns"))) + writer.WriteAttributeString(reader.Name, reader.Value); + } + // Move the reader back to the element node. + reader.MoveToElement(); + } + + //read html/head/title, save it to _currentTitle + if (reader.Depth == 2 && elementName == "title") + { + if (!reader.IsEmptyElement) //skip <Title/> node, fix bug 425406 + { + reader.Read(); + if (reader.NodeType == XmlNodeType.Text) + { + _currentTitle = reader.Value; + writer.WriteRaw(reader.Value); + } + } + } + + if (reader.IsEmptyElement) + writer.WriteEndElement(); + } + break; + + case XmlNodeType.Text: + writer.WriteValue(reader.Value); + break; + + case XmlNodeType.EndElement: + writer.WriteFullEndElement(); + break; + + case XmlNodeType.Whitespace: + case XmlNodeType.SignificantWhitespace: + writer.WriteWhitespace(reader.Value); + break; + + + default: + //Console.WriteLine(reader.Name); + break; + } + } + + writer.Close(); + + ReadXmlIsland(srcFile); + + _titles.Add(destFile.Substring(destFile.LastIndexOf("\\") + 1), _currentTitle); + } + + + /// <summary> + /// As XmlReader is forward only and we added support for leaving xmlisland data. + /// We have to use another xmlreader to find TocTile, keywords etc. + /// </summary> + /// <param name="filename"></param> + private void ReadXmlIsland(string filename) + { + XmlReaderSettings settings = new XmlReaderSettings(); + settings.ConformanceLevel = ConformanceLevel.Fragment; + settings.IgnoreWhitespace = false; + settings.IgnoreComments = true; + XmlReader reader = XmlReader.Create(filename, settings); + + //Fix TFS bug 289403: search if there is comma in k keyword except those in () or <>. + //sample1: "StoredNumber (T1,T2) class, about StoredNumber (T1,T2) class"; + //sample2: "StoredNumber <T1,T2> class, about StoredNumber <T1,T2> class"; + Regex r = new Regex(@",([^\)\>]+|([^\<\>]*\<[^\<\>]*\>[^\<\>]*)?|([^\(\)]*\([^\(\)]*\)[^\(\)]*)?)$"); + + while (reader.Read()) + { + if (reader.IsStartElement()) + { + if (reader.Name.ToLower() == "mshelp:toctitle") + { + string titleAttr = reader.GetAttribute("Title"); + if (!String.IsNullOrEmpty(titleAttr)) + _currentTitle = titleAttr; + } + + if (reader.Name.ToLower() == "mshelp:keyword") + { + string indexType = reader.GetAttribute("Index"); + if (indexType == "K") + { + KKeywordInfo kkwdinfo = new KKeywordInfo(); + string kkeyword = reader.GetAttribute("Term"); + if (!string.IsNullOrEmpty(kkeyword)) + { + kkeyword = ChmBuilder.ReplaceMarks(kkeyword); + Match match = r.Match(kkeyword); + if (match.Success) + { + kkwdinfo.MainEntry = kkeyword.Substring(0, match.Index); + kkwdinfo.SubEntry = kkeyword.Substring(match.Index + 1).TrimStart(new char[] { ' ' }); + } + else + { + kkwdinfo.MainEntry = kkeyword; + } + + kkwdinfo.File = _currentFile; + _kkeywords.Add(kkwdinfo); + } + } + } + } + + if (reader.NodeType == XmlNodeType.EndElement) + { + if (reader.Name == "xml") + return; + } + } + } + } +} diff --git a/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.csproj b/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.csproj new file mode 100644 index 0000000..8ee8adf --- /dev/null +++ b/tools/Sandcastle/Source/ChmBuilder/ChmBuilder.csproj @@ -0,0 +1,74 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.30729</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{D17FA1CB-06EF-43A6-B11E-2B8E2661AA6D}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>ChmBuilder</RootNamespace> + <AssemblyName>ChmBuilder</AssemblyName> + <SccProjectName> + </SccProjectName> + <SccLocalPath> + </SccLocalPath> + <SccAuxPath> + </SccAuxPath> + <SccProvider> + </SccProvider> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>2.0</OldToolsVersion> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ChmBuilder.cs"> + </Compile> + <Compile Include="ChmBuilderArgs.cs" /> + <Compile Include="GlobalSuppressions.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\CommandLine\CommandLine.csproj"> + <Project>{6CF7CA42-3706-4F6B-A2B4-10EF3F511888}</Project> + <Name>CommandLine</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="ChmBuilder.config"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <!-- Copy the output assemblies to a common binaries directory (ProductionTools). --> + <Target Name="AfterBuild"> + <CreateItem Include="$(OutputPath)\$(AssemblyName).*"> + <Output TaskParameter="Include" ItemName="ProductionFiles" /> + </CreateItem> + <Copy SourceFiles="@(ProductionFiles)" DestinationFolder="..\..\ProductionTools" /> + </Target> +</Project>
\ No newline at end of file diff --git a/tools/Sandcastle/Source/ChmBuilder/ChmBuilderArgs.cs b/tools/Sandcastle/Source/ChmBuilder/ChmBuilderArgs.cs new file mode 100644 index 0000000..7f21b83 --- /dev/null +++ b/tools/Sandcastle/Source/ChmBuilder/ChmBuilderArgs.cs @@ -0,0 +1,41 @@ +// Copyright © Microsoft Corporation. +// This source file is subject to the Microsoft Permissive License. +// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. +// All other rights reserved. + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Xml; +using System.Xml.XPath; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; +using System.Reflection; +using Microsoft.Ddue.Tools.CommandLine; + + +namespace Microsoft.Ddue.Tools +{ + public class ChmBuilderArgs + { + public string configFile; + public string htmlDirectory; + public int langid; + public bool metadata; + public string outputDirectory; + public string projectName; + public string tocFile; + + public ChmBuilderArgs() + { + this.langid = 1033; + this.tocFile = string.Empty; + this.metadata = false; + string configDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + this.configFile = Path.Combine(configDirectory, "ChmBuilder.config"); + } + + } +} diff --git a/tools/Sandcastle/Source/ChmBuilder/GlobalSuppressions.cs b/tools/Sandcastle/Source/ChmBuilder/GlobalSuppressions.cs new file mode 100644 index 0000000..07e378e --- /dev/null +++ b/tools/Sandcastle/Source/ChmBuilder/GlobalSuppressions.cs @@ -0,0 +1,53 @@ +// Copyright © Microsoft Corporation. +// This source file is subject to the Microsoft Permissive License. +// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. +// All other rights reserved. + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. +// +// To add a suppression to this file, right-click the message in the +// Error List, point to "Suppress Message(s)", and click +// "In Project Suppression File". +// You do not need to add suppressions to this file manually. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#GetChmTitle()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#ProcessDirectory(System.String,System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#ProcessFile(System.String,System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#ReadXmlIsland(System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Convert.ToInt32(System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#Main(System.String[])")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Convert.ToInt32(System.String)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#LoadLanginfo(System.Int32)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#LoadLanginfo(System.Int32)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#LoadLanginfo(System.Int32)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#Main(System.String[])")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#WriteHhc()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#WriteHhk()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#ProcessDirectory(System.String,System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#WriteHhc()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#WriteHhk()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#WriteHhp()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.CompareTo(System.String)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#CompareKeyword(Microsoft.Ddue.Tools.KKeywordInfo,Microsoft.Ddue.Tools.KKeywordInfo)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.EndsWith(System.String)", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#StripEndBackSlash(System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.LastIndexOf(System.String)", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#ProcessFile(System.String,System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.StartsWith(System.String)", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#ProcessFile(System.String,System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "BackSlash", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#StripEndBackSlash(System.String)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Chm")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Chm", Scope = "type", Target = "Microsoft.Ddue.Tools.ChmBuilder")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Chm", Scope = "type", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ddue", Scope = "namespace", Target = "Microsoft.Ddue.Tools")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "langid", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#langid")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#htmlDirectory")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#langid")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#metadata")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#outputDirectory")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#tocFile")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#projectName")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#.ctor(Microsoft.Ddue.Tools.ChmBuilderArgs)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#.ctor()")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilderArgs.#configFile")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily", Scope = "member", Target = "Microsoft.Ddue.Tools.HxsChmConverter.#.ctor(System.String,System.String,System.Collections.Hashtable,System.Collections.Generic.List`1<Microsoft.Ddue.Tools.KKeywordInfo>,System.Boolean)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#AddText(System.IO.FileStream,System.String,System.Text.Encoding)")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object[])", Scope = "member", Target = "Microsoft.Ddue.Tools.ChmBuilder.#WriteHhp()")] diff --git a/tools/Sandcastle/Source/ChmBuilder/Properties/AssemblyInfo.cs b/tools/Sandcastle/Source/ChmBuilder/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..6f99eff --- /dev/null +++ b/tools/Sandcastle/Source/ChmBuilder/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright © Microsoft Corporation. +// This source file is subject to the Microsoft Permissive License. +// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. +// All other rights reserved. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ChmBuilder")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("MS")] +[assembly: AssemblyProduct("ChmBuilder")] +[assembly: AssemblyCopyright("Copyright © MS 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: System.CLSCompliant(false)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("92e901de-6fa9-46c8-a46b-4ae15c60f3f2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("2.5.10626.00")] +[assembly: AssemblyFileVersion("2.5.10626.00")] |