/// <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); }
/// <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); }