/// <summary> /// Matches the header collection against this subtree, adds any new matches for this node to /// matchList, and uses the matchList to augment the result. /// </summary> /// <param name="header">the header collection to evaluate (invariant)</param> /// <param name="result">the result of the match (might be changed if a match is found)</param> /// <param name="matchList">the matches to use to do substitutions, /// possibly including new matches for this node.</param> /// <returns>true iff this node or one of it's descendants matches</returns> private bool ProcessSubtree(System.Collections.Specialized.NameValueCollection header, nBrowser.Result result, System.Collections.Generic.List<Match> matchList) { //---------------------------------------------------------------------- //This is just coded over from MS version since if you pass in an empty //string for the key it returns the UserAgent header as a response. //---------------------------------------------------------------------- result.AddCapabilities("", header["User-Agent"]); if (RefId.Length == 0 && this.NameType != NodeType.DefaultBrowser) { //---------------------------------------------------------------------- //BrowserIdentification adds all the Identifiction matches to the match //list if this node matches. //---------------------------------------------------------------------- if (!BrowserIdentification(header, result, matchList)) return false; } result.AddMatchingBrowserId (this.Id); #region Browser Identification Successfull //---------------------------------------------------------------------- //By reaching this point, it either means there were no Identification //items to be processed or that all the Identification items have been //passed. So just for debuging I want to output this Groups unique ID. //---------------------------------------------------------------------- result.AddTrack("[" + this.NameType + "]\t" + this.Id); //---------------------------------------------------------------------- //Just adding all the Adapters to the current list. //---------------------------------------------------------------------- if (Adapter != null) { LookupAdapterTypes(); for (int i = 0;i <= Adapter.Count - 1;i++) { result.AddAdapter(AdapterControlTypes [i], AdapterTypes [i]); } } //---------------------------------------------------------------------- //Set the MarkupTextWriter in the result if set in this node. //---------------------------------------------------------------------- if (MarkupTextWriterType != null && MarkupTextWriterType.Length > 0) { // Look for the type using a case-sensitive search result.MarkupTextWriter = Type.GetType(MarkupTextWriterType); // If we don't find it, try again using a case-insensitive search and throw // and exception if we can't find it. if (result.MarkupTextWriter == null) result.MarkupTextWriter = Type.GetType(MarkupTextWriterType, true, true); } #endregion #region Capture if (Capture != null) { //---------------------------------------------------------------------- //Adds all the sucessfull Capture matches to the matchList //---------------------------------------------------------------------- for (int i = 0;i <= Capture.Length - 1;i++) { //shouldn't happen often, the null should //signal the end of the list, I keep procssing //the rest just in case if (Capture[i] == null) { continue; } Match m = null; if (Capture[i].Group == "header") { m = Capture[i].GetMatch(header[Capture[i].Name]); } else if (Capture[i].Group == "capability") { m = Capture[i].GetMatch(result[Capture[i].Name]); } if (Capture[i].IsMatchSuccessful(m) && m.Groups.Count > 0) { matchList.Add(m); } } } #endregion #region Capabilities if (Capabilities != null) { //---------------------------------------------------------------------- //This section is what the whole exercise is about. Determining //the Browser Capabilities. We know already that the current //browser matches the criteria, now its a mater of updating //the results with the new Capabilties listed. //---------------------------------------------------------------------- for (int i = 0;i <= Capabilities.Count - 1;i++) { //---------------------------------------------------------------------- //We need to further process these Capabilities to //insert the proper information. //---------------------------------------------------------------------- string v = Capabilities[i]; //---------------------------------------------------------------------- //Loop though the list of Identifiction/Capture Matches //in reverse order. Meaning the newest Items in the list //get checked first, then working to the oldest. Often times //Minor /Major revisition numbers will be listed multple times //and only the newest one (most recent matches) are the ones //we want to insert. //---------------------------------------------------------------------- for (int a = matchList.Count - 1; a >= 0 && v != null && v.Length > 0 && v.IndexOf('$') > -1; a--) { // Don't do substitution if the match has no groups or was a nonMatch if (matchList[a].Groups.Count == 0 || !matchList[a].Success) continue; v = matchList[a].Result(v); } //---------------------------------------------------------------------- //Checks to make sure we extract the result we where looking for. //---------------------------------------------------------------------- if (v.IndexOf('$') > -1 || v.IndexOf('%') > -1) { //---------------------------------------------------------------------- //Microsoft has a nasty habbit of using capability items in regular expressions //so I have to figure a nice way to working around it // <capability name="msdomversion" value="${majorversion}${minorversion}" /> //---------------------------------------------------------------------- //double checks the values against the current Capabilities. to //find any last minute matches. that are not defined by regluar //expressions v = result.Replace(v); } result.AddCapabilities(Capabilities.Keys[i], v); } } #endregion //---------------------------------------------------------------------- //Run the Default Children after the Parent Node is finished with //what it is doing //---------------------------------------------------------------------- for (int i = 0;i <= DefaultChildren.Count - 1;i++) { string key = DefaultChildrenKeys[i]; Node node = DefaultChildren[key]; if (node.NameType == NodeType.DefaultBrowser) { node.Process(header, result, matchList); } } //---------------------------------------------------------------------- //processing all the children Browsers of this Parent if there are any. //---------------------------------------------------------------------- //In nBrowser files, the Gateways should of been sorted so they are all //at the top so that they can be ran first. //---------------------------------------------------------------------- //According to the msdn2 documentation Gateways are suppost to be //all processed first. before the browser objects. for (int i = 0;i <= Children.Count - 1;i++) { string key = ChildrenKeys[i]; Node node = Children[key]; if (node.NameType == NodeType.Gateway) { node.Process(header, result, matchList); } } for (int i = 0;i <= Children.Count - 1;i++) { string key = ChildrenKeys[i]; Node node = Children[key]; if (node.NameType == NodeType.Browser && node.Process(header, result, matchList)) break; } return true; }
private void AddBrowserFile(nBrowser.File file) { if (Browserfiles.ContainsKey(file.FileName) == false) { Browserfiles.Add(file.FileName, file); nbrowserfiles.Add(file); string[] keys = file.Keys; for (int i = 0;i <= keys.Length - 1;i++) { if (BrowserKeys.ContainsKey(keys[i]) == false) { BrowserKeys.Add(keys[i], file.FileName); } else { throw new nBrowser.Exception("Duplicate Key \"" + keys[i] + "\" found in " + file.FileName + " and in file " + BrowserKeys[keys[i]]); } } keys = file.DefaultKeys; for (int i = 0;i <= keys.Length - 1;i++) { if (DefaultKeys.ContainsKey(keys[i]) == false) { DefaultKeys.Add(keys[i], file.FileName); } else { throw new nBrowser.Exception("Duplicate Key \"" + keys[i] + "\" found in " + file.FileName + " and in file " + DefaultKeys[keys[i]]); } } } }
/// <summary> /// Matches the header collection against this subtree and uses the matchList /// and any new matches to augment the result. This method calls ProcessSubtree() /// but then removes the matches that it adds to the matchList. /// </summary> /// <param name="header">the header collection to evaluate (invariant)</param> /// <param name="result">the result of the match (might be changed if a match is found)</param> /// <param name="matchList">the matches to use to do substitutions (invariant)</param> /// <returns>true iff this node or one of it's descendants matches</returns> internal bool Process(System.Collections.Specialized.NameValueCollection header, nBrowser.Result result, System.Collections.Generic.List<Match> matchList) { // The real work is done in ProcessSubtree. This method just ensures that matchList is restored // to its original state before returning. int origMatchListCount = matchList.Count; bool matched = ProcessSubtree(header, result, matchList); if (matchList.Count > origMatchListCount) matchList.RemoveRange(origMatchListCount, matchList.Count-origMatchListCount); return matched; }