// 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();
}
}
}