a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
803 lines
22 KiB
C#
803 lines
22 KiB
C#
//
|
|
// System.Data.Common.DbConnectionStringBuilder.cs
|
|
//
|
|
// Author:
|
|
// Sureshkumar T (tsureshkumar@novell.com)
|
|
// Gert Driesen (drieseng@users.sourceforge.net
|
|
//
|
|
// Copyright (C) 2004 Novell, Inc (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.
|
|
//
|
|
|
|
#if NET_2_0
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Data.Common;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
|
|
namespace System.Data.Common
|
|
{
|
|
public class DbConnectionStringBuilder : IDictionary, ICollection, IEnumerable, ICustomTypeDescriptor
|
|
{
|
|
#region Fields
|
|
|
|
readonly Dictionary<string, object> _dictionary;
|
|
readonly bool useOdbcRules;
|
|
|
|
#endregion Fields
|
|
|
|
#region Constructors
|
|
|
|
public DbConnectionStringBuilder () : this (false)
|
|
{
|
|
}
|
|
|
|
public DbConnectionStringBuilder (bool useOdbcRules)
|
|
{
|
|
this.useOdbcRules = useOdbcRules;
|
|
_dictionary = new Dictionary <string, object> (StringComparer.InvariantCultureIgnoreCase);
|
|
}
|
|
|
|
#endregion // Constructors
|
|
|
|
#region Properties
|
|
|
|
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
|
|
[EditorBrowsable (EditorBrowsableState.Never)]
|
|
[Browsable (false)]
|
|
[DesignOnly (true)]
|
|
public bool BrowsableConnectionString {
|
|
get { throw new NotImplementedException (); }
|
|
set { throw new NotImplementedException (); }
|
|
}
|
|
|
|
[RefreshProperties (RefreshProperties.All)]
|
|
public string ConnectionString {
|
|
get {
|
|
IDictionary<string, object> dictionary = (IDictionary <string, object>) _dictionary;
|
|
StringBuilder sb = new StringBuilder ();
|
|
foreach (string key in Keys) {
|
|
object value = null;
|
|
if (!dictionary.TryGetValue (key, out value))
|
|
continue;
|
|
string val = value.ToString ();
|
|
AppendKeyValuePair (sb, key, val, useOdbcRules);
|
|
}
|
|
return sb.ToString ();
|
|
}
|
|
set {
|
|
Clear ();
|
|
if (value == null)
|
|
return;
|
|
if (value.Trim ().Length == 0)
|
|
return;
|
|
ParseConnectionString (value);
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual int Count
|
|
{
|
|
get { return _dictionary.Count; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual bool IsFixedSize
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public bool IsReadOnly
|
|
{
|
|
get { throw new NotImplementedException (); }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual object this [string keyword] {
|
|
get {
|
|
if (ContainsKey (keyword))
|
|
return _dictionary [keyword];
|
|
else
|
|
throw new ArgumentException (string.Format (
|
|
"Keyword '{0}' does not exist",
|
|
keyword));
|
|
}
|
|
set {
|
|
if (value == null) {
|
|
Remove (keyword);
|
|
return;
|
|
}
|
|
|
|
if (keyword == null)
|
|
throw new ArgumentNullException ("keyword");
|
|
|
|
if (keyword.Length == 0)
|
|
throw CreateInvalidKeywordException (keyword);
|
|
|
|
for (int i = 0; i < keyword.Length; i++) {
|
|
char c = keyword [i];
|
|
if (i == 0 && (Char.IsWhiteSpace (c) || c == ';'))
|
|
throw CreateInvalidKeywordException (keyword);
|
|
if (i == (keyword.Length - 1) && Char.IsWhiteSpace (c))
|
|
throw CreateInvalidKeywordException (keyword);
|
|
if (Char.IsControl (c))
|
|
throw CreateInvalidKeywordException (keyword);
|
|
}
|
|
|
|
if (ContainsKey (keyword))
|
|
_dictionary [keyword] = value;
|
|
else
|
|
_dictionary.Add (keyword, value);
|
|
}
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual ICollection Keys
|
|
{
|
|
get {
|
|
string [] keys = new string [_dictionary.Keys.Count];
|
|
((ICollection<string>) _dictionary.Keys).CopyTo (keys, 0);
|
|
ReadOnlyCollection<string> keyColl = new ReadOnlyCollection<string> (keys);
|
|
return keyColl;
|
|
}
|
|
}
|
|
|
|
bool ICollection.IsSynchronized
|
|
{
|
|
get { throw new NotImplementedException (); }
|
|
}
|
|
|
|
object ICollection.SyncRoot
|
|
{
|
|
get { throw new NotImplementedException (); }
|
|
}
|
|
|
|
object IDictionary.this [object keyword]
|
|
{
|
|
get { return this [(string) keyword]; }
|
|
set { this [(string) keyword] = value; }
|
|
}
|
|
|
|
[Browsable (false)]
|
|
public virtual ICollection Values {
|
|
get {
|
|
object [] values = new object [_dictionary.Values.Count];
|
|
((ICollection<object>) _dictionary.Values).CopyTo (values, 0);
|
|
ReadOnlyCollection<object> valuesColl = new ReadOnlyCollection<object> (values);
|
|
return valuesColl;
|
|
}
|
|
}
|
|
|
|
#endregion // Properties
|
|
|
|
#region Methods
|
|
|
|
public void Add (string keyword, object value)
|
|
{
|
|
this [keyword] = value;
|
|
}
|
|
|
|
public static void AppendKeyValuePair (StringBuilder builder, string keyword, string value,
|
|
bool useOdbcRules)
|
|
{
|
|
if (builder == null)
|
|
throw new ArgumentNullException ("builder");
|
|
if (keyword == null)
|
|
throw new ArgumentNullException ("keyName");
|
|
if (keyword.Length == 0)
|
|
throw new ArgumentException ("Empty keyword is not valid.");
|
|
|
|
if (builder.Length > 0)
|
|
builder.Append (';');
|
|
if (!useOdbcRules)
|
|
builder.Append (keyword.Replace ("=", "=="));
|
|
else
|
|
builder.Append (keyword);
|
|
builder.Append ('=');
|
|
|
|
if (value == null || value.Length == 0)
|
|
return;
|
|
|
|
if (!useOdbcRules) {
|
|
bool dquoteFound = (value.IndexOf ('\"') > -1);
|
|
bool squoteFound = (value.IndexOf ('\'') > -1);
|
|
|
|
if (dquoteFound && squoteFound) {
|
|
builder.Append ('\"');
|
|
builder.Append (value.Replace ("\"", "\"\""));
|
|
builder.Append ('\"');
|
|
} else if (dquoteFound) {
|
|
builder.Append ('\'');
|
|
builder.Append (value);
|
|
builder.Append ('\'');
|
|
} else if (squoteFound || value.IndexOf ('=') > -1 || value.IndexOf (';') > -1) {
|
|
builder.Append ('\"');
|
|
builder.Append (value);
|
|
builder.Append ('\"');
|
|
} else if (ValueNeedsQuoting (value)) {
|
|
builder.Append ('\"');
|
|
builder.Append (value);
|
|
builder.Append ('\"');
|
|
} else
|
|
builder.Append (value);
|
|
} else {
|
|
int braces = 0;
|
|
bool semicolonFound = false;
|
|
int len = value.Length;
|
|
bool needBraces = false;
|
|
|
|
int lastChar = -1;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
int peek = 0;
|
|
if (i == (len - 1))
|
|
peek = -1;
|
|
else
|
|
peek = value [i + 1];
|
|
|
|
char c = value [i];
|
|
switch (c) {
|
|
case '{':
|
|
braces++;
|
|
break;
|
|
case '}':
|
|
if (peek.Equals (c)) {
|
|
i++;
|
|
continue;
|
|
} else {
|
|
braces--;
|
|
if (peek != -1)
|
|
needBraces = true;
|
|
}
|
|
break;
|
|
case ';':
|
|
semicolonFound = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
lastChar = c;
|
|
}
|
|
|
|
if (value [0] == '{' && (lastChar != '}' || (braces == 0 && needBraces))) {
|
|
builder.Append ('{');
|
|
builder.Append (value.Replace ("}", "}}"));
|
|
builder.Append ('}');
|
|
return;
|
|
}
|
|
|
|
bool isDriver = (string.Compare (keyword, "Driver", StringComparison.InvariantCultureIgnoreCase) == 0);
|
|
if (isDriver) {
|
|
if (value [0] == '{' && lastChar == '}' && !needBraces) {
|
|
builder.Append (value);
|
|
return;
|
|
}
|
|
builder.Append ('{');
|
|
builder.Append (value.Replace ("}", "}}"));
|
|
builder.Append ('}');
|
|
return;
|
|
}
|
|
|
|
if (value [0] == '{' && (braces != 0 || lastChar != '}') && needBraces) {
|
|
builder.Append ('{');
|
|
builder.Append (value.Replace ("}", "}}"));
|
|
builder.Append ('}');
|
|
return;
|
|
}
|
|
|
|
if (value [0] != '{' && semicolonFound) {
|
|
builder.Append ('{');
|
|
builder.Append (value.Replace ("}", "}}"));
|
|
builder.Append ('}');
|
|
return;
|
|
}
|
|
|
|
builder.Append (value);
|
|
}
|
|
}
|
|
|
|
public static void AppendKeyValuePair (StringBuilder builder, string keyword, string value)
|
|
{
|
|
AppendKeyValuePair (builder, keyword, value, false);
|
|
}
|
|
|
|
public virtual void Clear ()
|
|
{
|
|
_dictionary.Clear ();
|
|
}
|
|
|
|
public virtual bool ContainsKey (string keyword)
|
|
{
|
|
if (keyword == null)
|
|
throw new ArgumentNullException ("keyword");
|
|
return _dictionary.ContainsKey (keyword);
|
|
}
|
|
|
|
public virtual bool EquivalentTo (DbConnectionStringBuilder connectionStringBuilder)
|
|
{
|
|
bool ret = true;
|
|
try {
|
|
if (Count != connectionStringBuilder.Count)
|
|
ret = false;
|
|
else {
|
|
foreach (string key in Keys) {
|
|
if (!this [key].Equals (connectionStringBuilder [key])) {
|
|
ret = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch (ArgumentException) {
|
|
ret = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
[MonoTODO]
|
|
protected virtual void GetProperties (Hashtable propertyDescriptors)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[MonoTODO]
|
|
protected internal void ClearPropertyDescriptors ()
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
public virtual bool Remove (string keyword)
|
|
{
|
|
if (keyword == null)
|
|
throw new ArgumentNullException ("keyword");
|
|
return _dictionary.Remove (keyword);
|
|
}
|
|
|
|
public virtual bool ShouldSerialize (string keyword)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
void ICollection.CopyTo (Array array, int index)
|
|
{
|
|
if (array == null)
|
|
throw new ArgumentNullException ("array");
|
|
KeyValuePair<string, object> [] arr = array as KeyValuePair<string, object> [];
|
|
if (arr == null)
|
|
throw new ArgumentException ("Target array type is not compatible with the type of items in the collection");
|
|
((ICollection<KeyValuePair<string, object>>) _dictionary).CopyTo (arr, index);
|
|
}
|
|
|
|
void IDictionary.Add (object keyword, object value)
|
|
{
|
|
this.Add ((string) keyword, value);
|
|
}
|
|
|
|
bool IDictionary.Contains (object keyword)
|
|
{
|
|
return ContainsKey ((string) keyword);
|
|
}
|
|
|
|
IDictionaryEnumerator IDictionary.GetEnumerator ()
|
|
{
|
|
return (IDictionaryEnumerator) _dictionary.GetEnumerator ();
|
|
}
|
|
|
|
void IDictionary.Remove (object keyword)
|
|
{
|
|
Remove ((string) keyword);
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator ()
|
|
{
|
|
return (IEnumerator) _dictionary.GetEnumerator ();
|
|
}
|
|
|
|
private static object _staticAttributeCollection = null;
|
|
AttributeCollection ICustomTypeDescriptor.GetAttributes ()
|
|
{
|
|
object value = _staticAttributeCollection;
|
|
if (value == null) {
|
|
CLSCompliantAttribute clsAttr = new CLSCompliantAttribute (true);
|
|
DefaultMemberAttribute defMemAttr = new DefaultMemberAttribute ("Item");
|
|
Attribute [] attrs = {clsAttr, defMemAttr};
|
|
value = new AttributeCollection (attrs);
|
|
}
|
|
System.Threading.Interlocked.CompareExchange (ref _staticAttributeCollection, value, null);
|
|
return _staticAttributeCollection as AttributeCollection;
|
|
}
|
|
|
|
string ICustomTypeDescriptor.GetClassName ()
|
|
{
|
|
return this.GetType ().ToString ();
|
|
}
|
|
|
|
string ICustomTypeDescriptor.GetComponentName ()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
TypeConverter ICustomTypeDescriptor.GetConverter ()
|
|
{
|
|
return new CollectionConverter ();
|
|
}
|
|
|
|
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent ()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty ()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
object ICustomTypeDescriptor.GetEditor (Type editorBaseType)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
EventDescriptorCollection ICustomTypeDescriptor.GetEvents ()
|
|
{
|
|
return EventDescriptorCollection.Empty;
|
|
}
|
|
|
|
EventDescriptorCollection ICustomTypeDescriptor.GetEvents (Attribute [] attributes)
|
|
{
|
|
return EventDescriptorCollection.Empty;
|
|
}
|
|
|
|
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties ()
|
|
{
|
|
return PropertyDescriptorCollection.Empty;
|
|
}
|
|
|
|
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties (Attribute [] attributes)
|
|
{
|
|
return PropertyDescriptorCollection.Empty;
|
|
}
|
|
|
|
object ICustomTypeDescriptor.GetPropertyOwner (PropertyDescriptor pd)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
public override string ToString ()
|
|
{
|
|
return ConnectionString;
|
|
}
|
|
|
|
public virtual bool TryGetValue (string keyword, out object value)
|
|
{
|
|
// FIXME : not sure, difference between this [keyword] and this method
|
|
bool found = ContainsKey (keyword);
|
|
if (found)
|
|
value = this [keyword];
|
|
else
|
|
value = null;
|
|
return found;
|
|
}
|
|
|
|
static ArgumentException CreateInvalidKeywordException (string keyword)
|
|
{
|
|
return new ArgumentException ("A keyword cannot contain "
|
|
+ "control characters, leading semicolons or "
|
|
+ "leading or trailing whitespace.", keyword);
|
|
}
|
|
|
|
static ArgumentException CreateConnectionStringInvalidException (int index)
|
|
{
|
|
return new ArgumentException ("Format of initialization "
|
|
+ "string does not conform to specifications at "
|
|
+ "index " + index + ".");
|
|
}
|
|
|
|
static bool ValueNeedsQuoting (string value)
|
|
{
|
|
foreach (char c in value) {
|
|
if (char.IsWhiteSpace (c))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void ParseConnectionString (string connectionString)
|
|
{
|
|
if (useOdbcRules)
|
|
ParseConnectionStringOdbc (connectionString);
|
|
else
|
|
ParseConnectionStringNonOdbc (connectionString);
|
|
}
|
|
|
|
void ParseConnectionStringOdbc (string connectionString)
|
|
{
|
|
bool inQuote = false;
|
|
bool inDQuote = false;
|
|
bool inName = true;
|
|
bool inBraces = false;
|
|
|
|
string name = String.Empty;
|
|
string val = String.Empty;
|
|
StringBuilder sb = new StringBuilder ();
|
|
int len = connectionString.Length;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
char c = connectionString [i];
|
|
int peek = (i == (len - 1)) ? -1 : connectionString [i + 1];
|
|
|
|
switch (c) {
|
|
case '{':
|
|
if (inName) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
if (sb.Length == 0)
|
|
inBraces = true;
|
|
sb.Append (c);
|
|
break;
|
|
case '}':
|
|
if (inName || !inBraces) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
if (peek == -1) {
|
|
sb.Append (c);
|
|
inBraces = false;
|
|
} else if (peek.Equals (c)) {
|
|
sb.Append (c);
|
|
sb.Append (c);
|
|
i++;
|
|
} else {
|
|
int next = NextNonWhitespaceChar (connectionString, i);
|
|
if (next != -1 && ((char) next) != ';')
|
|
throw CreateConnectionStringInvalidException (next);
|
|
sb.Append (c);
|
|
inBraces = false;
|
|
}
|
|
break;
|
|
case ';':
|
|
if (inName || inBraces) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
if (name.Length > 0 && sb.Length > 0) {
|
|
val = sb.ToString ();
|
|
name = name.ToLower ().TrimEnd ();
|
|
this [name] = val;
|
|
} else if (sb.Length > 0)
|
|
throw CreateConnectionStringInvalidException (c);
|
|
inName = true;
|
|
name = String.Empty;
|
|
sb.Length = 0;
|
|
break;
|
|
case '=':
|
|
if (inBraces || !inName) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
name = sb.ToString ();
|
|
if (name.Length == 0)
|
|
throw CreateConnectionStringInvalidException (c);
|
|
sb.Length = 0;
|
|
inName = false;
|
|
break;
|
|
default:
|
|
if (inDQuote || inQuote || inBraces)
|
|
sb.Append (c);
|
|
else if (char.IsWhiteSpace (c)) {
|
|
// ignore leading whitespace
|
|
if (sb.Length > 0) {
|
|
int nextChar = SkipTrailingWhitespace (connectionString, i);
|
|
if (nextChar == -1)
|
|
sb.Append (c);
|
|
else
|
|
i = nextChar;
|
|
}
|
|
} else
|
|
sb.Append (c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((inName && sb.Length > 0) || inDQuote || inQuote || inBraces)
|
|
throw CreateConnectionStringInvalidException (len - 1);
|
|
|
|
if (name.Length > 0 && sb.Length > 0) {
|
|
val = sb.ToString ();
|
|
name = name.ToLower ().TrimEnd ();
|
|
this [name] = val;
|
|
}
|
|
}
|
|
|
|
void ParseConnectionStringNonOdbc (string connectionString)
|
|
{
|
|
bool inQuote = false;
|
|
bool inDQuote = false;
|
|
bool inName = true;
|
|
|
|
string name = String.Empty;
|
|
string val = String.Empty;
|
|
StringBuilder sb = new StringBuilder ();
|
|
int len = connectionString.Length;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
char c = connectionString [i];
|
|
int peek = (i == (len - 1)) ? -1 : connectionString [i + 1];
|
|
|
|
switch (c) {
|
|
case '\'':
|
|
if (inName) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
if (inDQuote)
|
|
sb.Append (c);
|
|
else if (inQuote) {
|
|
if (peek == -1)
|
|
inQuote = false;
|
|
else if (peek.Equals (c)) {
|
|
sb.Append (c);
|
|
i++;
|
|
} else {
|
|
int next = NextNonWhitespaceChar (connectionString, i);
|
|
if (next != -1 && ((char) next) != ';')
|
|
throw CreateConnectionStringInvalidException (next);
|
|
inQuote = false;
|
|
}
|
|
|
|
if (!inQuote) {
|
|
val = sb.ToString ();
|
|
name = name.ToLower ().TrimEnd ();
|
|
this [name] = val;
|
|
inName = true;
|
|
name = String.Empty;
|
|
sb.Length = 0;
|
|
}
|
|
} else if (sb.Length == 0)
|
|
inQuote = true;
|
|
else
|
|
sb.Append (c);
|
|
break;
|
|
case '"':
|
|
if (inName) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
if (inQuote)
|
|
sb.Append (c);
|
|
else if (inDQuote) {
|
|
if (peek == -1)
|
|
inDQuote = false;
|
|
else if (peek.Equals (c)) {
|
|
sb.Append (c);
|
|
i++;
|
|
} else {
|
|
int next = NextNonWhitespaceChar (connectionString, i);
|
|
if (next != -1 && ((char) next) != ';')
|
|
throw CreateConnectionStringInvalidException (next);
|
|
inDQuote = false;
|
|
}
|
|
} else if (sb.Length == 0)
|
|
inDQuote = true;
|
|
else
|
|
sb.Append (c);
|
|
break;
|
|
case ';':
|
|
if (inName) {
|
|
sb.Append (c);
|
|
continue;
|
|
}
|
|
|
|
if (inDQuote || inQuote)
|
|
sb.Append (c);
|
|
else {
|
|
if (name.Length > 0 && sb.Length > 0) {
|
|
val = sb.ToString ();
|
|
name = name.ToLower ().TrimEnd ();
|
|
this [name] = val;
|
|
} else if (sb.Length > 0)
|
|
throw CreateConnectionStringInvalidException (c);
|
|
inName = true;
|
|
name = String.Empty;
|
|
sb.Length = 0;
|
|
}
|
|
break;
|
|
case '=':
|
|
if (inDQuote || inQuote || !inName)
|
|
sb.Append (c);
|
|
else if (peek != -1 && peek.Equals (c)) {
|
|
sb.Append (c);
|
|
i++;
|
|
} else {
|
|
name = sb.ToString ();
|
|
if (name.Length == 0)
|
|
throw CreateConnectionStringInvalidException (c);
|
|
sb.Length = 0;
|
|
inName = false;
|
|
}
|
|
break;
|
|
default:
|
|
if (inDQuote || inQuote)
|
|
sb.Append (c);
|
|
else if (char.IsWhiteSpace (c)) {
|
|
// ignore leading whitespace
|
|
if (sb.Length > 0) {
|
|
int nextChar = SkipTrailingWhitespace (connectionString, i);
|
|
if (nextChar == -1)
|
|
sb.Append (c);
|
|
else
|
|
i = nextChar;
|
|
}
|
|
} else
|
|
sb.Append (c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((inName && sb.Length > 0) || inDQuote || inQuote)
|
|
throw CreateConnectionStringInvalidException (len -1);
|
|
|
|
if (name.Length > 0 && sb.Length > 0) {
|
|
val = sb.ToString ();
|
|
name = name.ToLower ().TrimEnd ();
|
|
this [name] = val;
|
|
}
|
|
}
|
|
|
|
static int SkipTrailingWhitespace (string value, int index)
|
|
{
|
|
int len = value.Length;
|
|
for (int i = (index + 1); i < len; i++) {
|
|
char c = value [i];
|
|
if (c == ';')
|
|
return (i - 1);
|
|
if (!char.IsWhiteSpace (c))
|
|
return -1;
|
|
}
|
|
return len - 1;
|
|
}
|
|
|
|
static int NextNonWhitespaceChar (string value, int index)
|
|
{
|
|
int len = value.Length;
|
|
for (int i = (index + 1); i < len; i++) {
|
|
char c = value [i];
|
|
if (!char.IsWhiteSpace (c))
|
|
return (int) c;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#endregion // Public Methods
|
|
}
|
|
}
|
|
#endif // NET_2_0 using
|