2 // System.Web.CapabilitiesLoader
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.
9 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
11 // (c) 2003 Novell, Inc. (http://www.novell.com)
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Globalization;
40 using System.Text.RegularExpressions;
41 using System.Web.Configuration;
47 static char [] wildchars = new char [] {'*', '?'};
54 public BrowserData (string pattern)
56 int norx = pattern.IndexOfAny (wildchars);
60 this.pattern = pattern.Substring (norx);
61 text = pattern.Substring (0, norx);
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 ("*", ".*");
75 public BrowserData Parent {
76 get { return parent; }
77 set { parent = value; }
80 public void Add (string key, string value)
83 data = new ListDictionary ();
85 data.Add (key, value);
88 public Hashtable GetProperties (Hashtable tbl)
91 parent.GetProperties (tbl);
93 foreach (string key in data.Keys)
94 tbl [key] = data [key];
99 public string GetParentName ()
101 return (string) data ["parent"];
104 public string GetAlternateBrowser ()
106 return (pattern == null) ? text : null;
109 public string GetBrowser ()
114 return (string) data ["browser"];
117 public bool IsMatch (string expression)
119 if (expression == null || expression.Length == 0)
123 if (text [0] != expression [0] ||
124 String.Compare (text, 1, expression, 1,
125 text.Length - 1, false,
126 CultureInfo.InvariantCulture) != 0) {
129 expression = expression.Substring (text.Length);
133 return expression.Length == 0;
137 regex = new Regex (pattern);
140 return regex.Match (expression).Success;
144 class CapabilitiesLoader : MarshalByRefObject
146 const int userAgentsCacheSize = 3000;
147 static Hashtable defaultCaps;
148 static readonly object lockobj = new object ();
153 return alldata != null;
157 alldata = new ArrayList ();
161 const string alldataKey = "System.Web.CapabilitiesLoader.alldata";
162 static ICollection alldata {
164 return (ICollection) AppDomain.CurrentDomain.GetData (alldataKey);
167 AppDomain.CurrentDomain.SetData (alldataKey, value);
171 const string userAgentsCacheKey = "System.Web.CapabilitiesLoader.userAgentsCache";
172 static Hashtable userAgentsCache {
174 lock (typeof (CapabilitiesLoader)) {
175 Hashtable agentsCache = (Hashtable) AppDomain.CurrentDomain.GetData (userAgentsCacheKey);
176 if (agentsCache == null) {
177 agentsCache = Hashtable.Synchronized (new Hashtable (userAgentsCacheSize + 10));
178 AppDomain.CurrentDomain.SetData (userAgentsCacheKey, agentsCache);
186 static volatile bool loaded;
187 static ICollection alldata;
188 static Hashtable userAgentsCache = Hashtable.Synchronized(new Hashtable(userAgentsCacheSize+10));
191 private CapabilitiesLoader () {}
193 static CapabilitiesLoader ()
195 defaultCaps = new Hashtable ();
196 defaultCaps.Add ("frames", "True");
197 defaultCaps.Add ("tables", "True");
200 public static Hashtable GetCapabilities (string userAgent)
203 if (userAgent != null)
204 userAgent = userAgent.Trim ();
206 if (alldata == null || userAgent == null || userAgent == "")
209 Hashtable userBrowserCaps = (Hashtable) userAgentsCache [userAgent];
210 if (userBrowserCaps == null) {
211 foreach (BrowserData bd in alldata) {
212 if (bd.IsMatch (userAgent)) {
215 tbl = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
217 tbl = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
218 CaseInsensitiveComparer.DefaultInvariant);
220 userBrowserCaps = bd.GetProperties (tbl);
225 if (userBrowserCaps == null)
226 userBrowserCaps = defaultCaps;
228 lock (typeof (CapabilitiesLoader)) {
229 if (userAgentsCache.Count >= userAgentsCacheSize) {
230 userAgentsCache.Clear ();
233 userAgentsCache [userAgent] = userBrowserCaps;
235 return userBrowserCaps;
247 string filepath = "browscap.ini";
250 string dir = Path.GetDirectoryName (WebConfigurationManager.OpenMachineConfiguration().FilePath);
252 string dir = Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
254 string filepath = Path.Combine (dir, "browscap.ini");
255 if (!File.Exists (filepath)) {
256 // try removing the trailing version directory
257 dir = Path.GetDirectoryName (dir);
258 filepath = Path.Combine (dir, "browscap.ini");
263 } catch (Exception) { }
270 private static TextReader GetJavaTextReader(string filename)
275 java.lang.ClassLoader cl = (java.lang.ClassLoader)
276 AppDomain.CurrentDomain.GetData("GH_ContextClassLoader");
280 string custom = String.Concat("browscap/", filename);
282 java.io.InputStream inputStream = cl.getResourceAsStream(custom);
283 if (inputStream == null)
284 inputStream = cl.getResourceAsStream(filename);
286 s = (Stream)vmw.common.IOUtils.getStream(inputStream);
292 return new StreamReader (s);
296 static void LoadFile (string filename)
299 TextReader input = GetJavaTextReader(filename);
303 if (!File.Exists (filename))
306 TextReader input = new StreamReader (File.OpenRead (filename));
309 Hashtable allhash = new Hashtable ();
311 while ((str = input.ReadLine ()) != null) {
312 if (str.Length == 0 || str [0] == ';')
315 string userAgent = str.Substring (1, str.Length - 2);
316 BrowserData data = new BrowserData (userAgent);
317 ReadCapabilities (input, data);
319 /* Ignore default browser and file version information */
320 if (userAgent == "*" || userAgent == "GJK_Browscap_Version")
323 string key = data.GetBrowser ();
324 if (key == null || allhash.ContainsKey (key)) {
325 allhash.Add (aux++, data);
327 allhash.Add (key, data);
331 alldata = allhash.Values;
332 foreach (BrowserData data in alldata) {
333 if (data.Parent != null)
336 string pname = data.GetParentName ();
338 data.Parent = (BrowserData) allhash [pname];
342 static char [] eq = new char []{'='};
343 static void ReadCapabilities (TextReader input, BrowserData data)
346 while ((str = input.ReadLine ()) != null && str.Length != 0) {
347 string [] keyvalue = str.Split (eq, 2);
348 data.Add (keyvalue [0], keyvalue [1]);