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