summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/BuildAssembler/BuildComponents/ResolveArtLinksComponent.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/BuildComponents/ResolveArtLinksComponent.cs')
-rw-r--r--tools/Sandcastle/Source/BuildAssembler/BuildComponents/ResolveArtLinksComponent.cs192
1 files changed, 192 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/BuildComponents/ResolveArtLinksComponent.cs b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/ResolveArtLinksComponent.cs
new file mode 100644
index 0000000..3f13a7b
--- /dev/null
+++ b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/ResolveArtLinksComponent.cs
@@ -0,0 +1,192 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace Microsoft.Ddue.Tools {
+
+ public class ResolveArtLinksComponent : BuildComponent {
+
+ public ResolveArtLinksComponent (BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) {
+
+ XPathNodeIterator targets_nodes = configuration.Select("targets");
+ foreach (XPathNavigator targets_node in targets_nodes) {
+
+ string input = targets_node.GetAttribute("input", String.Empty);
+ if (String.IsNullOrEmpty(input)) WriteMessage(MessageLevel.Error, "Each targets element must have an input attribute specifying a directory containing art files.");
+ input = Environment.ExpandEnvironmentVariables(input);
+ if (!Directory.Exists(input)) WriteMessage(MessageLevel.Error, String.Format("The art input directory '{0}' does not exist.", input));
+
+ string baseOutputPath = targets_node.GetAttribute("baseOutput", String.Empty);
+ if (!String.IsNullOrEmpty(baseOutputPath)) {
+ baseOutputPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(baseOutputPath));
+ }
+
+ string outputPath_value = targets_node.GetAttribute("outputPath", string.Empty);
+ if (string.IsNullOrEmpty(outputPath_value)) WriteMessage(MessageLevel.Error, "Each targets element must have an output attribute specifying a directory in which to place referenced art files.");
+ XPathExpression output_XPath = XPathExpression.Compile(outputPath_value);
+
+ string linkValue = targets_node.GetAttribute("link", String.Empty);
+ if (String.IsNullOrEmpty(linkValue)) linkValue = "../art";
+ //linkValue = Environment.ExpandEnvironmentVariables(linkValue);
+
+ string map = targets_node.GetAttribute("map", String.Empty);
+ if (String.IsNullOrEmpty(map)) WriteMessage(MessageLevel.Error, "Each targets element must have a map attribute specifying a file that maps art ids to files in the input directory.");
+ map = Environment.ExpandEnvironmentVariables(map);
+ if (!File.Exists(map)) WriteMessage(MessageLevel.Error, String.Format("The art map file '{0}' does not exist.", map));
+
+ string format = targets_node.GetAttribute("format", String.Empty);
+ XPathExpression format_xpath = String.IsNullOrEmpty(format) ? null : XPathExpression.Compile(format);
+
+ string relative_to = targets_node.GetAttribute("relative-to", String.Empty);
+ XPathExpression relative_to_xpath = String.IsNullOrEmpty(relative_to) ? null : XPathExpression.Compile(relative_to);
+
+ AddTargets(map, input, baseOutputPath, output_XPath, linkValue, format_xpath, relative_to_xpath);
+
+ }
+
+ WriteMessage(MessageLevel.Info, String.Format("Indexed {0} art targets.", targets.Count));
+
+ }
+
+ private void AddTargets (string map, string input, string baseOutputPath, XPathExpression outputXPath, string link, XPathExpression formatXPath, XPathExpression relativeToXPath) {
+
+ XPathDocument document = new XPathDocument(map);
+
+ XPathNodeIterator items = document.CreateNavigator().Select("/*/item");
+ foreach (XPathNavigator item in items) {
+
+ string id = (string) item.Evaluate(artIdExpression);
+ string file = (string) item.Evaluate(artFileExpression);
+ string text = (string) item.Evaluate(artTextExpression);
+
+ id = id.ToLower();
+ string name = Path.GetFileName(file);
+
+ ArtTarget target = new ArtTarget();
+ target.Id = id;
+ target.InputPath = Path.Combine(input, file);
+ target.baseOutputPath = baseOutputPath;
+ target.OutputXPath = outputXPath;
+
+ if (string.IsNullOrEmpty(name)) target.LinkPath = link;
+ else target.LinkPath = string.Format("{0}/{1}", link, name);
+
+ target.Text = text;
+ target.Name = name;
+ target.FormatXPath = formatXPath;
+ target.RelativeToXPath = relativeToXPath;
+
+ targets[id] = target;
+ // targets.Add(id, target);
+ }
+
+ }
+
+ private XPathExpression artIdExpression = XPathExpression.Compile("string(@id)");
+ private XPathExpression artFileExpression = XPathExpression.Compile("string(image/@file)");
+ private XPathExpression artTextExpression = XPathExpression.Compile("string(image/altText)");
+
+ private Dictionary<string,ArtTarget> targets = new Dictionary<string,ArtTarget>();
+
+ public override void Apply (XmlDocument document, string id) {
+
+ XPathNodeIterator artLinkIterator = document.CreateNavigator().Select(artLinkExpression);
+ XPathNavigator[] artLinks = BuildComponentUtilities.ConvertNodeIteratorToArray(artLinkIterator);
+ foreach (XPathNavigator artLink in artLinks) {
+
+ string name = artLink.GetAttribute("target", String.Empty).ToLower();
+
+ if (targets.ContainsKey(name)) {
+ ArtTarget target = targets[name];
+
+ // evaluate the path
+ string path = document.CreateNavigator().Evaluate(target.OutputXPath).ToString();
+
+ if (target.baseOutputPath != null) path = Path.Combine(target.baseOutputPath, path);
+ string outputPath = Path.Combine(path, target.Name);
+
+ string targetDirectory = Path.GetDirectoryName(outputPath);
+
+ if (!Directory.Exists(targetDirectory)) Directory.CreateDirectory(targetDirectory);
+
+ if (File.Exists(target.InputPath)) {
+
+ if (File.Exists(outputPath)) {
+ File.SetAttributes(outputPath, FileAttributes.Normal);
+ }
+
+ File.Copy(target.InputPath, outputPath, true);
+ } else {
+ WriteMessage(MessageLevel.Warn, String.Format("The file '{0}' for the art target '{1}' was not found.", target.InputPath, name));
+ }
+
+ // Get the relative art path for HXF generation.
+ int index = target.LinkPath.IndexOf('/');
+ string artPath = target.LinkPath.Substring(index+1, target.LinkPath.Length - (index+1));
+
+ FileCreatedEventArgs fe = new FileCreatedEventArgs(artPath, Path.GetDirectoryName(path));
+ OnComponentEvent(fe);
+
+ XmlWriter writer = artLink.InsertAfter();
+
+ writer.WriteStartElement("img");
+ if (!String.IsNullOrEmpty(target.Text)) writer.WriteAttributeString("alt", target.Text);
+
+ if (target.FormatXPath == null) {
+ writer.WriteAttributeString("src", target.LinkPath);
+ }
+ else {
+ // WebDocs way, which uses the 'format' xpath expression to calculate the target path
+ // and then makes it relative to the current page if the 'relative-to' attribute is
+ // used.
+ string src = BuildComponentUtilities.EvalXPathExpr(document, target.FormatXPath, "key", Path.GetFileName(outputPath));
+ if (target.RelativeToXPath != null)
+ src = BuildComponentUtilities.GetRelativePath(src, BuildComponentUtilities.EvalXPathExpr(document, target.RelativeToXPath, "key", id));
+ writer.WriteAttributeString("src", src);
+ }
+
+ writer.WriteEndElement();
+
+ writer.Close();
+
+ artLink.DeleteSelf();
+
+ } else {
+ WriteMessage(MessageLevel.Warn, String.Format("Unknown art target '{0}'", name));
+ }
+
+ }
+
+ }
+
+ private static XPathExpression artLinkExpression = XPathExpression.Compile("//artLink");
+
+ }
+
+ internal class ArtTarget {
+
+ public string Id;
+
+ public string InputPath;
+
+ public string baseOutputPath;
+
+ public XPathExpression OutputXPath;
+
+ public string LinkPath;
+
+ public string Text;
+
+ public string Name;
+
+ public XPathExpression FormatXPath;
+
+ public XPathExpression RelativeToXPath;
+
+ }
+
+} \ No newline at end of file