[runtime] Disable some tests in full-aot mode which cannot be AOTed because of type...
[mono.git] / mcs / class / monodoc / Monodoc / index.cs
1 //
2 // index.cs: Handling of the index files
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@xamarin.com)
6 //
7 // (C) 2003 Ximian, Inc.
8 // Copyright 2003-2011 Novell Inc
9 // Copyright 2011 Xamarin Inc.
10 //
11 // Possible file format optimizations:
12 //   * Do not use 4 bytes for each index entry, use 3 bytes
13 //   * Find a way of compressing strings, there are plenty of duplicates
14 //     Find common roots, and use an encoding that uses a root to compress data.
15 //     "System", "System.Data", "System.Data class"
16 //     0: PLAIN: "System"
17 //     1: PLAIN: " class"
18 //     2: LINK0 PLAIN ".DATA"
19 //     3: LINK0 LINK1
20 //     
21 //     Maybe split everything at spaces and dots, and encode that:
22 //     string-1-idx "System."
23 //     string-1-idx "Data"
24 //     2-items [ string-1-idx string-2-idx]
25 //
26 //     Other variations are possible;  Like Archive "System", "System." when we
27 //     see "System.Data".
28 //
29 //
30
31 using System;
32 using System.IO;
33 using System.Text;
34 using System.Collections.Generic;
35
36 namespace Monodoc
37 {
38         public class Topic
39         {
40                 public readonly string Caption;
41                 public readonly string SortKey;
42                 public readonly string Url;
43
44                 public Topic (string caption, string sort_key, string url)
45                 {
46                         Caption = caption;
47                         SortKey = sort_key;
48                         Url = url;
49                 }
50         }
51
52         public class IndexEntry
53         {
54                 List<Topic> topics;
55
56                 public int Position {
57                         get;
58                         private set;
59                 }
60
61                 public IList<Topic> Topics {
62                         get {
63                                 return topics.AsReadOnly ();
64                         }
65                 }
66
67                 public int Count {
68                         get;
69                         private set;
70                 }
71                 
72                 public void Add (Topic t)
73                 {
74                         Count++;
75                         topics.Add (t);
76                 }
77
78                 public Topic this [int idx] {
79                         get {
80                                 if (idx < 0 || idx > topics.Count)
81                                         throw new ArgumentOutOfRangeException ("idx");
82                                 return topics[idx];
83                         }
84                 }
85
86                 //
87                 // Constructor from a stream
88                 //
89                 public IndexEntry (FileStream fs, BinaryReader reader, int position)
90                 {
91                         Count = reader.ReadInt32 ();
92                         int caption_offset = reader.ReadInt32 ();
93                         string caption;
94                         topics = new List<Topic> (Count);
95
96                         int [] offsets = new int [Count];
97                         for (int i = 0; i < Count; i++)
98                                 offsets [i] = reader.ReadInt32 ();
99
100                         fs.Position = caption_offset;
101                         caption = reader.ReadString ();
102                         for (int i = 0; i < Count; i++){
103                                 fs.Position = offsets [i];
104                                 string url = reader.ReadString ();
105                                 topics.Add (new Topic (caption, string.Empty, url));
106                         }
107                 }
108
109                 //
110                 // Regular constructor
111         
112                 public IndexEntry ()
113                 {
114                         topics = new List<Topic> ();
115                 }
116
117                 public void WriteTopics (IndexMaker maker, Stream stream, BinaryWriter writer)
118                 {
119                         //
120                         // Convention: entries with the same SortKey should have the same Caption
121                         //
122                         Position = (int) stream.Position;
123                         writer.Write (Count);
124
125                         if (Count == 0)
126                                 return;
127
128                         writer.Write (maker.GetCode (topics[0].Caption));
129                         foreach (Topic t in topics)
130                                 writer.Write (maker.GetCode (t.Url));
131                 }
132         }
133
134         public class IndexMaker
135         {
136                 Dictionary<string, IndexEntry> entries = new Dictionary<string, IndexEntry> ();
137                 Dictionary<string, int> all_strings = new Dictionary<string, int> ();
138                 int index_position;
139
140                 void AddString (string str)
141                 {
142                         if (!all_strings.ContainsKey (str))
143                                 all_strings.Add (str, 0);
144                 }
145
146                 public void AddTopic (Topic topic)
147                 {
148                         IndexEntry entry;
149                         if (!entries.TryGetValue (topic.SortKey, out entry)) {
150                                 entry = new IndexEntry ();
151                                 entries[topic.SortKey] = entry;
152                         }
153
154                         AddString (topic.SortKey);
155                         AddString (topic.Caption);
156                         AddString (topic.Url);
157                         entry.Add (topic);
158                 }
159
160                 public void Add (string caption, string sort_key, string url)
161                 {
162                         Topic t = new Topic (caption, sort_key, url);
163                         AddTopic (t);
164                 }
165         
166                 void SaveStringTable (Stream stream, BinaryWriter writer)
167                 {
168                         var keys = new List<string> (all_strings.Keys);
169                         foreach (string s in keys) {
170                                 int pos = (int) stream.Position;
171                                 writer.Write (s);
172                                 all_strings [s] = pos;
173                         }
174                 }
175
176                 public int GetCode (string s)
177                 {
178                         return all_strings [s];
179                 }
180
181                 void SaveTopics (Stream stream, BinaryWriter writer)
182                 {
183                         //
184                         // Convention: entries with the same SortKey should have the same Caption
185                         //
186                         foreach (IndexEntry e in entries.Values)
187                                 e.WriteTopics (this, stream, writer);
188                 }
189
190                 void SaveIndexEntries (Stream stream, BinaryWriter writer)
191                 {
192                         index_position = (int) stream.Position;
193                         writer.Write (entries.Count);
194                         var keys = new List<string> (entries.Keys);
195                         keys.Sort (StringComparer.OrdinalIgnoreCase);
196                 
197                         foreach (string s in keys){
198                                 IndexEntry e = entries [s];
199                                 writer.Write (e.Position);
200                         }
201                 }
202
203                 public void Save (string filename)
204                 {
205                         Encoding utf8 = new UTF8Encoding (false, true);
206
207                         using (FileStream fs = File.OpenWrite (filename)){
208                                 BinaryWriter writer = new BinaryWriter (fs, utf8);
209                                 writer.Write (new byte [] { (byte) 'M', 
210                                                             (byte) 'o', (byte) 'i', 
211                                                             (byte) 'x'});
212
213                                 // Leave room for pointer
214                                 fs.Position = 8;
215
216                                 SaveStringTable (fs, writer);
217                                 SaveTopics (fs, writer);
218
219                                 // index_position is set here
220                         
221                                 SaveIndexEntries (fs, writer);
222
223                                 fs.Position = 4;
224                                 writer.Write (index_position);
225                         }
226                 }
227         }
228
229         public interface IListModel
230         {
231                 int Rows { get; }
232                 string GetValue (int row);
233                 string GetDescription (int row);
234         }
235
236         public class IndexReader : IListModel
237         {
238                 Encoding utf8 = new UTF8Encoding (false, true);
239                 FileStream fs;
240                 BinaryReader reader;
241
242                 // The offset of the table of entries
243                 int table_offset;
244                 int entries;
245
246                 static public IndexReader Load (string filename)
247                 {
248                         if (!File.Exists (filename))
249                                 return null;
250
251                         try {
252                                 return new IndexReader (filename);
253                         } catch {
254                                 return null;
255                         }
256                 }
257         
258                 IndexReader (string filename)
259                 {
260                         fs = File.OpenRead (filename);
261                         reader = new BinaryReader (fs, utf8);
262
263                         if (fs.ReadByte () != 'M' ||
264                             fs.ReadByte () != 'o' ||
265                             fs.ReadByte () != 'i' ||
266                             fs.ReadByte () != 'x'){
267                                 throw new Exception ("Corrupt index");
268                         }
269
270                         // Seek to index_entries
271                         fs.Position = reader.ReadInt32 ();
272                 
273                         entries = reader.ReadInt32 ();
274
275                         table_offset = (int) fs.Position;
276                 }
277
278                 public int Rows {
279                         get {
280                                 return entries;
281                         }
282                 }
283
284                 public string GetValue (int row)
285                 {
286                         fs.Position = row * 4 + table_offset;
287                         fs.Position = reader.ReadInt32 () + 4;
288                         int code = reader.ReadInt32 ();
289                         fs.Position = code;
290                         string caption = reader.ReadString ();
291
292                         return caption;
293                 }
294
295                 public string GetDescription (int row)
296                 {
297                         return GetValue (row);
298                 }
299         
300                 public IndexEntry GetIndexEntry (int row)
301                 {
302                         fs.Position = row * 4 + table_offset;
303                         int entry_offset = reader.ReadInt32 ();
304                         fs.Position = entry_offset;
305                 
306                         return new IndexEntry (fs, reader, entry_offset);
307                 }
308         }
309 }
310