File: System\DirectoryServices\Protocols\common\DirectoryAttribute.cs
Web Access
Project: src\runtime\src\libraries\System.DirectoryServices.Protocols\src\System.DirectoryServices.Protocols.csproj (System.DirectoryServices.Protocols)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Text;

namespace System.DirectoryServices.Protocols
{
    public class DirectoryAttribute : CollectionBase
    {
        private string _attributeName = "";
        internal bool _isSearchResult;
        // Does not request Unicode byte order mark prefix be emitted, but turn on error detection.
        private static readonly UTF8Encoding s_utf8EncoderWithErrorDetection = new UTF8Encoding(false, true);
        // No Error detection.
        private static readonly UTF8Encoding s_encoder = new UTF8Encoding();

        public DirectoryAttribute()
        {
        }

        public DirectoryAttribute(string name, string value) : this(name, (object)value)
        {
        }

        public DirectoryAttribute(string name, byte[] value) : this(name, (object)value)
        {
        }

        public DirectoryAttribute(string name, Uri value) : this(name, (object)value)
        {
        }

        internal DirectoryAttribute(string name, object value) : this()
        {
            ArgumentNullException.ThrowIfNull(name);
            ArgumentNullException.ThrowIfNull(value);

            Name = name;
            Add(value);
        }

        public DirectoryAttribute(string name, params object[] values) : this()
        {
            ArgumentNullException.ThrowIfNull(name);
            ArgumentNullException.ThrowIfNull(values);

            Name = name;

            for (int i = 0; i < values.Length; i++)
            {
                Add(values[i]);
            }
        }

        public string Name
        {
            get => _attributeName;
            set => _attributeName = value ?? throw new ArgumentNullException(nameof(value));
        }

        public object[] GetValues(Type valuesType)
        {
            // Return the binary value.
            if (valuesType == typeof(byte[]))
            {
                int count = List.Count;
                byte[][] results = new byte[count][];

                for (int i = 0; i < count; i++)
                {
                    if (List[i] is string)
                    {
                        results[i] = s_encoder.GetBytes((string)List[i]);
                    }
                    else if (List[i] is byte[])
                    {
                        results[i] = (byte[])List[i];
                    }
                    else
                    {
                        throw new NotSupportedException(SR.DirectoryAttributeConversion);
                    }
                }

                return results;
            }
            // Return the string value.
            else if (valuesType == typeof(string))
            {
                int count = List.Count;
                string[] results = new string[count];

                for (int i = 0; i < count; i++)
                {
                    if (List[i] is string)
                    {
                        results[i] = (string)List[i];
                    }
                    else if (List[i] is byte[])
                    {
                        results[i] = s_encoder.GetString((byte[])List[i]);
                    }
                    else
                    {
                        throw new NotSupportedException(SR.DirectoryAttributeConversion);
                    }
                }

                return results;
            }

            throw new ArgumentException(SR.ValidDirectoryAttributeType, nameof(valuesType));
        }

        public object this[int index]
        {
            get
            {
                if (!_isSearchResult)
                {
                    return List[index];
                }

                if (List[index] is byte[] temp)
                {
                    try
                    {
                        return s_utf8EncoderWithErrorDetection.GetString(temp);
                    }
                    catch (ArgumentException)
                    {
                        return List[index];
                    }
                }

                // This hould not happen.
                return List[index];
            }
            set
            {
                ArgumentNullException.ThrowIfNull(value);
                if (!(value is string) && !(value is byte[]) && !(value is Uri))
                {
                    throw new ArgumentException(SR.ValidValueType, nameof(value));
                }

                List[index] = value;
            }
        }

        public int Add(byte[] value) => Add((object)value);

        public int Add(string value) => Add((object)value);

        public int Add(Uri value) => Add((object)value);

        internal int Add(object value)
        {
            ArgumentNullException.ThrowIfNull(value);

            if (!(value is string) && !(value is byte[]) && !(value is Uri))
            {
                throw new ArgumentException(SR.ValidValueType, nameof(value));
            }

            return List.Add(value);
        }

        public void AddRange(object[] values)
        {
            ArgumentNullException.ThrowIfNull(values);

            if (!(values is string[]) && !(values is byte[][]) && !(values is Uri[]))
            {
                throw new ArgumentException(SR.ValidValuesType, nameof(values));
            }

            for (int i = 0; i < values.Length; i++)
            {
                if (values[i] == null)
                {
                    throw new ArgumentException(SR.NullValueArray, nameof(values));
                }
            }

            InnerList.AddRange(values);
        }

        public bool Contains(object value) => List.Contains(value);

        public void CopyTo(object[] array, int index) => List.CopyTo(array, index);

        public int IndexOf(object value) => List.IndexOf(value);

        public void Insert(int index, byte[] value) => Insert(index, (object)value);

        public void Insert(int index, string value) => Insert(index, (object)value);

        public void Insert(int index, Uri value) => Insert(index, (object)value);

        private void Insert(int index, object value)
        {
            ArgumentNullException.ThrowIfNull(value);

            List.Insert(index, value);
        }

        public void Remove(object value) => List.Remove(value);

        protected override void OnValidate(object value)
        {
            ArgumentNullException.ThrowIfNull(value);

            if (!(value is string) && !(value is byte[]) && !(value is Uri))
            {
                throw new ArgumentException(SR.ValidValueType, nameof(value));
            }
        }
    }

    public class DirectoryAttributeModification : DirectoryAttribute
    {
        private DirectoryAttributeOperation _attributeOperation = DirectoryAttributeOperation.Replace;

        public DirectoryAttributeModification()
        {
        }

        public DirectoryAttributeOperation Operation
        {
            get => _attributeOperation;
            set
            {
                if (value < DirectoryAttributeOperation.Add || value > DirectoryAttributeOperation.Replace)
                {
                    throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(DirectoryAttributeOperation));
                }

                _attributeOperation = value;
            }
        }
    }

    public class SearchResultAttributeCollection : DictionaryBase
    {
        internal SearchResultAttributeCollection() { }

        public DirectoryAttribute this[string attributeName]
        {
            get
            {
                ArgumentNullException.ThrowIfNull(attributeName);

                object objectName = attributeName.ToLowerInvariant();
                return (DirectoryAttribute)InnerHashtable[objectName];
            }
        }

        public ICollection AttributeNames => Dictionary.Keys;

        public ICollection Values => Dictionary.Values;

        internal void Add(string name, DirectoryAttribute value)
        {
            Dictionary.Add(name.ToLowerInvariant(), value);
        }

        public bool Contains(string attributeName)
        {
            ArgumentNullException.ThrowIfNull(attributeName);

            object objectName = attributeName.ToLowerInvariant();
            return Dictionary.Contains(objectName);
        }

        public void CopyTo(DirectoryAttribute[] array, int index) => Dictionary.Values.CopyTo(array, index);
    }

    public class DirectoryAttributeCollection : CollectionBase
    {
        public DirectoryAttributeCollection()
        {
        }

        public DirectoryAttribute this[int index]
        {
            get => (DirectoryAttribute)List[index];
            set => List[index] = value ?? throw new ArgumentException(SR.NullDirectoryAttributeCollection);
        }

        public int Add(DirectoryAttribute attribute)
        {
            if (attribute == null)
            {
                throw new ArgumentException(SR.NullDirectoryAttributeCollection);
            }

            return List.Add(attribute);
        }

        public void AddRange(DirectoryAttribute[] attributes)
        {
            ArgumentNullException.ThrowIfNull(attributes);

            foreach (DirectoryAttribute attribute in attributes)
            {
                if (attribute == null)
                {
                    throw new ArgumentException(SR.NullDirectoryAttributeCollection);
                }
            }

            InnerList.AddRange(attributes);
        }

        public void AddRange(DirectoryAttributeCollection attributeCollection)
        {
            ArgumentNullException.ThrowIfNull(attributeCollection);

            int currentCount = attributeCollection.Count;
            for (int i = 0; i < currentCount; i = ((i) + (1)))
            {
                Add(attributeCollection[i]);
            }
        }

        public bool Contains(DirectoryAttribute value) => List.Contains(value);

        public void CopyTo(DirectoryAttribute[] array, int index) => List.CopyTo(array, index);

        public int IndexOf(DirectoryAttribute value) => List.IndexOf(value);

        public void Insert(int index, DirectoryAttribute value)
        {
            if (value == null)
            {
                throw new ArgumentException(SR.NullDirectoryAttributeCollection);
            }

            List.Insert(index, value);
        }

        public void Remove(DirectoryAttribute value) => List.Remove(value);

        protected override void OnValidate(object value)
        {
            if (value == null)
            {
                throw new ArgumentException(SR.NullDirectoryAttributeCollection);
            }
            if (!(value is DirectoryAttribute))
            {
                throw new ArgumentException(SR.Format(SR.InvalidValueType, nameof(DirectoryAttribute)), nameof(value));
            }
        }
    }

    public class DirectoryAttributeModificationCollection : CollectionBase
    {
        public DirectoryAttributeModificationCollection()
        {
        }

        public DirectoryAttributeModification this[int index]
        {
            get => (DirectoryAttributeModification)List[index];
            set => List[index] = value ?? throw new ArgumentException(SR.NullDirectoryAttributeCollection);
        }

        public int Add(DirectoryAttributeModification attribute)
        {
            if (attribute == null)
            {
                throw new ArgumentException(SR.NullDirectoryAttributeCollection);
            }

            return List.Add(attribute);
        }

        public void AddRange(DirectoryAttributeModification[] attributes)
        {
            ArgumentNullException.ThrowIfNull(attributes);

            foreach (DirectoryAttributeModification attribute in attributes)
            {
                if (attribute == null)
                {
                    throw new ArgumentException(SR.NullDirectoryAttributeCollection);
                }
            }

            InnerList.AddRange(attributes);
        }

        public void AddRange(DirectoryAttributeModificationCollection attributeCollection)
        {
            ArgumentNullException.ThrowIfNull(attributeCollection);

            int currentCount = attributeCollection.Count;
            for (int i = 0; i < currentCount; i = ((i) + (1)))
            {
                Add(attributeCollection[i]);
            }
        }

        public bool Contains(DirectoryAttributeModification value) => List.Contains(value);

        public void CopyTo(DirectoryAttributeModification[] array, int index) => List.CopyTo(array, index);

        public int IndexOf(DirectoryAttributeModification value) => List.IndexOf(value);

        public void Insert(int index, DirectoryAttributeModification value)
        {
            if (value == null)
            {
                throw new ArgumentException(SR.NullDirectoryAttributeCollection);
            }

            List.Insert(index, value);
        }

        public void Remove(DirectoryAttributeModification value) => List.Remove(value);

        protected override void OnValidate(object value)
        {
            if (value == null)
            {
                throw new ArgumentException(SR.NullDirectoryAttributeCollection);
            }
            if (!(value is DirectoryAttributeModification))
            {
                throw new ArgumentException(SR.Format(SR.InvalidValueType, nameof(DirectoryAttributeModification)), nameof(value));
            }
        }
    }
}