Node.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. #if NET_2_0
  2. /*
  3. Used to determine Browser Capabilities by the Browsers UserAgent String and related
  4. Browser supplied Headers.
  5. Copyright (C) 2002-Present Owen Brady (Ocean at owenbrady dot net)
  6. and Dean Brettle (dean at brettle dot com)
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is furnished
  12. to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in all
  14. copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  20. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. namespace System.Web.Configuration.nBrowser
  23. {
  24. using System;
  25. using System.Collections.Generic;
  26. using System.Text;
  27. using System.Text.RegularExpressions;
  28. internal class Node
  29. {
  30. #region Public Properties
  31. /// <summary>
  32. ///
  33. /// </summary>
  34. public NodeType NameType
  35. {
  36. get
  37. {
  38. return pName;
  39. }
  40. set
  41. {
  42. pName = value;
  43. }
  44. }
  45. /// <summary>
  46. ///
  47. /// </summary>
  48. public string Id
  49. {
  50. get
  51. {
  52. return pId;
  53. }
  54. set
  55. {
  56. pId = value;
  57. }
  58. }
  59. /// <summary>
  60. ///
  61. /// </summary>
  62. public string ParentId
  63. {
  64. get
  65. {
  66. return pParentID;
  67. }
  68. set
  69. {
  70. pParentID = value;
  71. }
  72. }
  73. /// <summary>
  74. ///
  75. /// </summary>
  76. public string RefId
  77. {
  78. get
  79. {
  80. return pRefID;
  81. }
  82. set
  83. {
  84. pRefID = value;
  85. }
  86. }
  87. /// <summary>
  88. ///
  89. /// </summary>
  90. public string MarkupTextWriterType
  91. {
  92. get
  93. {
  94. return pMarkupTextWriterType;
  95. }
  96. set
  97. {
  98. pMarkupTextWriterType = value;
  99. }
  100. }
  101. /// <summary>
  102. ///
  103. /// </summary>
  104. public string FileName
  105. {
  106. get
  107. {
  108. return pFileName;
  109. }
  110. set
  111. {
  112. pFileName = value;
  113. }
  114. }
  115. #endregion
  116. private NodeType pName = NodeType.None;
  117. private string pId = string.Empty;
  118. private string pParentID = string.Empty;
  119. private string pRefID = string.Empty;
  120. private string pMarkupTextWriterType = string.Empty;
  121. private string pFileName = string.Empty;
  122. private System.Xml.XmlNode xmlNode;
  123. private Identification[] Identification;
  124. private Identification[] Capture;
  125. private System.Collections.Specialized.NameValueCollection Capabilities;
  126. private System.Collections.Specialized.NameValueCollection Adapter;
  127. private Type[] AdapterControlTypes, AdapterTypes;
  128. private System.Collections.Generic.List<string> ChildrenKeys;
  129. private System.Collections.Generic.List<string> DefaultChildrenKeys;
  130. private System.Collections.Generic.SortedList<string, nBrowser.Node> Children;
  131. private System.Collections.Generic.SortedList<string, nBrowser.Node> DefaultChildren;
  132. private System.Collections.Specialized.NameValueCollection sampleHeaders;
  133. /// <summary>
  134. ///
  135. /// </summary>
  136. /// <param name="xmlNode"></param>
  137. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1059")]
  138. public Node(System.Xml.XmlNode xmlNode)
  139. {
  140. this.xmlNode = xmlNode;
  141. this.ResetChildern();
  142. this.Reset();
  143. }
  144. /// <summary>
  145. ///
  146. /// </summary>
  147. internal Node()
  148. {
  149. this.ResetChildern();
  150. Identification = new System.Web.Configuration.nBrowser.Identification[1];
  151. Identification[0] = new System.Web.Configuration.nBrowser.Identification(true, "header", "User-Agent", ".");
  152. this.Id = "[Base Node]";
  153. this.NameType = NodeType.Browser;
  154. }
  155. /// <summary>
  156. ///
  157. /// </summary>
  158. /// <param name="node"></param>
  159. private void ProcessIdentification(System.Xml.XmlNode node)
  160. {
  161. //I know not all of these will be used but enough will
  162. Identification = new System.Web.Configuration.nBrowser.Identification[node.ChildNodes.Count];
  163. int i = -1;
  164. for (int a = 0;a <= node.ChildNodes.Count - 1;a++)
  165. {
  166. switch (node.ChildNodes[a].NodeType)
  167. {
  168. case System.Xml.XmlNodeType.Text:
  169. continue;
  170. case System.Xml.XmlNodeType.Comment:
  171. continue;
  172. }
  173. string patterngroup = string.Empty;
  174. string patternname = string.Empty;
  175. if (string.Compare(node.ChildNodes[a].Name, "userAgent", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  176. {
  177. patterngroup = "header";
  178. patternname = "User-Agent";
  179. }
  180. else if (string.Compare(node.ChildNodes[a].Name, "header", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  181. {
  182. patterngroup = node.ChildNodes[a].Name;
  183. patternname = node.ChildNodes[a].Attributes["name"].Value;
  184. }
  185. else if (string.Compare(node.ChildNodes[a].Name, "capability", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  186. {
  187. patterngroup = node.ChildNodes[a].Name;
  188. patternname = node.ChildNodes[a].Attributes["name"].Value;
  189. }
  190. else
  191. {
  192. throw new nBrowser.Exception("Invalid Node found in Identification");
  193. }
  194. if (node.ChildNodes[a].Attributes["match"] != null)
  195. {
  196. i++;
  197. Identification[i] = new System.Web.Configuration.nBrowser.Identification(true, patterngroup, patternname, node.ChildNodes[a].Attributes["match"].Value);
  198. }
  199. else if (node.ChildNodes[a].Attributes["nonMatch"] != null)
  200. {
  201. i++;
  202. Identification[i] = new System.Web.Configuration.nBrowser.Identification(false, patterngroup, patternname, node.ChildNodes[a].Attributes["nonMatch"].Value);
  203. }
  204. }
  205. }
  206. /// <summary>
  207. ///
  208. /// </summary>
  209. /// <param name="node"></param>
  210. private void ProcessCapture(System.Xml.XmlNode node)
  211. {
  212. //I know not all of these will be used but enough will
  213. Capture = new System.Web.Configuration.nBrowser.Identification[node.ChildNodes.Count];
  214. int i = -1;
  215. for (int a = 0;a <= node.ChildNodes.Count - 1;a++)
  216. {
  217. switch (node.ChildNodes[a].NodeType)
  218. {
  219. case System.Xml.XmlNodeType.Text:
  220. continue;
  221. case System.Xml.XmlNodeType.Comment:
  222. continue;
  223. }
  224. string pattern = string.Empty;
  225. string patterngroup = string.Empty;
  226. string patternname = string.Empty;
  227. if (node.ChildNodes[a].Name == "userAgent")
  228. {
  229. patterngroup = "header";
  230. patternname = "User-Agent";
  231. }
  232. else
  233. {
  234. patterngroup = node.ChildNodes[a].Name;
  235. patternname = node.ChildNodes[a].Attributes["name"].Value;
  236. }
  237. pattern = node.ChildNodes[a].Attributes["match"].Value;
  238. i++;
  239. Capture[i] = new System.Web.Configuration.nBrowser.Identification(true, patterngroup, patternname, pattern);
  240. }
  241. }
  242. /// <summary>
  243. ///
  244. /// </summary>
  245. /// <param name="node"></param>
  246. private void ProcessCapabilities(System.Xml.XmlNode node)
  247. {
  248. Capabilities = new System.Collections.Specialized.NameValueCollection(node.ChildNodes.Count, StringComparer.OrdinalIgnoreCase);
  249. for (int a = 0;a <= node.ChildNodes.Count - 1;a++)
  250. {
  251. if (node.ChildNodes[a].NodeType == System.Xml.XmlNodeType.Comment)
  252. {
  253. continue;
  254. }
  255. string name = string.Empty;
  256. string value = string.Empty;
  257. for (int b = 0;b <= node.ChildNodes[a].Attributes.Count - 1;b++)
  258. {
  259. switch (node.ChildNodes[a].Attributes[b].Name)
  260. {
  261. case "name":
  262. name = node.ChildNodes[a].Attributes[b].Value;
  263. break;
  264. case "value":
  265. value = node.ChildNodes[a].Attributes[b].Value;
  266. break;
  267. }
  268. }
  269. if (name.Length > 0)
  270. {
  271. Capabilities[name] = value;
  272. }
  273. }
  274. }
  275. /// <summary>
  276. ///
  277. /// </summary>
  278. /// <param name="node"></param>
  279. private void ProcessControlAdapters(System.Xml.XmlNode node)
  280. {
  281. Adapter = new System.Collections.Specialized.NameValueCollection();
  282. for (int b = 0;b <= node.Attributes.Count - 1;b++)
  283. {
  284. switch (node.Attributes[b].Name)
  285. {
  286. case "markupTextWriterType":
  287. MarkupTextWriterType = node.Attributes[b].Value;
  288. break;
  289. }
  290. }
  291. for (int a = 0;a <= node.ChildNodes.Count - 1;a++)
  292. {
  293. if (node.ChildNodes[a].NodeType == System.Xml.XmlNodeType.Comment)
  294. {
  295. continue;
  296. }
  297. else if (node.ChildNodes[a].NodeType == System.Xml.XmlNodeType.Text)
  298. {
  299. continue;
  300. }
  301. System.Xml.XmlNode x = node.ChildNodes[a];
  302. string controlType = string.Empty;
  303. string adapterType = string.Empty;
  304. for (int i = 0;i <= x.Attributes.Count - 1;i++)
  305. {
  306. if (string.Compare(x.Attributes[i].Name, "controlType", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  307. {
  308. controlType = x.Attributes[i].Value;
  309. }
  310. else if (string.Compare(x.Attributes[i].Name, "adapterType", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  311. {
  312. adapterType = x.Attributes[i].Value;
  313. }
  314. }
  315. if (controlType.Length > 0 && adapterType.Length > 0)
  316. {
  317. Adapter[controlType] = adapterType;
  318. }
  319. }
  320. AdapterControlTypes = null;
  321. AdapterTypes = null;
  322. }
  323. /// <summary>
  324. ///
  325. /// </summary>
  326. /// <param name="node"></param>
  327. private void ProcessSampleHeaders(System.Xml.XmlNode node)
  328. {
  329. sampleHeaders = new System.Collections.Specialized.NameValueCollection(node.ChildNodes.Count);
  330. for (int a = 0;a <= node.ChildNodes.Count - 1;a++)
  331. {
  332. if (node.ChildNodes[a].NodeType == System.Xml.XmlNodeType.Comment)
  333. {
  334. continue;
  335. }
  336. string name = string.Empty;
  337. string value = string.Empty;
  338. for (int b = 0;b <= node.ChildNodes[a].Attributes.Count - 1;b++)
  339. {
  340. switch (node.ChildNodes[a].Attributes[b].Name)
  341. {
  342. case "name":
  343. name = node.ChildNodes[a].Attributes[b].Value;
  344. break;
  345. case "value":
  346. value = node.ChildNodes[a].Attributes[b].Value;
  347. break;
  348. }
  349. }
  350. if (name.Length > 0)
  351. {
  352. sampleHeaders[name] = value;
  353. }
  354. }
  355. }
  356. internal void ResetChildern()
  357. {
  358. Children = new System.Collections.Generic.SortedList<string, nBrowser.Node>();
  359. DefaultChildren = new System.Collections.Generic.SortedList<string, nBrowser.Node>();
  360. ChildrenKeys = new System.Collections.Generic.List<string>();
  361. DefaultChildrenKeys = new System.Collections.Generic.List<string>();
  362. }
  363. /// <summary>
  364. ///
  365. /// </summary>
  366. public bool HasChildren
  367. {
  368. get
  369. {
  370. if (Children.Count > -1)
  371. {
  372. return true;
  373. }
  374. return false;
  375. }
  376. }
  377. /// <summary>
  378. ///
  379. /// </summary>
  380. public void Reset()
  381. {
  382. //Making sure we start off on a good footing.
  383. Capture = null;
  384. Capabilities = null;
  385. Adapter = null;
  386. AdapterControlTypes = null;
  387. AdapterTypes = null;
  388. if (string.Compare(this.xmlNode.Name, "browser", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  389. {
  390. this.NameType = NodeType.Browser;
  391. }
  392. else if (string.Compare(this.xmlNode.Name, "defaultBrowser", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  393. {
  394. this.NameType = NodeType.DefaultBrowser;
  395. }
  396. else if (string.Compare(this.xmlNode.Name, "gateway", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  397. {
  398. this.NameType = NodeType.Gateway;
  399. }
  400. //-------------------------------------------------------------------------
  401. //Looping though the Attributes is easier since and more efficient
  402. //then doing finds for specific attribute names. This also handles the
  403. //cases where there are no attributes really well. Also it doesn't care
  404. //about the order in witch the attributes are found either
  405. //-------------------------------------------------------------------------
  406. for (int a = 0;a <= xmlNode.Attributes.Count - 1;a++)
  407. {
  408. //Reason I am not using a switch here because I do not have the ability
  409. //to make sure the items are in the same upper/lower case as I am expecting
  410. //so I default to ignore case and compare.
  411. if (string.Compare(xmlNode.Attributes[a].Name, "id", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  412. {
  413. Id = xmlNode.Attributes[a].Value.ToLower(System.Globalization.CultureInfo.CurrentCulture);
  414. }
  415. else if (string.Compare(xmlNode.Attributes[a].Name, "parentID", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  416. {
  417. ParentId = xmlNode.Attributes[a].Value.ToLower(System.Globalization.CultureInfo.CurrentCulture);
  418. }
  419. else if (string.Compare(xmlNode.Attributes[a].Name, "refID", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  420. {
  421. RefId = xmlNode.Attributes[a].Value.ToLower(System.Globalization.CultureInfo.CurrentCulture);
  422. }
  423. }
  424. for (int a = 0;a <= xmlNode.ChildNodes.Count - 1;a++)
  425. {
  426. //Reason I am not using a switch here because I do not have the ability
  427. //to make sure the items are in the same upper/lower case as I am expecting
  428. //so I default to ignore case and compare.
  429. if (string.Compare(xmlNode.ChildNodes[a].Name, "identification", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  430. {
  431. ProcessIdentification(xmlNode.ChildNodes[a]);
  432. }
  433. else if (string.Compare(xmlNode.ChildNodes[a].Name, "capture", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  434. {
  435. ProcessCapture(xmlNode.ChildNodes[a]);
  436. }
  437. else if (string.Compare(xmlNode.ChildNodes[a].Name, "capabilities", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  438. {
  439. ProcessCapabilities(xmlNode.ChildNodes[a]);
  440. }
  441. else if (string.Compare(xmlNode.ChildNodes[a].Name, "controlAdapters", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  442. {
  443. ProcessControlAdapters(xmlNode.ChildNodes[a]);
  444. }
  445. else if (string.Compare(xmlNode.ChildNodes[a].Name, "sampleHeaders", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  446. {
  447. ProcessSampleHeaders(xmlNode.ChildNodes[a]);
  448. }
  449. if (Id == "default" && (Identification == null || Identification.Length == 0))
  450. {
  451. Identification = new Identification[1];
  452. Identification[0] = new System.Web.Configuration.nBrowser.Identification(true, "header", "User-Agent", ".");
  453. }
  454. }
  455. }
  456. /// <summary>
  457. ///
  458. /// </summary>
  459. /// <param name="child"></param>
  460. public void AddChild(Node child)
  461. {
  462. if (child == null)
  463. {
  464. return;
  465. }
  466. if (child.NameType == nBrowser.NodeType.Browser || child.NameType == nBrowser.NodeType.Gateway)
  467. {
  468. Children.Add(child.Id, child);
  469. ChildrenKeys.Add(child.Id);
  470. }
  471. else if (child.NameType == NodeType.DefaultBrowser)
  472. {
  473. DefaultChildren.Add(child.Id, child);
  474. DefaultChildrenKeys.Add(child.Id);
  475. }
  476. }
  477. /// <summary>
  478. ///
  479. /// </summary>
  480. /// <param name="child"></param>
  481. public void RemoveChild(Node child)
  482. {
  483. if (child == null)
  484. {
  485. return;
  486. }
  487. if (child.NameType == nBrowser.NodeType.Browser || child.NameType == nBrowser.NodeType.Gateway)
  488. {
  489. Children.Remove(child.Id);
  490. ChildrenKeys.Remove(child.Id);
  491. }
  492. else if (child.NameType == NodeType.DefaultBrowser)
  493. {
  494. DefaultChildren.Remove(child.Id);
  495. DefaultChildrenKeys.Remove(child.Id);
  496. }
  497. }
  498. private Type FindType(string typeName)
  499. {
  500. foreach (System.Reflection.Assembly a in System.AppDomain.CurrentDomain.GetAssemblies())
  501. {
  502. string fullTypeName = typeName + "," + a.FullName;
  503. Type t = System.Type.GetType(fullTypeName); // case-sensitive
  504. if (t != null)
  505. return t;
  506. t = System.Type.GetType(fullTypeName, false, true); // case-insensitive
  507. if (t != null)
  508. return t;
  509. }
  510. throw new TypeLoadException(typeName);
  511. }
  512. /// <summary>
  513. /// Matches the header collection against this subtree and uses the matchList
  514. /// and any new matches to augment the result. This method calls ProcessSubtree()
  515. /// but then removes the matches that it adds to the matchList.
  516. /// </summary>
  517. /// <param name="header">the header collection to evaluate (invariant)</param>
  518. /// <param name="result">the result of the match (might be changed if a match is found)</param>
  519. /// <param name="matchList">the matches to use to do substitutions (invariant)</param>
  520. /// <returns>true iff this node or one of it's descendants matches</returns>
  521. internal bool Process(System.Collections.Specialized.NameValueCollection header, nBrowser.Result result,
  522. System.Collections.Generic.List<Match> matchList)
  523. {
  524. // The real work is done in ProcessSubtree. This method just ensures that matchList is restored
  525. // to its original state before returning.
  526. int origMatchListCount = matchList.Count;
  527. bool matched = ProcessSubtree(header, result, matchList);
  528. if (matchList.Count > origMatchListCount)
  529. matchList.RemoveRange(origMatchListCount, matchList.Count-origMatchListCount);
  530. return matched;
  531. }
  532. /// <summary>
  533. /// Matches the header collection against this subtree, adds any new matches for this node to
  534. /// matchList, and uses the matchList to augment the result.
  535. /// </summary>
  536. /// <param name="header">the header collection to evaluate (invariant)</param>
  537. /// <param name="result">the result of the match (might be changed if a match is found)</param>
  538. /// <param name="matchList">the matches to use to do substitutions,
  539. /// possibly including new matches for this node.</param>
  540. /// <returns>true iff this node or one of it's descendants matches</returns>
  541. private bool ProcessSubtree(System.Collections.Specialized.NameValueCollection header, nBrowser.Result result, System.Collections.Generic.List<Match> matchList)
  542. {
  543. //----------------------------------------------------------------------
  544. //This is just coded over from MS version since if you pass in an empty
  545. //string for the key it returns the UserAgent header as a response.
  546. //----------------------------------------------------------------------
  547. result.AddCapabilities("", header["User-Agent"]);
  548. if (RefId.Length == 0 && this.NameType != NodeType.DefaultBrowser)
  549. {
  550. //----------------------------------------------------------------------
  551. //BrowserIdentification adds all the Identifiction matches to the match
  552. //list if this node matches.
  553. //----------------------------------------------------------------------
  554. if (!BrowserIdentification(header, result, matchList))
  555. return false;
  556. }
  557. result.AddMatchingBrowserId (this.Id);
  558. #region Browser Identification Successfull
  559. //----------------------------------------------------------------------
  560. //By reaching this point, it either means there were no Identification
  561. //items to be processed or that all the Identification items have been
  562. //passed. So just for debuging I want to output this Groups unique ID.
  563. //----------------------------------------------------------------------
  564. result.AddTrack("[" + this.NameType + "]\t" + this.Id);
  565. //----------------------------------------------------------------------
  566. //Just adding all the Adapters to the current list.
  567. //----------------------------------------------------------------------
  568. if (Adapter != null)
  569. {
  570. LookupAdapterTypes();
  571. for (int i = 0;i <= Adapter.Count - 1;i++)
  572. {
  573. result.AddAdapter(AdapterControlTypes [i], AdapterTypes [i]);
  574. }
  575. }
  576. //----------------------------------------------------------------------
  577. //Set the MarkupTextWriter in the result if set in this node.
  578. //----------------------------------------------------------------------
  579. if (MarkupTextWriterType != null && MarkupTextWriterType.Length > 0)
  580. {
  581. // Look for the type using a case-sensitive search
  582. result.MarkupTextWriter = Type.GetType(MarkupTextWriterType);
  583. // If we don't find it, try again using a case-insensitive search and throw
  584. // and exception if we can't find it.
  585. if (result.MarkupTextWriter == null)
  586. result.MarkupTextWriter = Type.GetType(MarkupTextWriterType, true, true);
  587. }
  588. #endregion
  589. #region Capture
  590. if (Capture != null)
  591. {
  592. //----------------------------------------------------------------------
  593. //Adds all the sucessfull Capture matches to the matchList
  594. //----------------------------------------------------------------------
  595. for (int i = 0;i <= Capture.Length - 1;i++)
  596. {
  597. //shouldn't happen often, the null should
  598. //signal the end of the list, I keep procssing
  599. //the rest just in case
  600. if (Capture[i] == null)
  601. {
  602. continue;
  603. }
  604. Match m = null;
  605. if (Capture[i].Group == "header")
  606. {
  607. m = Capture[i].GetMatch(header[Capture[i].Name]);
  608. }
  609. else if (Capture[i].Group == "capability")
  610. {
  611. m = Capture[i].GetMatch(result[Capture[i].Name]);
  612. }
  613. if (Capture[i].IsMatchSuccessful(m) && m.Groups.Count > 0)
  614. {
  615. matchList.Add(m);
  616. }
  617. }
  618. }
  619. #endregion
  620. #region Capabilities
  621. if (Capabilities != null)
  622. {
  623. //----------------------------------------------------------------------
  624. //This section is what the whole exercise is about. Determining
  625. //the Browser Capabilities. We know already that the current
  626. //browser matches the criteria, now its a mater of updating
  627. //the results with the new Capabilties listed.
  628. //----------------------------------------------------------------------
  629. for (int i = 0;i <= Capabilities.Count - 1;i++)
  630. {
  631. //----------------------------------------------------------------------
  632. //We need to further process these Capabilities to
  633. //insert the proper information.
  634. //----------------------------------------------------------------------
  635. string v = Capabilities[i];
  636. //----------------------------------------------------------------------
  637. //Loop though the list of Identifiction/Capture Matches
  638. //in reverse order. Meaning the newest Items in the list
  639. //get checked first, then working to the oldest. Often times
  640. //Minor /Major revisition numbers will be listed multple times
  641. //and only the newest one (most recent matches) are the ones
  642. //we want to insert.
  643. //----------------------------------------------------------------------
  644. for (int a = matchList.Count - 1; a >= 0 && v != null && v.Length > 0 && v.IndexOf('$') > -1; a--)
  645. {
  646. // Don't do substitution if the match has no groups or was a nonMatch
  647. if (matchList[a].Groups.Count == 0 || !matchList[a].Success)
  648. continue;
  649. v = matchList[a].Result(v);
  650. }
  651. //----------------------------------------------------------------------
  652. //Checks to make sure we extract the result we where looking for.
  653. //----------------------------------------------------------------------
  654. if (v.IndexOf('$') > -1 || v.IndexOf('%') > -1)
  655. {
  656. //----------------------------------------------------------------------
  657. //Microsoft has a nasty habbit of using capability items in regular expressions
  658. //so I have to figure a nice way to working around it
  659. // <capability name="msdomversion" value="${majorversion}${minorversion}" />
  660. //----------------------------------------------------------------------
  661. //double checks the values against the current Capabilities. to
  662. //find any last minute matches. that are not defined by regluar
  663. //expressions
  664. v = result.Replace(v);
  665. }
  666. result.AddCapabilities(Capabilities.Keys[i], v);
  667. }
  668. }
  669. #endregion
  670. //----------------------------------------------------------------------
  671. //Run the Default Children after the Parent Node is finished with
  672. //what it is doing
  673. //----------------------------------------------------------------------
  674. for (int i = 0;i <= DefaultChildren.Count - 1;i++)
  675. {
  676. string key = DefaultChildrenKeys[i];
  677. Node node = DefaultChildren[key];
  678. if (node.NameType == NodeType.DefaultBrowser)
  679. {
  680. node.Process(header, result, matchList);
  681. }
  682. }
  683. //----------------------------------------------------------------------
  684. //processing all the children Browsers of this Parent if there are any.
  685. //----------------------------------------------------------------------
  686. //In nBrowser files, the Gateways should of been sorted so they are all
  687. //at the top so that they can be ran first.
  688. //----------------------------------------------------------------------
  689. //According to the msdn2 documentation Gateways are suppost to be
  690. //all processed first. before the browser objects.
  691. for (int i = 0;i <= Children.Count - 1;i++)
  692. {
  693. string key = ChildrenKeys[i];
  694. Node node = Children[key];
  695. if (node.NameType == NodeType.Gateway)
  696. {
  697. node.Process(header, result, matchList);
  698. }
  699. }
  700. for (int i = 0;i <= Children.Count - 1;i++)
  701. {
  702. string key = ChildrenKeys[i];
  703. Node node = Children[key];
  704. if (node.NameType == NodeType.Browser
  705. && node.Process(header, result, matchList))
  706. break;
  707. }
  708. return true;
  709. }
  710. /// <summary>
  711. ///
  712. /// </summary>
  713. /// <param name="header"></param>
  714. /// <param name="result"></param>
  715. /// <param name="matchList"></param>
  716. /// <returns>true iff this node is a match</returns>
  717. private bool BrowserIdentification(System.Collections.Specialized.NameValueCollection header, System.Web.Configuration.CapabilitiesResult result, System.Collections.Generic.List<Match> matchList)
  718. {
  719. if (Id.Length > 0 && RefId.Length > 0)
  720. {
  721. throw new nBrowser.Exception("Id and refID Attributes givin when there should only be one set not both");
  722. }
  723. if (Identification == null || Identification.Length == 0)
  724. {
  725. throw new nBrowser.Exception(String.Format("Missing Identification Section where one is required (Id={0}, RefID={1})", Id, RefId));
  726. }
  727. if (header == null)
  728. {
  729. throw new nBrowser.Exception("Null Value where NameValueCollection expected ");
  730. }
  731. if (result == null)
  732. {
  733. throw new nBrowser.Exception("Null Value where Result expected ");
  734. }
  735. #if trace
  736. System.Diagnostics.Trace.WriteLine(string.Format("{0}[{1}]", ("[" + this.Id + "]").PadRight(45), this.ParentId));
  737. #endif
  738. for (int i = 0;i <= Identification.Length - 1;i++)
  739. {
  740. //shouldn't happen often, the null should
  741. //signal the end of the list, I keep procssing
  742. //the rest just in case
  743. if (Identification[i] == null)
  744. {
  745. continue;
  746. }
  747. string v = string.Empty;
  748. if (string.Compare(Identification[i].Group, "header", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  749. {
  750. v = header[Identification[i].Name];
  751. }
  752. else if (string.Compare(Identification[i].Group, "capability", true, System.Globalization.CultureInfo.CurrentCulture) == 0)
  753. {
  754. v = result[Identification[i].Name];
  755. }
  756. //Not all headers will be sent by all browsers.
  757. //so often a header search will return Null.
  758. if (v == null)
  759. {
  760. v = string.Empty;
  761. }
  762. Match m = Identification[i].GetMatch(v);
  763. //----------------------------------------------------------------------
  764. //we exit this method return the orginal Result back to the calling method.
  765. //----------------------------------------------------------------------
  766. if (Identification[i].IsMatchSuccessful(m) == false)
  767. {
  768. #if trace
  769. System.Diagnostics.Trace.WriteLine(string.Format("{0}{1}", "Failed:".PadRight(45), Identification[i].Pattern));
  770. #endif
  771. return false;
  772. }
  773. else
  774. {
  775. #if trace
  776. System.Diagnostics.Trace.WriteLine(string.Format("{0}{1}", "Passed:".PadRight(45), Identification[i].Pattern));
  777. #endif
  778. if (m.Groups.Count > 0)
  779. {
  780. matchList.Add(m);
  781. }
  782. }
  783. }
  784. #if trace
  785. System.Diagnostics.Trace.WriteLine("");
  786. #endif
  787. return true;
  788. }
  789. private bool HaveAdapterTypes = false;
  790. private object LookupAdapterTypesLock = new object();
  791. private void LookupAdapterTypes()
  792. {
  793. if (Adapter == null || HaveAdapterTypes) return;
  794. lock (LookupAdapterTypesLock)
  795. {
  796. if (HaveAdapterTypes) return;
  797. /* Lookup the types and store them for future use */
  798. if (AdapterControlTypes == null)
  799. AdapterControlTypes = new Type [Adapter.Count];
  800. if (AdapterTypes == null)
  801. AdapterTypes = new Type [Adapter.Count];
  802. for (int i = 0;i <= Adapter.Count - 1;i++) {
  803. if (AdapterControlTypes [i] == null)
  804. AdapterControlTypes [i] = FindType (Adapter.GetKey (i));
  805. if (AdapterTypes [i] == null)
  806. AdapterTypes [i] = FindType (Adapter [i]);
  807. }
  808. HaveAdapterTypes = true;
  809. }
  810. }
  811. /// <summary>
  812. ///
  813. /// </summary>
  814. public System.Collections.Specialized.NameValueCollection SampleHeader
  815. {
  816. get
  817. {
  818. return sampleHeaders;
  819. }
  820. }
  821. /// <summary>
  822. /// Used to Display a Tree Like View of how the Nodes are organized.
  823. /// </summary>
  824. /// <param name="writer"></param>
  825. /// <param name="Position"></param>
  826. public void Tree(System.Xml.XmlTextWriter xmlwriter, int position)
  827. {
  828. if (position == 0)
  829. {
  830. xmlwriter.WriteStartDocument();
  831. xmlwriter.WriteStartElement(this.NameType.ToString());
  832. xmlwriter.WriteRaw(System.Environment.NewLine);
  833. }
  834. string f = this.FileName;
  835. xmlwriter.WriteStartElement(this.NameType.ToString());
  836. xmlwriter.WriteAttributeString("FileName", f);
  837. xmlwriter.WriteAttributeString("ID", this.Id);
  838. xmlwriter.WriteRaw(System.Environment.NewLine);
  839. if (position != int.MaxValue)
  840. {
  841. position++;
  842. }
  843. for (int i = 0;i <= DefaultChildren.Count - 1;i++)
  844. {
  845. string key = (string)DefaultChildrenKeys[i];
  846. Node node = DefaultChildren[key];
  847. if (node.NameType == nBrowser.NodeType.DefaultBrowser)
  848. {
  849. node.Tree(xmlwriter, position);
  850. }
  851. }
  852. for (int i = 0;i <= Children.Count - 1;i++)
  853. {
  854. string key = (string)ChildrenKeys[i];
  855. Node node = Children[key];
  856. if (node.NameType == nBrowser.NodeType.Gateway)
  857. {
  858. node.Tree(xmlwriter, position);
  859. }
  860. }
  861. for (int i = 0;i <= Children.Count - 1;i++)
  862. {
  863. string key = (string)ChildrenKeys[i];
  864. Node node = Children[key];
  865. if (node.NameType == nBrowser.NodeType.Browser)
  866. {
  867. node.Tree(xmlwriter, position);
  868. }
  869. }
  870. if (position != int.MinValue)
  871. {
  872. position--;
  873. }
  874. xmlwriter.WriteEndElement();
  875. xmlwriter.WriteRaw(System.Environment.NewLine);
  876. if (position == 0)
  877. {
  878. xmlwriter.WriteEndDocument();
  879. xmlwriter.Flush();
  880. }
  881. }
  882. public System.Collections.ObjectModel.Collection<string> HeaderNames(System.Collections.ObjectModel.Collection<string> list)
  883. {
  884. if (Identification != null)
  885. {
  886. for (int i = 0;i <= Identification.Length - 1;i++)
  887. {
  888. if (Identification[i] == null)
  889. {
  890. continue;
  891. }
  892. if (Identification[i].Group == "header")
  893. {
  894. if (list.Contains(Identification[i].Name) == false)
  895. {
  896. list.Add(Identification[i].Name);
  897. }
  898. }
  899. }
  900. }
  901. if (Capture != null)
  902. {
  903. for (int i = 0;i <= Capture.Length - 1;i++)
  904. {
  905. if (Capture[i] == null)
  906. {
  907. continue;
  908. }
  909. if (Capture[i].Group == "header")
  910. {
  911. if (list.Contains(Capture[i].Name) == false)
  912. {
  913. list.Add(Capture[i].Name);
  914. }
  915. }
  916. }
  917. }
  918. for (int i = 0;i <= DefaultChildren.Count - 1;i++)
  919. {
  920. string key = (string)DefaultChildrenKeys[i];
  921. Node node = DefaultChildren[key];
  922. if (node.NameType == nBrowser.NodeType.DefaultBrowser)
  923. {
  924. list = node.HeaderNames(list);
  925. }
  926. }
  927. for (int i = 0;i <= Children.Count - 1;i++)
  928. {
  929. string key = (string)ChildrenKeys[i];
  930. Node node = Children[key];
  931. if (node.NameType == nBrowser.NodeType.Gateway)
  932. {
  933. list = node.HeaderNames(list);
  934. }
  935. }
  936. for (int i = 0;i <= Children.Count - 1;i++)
  937. {
  938. string key = (string)ChildrenKeys[i];
  939. Node node = Children[key];
  940. if (node.NameType == nBrowser.NodeType.Browser)
  941. {
  942. list = node.HeaderNames(list);
  943. }
  944. }
  945. return list;
  946. }
  947. /// <summary>
  948. /// Merge capabilities, captures, markupTextWriters, and adapters from another Node into this Node.
  949. /// </summary>
  950. /// <param name="n">node to merge with this node</param>
  951. public void MergeFrom(Node n)
  952. {
  953. if (n.Capabilities != null)
  954. {
  955. if (Capabilities == null)
  956. Capabilities = new System.Collections.Specialized.NameValueCollection(n.Capabilities.Count, StringComparer.OrdinalIgnoreCase);
  957. foreach (string capName in n.Capabilities)
  958. Capabilities[capName] = n.Capabilities[capName];
  959. }
  960. int newLength = 0;
  961. if (Capture != null)
  962. newLength += Capture.Length;
  963. if (n.Capture != null)
  964. newLength += n.Capture.Length;
  965. Identification[] newCapture = new Identification[newLength];
  966. if (Capture != null)
  967. Array.Copy(Capture, 0, newCapture, 0, Capture.Length);
  968. if (n.Capture != null)
  969. Array.Copy(n.Capture, 0, newCapture, (Capture != null ? Capture.Length : 0), n.Capture.Length);
  970. Capture = newCapture;
  971. if (n.MarkupTextWriterType != null && n.MarkupTextWriterType.Length > 0)
  972. MarkupTextWriterType = n.MarkupTextWriterType;
  973. if (n.Adapter != null)
  974. {
  975. if (Adapter == null)
  976. Adapter = new System.Collections.Specialized.NameValueCollection();
  977. foreach (string controlType in n.Adapter)
  978. Adapter[controlType] = n.Adapter[controlType];
  979. }
  980. }
  981. }
  982. }
  983. #endif