summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Security/SecurityElement.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Security/SecurityElement.cs')
-rw-r--r--src/mscorlib/src/System/Security/SecurityElement.cs929
1 files changed, 929 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Security/SecurityElement.cs b/src/mscorlib/src/System/Security/SecurityElement.cs
new file mode 100644
index 0000000000..aa63029422
--- /dev/null
+++ b/src/mscorlib/src/System/Security/SecurityElement.cs
@@ -0,0 +1,929 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+namespace System.Security
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Security.Util;
+ using System.Text;
+ using System.Globalization;
+ using System.IO;
+ using System.Security.Permissions;
+ using System.Diagnostics.Contracts;
+
+ internal enum SecurityElementType
+ {
+ Regular = 0,
+ Format = 1,
+ Comment = 2
+ }
+
+
+ internal interface ISecurityElementFactory
+ {
+ SecurityElement CreateSecurityElement();
+
+ Object Copy();
+
+ String GetTag();
+
+ String Attribute( String attributeName );
+ }
+
+ [Serializable]
+[System.Runtime.InteropServices.ComVisible(true)]
+ sealed public class SecurityElement : ISecurityElementFactory
+ {
+ internal String m_strTag;
+ internal String m_strText;
+ private ArrayList m_lChildren;
+ internal ArrayList m_lAttributes;
+ internal SecurityElementType m_type = SecurityElementType.Regular;
+
+ private static readonly char[] s_tagIllegalCharacters = new char[] { ' ', '<', '>' };
+ private static readonly char[] s_textIllegalCharacters = new char[] { '<', '>' };
+ private static readonly char[] s_valueIllegalCharacters = new char[] { '<', '>', '\"' };
+ private const String s_strIndent = " ";
+
+ private const int c_AttributesTypical = 4 * 2; // 4 attributes, times 2 strings per attribute
+ private const int c_ChildrenTypical = 1;
+
+ private static readonly String[] s_escapeStringPairs = new String[]
+ {
+ // these must be all once character escape sequences or a new escaping algorithm is needed
+ "<", "&lt;",
+ ">", "&gt;",
+ "\"", "&quot;",
+ "\'", "&apos;",
+ "&", "&amp;"
+ };
+
+ private static readonly char[] s_escapeChars = new char[] { '<', '>', '\"', '\'', '&' };
+
+ //-------------------------- Constructors ---------------------------
+
+ internal SecurityElement()
+ {
+ }
+
+////// ISecurityElementFactory implementation
+
+ SecurityElement ISecurityElementFactory.CreateSecurityElement()
+ {
+ return this;
+ }
+
+ String ISecurityElementFactory.GetTag()
+ {
+ return ((SecurityElement)this).Tag;
+ }
+
+ Object ISecurityElementFactory.Copy()
+ {
+ return ((SecurityElement)this).Copy();
+ }
+
+ String ISecurityElementFactory.Attribute( String attributeName )
+ {
+ return ((SecurityElement)this).Attribute( attributeName );
+ }
+
+//////////////
+
+#if FEATURE_CAS_POLICY
+ public static SecurityElement FromString( String xml )
+ {
+ if (xml == null)
+ throw new ArgumentNullException( "xml" );
+ Contract.EndContractBlock();
+
+ return new Parser( xml ).GetTopElement();
+ }
+#endif // FEATURE_CAS_POLICY
+
+ public SecurityElement( String tag )
+ {
+ if (tag == null)
+ throw new ArgumentNullException( "tag" );
+
+ if (!IsValidTag( tag ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementTag" ), tag ) );
+ Contract.EndContractBlock();
+
+ m_strTag = tag;
+ m_strText = null;
+ }
+
+ public SecurityElement( String tag, String text )
+ {
+ if (tag == null)
+ throw new ArgumentNullException( "tag" );
+
+ if (!IsValidTag( tag ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementTag" ), tag ) );
+
+ if (text != null && !IsValidText( text ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementText" ), text ) );
+ Contract.EndContractBlock();
+
+ m_strTag = tag;
+ m_strText = text;
+ }
+
+ //-------------------------- Properties -----------------------------
+
+ public String Tag
+ {
+ [Pure]
+ get
+ {
+ return m_strTag;
+ }
+
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException( "Tag" );
+
+ if (!IsValidTag( value ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementTag" ), value ) );
+ Contract.EndContractBlock();
+
+ m_strTag = value;
+ }
+ }
+
+ public Hashtable Attributes
+ {
+ get
+ {
+ if (m_lAttributes == null || m_lAttributes.Count == 0)
+ {
+ return null;
+ }
+ else
+ {
+ Hashtable hashtable = new Hashtable( m_lAttributes.Count/2 );
+
+ int iMax = m_lAttributes.Count;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ for (int i = 0; i < iMax; i += 2)
+ {
+ hashtable.Add( m_lAttributes[i], m_lAttributes[i+1]);
+ }
+
+ return hashtable;
+ }
+ }
+
+ set
+ {
+ if (value == null || value.Count == 0)
+ {
+ m_lAttributes = null;
+ }
+ else
+ {
+ ArrayList list = new ArrayList(value.Count);
+
+ System.Collections.IDictionaryEnumerator enumerator = (System.Collections.IDictionaryEnumerator)value.GetEnumerator();
+
+ while (enumerator.MoveNext())
+ {
+ String attrName = (String)enumerator.Key;
+ String attrValue = (String)enumerator.Value;
+
+ if (!IsValidAttributeName( attrName ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementName" ), (String)enumerator.Current ) );
+
+ if (!IsValidAttributeValue( attrValue ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementValue" ), (String)enumerator.Value ) );
+
+ list.Add(attrName);
+ list.Add(attrValue);
+ }
+
+ m_lAttributes = list;
+ }
+ }
+ }
+
+ public String Text
+ {
+ get
+ {
+ return Unescape( m_strText );
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ m_strText = null;
+ }
+ else
+ {
+ if (!IsValidText( value ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementTag" ), value ) );
+
+ m_strText = value;
+ }
+ }
+ }
+
+ public ArrayList Children
+ {
+ get
+ {
+ ConvertSecurityElementFactories();
+ return m_lChildren;
+ }
+
+ set
+ {
+ if (value != null)
+ {
+ IEnumerator enumerator = value.GetEnumerator();
+
+ while (enumerator.MoveNext())
+ {
+ if (enumerator.Current == null)
+ throw new ArgumentException( Environment.GetResourceString( "ArgumentNull_Child" ) );
+ }
+ }
+
+ m_lChildren = value;
+ }
+ }
+
+ internal void ConvertSecurityElementFactories()
+ {
+ if (m_lChildren == null)
+ return;
+
+ for (int i = 0; i < m_lChildren.Count; ++i)
+ {
+ ISecurityElementFactory iseFactory = m_lChildren[i] as ISecurityElementFactory;
+ if (iseFactory != null && !(m_lChildren[i] is SecurityElement))
+ m_lChildren[i] = iseFactory.CreateSecurityElement();
+ }
+ }
+
+ internal ArrayList InternalChildren
+ {
+ get
+ {
+ // Beware! This array list can contain SecurityElements and other ISecurityElementFactories.
+ // If you want to get a consistent SecurityElement view, call get_Children.
+ return m_lChildren;
+ }
+ }
+
+ //-------------------------- Public Methods -----------------------------
+
+ internal void AddAttributeSafe( String name, String value )
+ {
+ if (m_lAttributes == null)
+ {
+ m_lAttributes = new ArrayList( c_AttributesTypical );
+ }
+ else
+ {
+ int iMax = m_lAttributes.Count;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ for (int i = 0; i < iMax; i += 2)
+ {
+ String strAttrName = (String)m_lAttributes[i];
+
+ if (String.Equals(strAttrName, name))
+ throw new ArgumentException( Environment.GetResourceString( "Argument_AttributeNamesMustBeUnique" ) );
+ }
+ }
+
+ m_lAttributes.Add(name);
+ m_lAttributes.Add(value);
+ }
+
+ public void AddAttribute( String name, String value )
+ {
+ if (name == null)
+ throw new ArgumentNullException( "name" );
+
+ if (value == null)
+ throw new ArgumentNullException( "value" );
+
+ if (!IsValidAttributeName( name ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementName" ), name ) );
+
+ if (!IsValidAttributeValue( value ))
+ throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidElementValue" ), value ) );
+ Contract.EndContractBlock();
+
+ AddAttributeSafe( name, value );
+ }
+
+ public void AddChild( SecurityElement child )
+ {
+ if (child == null)
+ throw new ArgumentNullException( "child" );
+ Contract.EndContractBlock();
+
+ if (m_lChildren == null)
+ m_lChildren = new ArrayList( c_ChildrenTypical );
+
+ m_lChildren.Add( child );
+ }
+
+ internal void AddChild( ISecurityElementFactory child )
+ {
+ if (child == null)
+ throw new ArgumentNullException( "child" );
+ Contract.EndContractBlock();
+
+ if (m_lChildren == null)
+ m_lChildren = new ArrayList( c_ChildrenTypical );
+
+ m_lChildren.Add( child );
+ }
+
+ internal void AddChildNoDuplicates( ISecurityElementFactory child )
+ {
+ if (child == null)
+ throw new ArgumentNullException( "child" );
+ Contract.EndContractBlock();
+
+ if (m_lChildren == null)
+ {
+ m_lChildren = new ArrayList( c_ChildrenTypical );
+ m_lChildren.Add( child );
+ }
+ else
+ {
+ for (int i = 0; i < m_lChildren.Count; ++i)
+ {
+ if (m_lChildren[i] == child)
+ return;
+ }
+ m_lChildren.Add( child );
+ }
+ }
+
+ public bool Equal( SecurityElement other )
+ {
+ if (other == null)
+ return false;
+
+ // Check if the tags are the same
+ if (!String.Equals(m_strTag, other.m_strTag))
+ return false;
+
+ // Check if the text is the same
+ if (!String.Equals(m_strText, other.m_strText))
+ return false;
+
+ // Check if the attributes are the same and appear in the same
+ // order.
+
+ // Maybe we can get away by only checking the number of attributes
+ if (m_lAttributes == null || other.m_lAttributes == null)
+ {
+ if (m_lAttributes != other.m_lAttributes)
+ return false;
+ }
+ else
+ {
+ int iMax = m_lAttributes.Count;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ if (iMax != other.m_lAttributes.Count)
+ return false;
+
+ for (int i = 0; i < iMax; i++)
+ {
+ String lhs = (String)m_lAttributes[i];
+ String rhs = (String)other.m_lAttributes[i];
+
+ if (!String.Equals(lhs, rhs))
+ return false;
+ }
+ }
+
+ // Finally we must check the child and make sure they are
+ // equal and in the same order
+
+ // Maybe we can get away by only checking the number of children
+ if (m_lChildren == null || other.m_lChildren == null)
+ {
+ if (m_lChildren != other.m_lChildren)
+ return false;
+ }
+ else
+ {
+ if (m_lChildren.Count != other.m_lChildren.Count)
+ return false;
+
+ this.ConvertSecurityElementFactories();
+ other.ConvertSecurityElementFactories();
+
+ // Okay, we'll need to go through each one of them
+ IEnumerator lhs = m_lChildren.GetEnumerator();
+ IEnumerator rhs = other.m_lChildren.GetEnumerator();
+
+ SecurityElement e1, e2;
+ while (lhs.MoveNext())
+ {
+ rhs.MoveNext();
+ e1 = (SecurityElement)lhs.Current;
+ e2 = (SecurityElement)rhs.Current;
+ if (e1 == null || !e1.Equal(e2))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public SecurityElement Copy()
+ {
+ SecurityElement element = new SecurityElement( this.m_strTag, this.m_strText );
+ element.m_lChildren = this.m_lChildren == null ? null : new ArrayList( this.m_lChildren );
+ element.m_lAttributes = this.m_lAttributes == null ? null : new ArrayList(this.m_lAttributes);
+
+ return element;
+ }
+
+ [Pure]
+ public static bool IsValidTag( String tag )
+ {
+ if (tag == null)
+ return false;
+
+ return tag.IndexOfAny( s_tagIllegalCharacters ) == -1;
+ }
+
+ [Pure]
+ public static bool IsValidText( String text )
+ {
+ if (text == null)
+ return false;
+
+ return text.IndexOfAny( s_textIllegalCharacters ) == -1;
+ }
+
+ [Pure]
+ public static bool IsValidAttributeName( String name )
+ {
+ return IsValidTag( name );
+ }
+
+ [Pure]
+ public static bool IsValidAttributeValue( String value )
+ {
+ if (value == null)
+ return false;
+
+ return value.IndexOfAny( s_valueIllegalCharacters ) == -1;
+ }
+
+ private static String GetEscapeSequence( char c )
+ {
+ int iMax = s_escapeStringPairs.Length;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ for (int i = 0; i < iMax; i += 2)
+ {
+ String strEscSeq = s_escapeStringPairs[i];
+ String strEscValue = s_escapeStringPairs[i+1];
+
+ if (strEscSeq[0] == c)
+ return strEscValue;
+ }
+
+ Contract.Assert( false, "Unable to find escape sequence for this character" );
+ return c.ToString();
+ }
+
+ public static String Escape( String str )
+ {
+ if (str == null)
+ return null;
+
+ StringBuilder sb = null;
+
+ int strLen = str.Length;
+ int index; // Pointer into the string that indicates the location of the current '&' character
+ int newIndex = 0; // Pointer into the string that indicates the start index of the "remaining" string (that still needs to be processed).
+
+
+ do
+ {
+ index = str.IndexOfAny( s_escapeChars, newIndex );
+
+ if (index == -1)
+ {
+ if (sb == null)
+ return str;
+ else
+ {
+ sb.Append( str, newIndex, strLen - newIndex );
+ return sb.ToString();
+ }
+ }
+ else
+ {
+ if (sb == null)
+ sb = new StringBuilder();
+
+ sb.Append( str, newIndex, index - newIndex );
+ sb.Append( GetEscapeSequence( str[index] ) );
+
+ newIndex = ( index + 1 );
+ }
+ }
+ while (true);
+
+ // no normal exit is possible
+ }
+
+ private static String GetUnescapeSequence( String str, int index, out int newIndex )
+ {
+ int maxCompareLength = str.Length - index;
+
+ int iMax = s_escapeStringPairs.Length;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ for (int i = 0; i < iMax; i += 2)
+ {
+ String strEscSeq = s_escapeStringPairs[i];
+ String strEscValue = s_escapeStringPairs[i+1];
+
+ int length = strEscValue.Length;
+
+ if (length <= maxCompareLength && String.Compare( strEscValue, 0, str, index, length, StringComparison.Ordinal) == 0)
+ {
+ newIndex = index + strEscValue.Length;
+ return strEscSeq;
+ }
+ }
+
+ newIndex = index + 1;
+ return str[index].ToString();
+ }
+
+
+ private static String Unescape( String str )
+ {
+ if (str == null)
+ return null;
+
+ StringBuilder sb = null;
+
+ int strLen = str.Length;
+ int index; // Pointer into the string that indicates the location of the current '&' character
+ int newIndex = 0; // Pointer into the string that indicates the start index of the "remainging" string (that still needs to be processed).
+
+ do
+ {
+ index = str.IndexOf( '&', newIndex );
+
+ if (index == -1)
+ {
+ if (sb == null)
+ return str;
+ else
+ {
+ sb.Append( str, newIndex, strLen - newIndex );
+ return sb.ToString();
+ }
+ }
+ else
+ {
+ if (sb == null)
+ sb = new StringBuilder();
+
+ sb.Append(str, newIndex, index - newIndex);
+ sb.Append( GetUnescapeSequence( str, index, out newIndex ) ); // updates the newIndex too
+
+ }
+ }
+ while (true);
+
+ // C# reports a warning if I leave this in, but I still kinda want to just in case.
+ // Contract.Assert( false, "If you got here, the execution engine or compiler is really confused" );
+ // return str;
+ }
+
+ private delegate void ToStringHelperFunc( Object obj, String str );
+
+ private static void ToStringHelperStringBuilder( Object obj, String str )
+ {
+ ((StringBuilder)obj).Append( str );
+ }
+
+ private static void ToStringHelperStreamWriter( Object obj, String str )
+ {
+ ((StreamWriter)obj).Write( str );
+ }
+
+ public override String ToString ()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ ToString( "", sb, new ToStringHelperFunc( ToStringHelperStringBuilder ) );
+
+ return sb.ToString();
+ }
+
+ internal void ToWriter( StreamWriter writer )
+ {
+ ToString( "", writer, new ToStringHelperFunc( ToStringHelperStreamWriter ) );
+ }
+
+ private void ToString( String indent, Object obj, ToStringHelperFunc func )
+ {
+ // First add the indent
+
+ // func( obj, indent );
+
+ // Add in the opening bracket and the tag.
+
+ func( obj, "<" );
+
+ switch (m_type)
+ {
+ case SecurityElementType.Format:
+ func( obj, "?" );
+ break;
+
+ case SecurityElementType.Comment:
+ func( obj, "!" );
+ break;
+
+ default:
+ break;
+ }
+
+ func( obj, m_strTag );
+
+ // If there are any attributes, plop those in.
+
+ if (m_lAttributes != null && m_lAttributes.Count > 0)
+ {
+ func( obj, " " );
+
+ int iMax = m_lAttributes.Count;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ for (int i = 0; i < iMax; i += 2)
+ {
+ String strAttrName = (String)m_lAttributes[i];
+ String strAttrValue = (String)m_lAttributes[i+1];
+
+ func( obj, strAttrName );
+ func( obj, "=\"" );
+ func( obj, strAttrValue );
+ func( obj, "\"" );
+
+ if (i != m_lAttributes.Count - 2)
+ {
+ if (m_type == SecurityElementType.Regular)
+ {
+ func( obj, Environment.NewLine );
+ }
+ else
+ {
+ func( obj, " " );
+ }
+ }
+ }
+ }
+
+ if (m_strText == null && (m_lChildren == null || m_lChildren.Count == 0))
+ {
+ // If we are a single tag with no children, just add the end of tag text.
+
+ switch (m_type)
+ {
+ case SecurityElementType.Comment:
+ func( obj, ">" );
+ break;
+
+ case SecurityElementType.Format:
+ func( obj, " ?>" );
+ break;
+
+ default:
+ func( obj, "/>" );
+ break;
+ }
+ func( obj, Environment.NewLine );
+ }
+ else
+ {
+ // Close the current tag.
+
+ func( obj, ">" );
+
+ // Output the text
+
+ func( obj, m_strText );
+
+ // Output any children.
+
+ if (m_lChildren != null)
+ {
+ this.ConvertSecurityElementFactories();
+
+ func( obj, Environment.NewLine );
+
+ // String childIndent = indent + s_strIndent;
+
+ for (int i = 0; i < m_lChildren.Count; ++i)
+ {
+ ((SecurityElement)m_lChildren[i]).ToString( "", obj, func );
+ }
+
+ // In the case where we have children, the close tag will not be on the same line as the
+ // opening tag, so we need to indent.
+
+ // func( obj, indent );
+ }
+
+ // Output the closing tag
+
+ func( obj, "</" );
+ func( obj, m_strTag );
+ func( obj, ">" );
+ func( obj, Environment.NewLine );
+ }
+ }
+
+
+
+ public String Attribute( String name )
+ {
+ if (name == null)
+ throw new ArgumentNullException( "name" );
+ Contract.EndContractBlock();
+
+ // Note: we don't check for validity here because an
+ // if an invalid name is passed we simply won't find it.
+
+ if (m_lAttributes == null)
+ return null;
+
+ // Go through all the attribute and see if we know about
+ // the one we are asked for
+
+ int iMax = m_lAttributes.Count;
+ Contract.Assert( iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly" );
+
+ for (int i = 0; i < iMax; i += 2)
+ {
+ String strAttrName = (String)m_lAttributes[i];
+
+ if (String.Equals(strAttrName, name))
+ {
+ String strAttrValue = (String)m_lAttributes[i+1];
+
+ return Unescape(strAttrValue);
+ }
+ }
+
+ // In the case where we didn't find it, we are expected to
+ // return null
+ return null;
+ }
+
+ public SecurityElement SearchForChildByTag( String tag )
+ {
+ // Go through all the children and see if we can
+ // find the one are are asked for (matching tags)
+
+ if (tag == null)
+ throw new ArgumentNullException( "tag" );
+ Contract.EndContractBlock();
+
+ // Note: we don't check for a valid tag here because
+ // an invalid tag simply won't be found.
+
+ if (m_lChildren == null)
+ return null;
+
+ IEnumerator enumerator = m_lChildren.GetEnumerator();
+
+ while (enumerator.MoveNext())
+ {
+ SecurityElement current = (SecurityElement)enumerator.Current;
+
+ if (current != null && String.Equals(current.Tag, tag))
+ return current;
+ }
+ return null;
+ }
+
+#if FEATURE_CAS_POLICY
+ internal IPermission ToPermission(bool ignoreTypeLoadFailures)
+ {
+ IPermission ip = XMLUtil.CreatePermission( this, PermissionState.None, ignoreTypeLoadFailures );
+ if (ip == null)
+ return null;
+ ip.FromXml(this);
+
+ // Get the permission token here to ensure that the token
+ // type is updated appropriately now that we've loaded the type.
+ PermissionToken token = PermissionToken.GetToken( ip );
+ Contract.Assert((token.m_type & PermissionTokenType.DontKnow) == 0, "Token type not properly assigned");
+
+ return ip;
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ internal Object ToSecurityObject()
+ {
+ switch (m_strTag)
+ {
+ case "PermissionSet":
+ PermissionSet pset = new PermissionSet(PermissionState.None);
+ pset.FromXml(this);
+ return pset;
+
+ default:
+ return ToPermission(false);
+ }
+ }
+#endif // FEATURE_CAS_POLICY
+
+ internal String SearchForTextOfLocalName(String strLocalName)
+ {
+ // Search on each child in order and each
+ // child's child, depth-first
+
+ if (strLocalName == null)
+ throw new ArgumentNullException( "strLocalName" );
+ Contract.EndContractBlock();
+
+ // Note: we don't check for a valid tag here because
+ // an invalid tag simply won't be found.
+
+ // First we check this.
+
+ if (m_strTag == null) return null;
+ if (m_strTag.Equals( strLocalName ) || m_strTag.EndsWith( ":" + strLocalName, StringComparison.Ordinal ))
+ return Unescape( m_strText );
+ if (m_lChildren == null)
+ return null;
+
+ IEnumerator enumerator = m_lChildren.GetEnumerator();
+
+ while (enumerator.MoveNext())
+ {
+ String current = ((SecurityElement)enumerator.Current).SearchForTextOfLocalName( strLocalName );
+
+ if (current != null)
+ return current;
+ }
+ return null;
+ }
+
+ public String SearchForTextOfTag( String tag )
+ {
+ // Search on each child in order and each
+ // child's child, depth-first
+
+ if (tag == null)
+ throw new ArgumentNullException( "tag" );
+ Contract.EndContractBlock();
+
+ // Note: we don't check for a valid tag here because
+ // an invalid tag simply won't be found.
+
+ // First we check this.
+
+ if (String.Equals(m_strTag, tag))
+ return Unescape( m_strText );
+ if (m_lChildren == null)
+ return null;
+
+ IEnumerator enumerator = m_lChildren.GetEnumerator();
+
+ this.ConvertSecurityElementFactories();
+
+ while (enumerator.MoveNext())
+ {
+ String current = ((SecurityElement)enumerator.Current).SearchForTextOfTag( tag );
+
+ if (current != null)
+ return current;
+ }
+ return null;
+ }
+ }
+}