// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Xml; using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.Documentation { /// /// Provides documentation from an .xml file (as generated by the Microsoft C# compiler). /// public class XmlDocumentationProvider : IDocumentationProvider { readonly IDictionary xmlDocumentation; #region Load From File public XmlDocumentationProvider(string fileName) { if (fileName == null) throw new ArgumentNullException("fileName"); this.xmlDocumentation = new Dictionary(); using (XmlTextReader xmlReader = new XmlTextReader(fileName)) { xmlReader.MoveToContent(); if (string.IsNullOrEmpty(xmlReader.GetAttribute("redirect"))) { ReadXmlDoc(xmlReader); } else { string redirectionTarget = GetRedirectionTarget(xmlReader.GetAttribute("redirect")); if (redirectionTarget != null) { Debug.WriteLine("XmlDoc " + fileName + " is redirecting to " + redirectionTarget); using (XmlTextReader redirectedXmlReader = new XmlTextReader(redirectionTarget)) { ReadXmlDoc(redirectedXmlReader); } } else { Debug.WriteLine("XmlDoc " + fileName + " is redirecting to " + xmlReader.GetAttribute("redirect") + ", but that file was not found."); } } } } static string GetRedirectionTarget(string target) { string programFilesDir = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); programFilesDir = AppendDirectorySeparator(programFilesDir); string corSysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); corSysDir = AppendDirectorySeparator(corSysDir); return LookupLocalizedXmlDoc(target.Replace("%PROGRAMFILESDIR%", programFilesDir) .Replace("%CORSYSDIR%", corSysDir)); } static string AppendDirectorySeparator(string dir) { if (dir.EndsWith("\\", StringComparison.Ordinal) || dir.EndsWith("/", StringComparison.Ordinal)) return dir; else return dir + Path.DirectorySeparatorChar; } internal static string LookupLocalizedXmlDoc(string fileName) { string xmlFileName = Path.ChangeExtension(fileName, ".xml"); string currentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; string localizedXmlDocFile = GetLocalizedName(xmlFileName, currentCulture); Debug.WriteLine("Try find XMLDoc @" + localizedXmlDocFile); if (File.Exists(localizedXmlDocFile)) { return localizedXmlDocFile; } Debug.WriteLine("Try find XMLDoc @" + xmlFileName); if (File.Exists(xmlFileName)) { return xmlFileName; } if (currentCulture != "en") { string englishXmlDocFile = GetLocalizedName(xmlFileName, "en"); Debug.WriteLine("Try find XMLDoc @" + englishXmlDocFile); if (File.Exists(englishXmlDocFile)) { return englishXmlDocFile; } } return null; } static string GetLocalizedName(string fileName, string language) { string localizedXmlDocFile = Path.GetDirectoryName(fileName); localizedXmlDocFile = Path.Combine(localizedXmlDocFile, language); localizedXmlDocFile = Path.Combine(localizedXmlDocFile, Path.GetFileName(fileName)); return localizedXmlDocFile; } #endregion #region Load from XmlReader public XmlDocumentationProvider(XmlReader reader) { if (reader == null) throw new ArgumentNullException("reader"); this.xmlDocumentation = new Dictionary(); ReadXmlDoc(reader); } public XmlDocumentationProvider(IDictionary dictionary) { if (dictionary == null) throw new ArgumentNullException("dictionary"); this.xmlDocumentation = dictionary; } void ReadXmlDoc(XmlReader reader) { while (reader.Read()) { if (reader.IsStartElement()) { switch (reader.LocalName) { case "members": ReadMembersSection(reader); break; } } } } void ReadMembersSection(XmlReader reader) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.EndElement: if (reader.LocalName == "members") { return; } break; case XmlNodeType.Element: if (reader.LocalName == "member") { string memberAttr = reader.GetAttribute(0); string innerXml = reader.ReadInnerXml(); xmlDocumentation[memberAttr] = innerXml; } break; } } } #endregion /// /// Gets all entries in the documentation file. /// public IDictionary XmlDocumentation { get { return xmlDocumentation; } } public string GetDocumentation(string key) { if (key == null) throw new ArgumentNullException("key"); string result; if (xmlDocumentation.TryGetValue(key, out result)) return result; else return null; } public string GetDocumentation(IEntity entity) { return GetDocumentation(GetDocumentationKey(entity)); } public static string GetDocumentationKey(IEntity entity) { if (entity == null) throw new ArgumentNullException("entity"); throw new NotImplementedException(); } } }