* ApplicationShutdownReason.cs: Fixed typos.
[mono.git] / mcs / class / System.Web / System.Web / CapabilitiesLoader.cs
1 // 
2 // System.Web.CapabilitiesLoader
3 //
4 // Loads data from browscap.ini file provided by Gary J. Keith from
5 // http://www.GaryKeith.com/browsers. Please don't abuse the
6 // site when updating browscap.ini file. Use the update-browscap.exe tool.
7 //
8 // Authors:
9 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 //
11 // (c) 2003 Novell, Inc. (http://www.novell.com)
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Globalization;
39 using System.IO;
40 using System.Text.RegularExpressions;
41 using System.Web.Configuration;
42
43 namespace System.Web
44 {
45         class BrowserData
46         {
47                 static char [] wildchars = new char [] {'*', '?'};
48                 BrowserData parent;
49                 string text;
50                 string pattern;
51                 Regex regex;
52                 ListDictionary data;
53
54                 public BrowserData (string pattern)
55                 {
56                         int norx = pattern.IndexOfAny (wildchars);
57                         if (norx == -1) {
58                                 text = pattern;
59                         } else {
60                                 this.pattern = pattern.Substring (norx);
61                                 text = pattern.Substring (0, norx);
62                                 if (text.Length == 0)
63                                         text = null;
64
65                                 this.pattern = this.pattern.Replace (".", "\\.");
66                                 this.pattern = this.pattern.Replace ("(", "\\(");
67                                 this.pattern = this.pattern.Replace (")", "\\)");
68                                 this.pattern = this.pattern.Replace ("[", "\\[");
69                                 this.pattern = this.pattern.Replace ("]", "\\]");
70                                 this.pattern = this.pattern.Replace ("?", ".");
71                                 this.pattern = this.pattern.Replace ("*", ".*");
72                         }
73                 }
74
75                 public BrowserData Parent {
76                         get { return parent; }
77                         set { parent = value; }
78                 }
79
80                 public void Add (string key, string value)
81                 {
82                         lock (this) {
83                                 if (data == null)
84                                         data = new ListDictionary ();
85
86                                 data.Add (key, value);
87                         }
88                 }
89
90                 public Hashtable GetProperties (Hashtable tbl)
91                 {
92                         if (parent != null)
93                                 parent.GetProperties (tbl);
94
95                         foreach (string key in data.Keys)
96                                 tbl [key] = data [key];
97
98                         return tbl;
99                 }
100                 
101                 public string GetParentName ()
102                 {
103                         return (string) data ["parent"];
104                 }
105                 
106                 public string GetAlternateBrowser ()
107                 {
108                         return (pattern == null) ? text : null;
109                 }
110
111                 public string GetBrowser ()
112                 {
113                         if (pattern == null)
114                                 return text;
115
116                         return (string) data ["browser"];
117                 }
118                 
119                 public bool IsMatch (string expression)
120                 {
121                         if (expression == null || expression.Length == 0)
122                                 return false;
123
124                         if (text != null) {
125                                 if (text [0] != expression [0] ||
126                                     String.Compare (text, 1, expression, 1,
127                                                     text.Length - 1, false,
128                                                     CultureInfo.InvariantCulture) != 0) {
129                                         return false;
130                                 }
131                                 expression = expression.Substring (text.Length);
132                         }
133                         
134                         lock (this) {
135                                 if (pattern == null)
136                                         return expression.Length == 0;
137
138                                 if (regex == null)
139                                         regex = new Regex (pattern);
140                         }
141
142                         return regex.Match (expression).Success;
143                 }
144         }
145         
146         class CapabilitiesLoader : MarshalByRefObject
147         {
148                 static bool loaded;
149                 static ICollection alldata;
150                 static Hashtable defaultCaps;
151                 private CapabilitiesLoader () {}
152
153                 public static Hashtable GetCapabilities (string userAgent)
154                 {
155                         Init ();
156                         if (userAgent != null)
157                                 userAgent = userAgent.Trim ();
158
159                         if (alldata == null || userAgent == null || userAgent == "")
160                                 return DefaultCapabilities;
161
162                         foreach (BrowserData bd in alldata) {
163                                 if (bd.IsMatch (userAgent)) {
164                                         return bd.GetProperties (new Hashtable ());
165                                 }
166                         }
167                         
168                         return DefaultCapabilities;
169                 }
170
171                 static void Init ()
172                 {
173                         lock (typeof (CapabilitiesLoader)) {
174                                 if (loaded)
175                                         return;
176
177                                 string path = Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
178                                 path = Path.Combine (path, "browscap.ini");
179                                 try {
180                                         LoadFile (path);
181                                 } catch (Exception) { }
182
183                                 loaded = true;
184                         }
185                 }
186
187                 static void LoadFile (string filename)
188                 {
189                         if (!File.Exists (filename))
190                                 return;
191
192                         TextReader input = new StreamReader (File.OpenRead (filename));
193                         string str;
194                         Hashtable allhash = new Hashtable ();
195                         int aux = 0;
196                         while ((str = input.ReadLine ()) != null) {
197                                 if (str.Length == 0 || str [0] == ';')
198                                         continue;
199
200                                 string userAgent = str.Substring (1, str.Length - 2);
201                                 BrowserData data = new BrowserData (userAgent);
202                                 ReadCapabilities (input, data);
203
204                                 /* Ignore default browser and file version information */
205                                 if (userAgent == "*" || userAgent == "GJK_Browscap_Version")
206                                         continue;
207
208                                 string key = data.GetBrowser ();
209                                 if (key == null || allhash.ContainsKey (key)) {
210                                         allhash.Add (aux++, data);
211                                 } else {
212                                         allhash.Add (key, data);
213                                 }
214                         }
215
216                         alldata = allhash.Values;
217                         foreach (BrowserData data in alldata) {
218                                 if (data.Parent != null)
219                                         continue;
220
221                                 string pname = data.GetParentName ();
222                                 if (pname != null)
223                                         data.Parent = (BrowserData) allhash [pname];
224                         }
225                 }
226
227                 static char [] eq = new char []{'='};
228                 static void ReadCapabilities (TextReader input, BrowserData data)
229                 {
230                         string str;
231                         while ((str = input.ReadLine ()) != null && str.Length != 0) {
232                                 string [] keyvalue = str.Split (eq, 2);
233                                 data.Add (keyvalue [0], keyvalue [1]);
234                         }
235                 }
236
237                 static Hashtable DefaultCapabilities {
238                         get {
239                                 lock (typeof (CapabilitiesLoader)) {
240                                         if (defaultCaps != null)
241                                                 return defaultCaps;
242
243                                         defaultCaps = new Hashtable ();
244                                         defaultCaps.Add ("frames", "True");
245                                         defaultCaps.Add ("tables", "True");
246                                         return defaultCaps;
247                                 }
248                         }
249                 }
250         }
251 }
252