6 using System.Collections.Generic;
11 /// This tree is populated by the documentation providers, or populated
12 /// from a binary encoding of the tree. The format of the tree is designed
13 /// to minimize the need to load it in full.
16 /* Ideally this class should also be abstracted to let user have something
17 * else than a file as a backing store, a database for instance
25 const long CurrentVersionNumber = 1;
26 public readonly HelpSource HelpSource;
28 FileStream InputStream;
29 BinaryReader InputReader;
31 // This is the node which contains all the other node of the tree
35 /// Load from file constructor
37 public Tree (HelpSource hs, string filename)
40 Encoding utf8 = new UTF8Encoding (false, true);
42 if (!File.Exists (filename)){
43 throw new FileNotFoundException ();
46 InputStream = File.OpenRead (filename);
47 InputReader = new BinaryReader (InputStream, utf8);
48 byte [] sig = InputReader.ReadBytes (4);
51 throw new Exception ("Invalid file format");
53 InputStream.Position = 4;
54 // Try to read version information
55 if (InputReader.ReadInt32 () == -(int)'v')
56 VersionNumber = InputReader.ReadInt64 ();
58 InputStream.Position -= 4;
60 var position = InputReader.ReadInt32 ();
61 rootNode = new Node (this, position);
62 InflateNode (rootNode);
66 /// Tree creation and merged tree constructor
68 public Tree (HelpSource hs, string caption, string url) : this (hs, null, caption, url)
72 public Tree (HelpSource hs, Node parent, string caption, string element)
75 rootNode = parent == null ? new Node (this, caption, element) : new Node (parent, caption, element);
79 /// Saves the tree into the specified file using the help file format.
81 public void Save (string file)
83 Encoding utf8 = new UTF8Encoding (false, true);
84 using (FileStream output = File.OpenWrite (file)){
85 // Skip over the pointer to the first node.
86 output.Position = 4 + 4 + 8 + 4;
88 using (BinaryWriter writer = new BinaryWriter (output, utf8)) {
90 rootNode.Serialize (output, writer);
93 writer.Write (new byte [] { (byte) 'M', (byte) 'o', (byte) 'H', (byte) 'P' });
94 writer.Write (-(int)'v');
95 writer.Write (CurrentVersionNumber);
96 writer.Write (rootNode.Address);
101 public Node RootNode {
107 public long VersionNumber {
112 static bool GoodSig (byte [] sig)
116 return sig [0] == (byte) 'M'
117 && sig [1] == (byte) 'o'
118 && sig [2] == (byte) 'H'
119 && sig [3] == (byte) 'P';
122 public void InflateNode (Node baseNode)
124 var address = baseNode.Address;
128 InputStream.Position = address;
129 baseNode.Deserialize (InputReader);
132 // Nodes use this value to know if they should manually re-sort their child
133 // if they come from an older generator version
134 internal bool ForceResort {
136 return VersionNumber == 0;
141 public static class TreeDumper
145 static void Indent ()
147 for (int i = 0; i < indent; i++)
151 public static void PrintTree (Node node)
154 Console.WriteLine ("{0},{1}\t[PublicUrl: {2}]", node.Element, node.Caption, node.PublicUrl);
155 if (node.Nodes.Count == 0)
159 foreach (Node n in node.Nodes)
164 public static string ExportToTocXml (Node root, string title, string desc)
167 throw new ArgumentNullException ("root");
168 // Return a toc index of sub-nodes
169 StringBuilder buf = new StringBuilder ();
170 var writer = XmlWriter.Create (buf);
171 writer.WriteStartElement ("toc");
172 writer.WriteAttributeString ("title", title ?? string.Empty);
173 writer.WriteElementString ("description", desc ?? string.Empty);
174 writer.WriteStartElement ("list");
175 foreach (Node n in root.Nodes) {
176 writer.WriteStartElement ("item");
177 writer.WriteAttributeString ("url", n.Element);
178 writer.WriteValue (n.Caption);
179 writer.WriteEndElement ();
181 writer.WriteEndElement ();
182 writer.WriteEndElement ();
186 return buf.ToString ();