SecurityElement.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // System.Security.SecurityElement.cs
  3. //
  4. // Author:
  5. // Miguel de Icaza ([email protected])
  6. // Lawrence Pit ([email protected])
  7. //
  8. // (C) Ximian, Inc. http://www.ximian.com
  9. using System.Globalization;
  10. using System.Collections;
  11. using System.Text;
  12. namespace System.Security
  13. {
  14. [Serializable]
  15. public sealed class SecurityElement
  16. {
  17. string text;
  18. string tag;
  19. Hashtable attributes;
  20. ArrayList children;
  21. // these values are determined by a simple test program against the MS.Net implementation:
  22. // for (int i = 0; i < 256; i++) {
  23. // if (!SecurityElement.IsValidTag ("" + ((char) i))) {
  24. // System.Console.WriteLine ("TAG: " + i);
  25. // }
  26. // }
  27. // note: this is actually an incorrect implementation of MS, as for example the &
  28. // character is not a valid character in tag names.
  29. private static char [] invalid_tag_chars = new char [] { ' ', '<', '>' };
  30. private static char [] invalid_text_chars = new char [] { '<', '>' };
  31. private static char [] invalid_attr_name_chars = new char [] { ' ', '<', '>' };
  32. private static char [] invalid_attr_value_chars = new char [] { '"', '<', '>' };
  33. private static char [] invalid_chars = new char [] { '<', '>', '"', '\'', '&' };
  34. public SecurityElement (string tag) : this (tag, null)
  35. {
  36. }
  37. public SecurityElement (string tag, string text)
  38. {
  39. this.Tag = tag;
  40. this.Text = (text == null) ? String.Empty : text;
  41. }
  42. public Hashtable Attributes {
  43. get {
  44. if (attributes == null)
  45. return null;
  46. Hashtable result = new Hashtable ();
  47. IDictionaryEnumerator e = attributes.GetEnumerator ();
  48. while (e.MoveNext ())
  49. result.Add (e.Key, e.Value);
  50. return result;
  51. }
  52. set {
  53. if (value == null || value.Count == 0) {
  54. attributes = null;
  55. return;
  56. }
  57. Hashtable result = new Hashtable ();
  58. IDictionaryEnumerator e = value.GetEnumerator ();
  59. while (e.MoveNext ()) {
  60. string key = (string) e.Key;
  61. string val = (string) e.Value;
  62. if (!IsValidAttributeName (key))
  63. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + key);
  64. if (!IsValidAttributeValue (val))
  65. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + key);
  66. result.Add (key, val);
  67. }
  68. attributes = result;
  69. }
  70. }
  71. public ArrayList Children {
  72. get {
  73. return children;
  74. }
  75. set {
  76. if (value != null) {
  77. foreach (object o in value) {
  78. if (o == null)
  79. throw new ArgumentNullException ();
  80. // shouldn't we also throw an exception
  81. // when o isn't an instance of SecurityElement?
  82. }
  83. }
  84. children = value;
  85. }
  86. }
  87. public string Tag {
  88. get {
  89. return tag;
  90. }
  91. set {
  92. if (value == null)
  93. throw new ArgumentNullException ();
  94. if (!IsValidTag (value))
  95. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
  96. tag = value;
  97. }
  98. }
  99. public string Text {
  100. get {
  101. return text;
  102. }
  103. set {
  104. if (!IsValidText (value))
  105. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + text);
  106. text = value;
  107. }
  108. }
  109. public void AddAttribute (string name, string value)
  110. {
  111. if (name == null || value == null)
  112. throw new ArgumentNullException ();
  113. if (attributes == null)
  114. attributes = new Hashtable ();
  115. //
  116. // The hashtable will throw ArgumentException if name is already there
  117. //
  118. if (!IsValidAttributeName (name))
  119. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + name);
  120. if (!IsValidAttributeValue (value))
  121. throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
  122. attributes.Add (name, value);
  123. }
  124. public void AddChild (SecurityElement child)
  125. {
  126. if (child == null)
  127. throw new ArgumentNullException ();
  128. if (children == null)
  129. children = new ArrayList ();
  130. children.Add (child);
  131. }
  132. public string Attribute (string name)
  133. {
  134. if (name == null)
  135. throw new ArgumentNullException ();
  136. if (attributes != null)
  137. return (string) attributes [name];
  138. else
  139. return null;
  140. }
  141. public bool Equal (SecurityElement other)
  142. {
  143. if (other == null)
  144. return false;
  145. if (this == other)
  146. return true;
  147. if (this.text != other.text)
  148. return false;
  149. if (this.tag != other.tag)
  150. return false;
  151. if (this.attributes == null && other.attributes != null && other.attributes.Count != 0)
  152. return false;
  153. if (other.attributes == null && this.attributes != null && this.attributes.Count != 0)
  154. return false;
  155. if (this.attributes != null && other.attributes != null) {
  156. if (this.attributes.Count != other.attributes.Count)
  157. return false;
  158. IDictionaryEnumerator e = attributes.GetEnumerator ();
  159. while (e.MoveNext ())
  160. if (other.attributes [e.Key] != e.Value)
  161. return false;
  162. }
  163. if (this.children == null && other.children != null && other.children.Count != 0)
  164. return false;
  165. if (other.children == null && this.children != null && this.children.Count != 0)
  166. return false;
  167. if (this.children != null && other.children != null) {
  168. if (this.children.Count != other.children.Count)
  169. return false;
  170. for (int i = 0; i < this.children.Count; i++)
  171. if (!((SecurityElement) this.children [i]).Equal ((SecurityElement) other.children [i]))
  172. return false;
  173. }
  174. return true;
  175. }
  176. public static string Escape (string str)
  177. {
  178. StringBuilder sb;
  179. if (str.IndexOfAny (invalid_chars) == -1)
  180. return str;
  181. sb = new StringBuilder ();
  182. int len = str.Length;
  183. for (int i = 0; i < len; i++) {
  184. char c = str [i];
  185. switch (c) {
  186. case '<': sb.Append ("&lt;"); break;
  187. case '>': sb.Append ("&gt;"); break;
  188. case '"': sb.Append ("&quot;"); break;
  189. case '\'': sb.Append ("&apos;"); break;
  190. case '&': sb.Append ("&amp;"); break;
  191. default: sb.Append (c); break;
  192. }
  193. }
  194. return sb.ToString ();
  195. }
  196. public static bool IsValidAttributeName (string name)
  197. {
  198. return name != null && name.IndexOfAny (invalid_attr_name_chars) == -1;
  199. }
  200. public static bool IsValidAttributeValue (string value)
  201. {
  202. return value != null && value.IndexOfAny (invalid_attr_value_chars) == -1;
  203. }
  204. public static bool IsValidTag (string value)
  205. {
  206. return value != null && value.IndexOfAny (invalid_tag_chars) == -1;
  207. }
  208. public static bool IsValidText (string value)
  209. {
  210. return value != null && value.IndexOfAny (invalid_text_chars) == -1;
  211. }
  212. public SecurityElement SearchForChildByTag (string tag)
  213. {
  214. if (tag == null)
  215. throw new ArgumentNullException ("tag");
  216. if (this.children == null)
  217. return null;
  218. for (int i = 0; i < children.Count; i++) {
  219. SecurityElement elem = (SecurityElement) children [i];
  220. if (elem.tag == tag)
  221. return elem;
  222. }
  223. return null;
  224. }
  225. public string SearchForTextOfTag (string tag)
  226. {
  227. if (tag == null)
  228. throw new ArgumentNullException ("tag");
  229. if (this.tag == tag)
  230. return this.text;
  231. if (this.children == null)
  232. return null;
  233. for (int i = 0; i < children.Count; i++) {
  234. string result = ((SecurityElement) children [i]).SearchForTextOfTag (tag);
  235. if (result != null)
  236. return result;
  237. }
  238. return null;
  239. }
  240. public override string ToString ()
  241. {
  242. StringBuilder s = new StringBuilder ();
  243. ToXml (ref s, 0);
  244. return s.ToString ();
  245. }
  246. private void ToXml(ref StringBuilder s, int level)
  247. {
  248. s.Append (' ', level << 2);
  249. s.Append ("<");
  250. s.Append (tag);
  251. if (attributes != null) {
  252. IDictionaryEnumerator e = attributes.GetEnumerator ();
  253. while (e.MoveNext ()) {
  254. s.Append (" ")
  255. .Append (e.Key)
  256. .Append ("=\"")
  257. .Append (e.Value)
  258. .Append ("\"");
  259. }
  260. }
  261. if ((text == null || text == String.Empty) &&
  262. (children == null || children.Count == 0))
  263. s.Append ("/>");
  264. else {
  265. s.Append (">").Append (text);
  266. if (children != null) {
  267. foreach (SecurityElement child in children) {
  268. s.Append (Environment.NewLine);
  269. child.ToXml (ref s, level + 1);
  270. }
  271. }
  272. s.Append (Environment.NewLine)
  273. .Append (' ', level << 2)
  274. .Append ("</")
  275. .Append (tag)
  276. .Append (">");
  277. }
  278. }
  279. }
  280. }