2008-11-18 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TagAttributes.cs
1 //
2 // System.Web.Compilation.TagAttributes
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Collections;
33 using System.Text;
34 using System.Web.Util;
35
36 namespace System.Web.Compilation
37 {
38         class TagAttributes
39         {
40                 Hashtable atts_hash;
41                 Hashtable tmp_hash;
42                 ArrayList keys;
43                 ArrayList values;
44                 bool got_hashed;
45
46                 public TagAttributes ()
47                 {
48                         got_hashed = false;
49                         keys = new ArrayList ();
50                         values = new ArrayList ();
51                 }
52
53                 void MakeHash ()
54                 {
55 #if NET_2_0
56                         atts_hash = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
57 #else
58                         atts_hash = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
59                                                    CaseInsensitiveComparer.DefaultInvariant);
60 #endif
61                         for (int i = 0; i < keys.Count; i++) {
62                                 CheckServerKey (keys [i]);
63                                 atts_hash.Add (keys [i], values [i]);
64                         }
65                         got_hashed = true;
66                         keys = null;
67                         values = null;
68                 }
69                 
70                 public bool IsRunAtServer ()
71                 {
72                         return got_hashed;
73                 }
74
75                 public void Add (object key, object value)
76                 {
77                         if (key != null && value != null &&
78                             0 == String.Compare ((string) key,  "runat", true)) {
79                                 if (0 != String.Compare ((string) value,  "server", true))
80                                         throw new HttpException ("runat attribute must have a 'server' value");
81
82                                 if (got_hashed)
83                                         return; // ignore duplicate runat="server"
84
85                                 MakeHash ();
86                         }
87
88                         if (value != null)
89                                 value = HttpUtility.HtmlDecode (value.ToString ());
90
91                         if (got_hashed) {
92                                 CheckServerKey (key);
93                                 if (atts_hash.ContainsKey (key))
94                                         throw new HttpException ("Tag contains duplicated '" + key +
95                                                                  "' attributes.");
96                                 atts_hash.Add (key, value);
97                         } else {
98                                 keys.Add (key);
99                                 values.Add (value);
100                         }
101                 }
102                 
103                 public ICollection Keys 
104                 {
105                         get { return (got_hashed ? atts_hash.Keys : keys); }
106                 }
107
108                 public ICollection Values 
109                 {
110                         get { return (got_hashed ? atts_hash.Values : values); }
111                 }
112
113                 int CaseInsensitiveSearch (string key)
114                 {
115                         // Hope not to have many attributes when the tag is not a server tag...
116                         for (int i = 0; i < keys.Count; i++){
117                                 if (0 == String.Compare ((string) keys [i], key, true))
118                                         return i;
119                         }
120                         return -1;
121                 }
122                 
123                 public object this [object key]
124                 {
125                         get {
126                                 if (got_hashed)
127                                         return atts_hash [key];
128
129                                 int idx = CaseInsensitiveSearch ((string) key);
130                                 if (idx == -1)
131                                         return null;
132                                                 
133                                 return values [idx];
134                         }
135
136                         set {
137                                 if (got_hashed) {
138                                         CheckServerKey (key);
139                                         atts_hash [key] = value;
140                                 } else {
141                                         int idx = CaseInsensitiveSearch ((string) key);
142                                         keys [idx] = value;
143                                 }
144                         }
145                 }
146                 
147                 public int Count 
148                 {
149                         get { return (got_hashed ? atts_hash.Count : keys.Count);}
150                 }
151
152                 public bool IsDataBound (string att)
153                 {
154                         if (att == null || !got_hashed)
155                                 return false;
156
157                         return (StrUtils.StartsWith (att, "<%#") && StrUtils.EndsWith (att, "%>"));
158                 }
159                 
160                 public Hashtable GetDictionary (string key)
161                 {
162                         if (got_hashed)
163                                 return atts_hash;
164
165                         if (tmp_hash == null)
166 #if NET_2_0
167                                 tmp_hash = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
168 #else
169                                 tmp_hash = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
170                                                           CaseInsensitiveComparer.DefaultInvariant);
171 #endif
172                         
173                         tmp_hash.Clear ();
174                         for (int i = keys.Count - 1; i >= 0; i--)
175                                 if (key == null || String.Compare (key, (string) keys [i], true) == 0)
176                                         tmp_hash [keys [i]] = values [i];
177
178                         return tmp_hash;
179                 }
180                 
181                 public override string ToString ()
182                 {
183                         StringBuilder result = new StringBuilder ();
184                         string value;
185                         foreach (string key in Keys){
186                                 result.Append (key);
187                                 value = this [key] as string;
188                                 if (value != null)
189                                         result.AppendFormat ("=\"{0}\"", value);
190
191                                 result.Append (' ');
192                         }
193
194                         if (result.Length > 0 && result [result.Length - 1] == ' ')
195                                 result.Length--;
196                                 
197                         return result.ToString ();
198                 }
199                 
200                 void CheckServerKey (object key)
201                 {
202                         if (key == null || ((string)key).Length == 0)
203                                 throw new HttpException ("The server tag is not well formed.");
204                 }
205         }
206 }
207