[monkeydoc] Add back several legacy members in their own class for maximum compatibility
[mono.git] / mcs / tools / monkeydoc / MonkeyDoc / Tree.cs
1 using System;
2 using System.IO;
3 using System.Text;
4 using System.Linq;
5 using System.Xml;
6 using System.Collections.Generic;
7
8 namespace MonkeyDoc
9 {
10         /// <summary>
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.
14         /// </summary>
15
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
18          */
19         public
20 #if LEGACY_MODE
21         partial
22 #endif
23         class Tree
24         {
25                 const long CurrentVersionNumber = 1;
26                 public readonly HelpSource HelpSource;
27         
28                 FileStream InputStream;
29                 BinaryReader InputReader;
30
31                 // This is the node which contains all the other node of the tree
32                 Node rootNode;
33
34                 /// <summary>
35                 ///   Load from file constructor
36                 /// </summary>
37                 public Tree (HelpSource hs, string filename)
38                 {
39                         HelpSource = hs;
40                         Encoding utf8 = new UTF8Encoding (false, true);
41
42                         if (!File.Exists (filename)){
43                                 throw new FileNotFoundException ();
44                         }
45                 
46                         InputStream = File.OpenRead (filename);
47                         InputReader = new BinaryReader (InputStream, utf8);
48                         byte [] sig = InputReader.ReadBytes (4);
49                 
50                         if (!GoodSig (sig))
51                                 throw new Exception ("Invalid file format");
52                 
53                         InputStream.Position = 4;
54                         // Try to read version information
55                         if (InputReader.ReadInt32 () == -(int)'v')
56                                 VersionNumber = InputReader.ReadInt64 ();
57                         else
58                                 InputStream.Position -= 4;
59
60                         var position = InputReader.ReadInt32 ();
61                         rootNode = new Node (this, position);
62                         InflateNode (rootNode);
63                 }
64
65                 /// <summary>
66                 ///    Tree creation and merged tree constructor
67                 /// </summary>
68                 public Tree (HelpSource hs, string caption, string url) : this (hs, null, caption, url)
69                 {
70                 }
71
72                 public Tree (HelpSource hs, Node parent, string caption, string element)
73                 {
74                         HelpSource = hs;
75                         rootNode = parent == null ? new Node (this, caption, element) : new Node (parent, caption, element);
76                 }
77
78                 /// <summary>
79                 ///    Saves the tree into the specified file using the help file format.
80                 /// </summary>
81                 public void Save (string file)
82                 {
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;
87                         
88                                 using (BinaryWriter writer = new BinaryWriter (output, utf8)) {
89                                         // Recursively dump
90                                         rootNode.Serialize (output, writer);
91
92                                         output.Position = 0;
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);
97                                 }
98                         }
99                 }
100
101                 public Node RootNode {
102                         get {
103                                 return rootNode;
104                         }
105                 }
106
107                 public long VersionNumber {
108                         get;
109                         private set;
110                 }
111
112                 static bool GoodSig (byte [] sig)
113                 {
114                         if (sig.Length != 4)
115                                 return false;
116                         return sig [0] == (byte) 'M'
117                                 && sig [1] == (byte) 'o'
118                             && sig [2] == (byte) 'H'
119                                 && sig [3] == (byte) 'P';
120                 }
121
122                 public void InflateNode (Node baseNode)
123                 {
124                         var address = baseNode.Address;
125                         if (address < 0)
126                                 address = -address;
127
128                         InputStream.Position = address;
129                         baseNode.Deserialize (InputReader);
130                 }
131
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 {
135                         get {
136                                 return VersionNumber == 0;
137                         }
138                 }
139         }
140
141         public static class TreeDumper
142         {
143                 static int indent;
144
145                 static void Indent ()
146                 {
147                         for (int i = 0; i < indent; i++)
148                                 Console.Write ("   ");
149                 }
150         
151                 public static void PrintTree (Node node)
152                 {
153                         Indent ();
154                         Console.WriteLine ("{0},{1}\t[PublicUrl: {2}]", node.Element, node.Caption, node.PublicUrl);
155                         if (node.Nodes.Count == 0)
156                                 return;
157
158                         indent++;
159                         foreach (Node n in node.Nodes)
160                                 PrintTree (n);
161                         indent--;
162                 }
163
164                 public static string ExportToTocXml (Node root, string title, string desc)
165                 {
166                         if (root == null)
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 ();
180                         }
181                         writer.WriteEndElement ();
182                         writer.WriteEndElement ();
183                         writer.Flush ();
184                         writer.Close ();
185
186                         return buf.ToString ();
187                 }
188         }
189 }