[Task] Add an extra check in Task.WaitAny to make sure the index returned is valid
[mono.git] / mcs / class / System.Data / System.Data.Common / DbConnectionStringBuilder.cs
1 //
2 // System.Data.Common.DbConnectionStringBuilder.cs
3 //
4 // Author:
5 //      Sureshkumar T (tsureshkumar@novell.com)
6 //      Gert Driesen (drieseng@users.sourceforge.net
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_0
31 using System;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Collections.ObjectModel;
35 using System.ComponentModel;
36 using System.Data;
37 using System.Data.Common;
38 using System.Reflection;
39 using System.Text;
40
41 namespace System.Data.Common
42 {
43         public class DbConnectionStringBuilder : IDictionary, ICollection, IEnumerable, ICustomTypeDescriptor
44         {
45                 #region Fields
46
47                 readonly Dictionary<string, object> _dictionary;
48                 readonly bool useOdbcRules;
49
50                 #endregion Fields
51
52                 #region Constructors
53
54                 public DbConnectionStringBuilder () : this (false)
55                 {
56                 }
57
58                 public DbConnectionStringBuilder (bool useOdbcRules)
59                 {
60                         this.useOdbcRules = useOdbcRules;
61                         _dictionary = new Dictionary <string, object> (StringComparer.InvariantCultureIgnoreCase);
62                 }
63
64                 #endregion // Constructors
65
66                 #region Properties
67
68                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
69                 [EditorBrowsable (EditorBrowsableState.Never)]
70                 [Browsable (false)]
71                 [DesignOnly (true)]
72                 public bool BrowsableConnectionString {
73                         get { throw new NotImplementedException (); }
74                         set { throw new NotImplementedException (); }
75                 }
76
77                 [RefreshProperties (RefreshProperties.All)]
78                 public string ConnectionString {
79                         get {
80                                 IDictionary<string, object> dictionary = (IDictionary <string, object>) _dictionary;
81                                 StringBuilder sb = new StringBuilder ();
82                                 foreach (string key in Keys) {
83                                         object value = null;
84                                         if (!dictionary.TryGetValue (key, out value))
85                                                 continue;
86                                         string val = value.ToString ();
87                                         AppendKeyValuePair (sb, key, val, useOdbcRules);
88                                 }
89                                 return sb.ToString ();
90                         }
91                         set {
92                                 Clear ();
93                                 if (value == null)
94                                         return;
95                                 if (value.Trim ().Length == 0)
96                                         return;
97                                 ParseConnectionString (value);
98                         }
99                 }
100
101                 [Browsable (false)]
102                 public virtual int Count
103                 {
104                         get { return _dictionary.Count; }
105                 }
106
107                 [Browsable (false)]
108                 public virtual bool IsFixedSize
109                 {
110                         get { return false; }
111                 }
112
113                 [Browsable (false)]
114                 public bool IsReadOnly
115                 {
116                         get { throw new NotImplementedException (); }
117                 }
118
119                 [Browsable (false)]
120                 public virtual object this [string keyword] {
121                         get {
122                                 if (ContainsKey (keyword))
123                                         return _dictionary [keyword];
124                                 else
125                                         throw new ArgumentException (string.Format (
126                                                 "Keyword '{0}' does not exist",
127                                                 keyword));
128                         }
129                         set {
130                                 if (value == null) {
131                                         Remove (keyword);
132                                         return;
133                                 }
134
135                                 if (keyword == null)
136                                         throw new ArgumentNullException ("keyword");
137
138                                 if (keyword.Length == 0)
139                                         throw CreateInvalidKeywordException (keyword);
140
141                                 for (int i = 0; i < keyword.Length; i++) {
142                                         char c = keyword [i];
143                                         if (i == 0 && (Char.IsWhiteSpace (c) || c == ';'))
144                                                 throw CreateInvalidKeywordException (keyword);
145                                         if (i == (keyword.Length - 1) && Char.IsWhiteSpace (c))
146                                                 throw CreateInvalidKeywordException (keyword);
147                                         if (Char.IsControl (c))
148                                                 throw CreateInvalidKeywordException (keyword);
149                                 }
150
151                                 if (ContainsKey (keyword))
152                                         _dictionary [keyword] = value;
153                                 else
154                                         _dictionary.Add (keyword, value);
155                         }
156                 }
157
158                 [Browsable (false)]
159                 public virtual ICollection Keys
160                 {
161                         get {
162                                 string [] keys = new string [_dictionary.Keys.Count];
163                                 ((ICollection<string>) _dictionary.Keys).CopyTo (keys, 0);
164                                 ReadOnlyCollection<string> keyColl = new ReadOnlyCollection<string> (keys);
165                                 return keyColl; 
166                         }
167                 }
168
169                 bool ICollection.IsSynchronized
170                 {
171                         get { throw new NotImplementedException (); }
172                 }
173
174                 object ICollection.SyncRoot
175                 {
176                         get { throw new NotImplementedException (); }
177                 }
178
179                 object IDictionary.this [object keyword]
180                 {
181                         get { return this [(string) keyword]; }
182                         set { this [(string) keyword] = value; }
183                 }
184
185                 [Browsable (false)]
186                 public virtual ICollection Values {
187                         get {
188                                 object [] values = new object [_dictionary.Values.Count];
189                                 ((ICollection<object>) _dictionary.Values).CopyTo (values, 0);
190                                 ReadOnlyCollection<object> valuesColl = new ReadOnlyCollection<object> (values);
191                                 return valuesColl; 
192                         }
193                 }
194
195                 #endregion // Properties
196
197                 #region Methods
198
199                 public void Add (string keyword, object value)
200                 {
201                         this [keyword] = value;
202                 }
203
204                 public static void AppendKeyValuePair (StringBuilder builder, string keyword, string value,
205                                                        bool useOdbcRules)
206                 {
207                         if (builder == null)
208                                 throw new ArgumentNullException ("builder");
209                         if (keyword == null)
210                                 throw new ArgumentNullException ("keyName");
211                         if (keyword.Length == 0)
212                                 throw new ArgumentException ("Empty keyword is not valid.");
213
214                         if (builder.Length > 0)
215                                 builder.Append (';');
216                         if (!useOdbcRules)
217                                 builder.Append (keyword.Replace ("=", "=="));
218                         else
219                                 builder.Append (keyword);
220                         builder.Append ('=');
221
222                         if (value == null || value.Length == 0)
223                                 return;
224
225                         if (!useOdbcRules) {
226                                 bool dquoteFound = (value.IndexOf ('\"') > -1);
227                                 bool squoteFound = (value.IndexOf ('\'') > -1);
228         
229                                 if (dquoteFound && squoteFound) {
230                                         builder.Append ('\"');
231                                         builder.Append (value.Replace ("\"", "\"\""));
232                                         builder.Append ('\"');
233                                 } else if (dquoteFound) {
234                                         builder.Append ('\'');
235                                         builder.Append (value);
236                                         builder.Append ('\'');
237                                 } else if (squoteFound || value.IndexOf ('=') > -1 || value.IndexOf (';') > -1) {
238                                         builder.Append ('\"');
239                                         builder.Append (value);
240                                         builder.Append ('\"');
241                                 } else if (ValueNeedsQuoting (value)) {
242                                         builder.Append ('\"');
243                                         builder.Append (value);
244                                         builder.Append ('\"');
245                                 } else
246                                         builder.Append (value);
247                         } else {
248                                 int braces = 0;
249                                 bool semicolonFound = false;
250                                 int len = value.Length;
251                                 bool needBraces = false;
252
253                                 int lastChar = -1;
254
255                                 for (int i = 0; i < len; i++) {
256                                         int peek = 0;
257                                         if (i == (len - 1))
258                                                 peek = -1;
259                                         else
260                                                 peek = value [i + 1];
261
262                                         char c = value [i];
263                                         switch (c) {
264                                         case '{':
265                                                 braces++;
266                                                 break;
267                                         case '}':
268                                                 if (peek.Equals (c)) {
269                                                         i++;
270                                                         continue;
271                                                 } else {
272                                                         braces--;
273                                                         if (peek != -1)
274                                                                 needBraces = true;
275                                                 }
276                                                 break;
277                                         case ';':
278                                                 semicolonFound = true;
279                                                 break;
280                                         default:
281                                                 break;
282                                         }
283                                         lastChar = c;
284                                 }
285
286                                 if (value [0] == '{' && (lastChar != '}' || (braces == 0 && needBraces))) {
287                                         builder.Append ('{');
288                                         builder.Append (value.Replace ("}", "}}"));
289                                         builder.Append ('}');
290                                         return;
291                                 }
292
293                                 bool isDriver = (string.Compare (keyword, "Driver", StringComparison.InvariantCultureIgnoreCase) == 0);
294                                 if (isDriver) {
295                                         if (value [0] == '{' && lastChar == '}' && !needBraces) {
296                                                 builder.Append (value);
297                                                 return;
298                                         }
299                                         builder.Append ('{');
300                                         builder.Append (value.Replace ("}", "}}"));
301                                         builder.Append ('}');
302                                         return;
303                                 }
304
305                                 if (value [0] == '{' && (braces != 0 || lastChar != '}') && needBraces) {
306                                         builder.Append ('{');
307                                         builder.Append (value.Replace ("}", "}}"));
308                                         builder.Append ('}');
309                                         return;
310                                 }
311
312                                 if (value [0] != '{' && semicolonFound) {
313                                         builder.Append ('{');
314                                         builder.Append (value.Replace ("}", "}}"));
315                                         builder.Append ('}');
316                                         return;
317                                 }
318
319                                 builder.Append (value);
320                         }
321                 }
322
323                 public static void AppendKeyValuePair (StringBuilder builder, string keyword, string value)
324                 {
325                         AppendKeyValuePair (builder, keyword, value, false);
326                 }
327
328                 public virtual void Clear ()
329                 {
330                         _dictionary.Clear ();
331                 }
332
333                 public virtual bool ContainsKey (string keyword)
334                 {
335                         if (keyword == null)
336                                 throw new ArgumentNullException ("keyword");
337                         return _dictionary.ContainsKey (keyword);
338                 }
339
340                 public virtual bool EquivalentTo (DbConnectionStringBuilder connectionStringBuilder)
341                 {
342                         bool ret = true;
343                         try {
344                                 if (Count != connectionStringBuilder.Count)
345                                         ret = false;
346                                 else {
347                                         foreach (string key in Keys) {
348                                                 if (!this [key].Equals (connectionStringBuilder [key])) {
349                                                         ret = false;
350                                                         break;
351                                                 }
352                                         }
353                                 }
354                         } catch (ArgumentException) {
355                                 ret = false;
356                         }
357                         return ret;
358                 }
359
360                 [MonoTODO]
361                 protected virtual void GetProperties (Hashtable propertyDescriptors)
362                 {
363                         throw new NotImplementedException ();
364                 }
365
366                 [MonoTODO]
367                 protected internal void ClearPropertyDescriptors ()
368                 {
369                         throw new NotImplementedException ();
370                 }
371
372                 public virtual bool Remove (string keyword)
373                 {
374                         if (keyword == null)
375                                 throw new ArgumentNullException ("keyword");
376                         return _dictionary.Remove (keyword);
377                 }
378
379                 public virtual bool ShouldSerialize (string keyword)
380                 {
381                         throw new NotImplementedException ();
382                 }
383
384                 void ICollection.CopyTo (Array array, int index)
385                 {
386                         if (array == null)
387                                 throw new ArgumentNullException ("array");
388                         KeyValuePair<string, object> [] arr = array as KeyValuePair<string, object> [];
389                         if (arr == null)
390                                 throw new ArgumentException ("Target array type is not compatible with the type of items in the collection");
391                         ((ICollection<KeyValuePair<string, object>>) _dictionary).CopyTo (arr, index);
392                 }
393
394                 void IDictionary.Add (object keyword, object value)
395                 {
396                         this.Add ((string) keyword, value);
397                 }
398
399                 bool IDictionary.Contains (object keyword)
400                 {
401                         return ContainsKey ((string) keyword);
402                 }
403
404                 IDictionaryEnumerator IDictionary.GetEnumerator ()
405                 {
406                         return (IDictionaryEnumerator) _dictionary.GetEnumerator ();
407                 }
408
409                 void IDictionary.Remove (object keyword)
410                 {
411                         Remove ((string) keyword);
412                 }
413
414                 IEnumerator IEnumerable.GetEnumerator ()
415                 {
416                         return (IEnumerator) _dictionary.GetEnumerator ();
417                 }
418
419                 private static object _staticAttributeCollection = null;
420                 AttributeCollection ICustomTypeDescriptor.GetAttributes ()
421                 {
422                         object value = _staticAttributeCollection;
423                         if (value == null) {
424                                 CLSCompliantAttribute clsAttr = new CLSCompliantAttribute (true);
425                                 DefaultMemberAttribute defMemAttr = new DefaultMemberAttribute ("Item");
426                                 Attribute [] attrs = {clsAttr, defMemAttr};
427                                 value = new AttributeCollection (attrs);
428                         }
429                         System.Threading.Interlocked.CompareExchange (ref _staticAttributeCollection, value, null);
430                         return _staticAttributeCollection as AttributeCollection;
431                 }
432
433                 string ICustomTypeDescriptor.GetClassName ()
434                 {
435                         return this.GetType ().ToString ();
436                 }
437
438                 string ICustomTypeDescriptor.GetComponentName ()
439                 {
440                         return null;
441                 }
442
443                 TypeConverter ICustomTypeDescriptor.GetConverter ()
444                 {
445                         return new CollectionConverter ();
446                 }
447
448                 EventDescriptor ICustomTypeDescriptor.GetDefaultEvent ()
449                 {
450                         return null;
451                 }
452
453                 PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty ()
454                 {
455                         return null;
456                 }
457
458                 object ICustomTypeDescriptor.GetEditor (Type editorBaseType)
459                 {
460                         return null;
461                 }
462
463                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents ()
464                 {
465                         return EventDescriptorCollection.Empty;
466                 }
467
468                 EventDescriptorCollection ICustomTypeDescriptor.GetEvents (Attribute [] attributes)
469                 {
470                         return EventDescriptorCollection.Empty;
471                 }
472
473                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties ()
474                 {
475                         return PropertyDescriptorCollection.Empty;
476                 }
477
478                 PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties (Attribute [] attributes)
479                 {
480                         return PropertyDescriptorCollection.Empty;
481                 }
482
483                 object ICustomTypeDescriptor.GetPropertyOwner (PropertyDescriptor pd)
484                 {
485                         throw new NotImplementedException ();
486                 }
487
488                 public override string ToString ()
489                 {
490                         return ConnectionString;
491                 }
492
493                 public virtual bool TryGetValue (string keyword, out object value)
494                 {
495                         // FIXME : not sure, difference between this [keyword] and this method
496                         bool found = ContainsKey (keyword);
497                         if (found)
498                                 value = this [keyword];
499                         else
500                                 value = null;
501                         return found;
502                 }
503
504                 static ArgumentException CreateInvalidKeywordException (string keyword)
505                 {
506                         return new ArgumentException ("A keyword cannot contain "
507                                 + "control characters, leading semicolons or "
508                                 + "leading or trailing whitespace.", keyword);
509                 }
510
511                 static ArgumentException CreateConnectionStringInvalidException (int index)
512                 {
513                         return new ArgumentException ("Format of initialization "
514                                 + "string does not conform to specifications at "
515                                 + "index " + index + ".");
516                 }
517
518                 static bool ValueNeedsQuoting (string value)
519                 {
520                         foreach (char c in value) {
521                                 if (char.IsWhiteSpace (c))
522                                         return true;
523                         }
524                         return false;
525                 }
526                 void ParseConnectionString (string connectionString)
527                 {
528                         if (useOdbcRules)
529                                 ParseConnectionStringOdbc (connectionString);
530                         else
531                                 ParseConnectionStringNonOdbc (connectionString);
532                 }
533
534                 void ParseConnectionStringOdbc (string connectionString)
535                 {
536                         bool inQuote = false;
537                         bool inDQuote = false;
538                         bool inName = true;
539                         bool inBraces = false;
540
541                         string name = String.Empty;
542                         string val = String.Empty;
543                         StringBuilder sb = new StringBuilder ();
544                         int len = connectionString.Length;
545
546                         for (int i = 0; i < len; i++) {
547                                 char c = connectionString [i];
548                                 int peek = (i == (len - 1)) ? -1 : connectionString [i + 1];
549
550                                 switch (c) {
551                                 case '{':
552                                         if (inName) {
553                                                 sb.Append (c);
554                                                 continue;
555                                         }
556
557                                         if (sb.Length == 0)
558                                                 inBraces = true;
559                                         sb.Append (c);
560                                         break;
561                                 case '}':
562                                         if (inName || !inBraces) {
563                                                 sb.Append (c);
564                                                 continue;
565                                         }
566
567                                         if (peek == -1) {
568                                                 sb.Append (c);
569                                                 inBraces = false;
570                                         } else if (peek.Equals (c)) {
571                                                 sb.Append (c);
572                                                 sb.Append (c);
573                                                 i++;
574                                         } else {
575                                                 int next = NextNonWhitespaceChar (connectionString, i);
576                                                 if (next != -1 && ((char) next) != ';')
577                                                         throw CreateConnectionStringInvalidException (next);
578                                                 sb.Append (c);
579                                                 inBraces = false;
580                                         }
581                                         break;
582                                 case ';':
583                                         if (inName || inBraces) {
584                                                 sb.Append (c);
585                                                 continue;
586                                         }
587
588                                         if (name.Length > 0 && sb.Length > 0) {
589                                                 val = sb.ToString ();
590                                                 name = name.ToLower ().TrimEnd ();
591                                                 this [name] = val;
592                                         } else if (sb.Length > 0)
593                                                 throw CreateConnectionStringInvalidException (c);
594                                         inName = true;
595                                         name = String.Empty;
596                                         sb.Length = 0;
597                                         break;
598                                 case '=':
599                                         if (inBraces || !inName) {
600                                                 sb.Append (c);
601                                                 continue;
602                                         }
603
604                                         name = sb.ToString ();
605                                         if (name.Length == 0)
606                                                 throw CreateConnectionStringInvalidException (c);
607                                         sb.Length = 0;
608                                         inName = false;
609                                         break;
610                                 default:
611                                         if (inDQuote || inQuote || inBraces)
612                                                 sb.Append (c);
613                                         else if (char.IsWhiteSpace (c)) {
614                                                 // ignore leading whitespace
615                                                 if (sb.Length > 0) {
616                                                         int nextChar = SkipTrailingWhitespace (connectionString, i);
617                                                         if (nextChar == -1)
618                                                                 sb.Append (c);
619                                                         else
620                                                                 i = nextChar;
621                                                 }
622                                         } else
623                                                 sb.Append (c);
624                                         break;
625                                 }
626                         }
627
628                         if ((inName && sb.Length > 0) || inDQuote || inQuote || inBraces)
629                                 throw CreateConnectionStringInvalidException (len - 1);
630
631                         if (name.Length > 0 && sb.Length > 0) {
632                                 val = sb.ToString ();
633                                 name = name.ToLower ().TrimEnd ();
634                                 this [name] = val;
635                         }
636                 }
637
638                 void ParseConnectionStringNonOdbc (string connectionString)
639                 {
640                         bool inQuote = false;
641                         bool inDQuote = false;
642                         bool inName = true;
643
644                         string name = String.Empty;
645                         string val = String.Empty;
646                         StringBuilder sb = new StringBuilder ();
647                         int len = connectionString.Length;
648
649                         for (int i = 0; i < len; i++) {
650                                 char c = connectionString [i];
651                                 int peek = (i == (len - 1)) ? -1 : connectionString [i + 1];
652
653                                 switch (c) {
654                                 case '\'':
655                                         if (inName) {
656                                                 sb.Append (c);
657                                                 continue;
658                                         }
659
660                                         if (inDQuote)
661                                                 sb.Append (c);
662                                         else if (inQuote) {
663                                                 if (peek == -1)
664                                                         inQuote = false;
665                                                 else if (peek.Equals (c)) {
666                                                         sb.Append (c);
667                                                         i++;
668                                                 } else {
669                                                         int next = NextNonWhitespaceChar (connectionString, i);
670                                                         if (next != -1 && ((char) next) != ';')
671                                                                 throw CreateConnectionStringInvalidException (next);
672                                                         inQuote = false;
673                                                 }
674
675                                                 if (!inQuote) {
676                                                         val = sb.ToString ();
677                                                         name = name.ToLower ().TrimEnd ();
678                                                         this [name] = val;
679                                                         inName = true;
680                                                         name = String.Empty;
681                                                         sb.Length = 0;
682                                                 }
683                                         } else if (sb.Length == 0)
684                                                 inQuote = true;
685                                         else
686                                                 sb.Append (c);
687                                         break;
688                                 case '"':
689                                         if (inName) {
690                                                 sb.Append (c);
691                                                 continue;
692                                         }
693
694                                         if (inQuote)
695                                                 sb.Append (c);
696                                         else if (inDQuote) {
697                                                 if (peek == -1)
698                                                         inDQuote = false;
699                                                 else if (peek.Equals (c)) {
700                                                         sb.Append (c);
701                                                         i++;
702                                                 } else {
703                                                         int next = NextNonWhitespaceChar (connectionString, i);
704                                                         if (next != -1 && ((char) next) != ';')
705                                                                 throw CreateConnectionStringInvalidException (next);
706                                                         inDQuote = false;
707                                                 }
708                                         } else if (sb.Length == 0)
709                                                 inDQuote = true;
710                                         else
711                                                 sb.Append (c);
712                                         break;
713                                 case ';':
714                                         if (inName) {
715                                                 sb.Append (c);
716                                                 continue;
717                                         }
718
719                                         if (inDQuote || inQuote)
720                                                 sb.Append (c);
721                                         else {
722                                                 if (name.Length > 0 && sb.Length > 0) {
723                                                         val = sb.ToString ();
724                                                         name = name.ToLower ().TrimEnd ();
725                                                         this [name] = val;
726                                                 } else if (sb.Length > 0)
727                                                         throw CreateConnectionStringInvalidException (c);
728                                                 inName = true;
729                                                 name = String.Empty;
730                                                 sb.Length = 0;
731                                         }
732                                         break;
733                                 case '=':
734                                         if (inDQuote || inQuote || !inName)
735                                                 sb.Append (c);
736                                         else if (peek != -1 && peek.Equals (c)) {
737                                                 sb.Append (c);
738                                                 i++;
739                                         } else {
740                                                 name = sb.ToString ();
741                                                 if (name.Length == 0)
742                                                         throw CreateConnectionStringInvalidException (c);
743                                                 sb.Length = 0;
744                                                 inName = false;
745                                         }
746                                         break;
747                                 default:
748                                         if (inDQuote || inQuote)
749                                                 sb.Append (c);
750                                         else if (char.IsWhiteSpace (c)) {
751                                                 // ignore leading whitespace
752                                                 if (sb.Length > 0) {
753                                                         int nextChar = SkipTrailingWhitespace (connectionString, i);
754                                                         if (nextChar == -1)
755                                                                 sb.Append (c);
756                                                         else
757                                                                 i = nextChar;
758                                                 }
759                                         } else
760                                                 sb.Append (c);
761                                         break;
762                                 }
763                         }
764
765                         if ((inName && sb.Length > 0) || inDQuote || inQuote)
766                                 throw CreateConnectionStringInvalidException (len -1);
767
768                         if (name.Length > 0 && sb.Length > 0) {
769                                 val = sb.ToString ();
770                                 name = name.ToLower ().TrimEnd ();
771                                 this [name] = val;
772                         }
773                 }
774
775                 static int SkipTrailingWhitespace (string value, int index)
776                 {
777                         int len = value.Length;
778                         for (int i = (index + 1); i < len; i++) {
779                                 char c = value [i];
780                                 if (c == ';')
781                                         return (i - 1);
782                                 if (!char.IsWhiteSpace (c))
783                                         return -1;
784                         }
785                         return len - 1;
786                 }
787
788                 static int NextNonWhitespaceChar (string value, int index)
789                 {
790                         int len = value.Length;
791                         for (int i = (index + 1); i < len; i++) {
792                                 char c = value [i];
793                                 if (!char.IsWhiteSpace (c))
794                                         return (int) c;
795                         }
796                         return -1;
797                 }
798
799                 #endregion // Public Methods
800         }
801 }
802 #endif // NET_2_0 using