Imported Upstream version 5.4.0.167

Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-08-21 15:34:15 +00:00
parent e49d6f06c0
commit 536cd135cc
12856 changed files with 563812 additions and 223249 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
// addins-provider.cs
//
// A provider to display Mono.Addins extension models
//
// Author:
// Lluis Sanchez Gual <lluis@novell.com>
//
// Copyright (c) 2007 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
using System;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Xml;
using System.Collections.Generic;
namespace Monodoc.Providers
{
public class AddinsProvider : Provider
{
string file;
public AddinsProvider (string xmlModelFile)
{
file = xmlModelFile;
if (!File.Exists (file))
throw new FileNotFoundException (String.Format ("The file `{0}' does not exist", file));
}
public override void PopulateTree (Tree tree)
{
string fileId = Path.GetFileNameWithoutExtension (file);
using (var f = File.OpenRead (file))
tree.HelpSource.Storage.Store (fileId, f);
XmlDocument doc = new XmlDocument ();
doc.Load (file);
foreach (XmlElement addin in doc.SelectNodes ("Addins/Addin")) {
string addinId = addin.GetAttribute ("fullId");
Node newNode = tree.RootNode.CreateNode (addin.GetAttribute ("name"), "addin:" + fileId + "#" + addinId);
foreach (XmlElement node in addin.SelectNodes ("ExtensionPoint")) {
string target = "extension-point:" + fileId + "#" + addinId + "#" + node.GetAttribute ("path");
Node newExt = newNode.CreateNode (node.GetAttribute ("name"), target);
foreach (XmlElement en in node.SelectNodes ("ExtensionNode")) {
string nid = en.GetAttribute ("id");
string nname = en.GetAttribute ("name");
newExt.CreateNode (nname, "extension-node:" + fileId + "#" + addinId + "#" + nid);
}
}
}
}
public override void CloseTree (HelpSource hs, Tree tree)
{
}
}
public class AddinsHelpSource : HelpSource
{
public AddinsHelpSource (string base_file, bool create) : base (base_file, create)
{
}
internal protected const string AddinPrefix = "addin:";
internal protected const string ExtensionPrefix = "extension-point:";
internal protected const string ExtensionNodePrefix = "extension-node:";
public override bool CanHandleUrl (string url)
{
return url.StartsWith (AddinPrefix, StringComparison.OrdinalIgnoreCase)
|| url.StartsWith (ExtensionPrefix, StringComparison.OrdinalIgnoreCase)
|| url.StartsWith (ExtensionNodePrefix, StringComparison.OrdinalIgnoreCase);
}
protected override string UriPrefix {
get {
return AddinPrefix;
}
}
public override DocumentType GetDocumentTypeForId (string id)
{
return DocumentType.AddinXml;
}
public override string GetInternalIdForUrl (string url, out Node node, out Dictionary<string, string> context)
{
var id = base.GetInternalIdForUrl (url, out node, out context);
var idParts = id.Split ('#');
context = new Dictionary<string, string> ();
context["FileID"] = idParts[0];
context["AddinID"] = idParts[1];
context["NodeID"] = idParts[2];
return idParts[0];
}
public override Node MatchNode (string url)
{
var prefix = new[] { AddinPrefix, ExtensionPrefix, ExtensionNodePrefix }.First (p => url.StartsWith (p, StringComparison.OrdinalIgnoreCase));
return base.MatchNode (prefix != null ? url.Substring (prefix.Length) : url);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,193 @@
//
// The ecmaspec provider is for ECMA specifications
//
// Authors:
// John Luke (jluke@cfl.rr.com)
// Ben Maurer (bmaurer@users.sourceforge.net)
//
// Use like this:
// mono assembler.exe --ecmaspec DIRECTORY --out name
//
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Xml;
using System.Collections.Generic;
using Lucene.Net.Index;
using Lucene.Net.Documents;
namespace Monodoc.Providers
{
public class EcmaSpecProvider : Provider
{
string basedir;
public EcmaSpecProvider (string base_directory)
{
basedir = base_directory;
if (!Directory.Exists (basedir))
throw new DirectoryNotFoundException (String.Format ("The directory `{0}' does not exist", basedir));
}
public override void PopulateTree (Tree tree)
{
XPathNavigator n = new XPathDocument (Path.Combine (basedir, "toc.xml")).CreateNavigator ();
n.MoveToRoot ();
n.MoveToFirstChild ();
PopulateNode (n.SelectChildren ("node", ""), tree.RootNode);
}
void PopulateNode (XPathNodeIterator nodes, Node treeNode)
{
foreach (XPathNavigator n in nodes) {
string secNumber = n.GetAttribute ("number", "");
string secName = n.GetAttribute ("name", "");
var storage = treeNode.Tree.HelpSource.Storage;
using (var file = File.OpenRead (Path.Combine (basedir, secNumber + ".xml")))
storage.Store (secNumber, file);
Node thisNode = treeNode.GetOrCreateNode (secNumber + ": " + secName, "ecmaspec:" + secNumber);
if (n.HasChildren)
PopulateNode (n.SelectChildren ("node", ""), thisNode);
}
}
public override void CloseTree (HelpSource hs, Tree tree)
{
}
}
public class EcmaSpecHelpSource : HelpSource
{
const string EcmaspecPrefix = "ecmaspec:";
const string TocPart = "%toc"; // What is returned as TocXml
const string SpecPart = "%spec"; // What is returned as Ecmaspec
public EcmaSpecHelpSource (string base_file, bool create) : base (base_file, create)
{
}
public override DocumentType GetDocumentTypeForId (string id)
{
return id.EndsWith (TocPart) ? DocumentType.TocXml : DocumentType.EcmaSpecXml;
}
public override bool IsGeneratedContent (string id)
{
return id == "root:" || id.EndsWith (TocPart);
}
public override bool IsMultiPart (string id, out IEnumerable<string> parts)
{
if (id == "root:" || id.EndsWith (TocPart) || id.EndsWith (SpecPart)) {
parts = null;
return false;
}
parts = MakeMultiPart (id);
return true;
}
IEnumerable<string> MakeMultiPart (string baseId)
{
yield return baseId + SpecPart;
yield return baseId + TocPart;
}
public override string GetText (string id)
{
Node n = id == "root:" ? Tree.RootNode : MatchNode (EcmaspecPrefix + id.Substring (0, id.Length - TocPart.Length));
if (n == null)
throw new ArgumentException ("id", string.Format ("{0} -> {1}", id, EcmaspecPrefix + id.Substring (0, id.Length - TocPart.Length)));
return TreeDumper.ExportToTocXml (n, "C# Language Specification", "In this section:");
}
public override Stream GetHelpStream (string id)
{
return id.EndsWith (SpecPart) ? base.GetHelpStream (id.Substring (0, id.IndexOf (SpecPart))) : base.GetHelpStream (id);
}
public override void PopulateSearchableIndex (IndexWriter writer)
{
foreach (Node n in Tree.RootNode.ChildNodes)
AddDocuments (writer, n);
}
protected override string UriPrefix {
get {
return EcmaspecPrefix;
}
}
void AddDocuments (IndexWriter writer, Node node)
{
string url = node.PublicUrl;
Stream file_stream = GetHelpStream (url.Substring (9));
if (file_stream == null) //Error
return;
XmlDocument xdoc = new XmlDocument ();
xdoc.Load (new XmlTextReader (file_stream));
//Obtain the title
XmlNode nelem = xdoc.DocumentElement;
string title = nelem.Attributes["number"].Value + ": " + nelem.Attributes["title"].Value;
//Obtain the text
StringBuilder s = new StringBuilder ();
GetTextNode (nelem, s);
string text = s.ToString ();
//Obtain the examples
StringBuilder s2 = new StringBuilder ();
GetExamples (nelem, s2);
string examples = s2.ToString ();
//Write to the Lucene Index all the parts
SearchableDocument doc = new SearchableDocument ();
doc.Title = title;
doc.HotText = title.Substring (title.IndexOf (':'));
doc.Url = url;
doc.Text = text;
doc.Examples = examples;
writer.AddDocument (doc.LuceneDoc);
if (node.IsLeaf)
return;
foreach (Node n in node.ChildNodes)
AddDocuments (writer, n);
}
void GetTextNode (XmlNode n, StringBuilder s)
{
//dont include c# code
if (n.Name == "code_example")
return;
//include all text from nodes
if (n.NodeType == XmlNodeType.Text)
s.Append (n.Value);
//recursively explore all nodes
if (n.HasChildNodes)
foreach (XmlNode n_child in n.ChildNodes)
GetTextNode (n_child, s);
}
void GetExamples (XmlNode n, StringBuilder s)
{
if (n.Name == "code_example") {
if (n.FirstChild.Name == "#cdata-section")
s.Append (n.FirstChild.Value);
} else {
if (n.HasChildNodes)
foreach (XmlNode n_child in n.ChildNodes)
GetExamples (n_child, s);
}
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using Monodoc.Ecma;
using Monodoc.Storage;
using Mono.Utilities;
namespace Monodoc.Providers
{
public class EcmaUncompiledHelpSource : EcmaHelpSource
{
readonly DirectoryInfo basedir;
readonly string basedoc;
public readonly string BasePath;
public new string Name {
get;
private set;
}
/* base_file: the directory containing the index.xml file, usually in Mono land .../Documentation/en
* markName: if true, we encase the node caption with [] to clearly mark it's from an uncompiled source
*/
public EcmaUncompiledHelpSource (string base_file, bool markName = true) : base ()
{
basedir = new DirectoryInfo (base_file);
BasePath = basedir.FullName;
basedoc = Path.Combine (basedir.FullName, "index.xml");
Name = ((string)XDocument.Load (basedoc).Root.Element ("Title")) ?? "UnnamedUncompiledSource";
if (markName)
Name = '[' + Name + ']';
Tree.RootNode.Caption = Name;
Func<XElement, string> indexGenerator = type => {
var nsName = (string)type.Parent.Attribute ("Name");
var typeName = (string)type.Attribute ("Name");
return Path.ChangeExtension (nsName + '/' + typeName, ".xml");
};
this.Storage = new UncompiledDocStorage (BasePath);
EcmaDoc.PopulateTreeFromIndexFile (basedoc, UriPrefix, Tree, null, null, indexGenerator);
}
protected override string UriPrefix {
get {
return "uncompiled:";
}
}
public override Stream GetImage (string url)
{
var path = Path.Combine (BasePath, "_images", url);
return File.Exists (path) ? File.OpenRead (path) : (Stream)null;
}
}
}

View File

@@ -0,0 +1,200 @@
//
// error-provider.cs
//
// Author:
// Ben Maurer (bmaurer@users.sourceforge.net)
//
// (C) 2003 Ben Maurer
// Copyright 2003-2011 Novell
// Copyright 2011 Xamarin Inc
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Linq;
using Lucene.Net.Index;
using Lucene.Net.Documents;
namespace Monodoc.Providers
{
public class ErrorProviderConfig
{
public string FilesPath;
public string Match;
public int ErrorNumSubstringStart;
public int ErrorNumSubstringLength;
public string FriendlyFormatString;
public override string ToString ()
{
var sb = new StringBuilder ();
var w = new StringWriter (sb);
w.WriteLine ("FilesPath: {0}", FilesPath);
w.WriteLine ("Match: {0}", Match);
w.WriteLine ("Error Number Substring: {0} Length:{1}", ErrorNumSubstringStart, ErrorNumSubstringLength);
w.WriteLine ("FriendlyFormatString: {0}", FriendlyFormatString);
return w.ToString ();
}
public Dictionary<string, ErrorDocumentation> Compile (HelpSource hs)
{
string[] files = Directory.GetFiles (FilesPath, Match);
var ret = new Dictionary<string, ErrorDocumentation> ();
foreach (string s in files) {
ErrorDocumentation d;
int errorNum = 0;
try {
errorNum = int.Parse (Path.GetFileName (s).Substring (ErrorNumSubstringStart, ErrorNumSubstringLength));
} catch {
Console.WriteLine ("Ignoring file {0}", s);
}
string errorName = String.Format (FriendlyFormatString, errorNum);
if (!ret.TryGetValue (errorName, out d))
ret[errorName] = d = new ErrorDocumentation (errorName);
if (d.Details == null) {
string xmlFile = Path.ChangeExtension (s, "xml");
if (File.Exists (xmlFile)) {
XmlSerializer cfgRdr = new XmlSerializer (typeof (ErrorDetails));
d.Details = (ErrorDetails)cfgRdr.Deserialize (new XmlTextReader (xmlFile));
}
}
// Encoding is same as used in MCS, so we will be able to do all those files
using (StreamReader reader = new StreamReader (s, Encoding.GetEncoding (28591))) {
d.Examples.Add (reader.ReadToEnd ());
}
}
return ret;
}
}
public class ErrorDocumentation
{
public string ErrorName;
public ErrorDetails Details;
public List<string> Examples = new List<string> ();
public ErrorDocumentation () {}
public ErrorDocumentation (string ErrorName)
{
this.ErrorName = ErrorName;
}
}
public class ErrorDetails
{
public XmlNode Summary;
public XmlNode Details;
}
public class ErrorProvider : Provider
{
ErrorProviderConfig config;
public ErrorProvider (string configFile)
{
config = ReadConfig (configFile);
}
public static ErrorProviderConfig ReadConfig (string file)
{
XmlSerializer cfgRdr = new XmlSerializer (typeof (ErrorProviderConfig));
ErrorProviderConfig ret = (ErrorProviderConfig)cfgRdr.Deserialize (new XmlTextReader (file));
// handle path rel to the config file
ret.FilesPath = Path.Combine (Path.GetDirectoryName (file), ret.FilesPath);
return ret;
}
public override void PopulateTree (Tree tree)
{
// everything is done in CloseTree so we can pack
}
public override void CloseTree (HelpSource hs, Tree tree)
{
var entries = config.Compile (hs);
MemoryStream ms = new MemoryStream ();
XmlSerializer writer = new XmlSerializer (typeof (ErrorDocumentation));
foreach (var de in entries) {
ErrorDocumentation d = de.Value;
string s = de.Key;
tree.RootNode.GetOrCreateNode (s, "error:" + s);
writer.Serialize (ms, d);
ms.Position = 0;
hs.Storage.Store (s, ms);
ms.SetLength (0);
}
tree.RootNode.Sort ();
}
}
public class ErrorHelpSource : HelpSource
{
public ErrorHelpSource (string base_file, bool create) : base (base_file, create)
{
}
public override string GetText (string id)
{
return TreeDumper.ExportToTocXml (Tree.RootNode, "Compiler Error Reference", "In this section:");
}
protected override string UriPrefix {
get {
return "error:";
}
}
public override bool IsGeneratedContent (string id)
{
return id == "root:";
}
public override DocumentType GetDocumentTypeForId (string id)
{
return id == "root:" ? DocumentType.TocXml : DocumentType.ErrorXml;
}
public override string GetInternalIdForUrl (string url, out Node node, out Dictionary<string, string> context)
{
var result = base.GetInternalIdForUrl (url, out node, out context);
return result.ToLower ();
}
public override void PopulateIndex (IndexMaker index_maker)
{
foreach (Node n in Tree.RootNode.ChildNodes)
index_maker.Add (n.Caption, n.Caption, n.Element);
}
public override void PopulateSearchableIndex (IndexWriter writer)
{
foreach (Node n in Tree.RootNode.ChildNodes) {
XmlSerializer reader = new XmlSerializer (typeof (ErrorDocumentation));
ErrorDocumentation d = (ErrorDocumentation)reader.Deserialize (GetHelpStream (n.Element.Substring (6)));
SearchableDocument doc = new SearchableDocument ();
doc.Title = d.ErrorName;
doc.Url = n.Element;
doc.Text = d.Details != null ? d.Details.ToString () : string.Empty;
doc.Examples = d.Examples.Cast<string> ().Aggregate ((e1, e2) => e1 + Environment.NewLine + e2);
doc.HotText = d.ErrorName;
writer.AddDocument (doc.LuceneDoc);
}
}
}
}

View File

@@ -0,0 +1,106 @@
//
// A provider to display man pages
//
// Authors:
// Johannes Roith <johannes@roith.de>
// Jonathan Pryor <jpryor@novell.com>
//
// (C) 2008 Novell, Inc.
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Linq;
using System.Collections.Generic;
namespace Monodoc.Providers
{
public class ManProvider : Provider
{
string[] tocFiles;
public ManProvider (string[] handbookTocFiles)
{
tocFiles = handbookTocFiles;
// huh...
if (!File.Exists (tocFiles[0]))
throw new FileNotFoundException (String.Format ("The table of contents, `{0}' does not exist", tocFiles[0]));
}
public override void PopulateTree (Tree tree)
{
foreach(string TocFile in tocFiles) {
XmlDocument doc = new XmlDocument();
doc.Load (TocFile);
XmlNodeList nodeList = doc.GetElementsByTagName("manpage");
Node nodeToAddChildrenTo = tree.RootNode;
var storage = nodeToAddChildrenTo.Tree.HelpSource.Storage;
foreach (XmlNode node in nodeList) {
XmlAttribute name = node.Attributes["name"];
XmlAttribute page = node.Attributes["page"];
if (name == null || page == null) continue;
if (!File.Exists (page.Value))
continue;
string target = "man:" + name.Value;
nodeToAddChildrenTo.CreateNode (name.Value, target);
if (File.Exists (page.Value))
using (var file = File.OpenRead (page.Value))
storage.Store (name.Value, file);
}
}
}
public override void CloseTree (HelpSource hs, Tree tree)
{
}
}
public class ManHelpSource : HelpSource
{
const string ManPrefix = "man:";
Dictionary<string, Node> nodesMap;
public ManHelpSource (string base_file, bool create) : base (base_file, create)
{
nodesMap = Tree.RootNode.ChildNodes.ToDictionary (n => n.Element);
}
// Since man always has a flat tree and rather small amount of item
// we store them in a dictionary
public override Node MatchNode (string url)
{
Node result;
return nodesMap.TryGetValue (url, out result) ? result : null;
}
public override DocumentType GetDocumentTypeForId (string id)
{
return id == "root:" ? DocumentType.TocXml : DocumentType.Man;
}
public override bool IsGeneratedContent (string id)
{
return id == "root:";
}
public override string GetText (string url)
{
return TreeDumper.ExportToTocXml (Tree.RootNode, "Mono Documentation Library", "Available man pages:");
}
protected override string UriPrefix {
get {
return ManPrefix;
}
}
}
}

View File

@@ -0,0 +1,153 @@
//
// The simple provider is an example provider
//
// Author:
// Miguel de Icaza (miguel@ximian.com)
//
// Use like this:
// mono assembler.exe --simple DIRECTORY --out name
//
// Then create a .source file in your sources directory, and copy
// name.tree and name.zip to the sources directory.
//
// To view the tree generated, use:
// mono dump.exe name.tree
//
namespace Monodoc {
using System;
using System.IO;
using System.Text;
//
// The simple provider generates the information source
//
public class SimpleProvider : Provider {
string basedir;
public SimpleProvider (string base_directory)
{
basedir = base_directory;
if (!Directory.Exists (basedir))
throw new FileNotFoundException (String.Format ("The directory `{0}' does not exist", basedir));
}
public override void PopulateTree (Tree tree)
{
Node top = tree.LookupNode ("Directory at: " + basedir, "simple:");
foreach (string dir in Directory.GetDirectories (basedir)){
string url = Path.GetFileName (dir);
Node n = top.LookupNode ("Dir: " + url, url);
PopulateDir (n, dir);
}
}
#pragma warning disable 219
void PopulateDir (Node me, string dir)
{
Console.WriteLine ("Adding: " + dir);
foreach (string child_dir in Directory.GetDirectories (dir)){
string url = Path.GetFileName (child_dir);
Node n = me.LookupNode ("Dir: " + url, "simple-directory:" + url);
PopulateDir (me, child_dir);
}
foreach (string file in Directory.GetFiles (dir)){
Console.WriteLine (" File: " + file);
string file_code = me.tree.HelpSource.PackFile (file);
//
// The url element encoded for the file is:
// originalfilename#CODE
//
// The code is assigned to us after the file has been packaged
// We use the original-filename later to render html or text files
//
Node n = me.LookupNode (Path.GetFileName (file), file + "#" + file_code);
}
}
public override void CloseTree (HelpSource hs, Tree tree)
{
}
}
//
// The HelpSource is used during the rendering phase.
//
public class SimpleHelpSource : HelpSource {
Encoding enc;
public SimpleHelpSource (string base_file, bool create) : base (base_file, create)
{
enc = new UTF8Encoding (false, false);
}
public override string GetText (string url, out Node match_node)
{
match_node = null;
string c = GetCachedText (url);
if (c != null)
return c;
if (url.StartsWith ("simple:") || url.StartsWith ("simple-directory:"))
return GetTextFromUrl (url);
return null;
}
string GetTextFromUrl (string url)
{
// Remove "simple:" prefix
url = url.Substring (7);
if (url.StartsWith ("simple-directory:"))
return String.Format ("<html>This is a directory entry point: {0} </html>",
url.Substring (17));
// Otherwise the last element of the url is the file code we got.
int pound = url.LastIndexOf ("#");
string code;
if (pound == -1)
code = url;
else
code = url.Substring (pound+1);
Stream s = GetHelpStream (code);
if (s == null)
return String.Format ("<html>No stream for this node: {0} </html>", url);
//
// Now, get the file type
//
int slash = url.LastIndexOf ("/");
string fname = url.Substring (slash + 1, pound - slash - 1).ToLower ();
if (fname.EndsWith (".html") || fname.EndsWith (".htm")){
TextReader r = new StreamReader (s, enc);
return r.ReadToEnd ();
}
if (fname.EndsWith (".png") || fname.EndsWith (".jpg") ||
fname.EndsWith (".jpeg") || fname.EndsWith (".gif")){
return "<html>Image file, have not implemented rendering this yet</html>";
}
// Convert text to HTML
StringBuilder result = new StringBuilder ("<html>");
TextReader reader = new StreamReader (s, enc);
string line;
while ((line = reader.ReadLine ()) != null){
result.Append (line);
result.Append ("<br>");
}
result.Append ("<html>");
return result.ToString ();
}
}
}

View File

@@ -0,0 +1,242 @@
//
// A provider that uses Windows help file xhtml TOC files and looks for the
// referenced documents to create the help source.
//
// Authors:
// Copyright 2003 Lee Mallabone <gnome@fonicmonkey.net>
// Johannes Roith <johannes@roith.de>
// Miguel de Icaza <miguel@ximian.com>
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
namespace Monodoc.Providers
{
public class XhtmlProvider : Provider
{
string tocFile;
readonly XNamespace ns = "http://www.w3.org/1999/xhtml";
public XhtmlProvider (string handbookTocFile)
{
tocFile = handbookTocFile;
if (!File.Exists (tocFile))
throw new FileNotFoundException (String.Format ("The table of contents, `{0}' does not exist", tocFile));
}
public override void PopulateTree (Tree tree)
{
var doc = XDocument.Load (tocFile);
var uls = doc.Descendants (ns + "body").First ().Elements (ns + "ul");
foreach (var ul in uls)
ParseUl (tree, tree.RootNode, ul);
}
void ParseUl (Tree tree, Node parent, XElement ul)
{
var storage = tree.HelpSource.Storage;
foreach (var e in ul.Elements (ns + "li")) {
var inner = e.Element (ns + "object");
if (inner == null)
continue;
string caption, element;
ObjectEntryToParams (inner, out caption, out element);
// Don't add if the backing file doesn't exist
if (!File.Exists (element)) {
Console.Error.WriteLine ("Warning: File `{0}' referenced in TOC but it doesn't exist. It will be ignored.", element);
continue;
}
using (var file = File.OpenRead (element))
storage.Store (element, file);
parent.CreateNode (caption, XhtmlHelpSource.XhtmlPrefix + element);
}
}
void ObjectEntryToParams (XElement obj, out string caption, out string element)
{
var ps = obj.Elements (ns + "param");
caption = ps
.Where (p => p.Attribute ("name").Value == "Name")
.Select (p => (string)p.Attribute ("value"))
.FirstOrDefault ();
caption = caption ?? string.Empty;
element = ps
.Where (p => p.Attribute ("name").Value == "Local")
.Select (p => (string)p.Attribute ("value"))
.FirstOrDefault ();
element = element ?? string.Empty;
}
public override void CloseTree (HelpSource hs, Tree tree)
{
}
}
public class XhtmlHelpSource : HelpSource
{
public XhtmlHelpSource (string base_file, bool create) : base (base_file, create)
{
}
internal const string XhtmlPrefix = "xhtml:";
protected override string UriPrefix {
get {
return XhtmlPrefix;
}
}
public override SortType SortType {
get {
return SortType.Element;
}
}
public override DocumentType GetDocumentTypeForId (string id)
{
return id == "root:" ? DocumentType.TocXml : DocumentType.MonoBook;
}
public override bool IsGeneratedContent (string id)
{
return id == "root:";
}
public override string GetText (string url)
{
return TreeDumper.ExportToTocXml (Tree.RootNode, "Mono Handbook", string.Empty);
}
public static string GetAbsoluteLink(string target, string url)
{
string value = null;
if (target.StartsWith ("#") ||
target.StartsWith ("T:") ||
target.StartsWith ("M:") ||
target.StartsWith ("P:") ||
target.StartsWith ("T:") ||
target.StartsWith ("E:") ||
target.StartsWith ("F:") ||
target.StartsWith ("O:") ||
target.StartsWith ("N:") ||
target.StartsWith ("api:"))
return null;
int endp = target.IndexOf(':');
if (endp == -1)
endp = 0;
string protocol = target.Substring(0, endp);
switch (protocol) {
case "mailto":
case "http":
case "https":
case "ftp":
case "news":
case "irc":
break;
default:
// handle absolute urls like: /html/en/images/empty.png
if (!target.StartsWith("/")) {
// url is something like "gnome/bindings/mono.html"
// This will get the path "gnome/bindings"
int slash = url.LastIndexOf ("/");
string tmpurl = url;
if (slash != -1)
tmpurl = url.Substring(0, slash);
// Count "../" in target and go one level down
// for each in tmpurl, eventually, then remove "../".
Regex reg1 = new Regex("../");
MatchCollection matches = reg1.Matches(target);
for(int i = 1; i < matches.Count; i++) {
slash = tmpurl.LastIndexOf ("/");
if (slash != -1)
tmpurl = tmpurl.Substring(0, slash);
}
target = target.Replace("../", "");
value = tmpurl + "/" + target;
} else {
value = target.Substring(1, target.Length - 1);
}
break;
}
return value;
}
XmlDocument RewriteLinks(XmlDocument docToProcess, string url)
{
XmlNodeList nodeList = docToProcess.GetElementsByTagName("a");
foreach(XmlNode node in nodeList) {
XmlElement element = (XmlElement) node;
if (element.HasAttribute("href") ){
XmlAttribute href = element.GetAttributeNode("href");
string target = href.Value;
target = GetAbsoluteLink(target, url);
if (target != null) {
string newtarget = String.Format ("source-id:{0}:xhtml:{1}", SourceID, target);
href.Value = newtarget;
}
}
}
nodeList = docToProcess.GetElementsByTagName("img");
foreach(XmlNode node in nodeList) {
XmlElement element = (XmlElement) node;
if (element.HasAttribute("src") ){
XmlAttribute href = element.GetAttributeNode("src");
string target = href.Value;
target = GetAbsoluteLink(target, url);
if (target != null) {
string newtarget = String.Format ("source-id:{0}:xhtml:{1}", SourceID, target);
href.Value = newtarget;
}
}
}
return docToProcess;
}
public override void PopulateIndex (IndexMaker index_maker)
{
PopulateIndexFromNodes (Tree.RootNode);
}
void PopulateIndexFromNodes (Node start)
{
/*var nodes = start.Nodes;
if (nodes != null) {
foreach (Node n in nodes)
PopulateIndexFromNodes (n);
}*/
}
}
}