2 // System.Security.SecurityElement.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Lawrence Pit (loz@cable.a2000.nl)
7 // Sebastien Pouliot <sebastien@ximian.com>
9 // (C) Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 using System
.Globalization
;
33 using System
.Collections
;
34 using System
.Runtime
.InteropServices
;
39 namespace System
.Security
{
43 public sealed class SecurityElement
45 internal class SecurityAttribute
{
48 private string _value
;
50 public SecurityAttribute (string name
, string value)
52 if (!IsValidAttributeName (name
))
53 throw new ArgumentException (Locale
.GetText ("Invalid XML attribute name") + ": " + name
);
55 if (!IsValidAttributeValue (value))
56 throw new ArgumentException (Locale
.GetText ("Invalid XML attribute value") + ": " + value);
59 _value
= SecurityElement
.Unescape (value);
67 get { return _value; }
76 // these values are determined by a simple test program against the MS.Net implementation:
77 // for (int i = 0; i < 256; i++) {
78 // if (!SecurityElement.IsValidTag ("" + ((char) i))) {
79 // System.Console.WriteLine ("TAG: " + i);
82 // note: this is actually an incorrect implementation of MS, as for example the &
83 // character is not a valid character in tag names.
84 private static readonly char [] invalid_tag_chars
= new char [] { ' ', '<', '>' }
;
85 private static readonly char [] invalid_text_chars
= new char [] { '<', '>' }
;
86 private static readonly char [] invalid_attr_name_chars
= new char [] { ' ', '<', '>' }
;
87 private static readonly char [] invalid_attr_value_chars
= new char [] { '"', '<', '>' }
;
88 private static readonly char [] invalid_chars
= new char [] { '<', '>', '"', '\'', '&' }
;
90 public SecurityElement (string tag
) : this (tag
, null)
94 public SecurityElement (string tag
, string text
)
97 throw new ArgumentNullException ("tag");
98 if (!IsValidTag (tag
))
99 throw new ArgumentException (Locale
.GetText ("Invalid XML string") + ": " + tag
);
105 // not a deep copy (childs are references)
106 internal SecurityElement (SecurityElement se
)
111 if (se
.attributes
!= null) {
112 foreach (SecurityAttribute sa
in se
.attributes
) {
113 this.AddAttribute (sa
.Name
, sa
.Value
);
116 if (se
.children
!= null) {
117 foreach (SecurityElement child
in se
.children
) {
118 this.AddChild (child
);
123 public Hashtable Attributes
{
125 if (attributes
== null)
128 Hashtable result
= new Hashtable (attributes
.Count
);
129 foreach (SecurityAttribute sa
in attributes
) {
130 result
.Add (sa
.Name
, sa
.Value
);
136 if (value == null || value.Count
== 0) {
141 if (attributes
== null)
142 attributes
= new ArrayList ();
145 IDictionaryEnumerator e
= value.GetEnumerator ();
146 while (e
.MoveNext ()) {
147 attributes
.Add (new SecurityAttribute ((string) e
.Key
, (string) e
.Value
));
152 public ArrayList Children
{
159 foreach (object o
in value) {
161 throw new ArgumentNullException ();
162 // shouldn't we also throw an exception
163 // when o isn't an instance of SecurityElement?
176 throw new ArgumentNullException ("Tag");
177 if (!IsValidTag (value))
178 throw new ArgumentException (Locale
.GetText ("Invalid XML string") + ": " + value);
190 if (!IsValidText (value))
191 throw new ArgumentException (
192 Locale
.GetText ("Invalid XML string")
195 text
= Unescape (value);
199 public void AddAttribute (string name
, string value)
202 throw new ArgumentNullException ("name");
204 throw new ArgumentNullException ("value");
205 if (GetAttribute (name
) != null)
206 throw new ArgumentException (Locale
.GetText ("Duplicate attribute : " + name
));
208 if (attributes
== null)
209 attributes
= new ArrayList ();
210 attributes
.Add (new SecurityAttribute (name
, value));
213 public void AddChild (SecurityElement child
)
216 throw new ArgumentNullException ("child");
218 if (children
== null)
219 children
= new ArrayList ();
221 children
.Add (child
);
224 public string Attribute (string name
)
227 throw new ArgumentNullException ("name");
229 SecurityAttribute sa
= GetAttribute (name
);
230 return ((sa
== null) ? null : sa
.Value
);
234 public SecurityElement
Copy ()
236 return new SecurityElement (this);
239 public bool Equal (SecurityElement other
)
247 if (this.text
!= other
.text
)
250 if (this.tag
!= other
.tag
)
253 if (this.attributes
== null && other
.attributes
!= null && other
.attributes
.Count
!= 0)
256 if (other
.attributes
== null && this.attributes
!= null && this.attributes
.Count
!= 0)
259 if (this.attributes
!= null && other
.attributes
!= null) {
260 if (this.attributes
.Count
!= other
.attributes
.Count
)
262 foreach (SecurityAttribute sa1
in attributes
) {
263 SecurityAttribute sa2
= other
.GetAttribute (sa1
.Name
);
264 if ((sa2
== null) || (sa1
.Value
!= sa2
.Value
))
269 if (this.children
== null && other
.children
!= null && other
.children
.Count
!= 0)
272 if (other
.children
== null && this.children
!= null && this.children
.Count
!= 0)
275 if (this.children
!= null && other
.children
!= null) {
276 if (this.children
.Count
!= other
.children
.Count
)
278 for (int i
= 0; i
< this.children
.Count
; i
++)
279 if (!((SecurityElement
) this.children
[i
]).Equal ((SecurityElement
) other
.children
[i
]))
286 public static string Escape (string str
)
293 if (str
.IndexOfAny (invalid_chars
) == -1)
296 sb
= new StringBuilder ();
297 int len
= str
.Length
;
299 for (int i
= 0; i
< len
; i
++) {
303 case '<': sb
.Append ("<"); break;
304 case '>': sb
.Append (">"); break;
305 case '"': sb
.Append ("""); break;
306 case '\'': sb
.Append ("'"); break;
307 case '&': sb
.Append ("&"); break;
308 default: sb
.Append (c
); break;
312 return sb
.ToString ();
315 private static string Unescape (string str
)
322 sb
= new StringBuilder (str
);
323 sb
.Replace ("<", "<");
324 sb
.Replace (">", ">");
325 sb
.Replace ("&", "&");
326 sb
.Replace (""", "\"");
327 sb
.Replace ("'", "'");
328 return sb
.ToString ();
331 public static SecurityElement
FromString (string xml
)
334 throw new ArgumentNullException ("xml");
336 throw new XmlSyntaxException (Locale
.GetText ("Empty string."));
339 SecurityParser sp
= new SecurityParser ();
342 } catch (Exception e
) {
343 string msg
= Locale
.GetText ("Invalid XML.");
344 throw new XmlSyntaxException (msg
, e
);
348 public static bool IsValidAttributeName (string name
)
350 return name
!= null && name
.IndexOfAny (invalid_attr_name_chars
) == -1;
353 public static bool IsValidAttributeValue (string value)
355 return value != null && value.IndexOfAny (invalid_attr_value_chars
) == -1;
358 public static bool IsValidTag (string tag
)
360 return tag
!= null && tag
.IndexOfAny (invalid_tag_chars
) == -1;
363 public static bool IsValidText (string text
)
365 return text
!= null && text
.IndexOfAny (invalid_text_chars
) == -1;
368 public SecurityElement
SearchForChildByTag (string tag
)
371 throw new ArgumentNullException ("tag");
373 if (this.children
== null)
376 for (int i
= 0; i
< children
.Count
; i
++) {
377 SecurityElement elem
= (SecurityElement
) children
[i
];
384 public string SearchForTextOfTag (string tag
)
387 throw new ArgumentNullException ("tag");
392 if (this.children
== null)
395 for (int i
= 0; i
< children
.Count
; i
++) {
396 string result
= ((SecurityElement
) children
[i
]).SearchForTextOfTag (tag
);
404 public override string ToString ()
406 StringBuilder s
= new StringBuilder ();
408 return s
.ToString ();
411 private void ToXml (ref StringBuilder s
, int level
)
416 if (attributes
!= null) {
418 for (int i
=0; i
< attributes
.Count
; i
++) {
419 SecurityAttribute sa
= (SecurityAttribute
) attributes
[i
];
422 .Append (Escape (sa
.Value
))
424 if (i
!= attributes
.Count
- 1)
425 s
.Append (Environment
.NewLine
);
429 if ((text
== null || text
== String
.Empty
) &&
430 (children
== null || children
.Count
== 0))
431 s
.Append ("/>").Append (Environment
.NewLine
);
433 s
.Append (">").Append (Escape (text
));
434 if (children
!= null) {
435 s
.Append (Environment
.NewLine
);
436 foreach (SecurityElement child
in children
) {
437 child
.ToXml (ref s
, level
+ 1);
440 s
.Append (' ', level
* 3);
446 .Append (Environment
.NewLine
);
450 internal SecurityAttribute
GetAttribute (string name
)
452 if (attributes
!= null) {
453 foreach (SecurityAttribute sa
in attributes
) {