//
// 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
|