2009-08-20 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System / System.Collections.Specialized / NameValueCollection.cs
index cce56a3d27473641a1ad854b134fc5f33af48b7e..27432912015170d929f098d10eaae0ca06e4801c 100644 (file)
@@ -1,16 +1,39 @@
-/**
- * System.Collections.Specialized.NamaValueCollection class implementation
- * 
- * Author: Gleb Novodran
- */
-// created on 7/21/2001 at 5:15 PM
-using System;
-using System.Collections;
-using System.Collections.Specialized;
+//
+// System.Collections.Specialized.NameValueCollection.cs
+//
+// Author:
+//   Gleb Novodran
+//
+// (C) Ximian, Inc.  http://www.ximian.com
+// Copyright (C) 2004-2005 Novell (http://www.novell.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using System.Runtime.Serialization;
 using System.Text;
 
 namespace System.Collections.Specialized{
+
        [Serializable]
        public class NameValueCollection : NameObjectCollectionBase
        {
@@ -19,342 +42,310 @@ namespace System.Collections.Specialized{
 
                //--------------------- Constructors -----------------------------
 
-               /// <summary> SDK: Initializes a new instance of the NameValueCollection class that is empty,
-               /// has the default initial capacity and uses the default case-insensitive hash code provider and the default case-insensitive comparer.
-               /// </summary>
-               public NameValueCollection() : base()
+               public NameValueCollection () : base ()
                {
-                       
                }
                
-               /// <summary> SDK: Initializes a new instance of the NameValueCollection class that is empty, 
-               /// has the specified initial capacity and uses the default case-insensitive hash code provider and the default case-insensitive comparer.
-               ///</summary>
-               public NameValueCollection( int capacity ) : base(capacity)
+               public NameValueCollection (int capacity) : base (capacity)
                {
-                       
                }
-
-               /// <summary> SDK: Copies the entries from the specified NameValueCollection to a new 
-               /// NameValueCollection with the same initial capacity as the number of entries copied 
-               /// and using the same case-insensitive hash code provider and the same case-insensitive 
-               /// comparer as the source collection.
-               /// </summary>
-               /// TODO: uncomment constructor below after it will be possible to compile NameValueCollection and
-               /// NameObjectCollectionBase to the same assembly 
-               
-               public NameValueCollection( NameValueCollection col ) : base(col.HashCodeProvider,col.Comparer)
+#if NET_2_0
+        public NameValueCollection (NameValueCollection col) : base (( col == null ) ? null : col.EqualityComparer ,
+                                                                (col == null) ? null : col.Comparer, 
+                                                                (col == null) ? null : col.HashCodeProvider)
+        {
+            if (col==null)
+                throw new ArgumentNullException ("col");               
+            Add(col);
+        }
+#else
+               public NameValueCollection (NameValueCollection col) : base ((col == null) ? null : col.HashCodeProvider ,
+                                                                                                                               (col == null) ? null : col.Comparer)                                                                                                                            
                {
                        if (col==null)
-                               throw new ArgumentNullException("Null argument is not allowed");
+                               throw new NullReferenceException ();            
                        Add(col);
                }
+#endif
 
-               ///<summary>SDK: Initializes a new instance of the NameValueCollection class that is empty, 
-               ///has the default initial capacity and uses the specified hash code provider and 
-               ///the specified comparer.</summary>
-               public NameValueCollection( IHashCodeProvider hashProvider, IComparer comparer )
-                       : base(hashProvider, comparer)
+#if NET_2_0
+               [Obsolete ("Use NameValueCollection (IEqualityComparer)")]
+#endif
+               public NameValueCollection (IHashCodeProvider hashProvider, IComparer comparer)
+                       : base (hashProvider, comparer)
                {
                        
                }
 
-               /// <summary>
-               /// SDK: Copies the entries from the specified NameValueCollection to a new NameValueCollection
-               /// with the specified initial capacity or the same initial capacity as the number of entries 
-               /// copied, whichever is greater, and using the default case-insensitive hash code provider and 
-               /// the default case-insensitive comparer.
-               /// </summary>
-               /// TODO: uncomment constructor below after it will be possible to compile NameValueCollection and
-               /// NameObjectCollectionBase to the same assembly 
-               
-/*             public NameValueCollection( int capacity, NameValueCollection col )
-                       : base(capacity, col.get_HashCodeProvider(),col.Comparer)
+               public NameValueCollection (int capacity, NameValueCollection col)
+                       : base (capacity, (col == null) ? null : col.HashCodeProvider, 
+                                       (col == null) ? null : col.Comparer)
                {
-                       if (col==null)
-                               throw new ArgumentNullException("Null argument is not allowed");
-                       Add(col);                       
+                       Add (col);                      
                }
-*/             
-               /// <summary>
-               /// SDK: Initializes a new instance of the NameValueCollection class that is serializable
-               /// and uses the specified System.Runtime.Serialization.SerializationInfo and 
-               /// System.Runtime.Serialization.StreamingContext.
-               /// </summary>
-               protected NameValueCollection( SerializationInfo info, StreamingContext context )
-                       :base(info, context)
+
+               protected NameValueCollection (SerializationInfo info, StreamingContext context)
+                       :base (info, context)
                {
                        
                }
                
-               /// <summary>
-               /// SDK: Initializes a new instance of the NameValueCollection class that is empty, 
-               /// has the specified initial capacity and uses the specified hash code provider and 
-               /// the specified comparer.
-               /// </summary>
-               public NameValueCollection( int capacity, IHashCodeProvider hashProvider, IComparer comparer )
-                       :base(capacity, hashProvider, comparer)
+#if NET_2_0
+               [Obsolete ("Use NameValueCollection (IEqualityComparer)")]
+#endif
+               public NameValueCollection (int capacity, IHashCodeProvider hashProvider, IComparer comparer)
+                       :base (capacity, hashProvider, comparer)
                {
                        
                }
 
-        //----------------------- Public Instance Properties -------------------------------
+#if NET_2_0
+               public NameValueCollection (IEqualityComparer equalityComparer)
+                       : base (equalityComparer)
+               {
+               }
+
+               public NameValueCollection (int capacity, IEqualityComparer equalityComparer)
+                       : base (capacity, equalityComparer)
+               {
+               }
+#endif
 
-               
-               ///<summary> SDK:
-               /// Gets all the keys in the NameValueCollection.
-               /// The arrays returned by AllKeys are cached for better performance and are 
-               /// automatically refreshed when the collection changes. A derived class can 
-               /// invalidate the cached version by calling InvalidateCachedArrays, thereby 
-               /// forcing the arrays to be recreated.
-               /// </summary>
                public virtual string[] AllKeys 
                {
                        get {
-                               if (cachedAllKeys==null)
-                                       cachedAllKeys = BaseGetAllKeys();
+                               if (cachedAllKeys == null)
+                                       cachedAllKeys = BaseGetAllKeys ();
                                return this.cachedAllKeys;
                        }
                }
                
-               public string this[ int index 
+               public string this [int index
                {
                        get{
-                               return this.Get(index);
+                               return this.Get (index);
                        }
                }
                
-               public string this[ string name ] {
+               public string this [string name] {
                        get{
-                               return this.Get(name);
+                               return this.Get (name);
                        }
                        set{
-                               this.Set(name,value);
+                               this.Set (name,value);
                        }
                }
                
-/////////////////////////////// Public Instance Methods //////////////////////////////
-               
-               /// <summary> SDK: Copies the entries in the specified NameValueCollection 
-               /// to the current NameValueCollection.</summary>
-               /// LAMESPEC: see description that comes this Add(string, string)
-               
                public void Add (NameValueCollection c)
                {
                        if (this.IsReadOnly)
                                throw new NotSupportedException ("Collection is read-only");
+#if NET_2_0
                        if (c == null)
-                               throw new ArgumentNullException ();
+                               throw new ArgumentNullException ("c");
+#endif
+// make sense - but it's not the exception thrown
+//                             throw new ArgumentNullException ();
                        
                        InvalidateCachedArrays ();
                        int max = c.Count;
                        for (int i=0; i < max; i++){
                                string key = c.GetKey (i);
-                               string [] values = c.GetValues (i);
-                               foreach (string value in values)
-                                       Add (key, value);
+                               ArrayList new_values = (ArrayList) c.BaseGet (i);
+                               ArrayList values = (ArrayList) BaseGet (key);
+                               if (values != null && new_values != null)
+                                       values.AddRange (new_values);
+                               else if (new_values != null)
+                                       values = new ArrayList (new_values);
+                               BaseSet (key, values);
                        }
                }
 
-               
-               /// <summary> SDK: Adds an entry with the specified name and value to the 
-               /// NameValueCollection. </summary>
-               /// 
-               /// LAMESPEC: 
                /// in SDK doc: If the same value already exists under the same key in the collection, 
-               /// the new value overwrites the old value.
-               /// however the Microsoft implemenatation in this case just adds one more value
-               /// in other words after
+               /// it just adds one more value in other words after
                /// <code>
                /// NameValueCollection nvc;
-               /// nvc.Add("LAZY","BASTARD")
-               /// nvc.Add("LAZY","BASTARD")
+               /// nvc.Add ("LAZY","BASTARD")
+               /// nvc.Add ("LAZY","BASTARD")
                /// </code>
-               /// nvc.Get("LAZY") will be "BASTARD,BASTARD" instead of "BASTARD"
+               /// nvc.Get ("LAZY") will be "BASTARD,BASTARD" instead of "BASTARD"
 
-               public virtual void Add( string name, string val )
+               public virtual void Add (string name, string val)
                {
-                       
                        if (this.IsReadOnly)
-                               throw new NotSupportedException("Collection is read-only");
+                               throw new NotSupportedException ("Collection is read-only");
                        
-                       InvalidateCachedArrays();
-                       ArrayList values = (ArrayList)BaseGet(name);
-                       if (values==null){
-                               values = new ArrayList();
-                               if (val!=null)
-                                       values.Add(val);
-                               BaseAdd(name,values);
+                       InvalidateCachedArrays ();
+                       ArrayList values = (ArrayList)BaseGet (name);
+                       if (values == null){
+                               values = new ArrayList ();
+                               if (val != null)
+                                       values.Add (val);
+                               BaseAdd (name, values);
                        }
                        else {
-                               if (val!=null)
-                                       values.Add(val);
+                               if (val != null)
+                                       values.Add (val);
                        }
 
                }
 
-               /// <summary> SDK: Invalidates the cached arrays and removes all entries from 
-               /// the NameValueCollection.</summary>
-                
-               public void Clear(){
+#if NET_2_0
+               public virtual void Clear ()
+#else
+               public void Clear ()
+#endif
+               {
                        if (this.IsReadOnly)
-                               throw new NotSupportedException("Collection is read-only");
-                       InvalidateCachedArrays();
-                       BaseClear();
+                               throw new NotSupportedException ("Collection is read-only");
+                       InvalidateCachedArrays ();
+                       BaseClear ();
                }
 
-               /// <summary> SDK: Copies the entire NameValueCollection to a compatible one-dimensional Array,
-               /// starting at the specified index of the target array.</summary>
-
-               [MonoTODO]
-               public void CopyTo( Array dest, int index )
+               public void CopyTo (Array dest, int index)
                {
-                       if (dest==null)
-                               throw new ArgumentNullException("Null argument - dest");
-                       if (index<0)
-                               throw new ArgumentOutOfRangeException("index is less than 0");
-//                     throw new Exception("Not implemented yet");
-                       
-                       //TODO: add implementation here
-                       if (cachedAll==null)
-                               RefreshCachedAll();
-                       cachedAll.CopyTo(dest, index);
+                       if (dest == null)
+                               throw new ArgumentNullException ("dest", "Null argument - dest");
+                       if (index < 0)
+                               throw new ArgumentOutOfRangeException ("index", "index is less than 0");
+                       if (dest.Rank > 1)
+                               throw new ArgumentException ("dest", "multidim");
+
+                       if (cachedAll == null)
+                               RefreshCachedAll ();
+#if NET_2_0
+                       try {
+#endif                 
+                       cachedAll.CopyTo (dest, index);
+#if NET_2_0
+                       }
+                       catch (ArrayTypeMismatchException)  
+                       {
+                               throw new InvalidCastException();
+                       }
+#endif                 
                }
-               protected void RefreshCachedAll()
+
+               private void RefreshCachedAll ()
                {
-                       this.cachedAll=null;
+                       this.cachedAll = null;
                        int max = this.Count;
-                       cachedAll = new string[max];
-                       for(int i=0;i<max;i++){
-                               cachedAll[i] = this.Get(i);
-                       }
-                       
+                       cachedAll = new string [max];
+                       for (int i = 0; i < max; i++)
+                               cachedAll [i] = this.Get (i);
                }
                
-               /// <summary> SDK: Gets the values at the specified index of the NameValueCollection combined
-               /// into one comma-separated list.</summary>
-               
-               public virtual string Get( int index )
+               public virtual string Get (int index)
                {
-                       ArrayList values = (ArrayList)BaseGet(index);
+                       ArrayList values = (ArrayList)BaseGet (index);
                        // if index is out of range BaseGet throws an ArgumentOutOfRangeException
 
-                       return AsSingleString(values);
-                       
+                       return AsSingleString (values);
                }
                
-               /**
-                * SDK: Gets the values associated with the specified key from the NameValueCollection
-                * combined into one comma-separated list.
-                */
-               public virtual string Get( string name )
+               public virtual string Get (string name)
                {
-                       ArrayList values = (ArrayList)BaseGet(name);
-/*                     if (values==null) 
-                               Console.WriteLine("BaseGet returned null");*/
-                       return AsSingleString(values);
-// -------------------------------------------------------------
-
+                       ArrayList values = (ArrayList)BaseGet (name);
+                       return AsSingleString (values);
                }
-               /// <summary></summary>
-               [MonoTODO]
-               private static string AsSingleString(ArrayList values)
+
+               private static string AsSingleString (ArrayList values)
                {
                        const char separator = ',';
                        
-                       if (values==null)
+                       if (values == null)
                                return null;
                        int max = values.Count;
                        
-                       if (max==0)
+                       switch (max) {
+                       case 0:
                                return null;
-                       //TODO: reimplement this
-                       StringBuilder sb = new StringBuilder((string)values[0]);
-                       for (int i=1; i<max; i++){
-                               sb.Append(separator);
-                               sb.Append(values[i]);
-                       }
+                       case 1:
+                               return (string)values [0];
+                       case 2:
+                               return String.Concat ((string)values [0], separator, (string)values [1]);
+                       default:
+                               int len = max;
+                               for (int i = 0; i < max; i++)
+                                       len += ((string)values [i]).Length;
+                               StringBuilder sb = new StringBuilder ((string)values [0], len);
+                               for (int i = 1; i < max; i++){
+                                       sb.Append (separator);
+                                       sb.Append (values [i]);
+                               }
 
-                       return sb.ToString();                   
+                               return sb.ToString ();
+                       }
                }
                
                
-               /// <summary>SDK: Gets the key at the specified index of the NameValueCollection.</summary>
-               public virtual string GetKey( int index )
+               public virtual string GetKey (int index)
                {
-                       return BaseGetKey(index);
+                       return BaseGetKey (index);
                }
                
                
-               /// <summary>SDK: Gets the values at the specified index of the NameValueCollection.</summary>
-                
-               public virtual string[] GetValues( int index )
+               public virtual string[] GetValues (int index)
                {
-                       ArrayList values = (ArrayList)BaseGet(index);
+                       ArrayList values = (ArrayList)BaseGet (index);
                        
-                       return AsStringArray(values);
+                       return AsStringArray (values);
                }
                
                
-               public virtual string[] GetValues( string name )
+               public virtual string[] GetValues (string name)
                {
-                       ArrayList values = (ArrayList)BaseGet(name);
+                       ArrayList values = (ArrayList)BaseGet (name);
                        
-                       return AsStringArray(values);
+                       return AsStringArray (values);
                }
                
-               private static string[] AsStringArray(ArrayList values)
+               private static string[] AsStringArray (ArrayList values)
                {
                        if (values == null)
                                return null;
-                       int max = values.Count;//get_Count();
-                       if (max==0)
+                       int max = values.Count;//get_Count ();
+                       if (max == 0)
                                return null;
                        
-                       string[] valArray =new string[max];
-                       values.CopyTo(valArray);
+                       string[] valArray = new string[max];
+                       values.CopyTo (valArray);
                        return valArray;
                }
                
-               
-               /// <summary>
-               /// SDK: Gets a value indicating whether the NameValueCollection contains keys that
-               /// are not a null reference 
-               /// </summary>
-
-               public bool HasKeys()
+               public bool HasKeys ()
                {
-                       return BaseHasKeys();
+                       return BaseHasKeys ();
                }
                
-               public virtual void Remove( string name )
+               public virtual void Remove (string name)
                {
                        if (this.IsReadOnly)
-                               throw new NotSupportedException("Collection is read-only");
-                       InvalidateCachedArrays();
-                       BaseRemove(name);
+                               throw new NotSupportedException ("Collection is read-only");
+                       InvalidateCachedArrays ();
+                       BaseRemove (name);
                        
                }
                
-               /// <summary>
-               /// Sets the value of an entry in the NameValueCollection.
-               /// </summary>
-               public virtual void Set( string name, string value )
+               public virtual void Set (string name, string value)
                {
                        if (this.IsReadOnly)
-                               throw new NotSupportedException("Collection is read-only");
-                       InvalidateCachedArrays();
-                       
-                       ArrayList values = new ArrayList();
-                       values.Add(value);
-                       BaseSet(name,values);
+                               throw new NotSupportedException ("Collection is read-only");
 
+                       InvalidateCachedArrays ();
+                       
+                       ArrayList values = new ArrayList ();
+                       if (value != null) {
+                               values.Add (value);
+                               BaseSet (name,values);
+                       }
+                       else {
+                               // remove all entries
+                               BaseSet (name, null);
+                       }
                }
                
-
-//---------------------- Protected Instance Methods ----------------------     
-
-               protected void InvalidateCachedArrays()
+               protected void InvalidateCachedArrays ()
                {
                        cachedAllKeys = null;
                        cachedAll = null;