PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/corlib/System.Security/SecurityElement.cs

https://github.com/acken/mono
C# | 458 lines | 366 code | 51 blank | 41 comment | 99 complexity | 9b738a1ed5e38933a9f61a012b269dcd MD5 | raw file
  1. //
  2. // System.Security.SecurityElement.cs
  3. //
  4. // Authors:
  5. // Miguel de Icaza (miguel@ximian.com)
  6. // Lawrence Pit (loz@cable.a2000.nl)
  7. // Sebastien Pouliot <sebastien@ximian.com>
  8. //
  9. // (C) Ximian, Inc. http://www.ximian.com
  10. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System.Globalization;
  32. using System.Collections;
  33. using System.Runtime.InteropServices;
  34. using System.Text;
  35. using Mono.Xml;
  36. namespace System.Security {
  37. [ComVisible (true)]
  38. [Serializable]
  39. public sealed class SecurityElement
  40. {
  41. internal class SecurityAttribute {
  42. private string _name;
  43. private string _value;
  44. public SecurityAttribute (string name, string value)
  45. {
  46. if (!IsValidAttributeName (name))
  47. throw new ArgumentException (Locale.GetText ("Invalid XML attribute name") + ": " + name);
  48. if (!IsValidAttributeValue (value))
  49. throw new ArgumentException (Locale.GetText ("Invalid XML attribute value") + ": " + value);
  50. _name = name;
  51. _value = SecurityElement.Unescape (value);
  52. }
  53. public string Name {
  54. get { return _name; }
  55. }
  56. public string Value {
  57. get { return _value; }
  58. }
  59. }
  60. string text;
  61. string tag;
  62. ArrayList attributes;
  63. ArrayList children;
  64. // these values are determined by a simple test program against the MS.Net implementation:
  65. // for (int i = 0; i < 256; i++) {
  66. // if (!SecurityElement.IsValidTag ("" + ((char) i))) {
  67. // System.Console.WriteLine ("TAG: " + i);
  68. // }
  69. // }
  70. // note: this is actually an incorrect implementation of MS, as for example the &
  71. // character is not a valid character in tag names.
  72. private static readonly char [] invalid_tag_chars = new char [] { ' ', '<', '>' };
  73. private static readonly char [] invalid_text_chars = new char [] { '<', '>' };
  74. private static readonly char [] invalid_attr_name_chars = new char [] { ' ', '<', '>' };
  75. private static readonly char [] invalid_attr_value_chars = new char [] { '"', '<', '>' };
  76. private static readonly char [] invalid_chars = new char [] { '<', '>', '"', '\'', '&' };
  77. public SecurityElement (string tag) : this (tag, null)
  78. {
  79. }
  80. public SecurityElement (string tag, string text)
  81. {
  82. if (tag == null)
  83. throw new ArgumentNullException ("tag");
  84. if (!IsValidTag (tag))
  85. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + tag);
  86. this.tag = tag;
  87. Text = text;
  88. }
  89. // not a deep copy (childs are references)
  90. internal SecurityElement (SecurityElement se)
  91. {
  92. this.Tag = se.Tag;
  93. this.Text = se.Text;
  94. if (se.attributes != null) {
  95. foreach (SecurityAttribute sa in se.attributes) {
  96. this.AddAttribute (sa.Name, sa.Value);
  97. }
  98. }
  99. if (se.children != null) {
  100. foreach (SecurityElement child in se.children) {
  101. this.AddChild (child);
  102. }
  103. }
  104. }
  105. public Hashtable Attributes {
  106. get {
  107. if (attributes == null)
  108. return null;
  109. Hashtable result = new Hashtable (attributes.Count);
  110. foreach (SecurityAttribute sa in attributes) {
  111. result.Add (sa.Name, sa.Value);
  112. }
  113. return result;
  114. }
  115. set {
  116. if (value == null || value.Count == 0) {
  117. attributes.Clear ();
  118. return;
  119. }
  120. if (attributes == null)
  121. attributes = new ArrayList ();
  122. else
  123. attributes.Clear ();
  124. IDictionaryEnumerator e = value.GetEnumerator ();
  125. while (e.MoveNext ()) {
  126. attributes.Add (new SecurityAttribute ((string) e.Key, (string) e.Value));
  127. }
  128. }
  129. }
  130. public ArrayList Children {
  131. get {
  132. return children;
  133. }
  134. set {
  135. if (value != null) {
  136. foreach (object o in value) {
  137. if (o == null)
  138. throw new ArgumentNullException ();
  139. // shouldn't we also throw an exception
  140. // when o isn't an instance of SecurityElement?
  141. }
  142. }
  143. children = value;
  144. }
  145. }
  146. public string Tag {
  147. get {
  148. return tag;
  149. }
  150. set {
  151. if (value == null)
  152. throw new ArgumentNullException ("Tag");
  153. if (!IsValidTag (value))
  154. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
  155. tag = value;
  156. }
  157. }
  158. public string Text {
  159. get {
  160. return text;
  161. }
  162. set {
  163. if (value != null) {
  164. if (!IsValidText (value))
  165. throw new ArgumentException (
  166. Locale.GetText ("Invalid XML string")
  167. + ": " + value);
  168. }
  169. text = Unescape (value);
  170. }
  171. }
  172. public void AddAttribute (string name, string value)
  173. {
  174. if (name == null)
  175. throw new ArgumentNullException ("name");
  176. if (value == null)
  177. throw new ArgumentNullException ("value");
  178. if (GetAttribute (name) != null)
  179. throw new ArgumentException (Locale.GetText ("Duplicate attribute : " + name));
  180. if (attributes == null)
  181. attributes = new ArrayList ();
  182. attributes.Add (new SecurityAttribute (name, value));
  183. }
  184. public void AddChild (SecurityElement child)
  185. {
  186. if (child == null)
  187. throw new ArgumentNullException ("child");
  188. if (children == null)
  189. children = new ArrayList ();
  190. children.Add (child);
  191. }
  192. public string Attribute (string name)
  193. {
  194. if (name == null)
  195. throw new ArgumentNullException ("name");
  196. SecurityAttribute sa = GetAttribute (name);
  197. return ((sa == null) ? null : sa.Value);
  198. }
  199. [ComVisible (false)]
  200. public SecurityElement Copy ()
  201. {
  202. return new SecurityElement (this);
  203. }
  204. public bool Equal (SecurityElement other)
  205. {
  206. if (other == null)
  207. return false;
  208. if (this == other)
  209. return true;
  210. if (this.text != other.text)
  211. return false;
  212. if (this.tag != other.tag)
  213. return false;
  214. if (this.attributes == null && other.attributes != null && other.attributes.Count != 0)
  215. return false;
  216. if (other.attributes == null && this.attributes != null && this.attributes.Count != 0)
  217. return false;
  218. if (this.attributes != null && other.attributes != null) {
  219. if (this.attributes.Count != other.attributes.Count)
  220. return false;
  221. foreach (SecurityAttribute sa1 in attributes) {
  222. SecurityAttribute sa2 = other.GetAttribute (sa1.Name);
  223. if ((sa2 == null) || (sa1.Value != sa2.Value))
  224. return false;
  225. }
  226. }
  227. if (this.children == null && other.children != null && other.children.Count != 0)
  228. return false;
  229. if (other.children == null && this.children != null && this.children.Count != 0)
  230. return false;
  231. if (this.children != null && other.children != null) {
  232. if (this.children.Count != other.children.Count)
  233. return false;
  234. for (int i = 0; i < this.children.Count; i++)
  235. if (!((SecurityElement) this.children [i]).Equal ((SecurityElement) other.children [i]))
  236. return false;
  237. }
  238. return true;
  239. }
  240. public static string Escape (string str)
  241. {
  242. StringBuilder sb;
  243. if (str == null)
  244. return null;
  245. if (str.IndexOfAny (invalid_chars) == -1)
  246. return str;
  247. sb = new StringBuilder ();
  248. int len = str.Length;
  249. for (int i = 0; i < len; i++) {
  250. char c = str [i];
  251. switch (c) {
  252. case '<': sb.Append ("&lt;"); break;
  253. case '>': sb.Append ("&gt;"); break;
  254. case '"': sb.Append ("&quot;"); break;
  255. case '\'': sb.Append ("&apos;"); break;
  256. case '&': sb.Append ("&amp;"); break;
  257. default: sb.Append (c); break;
  258. }
  259. }
  260. return sb.ToString ();
  261. }
  262. private static string Unescape (string str)
  263. {
  264. StringBuilder sb;
  265. if (str == null)
  266. return null;
  267. sb = new StringBuilder (str);
  268. sb.Replace ("&lt;", "<");
  269. sb.Replace ("&gt;", ">");
  270. sb.Replace ("&amp;", "&");
  271. sb.Replace ("&quot;", "\"");
  272. sb.Replace ("&apos;", "'");
  273. return sb.ToString ();
  274. }
  275. public static SecurityElement FromString (string xml)
  276. {
  277. if (xml == null)
  278. throw new ArgumentNullException ("xml");
  279. if (xml.Length == 0)
  280. throw new XmlSyntaxException (Locale.GetText ("Empty string."));
  281. try {
  282. SecurityParser sp = new SecurityParser ();
  283. sp.LoadXml (xml);
  284. return sp.ToXml ();
  285. } catch (Exception e) {
  286. string msg = Locale.GetText ("Invalid XML.");
  287. throw new XmlSyntaxException (msg, e);
  288. }
  289. }
  290. public static bool IsValidAttributeName (string name)
  291. {
  292. return name != null && name.IndexOfAny (invalid_attr_name_chars) == -1;
  293. }
  294. public static bool IsValidAttributeValue (string value)
  295. {
  296. return value != null && value.IndexOfAny (invalid_attr_value_chars) == -1;
  297. }
  298. public static bool IsValidTag (string tag)
  299. {
  300. return tag != null && tag.IndexOfAny (invalid_tag_chars) == -1;
  301. }
  302. public static bool IsValidText (string text)
  303. {
  304. return text != null && text.IndexOfAny (invalid_text_chars) == -1;
  305. }
  306. public SecurityElement SearchForChildByTag (string tag)
  307. {
  308. if (tag == null)
  309. throw new ArgumentNullException ("tag");
  310. if (this.children == null)
  311. return null;
  312. for (int i = 0; i < children.Count; i++) {
  313. SecurityElement elem = (SecurityElement) children [i];
  314. if (elem.tag == tag)
  315. return elem;
  316. }
  317. return null;
  318. }
  319. public string SearchForTextOfTag (string tag)
  320. {
  321. if (tag == null)
  322. throw new ArgumentNullException ("tag");
  323. if (this.tag == tag)
  324. return this.text;
  325. if (this.children == null)
  326. return null;
  327. for (int i = 0; i < children.Count; i++) {
  328. string result = ((SecurityElement) children [i]).SearchForTextOfTag (tag);
  329. if (result != null)
  330. return result;
  331. }
  332. return null;
  333. }
  334. public override string ToString ()
  335. {
  336. StringBuilder s = new StringBuilder ();
  337. ToXml (ref s, 0);
  338. return s.ToString ();
  339. }
  340. private void ToXml (ref StringBuilder s, int level)
  341. {
  342. s.Append ("<");
  343. s.Append (tag);
  344. if (attributes != null) {
  345. s.Append (" ");
  346. for (int i=0; i < attributes.Count; i++) {
  347. SecurityAttribute sa = (SecurityAttribute) attributes [i];
  348. s.Append (sa.Name)
  349. .Append ("=\"")
  350. .Append (Escape (sa.Value))
  351. .Append ("\"");
  352. if (i != attributes.Count - 1)
  353. s.Append (Environment.NewLine);
  354. }
  355. }
  356. if ((text == null || text == String.Empty) &&
  357. (children == null || children.Count == 0))
  358. s.Append ("/>").Append (Environment.NewLine);
  359. else {
  360. s.Append (">").Append (Escape (text));
  361. if (children != null) {
  362. s.Append (Environment.NewLine);
  363. foreach (SecurityElement child in children) {
  364. child.ToXml (ref s, level + 1);
  365. }
  366. }
  367. s.Append ("</")
  368. .Append (tag)
  369. .Append (">")
  370. .Append (Environment.NewLine);
  371. }
  372. }
  373. internal SecurityAttribute GetAttribute (string name)
  374. {
  375. if (attributes != null) {
  376. foreach (SecurityAttribute sa in attributes) {
  377. if (sa.Name == name)
  378. return sa;
  379. }
  380. }
  381. return null;
  382. }
  383. }
  384. }