Fix eglib targets and filters.
[mono.git] / docs / HtmlAgilityPack / MixedCodeDocument.cs
1 // HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>\r
2 using System;\r
3 using System.IO;\r
4 using System.Text;\r
5 \r
6 namespace HtmlAgilityPack\r
7 {\r
8     /// <summary>\r
9     /// Represents a document with mixed code and text. ASP, ASPX, JSP, are good example of such documents.\r
10     /// </summary>\r
11     public class MixedCodeDocument\r
12     {\r
13         #region Fields\r
14 \r
15         private int _c;\r
16         internal MixedCodeDocumentFragmentList _codefragments;\r
17         private MixedCodeDocumentFragment _currentfragment;\r
18         internal MixedCodeDocumentFragmentList _fragments;\r
19         private int _index;\r
20         private int _line;\r
21         private int _lineposition;\r
22         private ParseState _state;\r
23         private Encoding _streamencoding;\r
24         internal string _text;\r
25         internal MixedCodeDocumentFragmentList _textfragments;\r
26 \r
27         /// <summary>\r
28         /// Gets or sets the token representing code end.\r
29         /// </summary>\r
30         public string TokenCodeEnd = "%>";\r
31 \r
32         /// <summary>\r
33         /// Gets or sets the token representing code start.\r
34         /// </summary>\r
35         public string TokenCodeStart = "<%";\r
36 \r
37         /// <summary>\r
38         /// Gets or sets the token representing code directive.\r
39         /// </summary>\r
40         public string TokenDirective = "@";\r
41 \r
42         /// <summary>\r
43         /// Gets or sets the token representing response write directive.\r
44         /// </summary>\r
45         public string TokenResponseWrite = "Response.Write ";\r
46 \r
47 \r
48         private string TokenTextBlock = "TextBlock({0})";\r
49 \r
50         #endregion\r
51 \r
52         #region Constructors\r
53 \r
54         /// <summary>\r
55         /// Creates a mixed code document instance.\r
56         /// </summary>\r
57         public MixedCodeDocument()\r
58         {\r
59             _codefragments = new MixedCodeDocumentFragmentList(this);\r
60             _textfragments = new MixedCodeDocumentFragmentList(this);\r
61             _fragments = new MixedCodeDocumentFragmentList(this);\r
62         }\r
63 \r
64         #endregion\r
65 \r
66         #region Properties\r
67 \r
68         /// <summary>\r
69         /// Gets the code represented by the mixed code document seen as a template.\r
70         /// </summary>\r
71         public string Code\r
72         {\r
73             get\r
74             {\r
75                 string s = "";\r
76                 int i = 0;\r
77                 foreach (MixedCodeDocumentFragment frag in _fragments)\r
78                 {\r
79                     switch (frag._type)\r
80                     {\r
81                         case MixedCodeDocumentFragmentType.Text:\r
82                             s += TokenResponseWrite + string.Format(TokenTextBlock, i) + "\n";\r
83                             i++;\r
84                             break;\r
85 \r
86                         case MixedCodeDocumentFragmentType.Code:\r
87                             s += ((MixedCodeDocumentCodeFragment) frag).Code + "\n";\r
88                             break;\r
89                     }\r
90                 }\r
91                 return s;\r
92             }\r
93         }\r
94 \r
95         /// <summary>\r
96         /// Gets the list of code fragments in the document.\r
97         /// </summary>\r
98         public MixedCodeDocumentFragmentList CodeFragments\r
99         {\r
100             get { return _codefragments; }\r
101         }\r
102 \r
103         /// <summary>\r
104         /// Gets the list of all fragments in the document.\r
105         /// </summary>\r
106         public MixedCodeDocumentFragmentList Fragments\r
107         {\r
108             get { return _fragments; }\r
109         }\r
110 \r
111         /// <summary>\r
112         /// Gets the encoding of the stream used to read the document.\r
113         /// </summary>\r
114         public Encoding StreamEncoding\r
115         {\r
116             get { return _streamencoding; }\r
117         }\r
118 \r
119         /// <summary>\r
120         /// Gets the list of text fragments in the document.\r
121         /// </summary>\r
122         public MixedCodeDocumentFragmentList TextFragments\r
123         {\r
124             get { return _textfragments; }\r
125         }\r
126 \r
127         #endregion\r
128 \r
129         #region Public Methods\r
130 \r
131         /// <summary>\r
132         /// Create a code fragment instances.\r
133         /// </summary>\r
134         /// <returns>The newly created code fragment instance.</returns>\r
135         public MixedCodeDocumentCodeFragment CreateCodeFragment()\r
136         {\r
137             return (MixedCodeDocumentCodeFragment) CreateFragment(MixedCodeDocumentFragmentType.Code);\r
138         }\r
139 \r
140         /// <summary>\r
141         /// Create a text fragment instances.\r
142         /// </summary>\r
143         /// <returns>The newly created text fragment instance.</returns>\r
144         public MixedCodeDocumentTextFragment CreateTextFragment()\r
145         {\r
146             return (MixedCodeDocumentTextFragment) CreateFragment(MixedCodeDocumentFragmentType.Text);\r
147         }\r
148 \r
149         /// <summary>\r
150         /// Loads a mixed code document from a stream.\r
151         /// </summary>\r
152         /// <param name="stream">The input stream.</param>\r
153         public void Load(Stream stream)\r
154         {\r
155             Load(new StreamReader(stream));\r
156         }\r
157 \r
158         /// <summary>\r
159         /// Loads a mixed code document from a stream.\r
160         /// </summary>\r
161         /// <param name="stream">The input stream.</param>\r
162         /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
163         public void Load(Stream stream, bool detectEncodingFromByteOrderMarks)\r
164         {\r
165             Load(new StreamReader(stream, detectEncodingFromByteOrderMarks));\r
166         }\r
167 \r
168         /// <summary>\r
169         /// Loads a mixed code document from a stream.\r
170         /// </summary>\r
171         /// <param name="stream">The input stream.</param>\r
172         /// <param name="encoding">The character encoding to use.</param>\r
173         public void Load(Stream stream, Encoding encoding)\r
174         {\r
175             Load(new StreamReader(stream, encoding));\r
176         }\r
177 \r
178         /// <summary>\r
179         /// Loads a mixed code document from a stream.\r
180         /// </summary>\r
181         /// <param name="stream">The input stream.</param>\r
182         /// <param name="encoding">The character encoding to use.</param>\r
183         /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
184         public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
185         {\r
186             Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks));\r
187         }\r
188 \r
189         /// <summary>\r
190         /// Loads a mixed code document from a stream.\r
191         /// </summary>\r
192         /// <param name="stream">The input stream.</param>\r
193         /// <param name="encoding">The character encoding to use.</param>\r
194         /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
195         /// <param name="buffersize">The minimum buffer size.</param>\r
196         public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
197         {\r
198             Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks, buffersize));\r
199         }\r
200 \r
201         /// <summary>\r
202         /// Loads a mixed code document from a file.\r
203         /// </summary>\r
204         /// <param name="path">The complete file path to be read.</param>\r
205         public void Load(string path)\r
206         {\r
207             Load(new StreamReader(path));\r
208         }\r
209 \r
210         /// <summary>\r
211         /// Loads a mixed code document from a file.\r
212         /// </summary>\r
213         /// <param name="path">The complete file path to be read.</param>\r
214         /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
215         public void Load(string path, bool detectEncodingFromByteOrderMarks)\r
216         {\r
217             Load(new StreamReader(path, detectEncodingFromByteOrderMarks));\r
218         }\r
219 \r
220         /// <summary>\r
221         /// Loads a mixed code document from a file.\r
222         /// </summary>\r
223         /// <param name="path">The complete file path to be read.</param>\r
224         /// <param name="encoding">The character encoding to use.</param>\r
225         public void Load(string path, Encoding encoding)\r
226         {\r
227             Load(new StreamReader(path, encoding));\r
228         }\r
229 \r
230         /// <summary>\r
231         /// Loads a mixed code document from a file.\r
232         /// </summary>\r
233         /// <param name="path">The complete file path to be read.</param>\r
234         /// <param name="encoding">The character encoding to use.</param>\r
235         /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
236         public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
237         {\r
238             Load(new StreamReader(path, encoding, detectEncodingFromByteOrderMarks));\r
239         }\r
240 \r
241         /// <summary>\r
242         /// Loads a mixed code document from a file.\r
243         /// </summary>\r
244         /// <param name="path">The complete file path to be read.</param>\r
245         /// <param name="encoding">The character encoding to use.</param>\r
246         /// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>\r
247         /// <param name="buffersize">The minimum buffer size.</param>\r
248         public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)\r
249         {\r
250             Load(new StreamReader(path, encoding, detectEncodingFromByteOrderMarks, buffersize));\r
251         }\r
252 \r
253         /// <summary>\r
254         /// Loads the mixed code document from the specified TextReader.\r
255         /// </summary>\r
256         /// <param name="reader">The TextReader used to feed the HTML data into the document.</param>\r
257         public void Load(TextReader reader)\r
258         {\r
259             _codefragments.Clear();\r
260             _textfragments.Clear();\r
261 \r
262             // all pseudo constructors get down to this one\r
263             StreamReader sr = reader as StreamReader;\r
264             if (sr != null)\r
265             {\r
266                 _streamencoding = sr.CurrentEncoding;\r
267             }\r
268 \r
269             _text = reader.ReadToEnd();\r
270             reader.Close();\r
271             Parse();\r
272         }\r
273 \r
274         /// <summary>\r
275         /// Loads a mixed document from a text\r
276         /// </summary>\r
277         /// <param name="html">The text to load.</param>\r
278         public void LoadHtml(string html)\r
279         {\r
280             Load(new StringReader(html));\r
281         }\r
282 \r
283         /// <summary>\r
284         /// Saves the mixed document to the specified stream.\r
285         /// </summary>\r
286         /// <param name="outStream">The stream to which you want to save.</param>\r
287         public void Save(Stream outStream)\r
288         {\r
289             StreamWriter sw = new StreamWriter(outStream, GetOutEncoding());\r
290             Save(sw);\r
291         }\r
292 \r
293         /// <summary>\r
294         /// Saves the mixed document to the specified stream.\r
295         /// </summary>\r
296         /// <param name="outStream">The stream to which you want to save.</param>\r
297         /// <param name="encoding">The character encoding to use.</param>\r
298         public void Save(Stream outStream, Encoding encoding)\r
299         {\r
300             StreamWriter sw = new StreamWriter(outStream, encoding);\r
301             Save(sw);\r
302         }\r
303 \r
304         /// <summary>\r
305         /// Saves the mixed document to the specified file.\r
306         /// </summary>\r
307         /// <param name="filename">The location of the file where you want to save the document.</param>\r
308         public void Save(string filename)\r
309         {\r
310             StreamWriter sw = new StreamWriter(filename, false, GetOutEncoding());\r
311             Save(sw);\r
312         }\r
313 \r
314         /// <summary>\r
315         /// Saves the mixed document to the specified file.\r
316         /// </summary>\r
317         /// <param name="filename">The location of the file where you want to save the document.</param>\r
318         /// <param name="encoding">The character encoding to use.</param>\r
319         public void Save(string filename, Encoding encoding)\r
320         {\r
321             StreamWriter sw = new StreamWriter(filename, false, encoding);\r
322             Save(sw);\r
323         }\r
324 \r
325         /// <summary>\r
326         /// Saves the mixed document to the specified StreamWriter.\r
327         /// </summary>\r
328         /// <param name="writer">The StreamWriter to which you want to save.</param>\r
329         public void Save(StreamWriter writer)\r
330         {\r
331             Save((TextWriter) writer);\r
332         }\r
333 \r
334         /// <summary>\r
335         /// Saves the mixed document to the specified TextWriter.\r
336         /// </summary>\r
337         /// <param name="writer">The TextWriter to which you want to save.</param>\r
338         public void Save(TextWriter writer)\r
339         {\r
340             writer.Flush();\r
341         }\r
342 \r
343         #endregion\r
344 \r
345         #region Internal Methods\r
346 \r
347         internal MixedCodeDocumentFragment CreateFragment(MixedCodeDocumentFragmentType type)\r
348         {\r
349             switch (type)\r
350             {\r
351                 case MixedCodeDocumentFragmentType.Text:\r
352                     return new MixedCodeDocumentTextFragment(this);\r
353 \r
354                 case MixedCodeDocumentFragmentType.Code:\r
355                     return new MixedCodeDocumentCodeFragment(this);\r
356 \r
357                 default:\r
358                     throw new NotSupportedException();\r
359             }\r
360         }\r
361 \r
362         internal Encoding GetOutEncoding()\r
363         {\r
364             if (_streamencoding != null)\r
365                 return _streamencoding;\r
366             return Encoding.Default;\r
367         }\r
368 \r
369         #endregion\r
370 \r
371         #region Private Methods\r
372 \r
373         private void IncrementPosition()\r
374         {\r
375             _index++;\r
376             if (_c == 10)\r
377             {\r
378                 _lineposition = 1;\r
379                 _line++;\r
380             }\r
381             else\r
382                 _lineposition++;\r
383         }\r
384 \r
385         private void Parse()\r
386         {\r
387             _state = ParseState.Text;\r
388             _index = 0;\r
389             _currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Text);\r
390 \r
391             while (_index < _text.Length)\r
392             {\r
393                 _c = _text[_index];\r
394                 IncrementPosition();\r
395 \r
396                 switch (_state)\r
397                 {\r
398                     case ParseState.Text:\r
399                         if (_index + TokenCodeStart.Length < _text.Length)\r
400                         {\r
401                             if (_text.Substring(_index - 1, TokenCodeStart.Length) == TokenCodeStart)\r
402                             {\r
403                                 _state = ParseState.Code;\r
404                                 _currentfragment.Length = _index - 1 - _currentfragment.Index;\r
405                                 _currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Code);\r
406                                 SetPosition();\r
407                                 continue;\r
408                             }\r
409                         }\r
410                         break;\r
411 \r
412                     case ParseState.Code:\r
413                         if (_index + TokenCodeEnd.Length < _text.Length)\r
414                         {\r
415                             if (_text.Substring(_index - 1, TokenCodeEnd.Length) == TokenCodeEnd)\r
416                             {\r
417                                 _state = ParseState.Text;\r
418                                 _currentfragment.Length = _index + TokenCodeEnd.Length - _currentfragment.Index;\r
419                                 _index += TokenCodeEnd.Length;\r
420                                 _lineposition += TokenCodeEnd.Length;\r
421                                 _currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Text);\r
422                                 SetPosition();\r
423                                 continue;\r
424                             }\r
425                         }\r
426                         break;\r
427                 }\r
428             }\r
429 \r
430             _currentfragment.Length = _index - _currentfragment.Index;\r
431         }\r
432 \r
433         private void SetPosition()\r
434         {\r
435             _currentfragment.Line = _line;\r
436             _currentfragment._lineposition = _lineposition;\r
437             _currentfragment.Index = _index - 1;\r
438             _currentfragment.Length = 0;\r
439         }\r
440 \r
441         #endregion\r
442 \r
443         #region Nested type: ParseState\r
444 \r
445         private enum ParseState\r
446         {\r
447             Text,\r
448             Code\r
449         }\r
450 \r
451         #endregion\r
452     }\r
453 }