2007-07-03 Jonathan Chambers <joncham@gmail.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / HtmlTextWriter.cs
1 // 
2 // System.Web.UI.HtmlTextWriter
3 //
4 // Author:
5 //        Ben Maurer <bmaurer@novell.com>
6 //
7 // (c) 2005 Novell
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.IO;
30 using System.Globalization;
31 using System.Collections;
32 using System.Security.Permissions;
33 using System.Text;
34 using System.Web.UI.WebControls;
35
36 namespace System.Web.UI {
37
38         // CAS
39         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
40         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
41         public class HtmlTextWriter : TextWriter {
42
43
44                 readonly static Hashtable _tagTable;
45                 readonly static Hashtable _attributeTable;
46                 readonly static Hashtable _styleTable;
47
48                 static HtmlTextWriter ()
49                 {
50                         _tagTable = new Hashtable (tags.Length, 
51                                 CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
52                         
53                         _attributeTable = new Hashtable (htmlattrs.Length, 
54                                 CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
55                         
56                         _styleTable = new Hashtable (htmlstyles.Length, 
57                                 CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
58
59                         foreach (HtmlTag tag in tags)
60                                 _tagTable.Add (tag.name, tag);
61
62                         foreach (HtmlAttribute attr in htmlattrs)
63                                 _attributeTable.Add (attr.name, attr);
64
65                         foreach (HtmlStyle style in htmlstyles)
66                                 _styleTable.Add (style.name, style);
67                 }
68
69                 public HtmlTextWriter (TextWriter writer) : this (writer, DefaultTabString)
70                 {
71                 }
72
73                 public HtmlTextWriter (TextWriter writer, string tabString)
74                 {
75                         b = writer;
76                         tab_string = tabString;
77                 }
78
79                 internal static string StaticGetStyleName (System.Web.UI.HtmlTextWriterStyle styleKey)
80                 {
81                         if ((int) styleKey < htmlstyles.Length)
82                                 return htmlstyles [(int) styleKey].name;
83
84                         return null;
85                 }
86
87                 [MonoTODO ("Does nothing")]
88                 protected static void RegisterAttribute (string name, HtmlTextWriterAttribute key)
89                 {
90                 }
91
92                 [MonoTODO ("Does nothing")]
93                 protected static void RegisterStyle (string name, HtmlTextWriterStyle key)
94                 {
95                 }
96
97                 [MonoTODO ("Does nothing")]
98                 protected static void RegisterTag (string name, HtmlTextWriterTag key)
99                 {
100                 }
101
102
103                 public virtual void AddAttribute (HtmlTextWriterAttribute key, string value, bool fEncode)
104                 {
105                         if (fEncode)
106                                 value = EncodeAttributeValue (key, value);
107                         AddAttribute (GetAttributeName (key), value, key);
108                 }
109
110
111                 public virtual void AddAttribute (HtmlTextWriterAttribute key, string value)
112                 {
113                         bool fEncode = key != HtmlTextWriterAttribute.Name;
114                         AddAttribute (key, value, fEncode);
115                 }
116
117
118                 public virtual void AddAttribute (string name, string value, bool fEncode)
119                 {
120                         if (fEncode)
121                                 value = HttpUtility.HtmlAttributeEncode (value);
122
123                         AddAttribute (name, value, GetAttributeKey (name));
124                 }
125
126                 public virtual void AddAttribute (string name, string value)
127                 {
128                         bool fEncode = String.Compare ("name", name, true, CultureInfo.InvariantCulture) != 0;
129                         AddAttribute (name, value, fEncode);
130                 }
131
132                 protected virtual void AddAttribute (string name, string value, HtmlTextWriterAttribute key)
133                 {
134                         NextAttrStack ();
135 #if TARGET_JVM
136                         if (attrs [attrs_pos] == null)
137                                 attrs [attrs_pos] = new AddedAttr ();
138 #endif
139                         attrs [attrs_pos].name = name;
140                         attrs [attrs_pos].value = value;
141                         attrs [attrs_pos].key = key;
142                 }
143
144
145                 protected virtual void AddStyleAttribute (string name, string value, HtmlTextWriterStyle key)
146                 {
147                         NextStyleStack ();
148 #if TARGET_JVM
149                         if (styles [styles_pos] == null)
150                                 styles [styles_pos] = new AddedStyle ();
151 #endif
152                         styles [styles_pos].name = name;
153 #if NET_2_0
154                         value = HttpUtility.HtmlAttributeEncode (value);
155 #endif
156                         styles [styles_pos].value = value;
157                         styles [styles_pos].key = key;
158                 }
159
160
161                 public virtual void AddStyleAttribute (string name, string value)
162                 {
163                         AddStyleAttribute (name, value, GetStyleKey (name));
164                 }
165
166                 public virtual void AddStyleAttribute (HtmlTextWriterStyle key, string value)
167                 {
168                         AddStyleAttribute (GetStyleName (key), value, key);
169                 }
170
171                 public override void Close ()
172                 {
173                         b.Close ();
174                 }
175
176                 protected virtual string EncodeAttributeValue (HtmlTextWriterAttribute attrKey, string value)
177                 {
178                         return HttpUtility.HtmlAttributeEncode (value);
179                 }
180
181                 protected string EncodeAttributeValue (string value, bool fEncode)
182                 {
183                         if (fEncode)
184                                 return HttpUtility.HtmlAttributeEncode (value);
185                         return value;
186                 }
187
188                 protected string EncodeUrl (string url)
189                 {
190                         return HttpUtility.UrlPathEncode (url);
191                 }
192
193
194                 protected virtual void FilterAttributes ()
195                 {
196                         AddedAttr style_attr = new AddedAttr ();
197
198                         for (int i = 0; i <= attrs_pos; i++) {
199                                 AddedAttr a = attrs [i];
200                                 if (OnAttributeRender (a.name, a.value, a.key)) {
201                                         if (a.key == HtmlTextWriterAttribute.Style) {
202                                                 style_attr = a;
203                                                 continue;
204                                         }
205
206                                         WriteAttribute (a.name, a.value, false);
207                                 }
208                         }
209
210                         if (styles_pos != -1 || style_attr.value != null) {
211                                 Write (SpaceChar);
212                                 Write ("style");
213                                 Write (EqualsDoubleQuoteString);
214
215
216                                 for (int i = 0; i <= styles_pos; i++) {
217                                         AddedStyle a = styles [i];
218                                         if (OnStyleAttributeRender (a.name, a.value, a.key)) {
219 #if NET_2_0
220                                                 if (a.key == HtmlTextWriterStyle.BackgroundImage) {
221                                                         a.value = String.Concat ("url(", HttpUtility.UrlPathEncode (a.value), ")");
222                                                 }
223 #endif
224                                                 WriteStyleAttribute (a.name, a.value, false);
225                                         }
226                                 }
227
228                                 Write (style_attr.value);
229                                 Write (DoubleQuoteChar);
230                         }
231
232                         styles_pos = attrs_pos = -1;
233                 }
234
235                 public override void Flush ()
236                 {
237                         b.Flush ();
238                 }
239
240                 protected HtmlTextWriterAttribute GetAttributeKey (string attrName)
241                 {
242                         object attribute = _attributeTable [attrName];
243                         if (attribute == null)
244                                 return (HtmlTextWriterAttribute) (-1);
245
246                         return (HtmlTextWriterAttribute) ((HtmlAttribute) attribute).key;
247                 }
248
249                 protected string GetAttributeName (HtmlTextWriterAttribute attrKey)
250                 {
251                         if ((int) attrKey < htmlattrs.Length)
252                                 return htmlattrs [(int) attrKey].name;
253
254                         return null;
255                 }
256
257                 protected HtmlTextWriterStyle GetStyleKey (string styleName)
258                 {
259                         object style = _styleTable [styleName];
260                         if (style == null)
261                                 return (HtmlTextWriterStyle) (-1);
262
263                         return (HtmlTextWriterStyle) ((HtmlStyle) style).key;
264                 }
265
266                 protected string GetStyleName (HtmlTextWriterStyle styleKey)
267                 {
268                         return StaticGetStyleName (styleKey);
269                 }
270
271                 protected virtual HtmlTextWriterTag GetTagKey (string tagName)
272                 {
273                         object tag = _tagTable [tagName];
274                         if (tag == null)
275                                 return HtmlTextWriterTag.Unknown;
276
277                         return (HtmlTextWriterTag) ((HtmlTag) tag).key;
278                 }
279
280                 internal static string StaticGetTagName (HtmlTextWriterTag tagKey)
281                 {
282                         if ((int) tagKey < tags.Length)
283                                 return tags [(int) tagKey].name;
284
285                         return null;
286                 }
287
288
289                 protected virtual string GetTagName (HtmlTextWriterTag tagKey)
290                 {
291                         if ((int) tagKey < tags.Length)
292                                 return tags [(int) tagKey].name;
293
294                         return null;
295                 }
296
297                 protected bool IsAttributeDefined (HtmlTextWriterAttribute key)
298                 {
299                         string value;
300                         return IsAttributeDefined (key, out value);
301                 }
302
303                 protected bool IsAttributeDefined (HtmlTextWriterAttribute key, out string value)
304                 {
305                         for (int i = 0; i <= attrs_pos; i++)
306                                 if (attrs [i].key == key) {
307                                         value = attrs [i].value;
308                                         return true;
309                                 }
310
311                         value = null;
312                         return false;
313                 }
314
315                 protected bool IsStyleAttributeDefined (HtmlTextWriterStyle key)
316                 {
317                         string value;
318                         return IsStyleAttributeDefined (key, out value);
319                 }
320
321                 protected bool IsStyleAttributeDefined (HtmlTextWriterStyle key, out string value)
322                 {
323                         for (int i = 0; i <= styles_pos; i++)
324                                 if (styles [i].key == key) {
325                                         value = styles [i].value;
326                                         return true;
327                                 }
328
329                         value = null;
330                         return false;
331                 }
332
333                 protected virtual bool OnAttributeRender (string name, string value, HtmlTextWriterAttribute key)
334                 {
335                         return true;
336                 }
337
338                 protected virtual bool OnStyleAttributeRender (string name, string value, HtmlTextWriterStyle key)
339                 {
340                         return true;
341                 }
342
343                 protected virtual bool OnTagRender (string name, HtmlTextWriterTag key)
344                 {
345                         return true;
346                 }
347
348
349                 protected virtual void OutputTabs ()
350                 {
351                         if (!newline)
352                                 return;
353                         newline = false;
354
355                         for (int i = 0; i < Indent; i++)
356                                 b.Write (tab_string);
357                 }
358
359
360
361                 protected string PopEndTag ()
362                 {
363                         if (tagstack_pos == -1)
364                                 throw new InvalidOperationException ();
365
366                         string s = TagName;
367                         tagstack_pos--;
368                         return s;
369                 }
370
371                 protected void PushEndTag (string endTag)
372                 {
373                         NextTagStack ();
374                         TagName = endTag;
375                 }
376
377                 void PushEndTag (HtmlTextWriterTag t)
378                 {
379                         NextTagStack ();
380                         TagKey = t;
381                 }
382
383
384                 protected virtual string RenderAfterContent ()
385                 {
386                         return null;
387                 }
388
389                 protected virtual string RenderAfterTag ()
390                 {
391                         return null;
392                 }
393
394                 protected virtual string RenderBeforeContent ()
395                 {
396                         return null;
397                 }
398
399                 protected virtual string RenderBeforeTag ()
400                 {
401                         return null;
402                 }
403
404                 public virtual void RenderBeginTag (string tagName)
405                 {
406                         if (!OnTagRender (tagName, GetTagKey (tagName)))
407                                 return;
408
409                         PushEndTag (tagName);
410
411                         DoBeginTag ();
412                 }
413
414                 public virtual void RenderBeginTag (HtmlTextWriterTag tagKey)
415                 {
416                         if (!OnTagRender (GetTagName (tagKey), tagKey))
417                                 return;
418
419                         PushEndTag (tagKey);
420
421                         DoBeginTag ();
422                 }
423
424                 void WriteIfNotNull (string s)
425                 {
426                         if (s != null)
427                                 Write (s);
428                 }
429
430
431                 void DoBeginTag ()
432                 {
433                         WriteIfNotNull (RenderBeforeTag ());
434                         WriteBeginTag (TagName);
435                         FilterAttributes ();
436
437                         HtmlTextWriterTag key = (int) TagKey < tags.Length ? TagKey : HtmlTextWriterTag.Unknown;
438
439                         switch (tags [(int) key].tag_type) {
440                                 case TagType.Inline:
441                                         Write (TagRightChar);
442                                         break;
443                                 case TagType.Block:
444                                         Write (TagRightChar);
445                                         WriteLine ();
446                                         Indent++;
447                                         break;
448                                 case TagType.SelfClosing:
449                                         Write (SelfClosingTagEnd);
450                                         break;
451                         }
452
453                         // FIXME what do i do for self close here?
454                         WriteIfNotNull (RenderBeforeContent ());
455                 }
456
457
458                 public virtual void RenderEndTag ()
459                 {
460                         // FIXME what do i do for self close here?
461                         WriteIfNotNull (RenderAfterContent ());
462
463                         HtmlTextWriterTag key = (int) TagKey < tags.Length ? TagKey : HtmlTextWriterTag.Unknown;
464
465                         switch (tags [(int) key].tag_type) {
466                                 case TagType.Inline:
467                                         WriteEndTag (TagName);
468                                         break;
469                                 case TagType.Block:
470                                         Indent--;
471                                         WriteLineNoTabs ("");
472                                         WriteEndTag (TagName);
473
474                                         break;
475                                 case TagType.SelfClosing:
476                                         // NADA
477                                         break;
478                         }
479                         WriteIfNotNull (RenderAfterTag ());
480
481                         PopEndTag ();
482                 }
483
484
485                 public virtual void WriteAttribute (string name, string value, bool fEncode)
486                 {
487                         Write (SpaceChar);
488                         Write (name);
489                         if (value != null) {
490                                 Write (EqualsDoubleQuoteString);
491                                 value = EncodeAttributeValue (value, fEncode);
492                                 Write (value);
493                                 Write (DoubleQuoteChar);
494                         }
495                 }
496
497
498                 public virtual void WriteBeginTag (string tagName)
499                 {
500                         Write (TagLeftChar);
501                         Write (tagName);
502                 }
503
504                 public virtual void WriteEndTag (string tagName)
505                 {
506                         Write (EndTagLeftChars);
507                         Write (tagName);
508                         Write (TagRightChar);
509                 }
510
511                 public virtual void WriteFullBeginTag (string tagName)
512                 {
513                         Write (TagLeftChar);
514                         Write (tagName);
515                         Write (TagRightChar);
516                 }
517
518                 public virtual void WriteStyleAttribute (string name, string value)
519                 {
520                         WriteStyleAttribute (name, value, false);
521                 }
522
523                 public virtual void WriteStyleAttribute (string name, string value, bool fEncode)
524                 {
525                         Write (name);
526                         Write (StyleEqualsChar);
527                         Write (EncodeAttributeValue (value, fEncode));
528                         Write (SemicolonChar);
529                 }
530
531                 public override void Write (char [] buffer, int index, int count)
532                 {
533                         OutputTabs ();
534                         b.Write (buffer, index, count);
535                 }
536
537                 public override void Write (double value)
538                 {
539                         OutputTabs ();
540                         b.Write (value);
541                 }
542
543                 public override void Write (char value)
544                 {
545                         OutputTabs ();
546                         b.Write (value);
547                 }
548
549                 public override void Write (char [] buffer)
550                 {
551                         OutputTabs ();
552                         b.Write (buffer);
553                 }
554
555                 public override void Write (int value)
556                 {
557                         OutputTabs ();
558                         b.Write (value);
559                 }
560
561                 public override void Write (string format, object arg0)
562                 {
563                         OutputTabs ();
564                         b.Write (format, arg0);
565                 }
566
567                 public override void Write (string format, object arg0, object arg1)
568                 {
569                         OutputTabs ();
570                         b.Write (format, arg0, arg1);
571                 }
572
573                 public override void Write (string format, params object [] args)
574                 {
575                         OutputTabs ();
576                         b.Write (format, args);
577                 }
578
579                 public override void Write (string s)
580                 {
581                         OutputTabs ();
582                         b.Write (s);
583                 }
584
585                 public override void Write (long value)
586                 {
587                         OutputTabs ();
588                         b.Write (value);
589                 }
590
591                 public override void Write (object value)
592                 {
593                         OutputTabs ();
594                         b.Write (value);
595                 }
596
597                 public override void Write (float value)
598                 {
599                         OutputTabs ();
600                         b.Write (value);
601                 }
602
603                 public override void Write (bool value)
604                 {
605                         OutputTabs ();
606                         b.Write (value);
607                 }
608
609                 public virtual void WriteAttribute (string name, string value)
610                 {
611                         WriteAttribute (name, value, false);
612                 }
613
614                 public override void WriteLine (char value)
615                 {
616                         OutputTabs ();
617                         b.WriteLine (value);
618                         newline = true;
619                 }
620
621                 public override void WriteLine (long value)
622                 {
623                         OutputTabs ();
624                         b.WriteLine (value);
625                         newline = true;
626                 }
627
628                 public override void WriteLine (object value)
629                 {
630                         OutputTabs ();
631                         b.WriteLine (value);
632                         newline = true;
633                 }
634
635                 public override void WriteLine (double value)
636                 {
637                         OutputTabs ();
638                         b.WriteLine (value);
639                         newline = true;
640                 }
641
642                 public override void WriteLine (char [] buffer, int index, int count)
643                 {
644                         OutputTabs ();
645                         b.WriteLine (buffer, index, count);
646                         newline = true;
647                 }
648
649                 public override void WriteLine (char [] buffer)
650                 {
651                         OutputTabs ();
652                         b.WriteLine (buffer);
653                         newline = true;
654                 }
655
656                 public override void WriteLine (bool value)
657                 {
658                         OutputTabs ();
659                         b.WriteLine (value);
660                         newline = true;
661                 }
662
663                 public override void WriteLine ()
664                 {
665                         OutputTabs ();
666                         b.WriteLine ();
667                         newline = true;
668                 }
669
670                 public override void WriteLine (int value)
671                 {
672                         OutputTabs ();
673                         b.WriteLine (value);
674                         newline = true;
675                 }
676
677                 public override void WriteLine (string format, object arg0, object arg1)
678                 {
679                         OutputTabs ();
680                         b.WriteLine (format, arg0, arg1);
681                         newline = true;
682                 }
683
684                 public override void WriteLine (string format, object arg0)
685                 {
686                         OutputTabs ();
687                         b.WriteLine (format, arg0);
688                         newline = true;
689                 }
690
691                 public override void WriteLine (string format, params object [] args)
692                 {
693                         OutputTabs ();
694                         b.WriteLine (format, args);
695                         newline = true;
696                 }
697
698                 [CLSCompliant (false)]
699                 public override void WriteLine (uint value)
700                 {
701                         OutputTabs ();
702                         b.WriteLine (value);
703                         newline = true;
704                 }
705
706                 public override void WriteLine (string s)
707                 {
708                         OutputTabs ();
709                         b.WriteLine (s);
710                         newline = true;
711                 }
712
713                 public override void WriteLine (float value)
714                 {
715                         OutputTabs ();
716                         b.WriteLine (value);
717                         newline = true;
718                 }
719
720                 public void WriteLineNoTabs (string s)
721                 {
722                         b.WriteLine (s);
723                         newline = true;
724                 }
725
726                 public override Encoding Encoding {
727                         get {
728                                 return b.Encoding;
729                         }
730                 }
731
732                 int indent;
733                 public int Indent {
734                         get {
735                                 return indent;
736                         }
737                         set {
738                                 indent = value;
739                         }
740                 }
741
742                 public System.IO.TextWriter InnerWriter {
743                         get {
744                                 return b;
745                         }
746                         set {
747                                 b = value;
748                         }
749                 }
750
751                 public override string NewLine {
752                         get {
753                                 return b.NewLine;
754                         }
755                         set {
756                                 b.NewLine = value;
757                         }
758                 }
759
760                 protected HtmlTextWriterTag TagKey {
761                         get {
762                                 if (tagstack_pos == -1)
763                                         throw new InvalidOperationException ();
764
765                                 return tagstack [tagstack_pos].key;
766                         }
767                         set {
768 #if TARGET_JVM
769                                 if (tagstack [tagstack_pos] == null)
770                                         tagstack [tagstack_pos] = new AddedTag ();
771 #endif
772                                 tagstack [tagstack_pos].key = value;
773                                 tagstack [tagstack_pos].name = GetTagName (value);
774                         }
775                 }
776
777                 protected string TagName {
778                         get {
779                                 if (tagstack_pos == -1)
780                                         throw new InvalidOperationException ();
781
782                                 return tagstack [tagstack_pos].name;
783                         }
784                         set {
785 #if TARGET_JVM
786                                 if (tagstack [tagstack_pos] == null)
787                                         tagstack [tagstack_pos] = new AddedTag ();
788 #endif
789                                 tagstack [tagstack_pos].name = value;
790                                 tagstack [tagstack_pos].key = GetTagKey (value);
791                                 if (tagstack [tagstack_pos].key != HtmlTextWriterTag.Unknown)
792                                         tagstack [tagstack_pos].name = GetTagName (tagstack [tagstack_pos].key);
793                         }
794                 }
795
796
797                 TextWriter b;
798                 string tab_string;
799                 bool newline;
800
801                 //
802                 // These emulate generic Stack <T>, since we can't use that ;-(. _pos is the current
803                 // element.IE, you edit blah [blah_pos]. I *really* want generics, sigh.
804                 //
805                 AddedStyle [] styles;
806                 AddedAttr [] attrs;
807                 AddedTag [] tagstack;
808
809                 int styles_pos = -1, attrs_pos = -1, tagstack_pos = -1;
810
811 #if TARGET_JVM
812                 class
813 #else
814                 struct 
815 #endif
816                 AddedTag {
817                         public string name;
818                         public HtmlTextWriterTag key;
819                 }
820
821 #if TARGET_JVM
822                 class
823 #else
824                 struct 
825 #endif
826                 AddedStyle {
827                         public string name;
828                         public HtmlTextWriterStyle key;
829                         public string value;
830                 }
831
832 #if TARGET_JVM
833                 class
834 #else
835                 struct 
836 #endif
837                 AddedAttr {
838                         public string name;
839                         public HtmlTextWriterAttribute key;
840                         public string value;
841                 }
842
843                 void NextStyleStack ()
844                 {
845                         if (styles == null)
846                                 styles = new AddedStyle [16];
847
848                         if (++styles_pos < styles.Length)
849                                 return;
850
851                         int nsize = styles.Length * 2;
852                         AddedStyle [] ncontents = new AddedStyle [nsize];
853
854                         Array.Copy (styles, ncontents, styles.Length);
855                         styles = ncontents;
856                 }
857
858                 void NextAttrStack ()
859                 {
860                         if (attrs == null)
861                                 attrs = new AddedAttr [16];
862
863                         if (++attrs_pos < attrs.Length)
864                                 return;
865
866                         int nsize = attrs.Length * 2;
867                         AddedAttr [] ncontents = new AddedAttr [nsize];
868
869                         Array.Copy (attrs, ncontents, attrs.Length);
870                         attrs = ncontents;
871                 }
872
873                 void NextTagStack ()
874                 {
875                         if (tagstack == null)
876                                 tagstack = new AddedTag [16];
877
878                         if (++tagstack_pos < tagstack.Length)
879                                 return;
880
881                         int nsize = tagstack.Length * 2;
882                         AddedTag [] ncontents = new AddedTag [nsize];
883
884                         Array.Copy (tagstack, ncontents, tagstack.Length);
885                         tagstack = ncontents;
886                 }
887
888                 public const string DefaultTabString = "\t";
889                 public const char DoubleQuoteChar = '"';
890                 public const string EndTagLeftChars = "</";
891                 public const char EqualsChar = '=';
892                 public const string EqualsDoubleQuoteString = "=\"";
893                 public const string SelfClosingChars = " /";
894                 public const string SelfClosingTagEnd = " />";
895                 public const char SemicolonChar = ';';
896                 public const char SingleQuoteChar = '\'';
897                 public const char SlashChar = '/';
898                 public const char SpaceChar = ' ';
899                 public const char StyleEqualsChar = ':';
900                 public const char TagLeftChar = '<';
901                 public const char TagRightChar = '>';
902
903                 enum TagType {
904                         Block,
905                         Inline,
906                         SelfClosing,
907                 }
908
909
910                 sealed class HtmlTag {
911                         readonly public HtmlTextWriterTag key;
912                         readonly public string name;
913                         readonly public TagType tag_type;
914
915                         public HtmlTag (HtmlTextWriterTag k, string n, TagType tt)
916                         {
917                                 key = k;
918                                 name = n;
919                                 tag_type = tt;
920                         }
921                 }
922
923                 sealed class HtmlStyle {
924                         readonly public HtmlTextWriterStyle key;
925                         readonly public string name;
926
927                         public HtmlStyle (HtmlTextWriterStyle k, string n)
928                         {
929                                 key = k;
930                                 name = n;
931                         }
932                 }
933
934
935                 sealed class HtmlAttribute {
936                         readonly public HtmlTextWriterAttribute key;
937                         readonly public string name;
938
939                         public HtmlAttribute (HtmlTextWriterAttribute k, string n)
940                         {
941                                 key = k;
942                                 name = n;
943                         }
944                 }
945
946                 static HtmlTag [] tags = {
947                         new HtmlTag (HtmlTextWriterTag.Unknown,    "",                  TagType.Block),
948                         new HtmlTag (HtmlTextWriterTag.A,          "a",                 TagType.Inline),
949                         new HtmlTag (HtmlTextWriterTag.Acronym,    "acronym",           TagType.Inline),
950                         new HtmlTag (HtmlTextWriterTag.Address,    "address",           TagType.Block),
951                         new HtmlTag (HtmlTextWriterTag.Area,       "area",              TagType.Block),
952                         new HtmlTag (HtmlTextWriterTag.B,          "b",                 TagType.Inline),
953                         new HtmlTag (HtmlTextWriterTag.Base,       "base",              TagType.SelfClosing),
954                         new HtmlTag (HtmlTextWriterTag.Basefont,   "basefont",          TagType.SelfClosing),
955                         new HtmlTag (HtmlTextWriterTag.Bdo,        "bdo",               TagType.Inline),
956                         new HtmlTag (HtmlTextWriterTag.Bgsound,    "bgsound",           TagType.SelfClosing),
957                         new HtmlTag (HtmlTextWriterTag.Big,        "big",               TagType.Inline),
958                         new HtmlTag (HtmlTextWriterTag.Blockquote, "blockquote",        TagType.Block),
959                         new HtmlTag (HtmlTextWriterTag.Body,       "body",              TagType.Block),
960                         new HtmlTag (HtmlTextWriterTag.Br,         "br",                TagType.Block),
961                         new HtmlTag (HtmlTextWriterTag.Button,     "button",            TagType.Inline),
962                         new HtmlTag (HtmlTextWriterTag.Caption,    "caption",           TagType.Block),
963                         new HtmlTag (HtmlTextWriterTag.Center,     "center",            TagType.Block),
964                         new HtmlTag (HtmlTextWriterTag.Cite,       "cite",              TagType.Inline),
965                         new HtmlTag (HtmlTextWriterTag.Code,       "code",              TagType.Inline),
966                         new HtmlTag (HtmlTextWriterTag.Col,        "col",               TagType.SelfClosing),
967                         new HtmlTag (HtmlTextWriterTag.Colgroup,   "colgroup",          TagType.Block),
968                         new HtmlTag (HtmlTextWriterTag.Dd,         "dd",                TagType.Inline),
969                         new HtmlTag (HtmlTextWriterTag.Del,        "del",               TagType.Inline),
970                         new HtmlTag (HtmlTextWriterTag.Dfn,        "dfn",               TagType.Inline),
971                         new HtmlTag (HtmlTextWriterTag.Dir,        "dir",               TagType.Block),
972                         new HtmlTag (HtmlTextWriterTag.Div,        "div",               TagType.Block),
973                         new HtmlTag (HtmlTextWriterTag.Dl,         "dl",                TagType.Block),
974                         new HtmlTag (HtmlTextWriterTag.Dt,         "dt",                TagType.Inline),
975                         new HtmlTag (HtmlTextWriterTag.Em,         "em",                TagType.Inline),
976                         new HtmlTag (HtmlTextWriterTag.Embed,      "embed",             TagType.SelfClosing),
977                         new HtmlTag (HtmlTextWriterTag.Fieldset,   "fieldset",          TagType.Block),
978                         new HtmlTag (HtmlTextWriterTag.Font,       "font",              TagType.Inline),
979                         new HtmlTag (HtmlTextWriterTag.Form,       "form",              TagType.Block),
980                         new HtmlTag (HtmlTextWriterTag.Frame,      "frame",             TagType.SelfClosing),
981                         new HtmlTag (HtmlTextWriterTag.Frameset,   "frameset",          TagType.Block),
982                         new HtmlTag (HtmlTextWriterTag.H1,         "h1",                TagType.Block),
983                         new HtmlTag (HtmlTextWriterTag.H2,         "h2",                TagType.Block),
984                         new HtmlTag (HtmlTextWriterTag.H3,         "h3",                TagType.Block),
985                         new HtmlTag (HtmlTextWriterTag.H4,         "h4",                TagType.Block),
986                         new HtmlTag (HtmlTextWriterTag.H5,         "h5",                TagType.Block),
987                         new HtmlTag (HtmlTextWriterTag.H6,         "h6",                TagType.Block),
988                         new HtmlTag (HtmlTextWriterTag.Head,       "head",              TagType.Block),
989                         new HtmlTag (HtmlTextWriterTag.Hr,         "hr",                TagType.SelfClosing),
990                         new HtmlTag (HtmlTextWriterTag.Html,       "html",              TagType.Block),
991                         new HtmlTag (HtmlTextWriterTag.I,          "i",                 TagType.Inline),
992                         new HtmlTag (HtmlTextWriterTag.Iframe,     "iframe",            TagType.Block),
993                         new HtmlTag (HtmlTextWriterTag.Img,        "img",               TagType.SelfClosing),
994                         new HtmlTag (HtmlTextWriterTag.Input,      "input",             TagType.SelfClosing),
995                         new HtmlTag (HtmlTextWriterTag.Ins,        "ins",               TagType.Inline),
996                         new HtmlTag (HtmlTextWriterTag.Isindex,    "isindex",           TagType.SelfClosing),
997                         new HtmlTag (HtmlTextWriterTag.Kbd,        "kbd",               TagType.Inline),
998                         new HtmlTag (HtmlTextWriterTag.Label,      "label",             TagType.Inline),
999                         new HtmlTag (HtmlTextWriterTag.Legend,     "legend",            TagType.Block),
1000                         new HtmlTag (HtmlTextWriterTag.Li,         "li",                TagType.Inline),
1001                         new HtmlTag (HtmlTextWriterTag.Link,       "link",              TagType.SelfClosing),
1002                         new HtmlTag (HtmlTextWriterTag.Map,        "map",               TagType.Block),
1003                         new HtmlTag (HtmlTextWriterTag.Marquee,    "marquee",           TagType.Block),
1004                         new HtmlTag (HtmlTextWriterTag.Menu,       "menu",              TagType.Block),
1005                         new HtmlTag (HtmlTextWriterTag.Meta,       "meta",              TagType.SelfClosing),
1006                         new HtmlTag (HtmlTextWriterTag.Nobr,       "nobr",              TagType.Inline),
1007                         new HtmlTag (HtmlTextWriterTag.Noframes,   "noframes",          TagType.Block),
1008                         new HtmlTag (HtmlTextWriterTag.Noscript,   "noscript",          TagType.Block),
1009                         new HtmlTag (HtmlTextWriterTag.Object,     "object",            TagType.Block),
1010                         new HtmlTag (HtmlTextWriterTag.Ol,         "ol",                TagType.Block),
1011                         new HtmlTag (HtmlTextWriterTag.Option,     "option",            TagType.Block),
1012                         new HtmlTag (HtmlTextWriterTag.P,          "p",                 TagType.Inline),
1013                         new HtmlTag (HtmlTextWriterTag.Param,      "param",             TagType.Block),
1014                         new HtmlTag (HtmlTextWriterTag.Pre,        "pre",               TagType.Block),
1015                         new HtmlTag (HtmlTextWriterTag.Q,          "q",                 TagType.Inline),
1016                         new HtmlTag (HtmlTextWriterTag.Rt,         "rt",                TagType.Block),
1017                         new HtmlTag (HtmlTextWriterTag.Ruby,       "ruby",              TagType.Block),
1018                         new HtmlTag (HtmlTextWriterTag.S,          "s",                 TagType.Inline),
1019                         new HtmlTag (HtmlTextWriterTag.Samp,       "samp",              TagType.Inline),
1020                         new HtmlTag (HtmlTextWriterTag.Script,     "script",            TagType.Block),
1021                         new HtmlTag (HtmlTextWriterTag.Select,     "select",            TagType.Block),
1022                         new HtmlTag (HtmlTextWriterTag.Small,      "small",             TagType.Block),
1023                         new HtmlTag (HtmlTextWriterTag.Span,       "span",              TagType.Inline),
1024                         new HtmlTag (HtmlTextWriterTag.Strike,     "strike",            TagType.Inline),
1025                         new HtmlTag (HtmlTextWriterTag.Strong,     "strong",            TagType.Inline),
1026                         new HtmlTag (HtmlTextWriterTag.Style,      "style",             TagType.Block),
1027                         new HtmlTag (HtmlTextWriterTag.Sub,        "sub",               TagType.Inline),
1028                         new HtmlTag (HtmlTextWriterTag.Sup,        "sup",               TagType.Inline),
1029                         new HtmlTag (HtmlTextWriterTag.Table,      "table",             TagType.Block),
1030                         new HtmlTag (HtmlTextWriterTag.Tbody,      "tbody",             TagType.Block),
1031                         new HtmlTag (HtmlTextWriterTag.Td,         "td",                TagType.Inline),
1032                         new HtmlTag (HtmlTextWriterTag.Textarea,   "textarea",          TagType.Inline),
1033                         new HtmlTag (HtmlTextWriterTag.Tfoot,      "tfoot",             TagType.Block),
1034                         new HtmlTag (HtmlTextWriterTag.Th,         "th",                TagType.Inline),
1035                         new HtmlTag (HtmlTextWriterTag.Thead,      "thead",             TagType.Block),
1036                         new HtmlTag (HtmlTextWriterTag.Title,      "title",             TagType.Block),
1037                         new HtmlTag (HtmlTextWriterTag.Tr,         "tr",                TagType.Block),
1038                         new HtmlTag (HtmlTextWriterTag.Tt,         "tt",                TagType.Inline),
1039                         new HtmlTag (HtmlTextWriterTag.U,          "u",                 TagType.Inline),
1040                         new HtmlTag (HtmlTextWriterTag.Ul,         "ul",                TagType.Block),
1041                         new HtmlTag (HtmlTextWriterTag.Var,        "var",               TagType.Inline),
1042                         new HtmlTag (HtmlTextWriterTag.Wbr,        "wbr",               TagType.SelfClosing),
1043                         new HtmlTag (HtmlTextWriterTag.Xml,        "xml",               TagType.Block),
1044                 };
1045
1046                 static HtmlAttribute [] htmlattrs = {
1047                         new HtmlAttribute (HtmlTextWriterAttribute.Accesskey,         "accesskey"),
1048                         new HtmlAttribute (HtmlTextWriterAttribute.Align,             "align"),
1049                         new HtmlAttribute (HtmlTextWriterAttribute.Alt,               "alt"),
1050                         new HtmlAttribute (HtmlTextWriterAttribute.Background,        "background"),
1051                         new HtmlAttribute (HtmlTextWriterAttribute.Bgcolor,           "bgcolor"),
1052                         new HtmlAttribute (HtmlTextWriterAttribute.Border,            "border"),
1053                         new HtmlAttribute (HtmlTextWriterAttribute.Bordercolor,       "bordercolor"),
1054                         new HtmlAttribute (HtmlTextWriterAttribute.Cellpadding,       "cellpadding"),
1055                         new HtmlAttribute (HtmlTextWriterAttribute.Cellspacing,       "cellspacing"),
1056                         new HtmlAttribute (HtmlTextWriterAttribute.Checked,           "checked"),
1057                         new HtmlAttribute (HtmlTextWriterAttribute.Class,             "class"),
1058                         new HtmlAttribute (HtmlTextWriterAttribute.Cols,              "cols"),
1059                         new HtmlAttribute (HtmlTextWriterAttribute.Colspan,           "colspan"),
1060                         new HtmlAttribute (HtmlTextWriterAttribute.Disabled,          "disabled"),
1061                         new HtmlAttribute (HtmlTextWriterAttribute.For,               "for"),
1062                         new HtmlAttribute (HtmlTextWriterAttribute.Height,            "height"),
1063                         new HtmlAttribute (HtmlTextWriterAttribute.Href,              "href"),
1064                         new HtmlAttribute (HtmlTextWriterAttribute.Id,                "id"),
1065                         new HtmlAttribute (HtmlTextWriterAttribute.Maxlength,         "maxlength"),
1066                         new HtmlAttribute (HtmlTextWriterAttribute.Multiple,          "multiple"),
1067                         new HtmlAttribute (HtmlTextWriterAttribute.Name,              "name"),
1068                         new HtmlAttribute (HtmlTextWriterAttribute.Nowrap,            "nowrap"),
1069                         new HtmlAttribute (HtmlTextWriterAttribute.Onchange,          "onchange"),
1070                         new HtmlAttribute (HtmlTextWriterAttribute.Onclick,           "onclick"),
1071                         new HtmlAttribute (HtmlTextWriterAttribute.ReadOnly,          "readonly"),
1072                         new HtmlAttribute (HtmlTextWriterAttribute.Rows,              "rows"),
1073                         new HtmlAttribute (HtmlTextWriterAttribute.Rowspan,           "rowspan"),
1074                         new HtmlAttribute (HtmlTextWriterAttribute.Rules,             "rules"),
1075                         new HtmlAttribute (HtmlTextWriterAttribute.Selected,          "selected"),
1076                         new HtmlAttribute (HtmlTextWriterAttribute.Size,              "size"),
1077                         new HtmlAttribute (HtmlTextWriterAttribute.Src,               "src"),
1078                         new HtmlAttribute (HtmlTextWriterAttribute.Style,             "style"),
1079                         new HtmlAttribute (HtmlTextWriterAttribute.Tabindex,          "tabindex"),
1080                         new HtmlAttribute (HtmlTextWriterAttribute.Target,            "target"),
1081                         new HtmlAttribute (HtmlTextWriterAttribute.Title,             "title"),
1082                         new HtmlAttribute (HtmlTextWriterAttribute.Type,              "type"),
1083                         new HtmlAttribute (HtmlTextWriterAttribute.Valign,            "valign"),
1084                         new HtmlAttribute (HtmlTextWriterAttribute.Value,             "value"),
1085                         new HtmlAttribute (HtmlTextWriterAttribute.Width,             "width"),
1086                         new HtmlAttribute (HtmlTextWriterAttribute.Wrap,              "wrap"),
1087 #if NET_2_0
1088                         new HtmlAttribute (HtmlTextWriterAttribute.Abbr,              "abbr"),
1089                         new HtmlAttribute (HtmlTextWriterAttribute.AutoComplete,      "autocomplete"),
1090                         new HtmlAttribute (HtmlTextWriterAttribute.Axis,              "axis"),
1091                         new HtmlAttribute (HtmlTextWriterAttribute.Content,           "content"),
1092                         new HtmlAttribute (HtmlTextWriterAttribute.Coords,            "coords"),
1093                         new HtmlAttribute (HtmlTextWriterAttribute.DesignerRegion,    "_designerregion"),
1094                         new HtmlAttribute (HtmlTextWriterAttribute.Dir,               "dir"),
1095                         new HtmlAttribute (HtmlTextWriterAttribute.Headers,           "headers"),
1096                         new HtmlAttribute (HtmlTextWriterAttribute.Longdesc,          "longdesc"),
1097                         new HtmlAttribute (HtmlTextWriterAttribute.Rel,               "rel"),
1098                         new HtmlAttribute (HtmlTextWriterAttribute.Scope,             "scope"),
1099                         new HtmlAttribute (HtmlTextWriterAttribute.Shape,             "shape"),
1100                         new HtmlAttribute (HtmlTextWriterAttribute.Usemap,            "usemap"),
1101                         new HtmlAttribute (HtmlTextWriterAttribute.VCardName,         "vcard_name"),
1102 #endif
1103                 };
1104
1105                 static HtmlStyle [] htmlstyles = {
1106                         new HtmlStyle (HtmlTextWriterStyle.BackgroundColor,    "background-color"),
1107                         new HtmlStyle (HtmlTextWriterStyle.BackgroundImage,    "background-image"),
1108                         new HtmlStyle (HtmlTextWriterStyle.BorderCollapse,     "border-collapse"),
1109                         new HtmlStyle (HtmlTextWriterStyle.BorderColor,        "border-color"),
1110                         new HtmlStyle (HtmlTextWriterStyle.BorderStyle,        "border-style"),
1111                         new HtmlStyle (HtmlTextWriterStyle.BorderWidth,        "border-width"),
1112                         new HtmlStyle (HtmlTextWriterStyle.Color,              "color"),
1113                         new HtmlStyle (HtmlTextWriterStyle.FontFamily,         "font-family"),
1114                         new HtmlStyle (HtmlTextWriterStyle.FontSize,           "font-size"),
1115                         new HtmlStyle (HtmlTextWriterStyle.FontStyle,          "font-style"),
1116                         new HtmlStyle (HtmlTextWriterStyle.FontWeight,         "font-weight"),
1117                         new HtmlStyle (HtmlTextWriterStyle.Height,             "height"),
1118                         new HtmlStyle (HtmlTextWriterStyle.TextDecoration,     "text-decoration"),
1119                         new HtmlStyle (HtmlTextWriterStyle.Width,              "width"),
1120 #if NET_2_0
1121                         new HtmlStyle (HtmlTextWriterStyle.ListStyleImage,     "list-style-image"),
1122                         new HtmlStyle (HtmlTextWriterStyle.ListStyleType,      "list-style-type"),
1123                         new HtmlStyle (HtmlTextWriterStyle.Cursor,             "cursor"),
1124                         new HtmlStyle (HtmlTextWriterStyle.Direction,          "direction"),
1125                         new HtmlStyle (HtmlTextWriterStyle.Display,            "display"),
1126                         new HtmlStyle (HtmlTextWriterStyle.Filter,             "filter"),
1127                         new HtmlStyle (HtmlTextWriterStyle.FontVariant,        "font-variant"),
1128                         new HtmlStyle (HtmlTextWriterStyle.Left,               "left"),
1129                         new HtmlStyle (HtmlTextWriterStyle.Margin,             "margin"),
1130                         new HtmlStyle (HtmlTextWriterStyle.MarginBottom,       "margin-bottom"),
1131                         new HtmlStyle (HtmlTextWriterStyle.MarginLeft,         "margin-left"),
1132                         new HtmlStyle (HtmlTextWriterStyle.MarginRight,        "margin-right"),
1133                         new HtmlStyle (HtmlTextWriterStyle.MarginTop,          "margin-top"),
1134                         new HtmlStyle (HtmlTextWriterStyle.Overflow,           "overflow"),
1135                         new HtmlStyle (HtmlTextWriterStyle.OverflowX,          "overflow-x"),
1136                         new HtmlStyle (HtmlTextWriterStyle.OverflowY,          "overflow-y"),
1137                         new HtmlStyle (HtmlTextWriterStyle.Padding,            "padding"),
1138                         new HtmlStyle (HtmlTextWriterStyle.PaddingBottom,      "padding-bottom"),
1139                         new HtmlStyle (HtmlTextWriterStyle.PaddingLeft,        "padding-left"),
1140                         new HtmlStyle (HtmlTextWriterStyle.PaddingRight,       "padding-right"),
1141                         new HtmlStyle (HtmlTextWriterStyle.PaddingTop,         "padding-top"),
1142                         new HtmlStyle (HtmlTextWriterStyle.Position,           "position"),
1143                         new HtmlStyle (HtmlTextWriterStyle.TextAlign,          "text-align"),
1144                         new HtmlStyle (HtmlTextWriterStyle.VerticalAlign,      "vertical-align"),
1145                         new HtmlStyle (HtmlTextWriterStyle.TextOverflow,       "text-overflow"),
1146                         new HtmlStyle (HtmlTextWriterStyle.Top,                "top"),
1147                         new HtmlStyle (HtmlTextWriterStyle.Visibility,         "visibility"),
1148                         new HtmlStyle (HtmlTextWriterStyle.WhiteSpace,         "white-space"),
1149                         new HtmlStyle (HtmlTextWriterStyle.ZIndex,             "z-index"),
1150 #endif
1151                 };
1152
1153 #if NET_2_0
1154                 public virtual bool IsValidFormAttribute (string attribute)
1155                 {
1156                         return true;
1157                 }
1158
1159                 // writes <br />
1160                 public virtual void WriteBreak ()
1161                 {
1162                         string br = GetTagName (HtmlTextWriterTag.Br);
1163                         WriteBeginTag (br);
1164                         Write (SelfClosingTagEnd);
1165                 }
1166
1167                 public virtual void WriteEncodedText (string text)
1168                 {
1169                         Write (HttpUtility.HtmlEncode (text));
1170                 }
1171
1172                 [MonoNotSupported ("")]
1173                 public virtual void WriteEncodedUrl (string url)
1174                 {
1175                         // WriteUrlEncodedString (url, false);
1176                         throw new NotImplementedException ();
1177                 }
1178
1179                 [MonoNotSupported ("")]
1180                 public virtual void WriteEncodedUrlParameter (string urlText)
1181                 {
1182                         // WriteUrlEncodedString (urlText, true);
1183                         throw new NotImplementedException ();
1184                 }
1185
1186                 [MonoNotSupported ("")]
1187                 protected void WriteUrlEncodedString (string text, bool argument)
1188                 {
1189                         throw new NotImplementedException ();
1190                 }
1191
1192                 [MonoNotSupported ("")]
1193                 public virtual void EnterStyle (Style style)
1194                 {
1195                         throw new NotImplementedException ();
1196                 }
1197
1198                 [MonoNotSupported ("")]
1199                 public virtual void EnterStyle (Style style, HtmlTextWriterTag tag)
1200                 {
1201                         throw new NotImplementedException ();
1202                 }
1203
1204                 [MonoNotSupported ("")]
1205                 public virtual void ExitStyle (Style style)
1206                 {
1207                         throw new NotImplementedException ();
1208                 }
1209
1210                 [MonoNotSupported ("")]
1211                 public virtual void ExitStyle (Style style, HtmlTextWriterTag tag)
1212                 {
1213                         throw new NotImplementedException ();
1214                 }
1215
1216 #endif
1217         }
1218 }