DbConnectionOptions.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / Common / DbConnectionOptions.cs / 1305376 / DbConnectionOptions.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.Common {
 
    using System;
    using System.Collections;
    using System.Data;
#if ORACLE 
    using System.Data.OracleClient;
#endif //ORACLE 
    using System.Diagnostics; 
    using System.Globalization;
    using System.Runtime.Serialization; 
    using System.Security.Permissions;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Runtime.Versioning; 

    internal class DbConnectionOptions { 
        // instances of this class are intended to be immutable, i.e readonly 
        // used by pooling classes so it is much easier to verify correctness
        // when not worried about the class being modified during execution 

#if DEBUG
        /*private const string ConnectionStringPatternV1 =
             "[\\s;]*" 
            +"(?([^=\\s]|\\s+[^=\\s]|\\s+==|==)+)"
            +   "\\s*=(?!=)\\s*" 
            +"(?(" 
            +   "(" + "\"" + "([^\"]|\"\")*" + "\"" + ")"
            +   "|" 
            +   "(" + "'" + "([^']|'')*" + "'" + ")"
            +   "|"
            +   "(" + "(?![\"'])" + "([^\\s;]|\\s+[^\\s;])*" + "(?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}]|\\s+==|==)+)"  // allow any visible character for keyname except '=' which must quoted as '=='
            + "\\s*=(?!=)\\s*"                                          // the equal sign divides the key and value parts
            + "(?"
            +  "(\"([^\"\u0000]|\"\")*\")"                              // double quoted string, " must be quoted as "" 
            +  "|"
            +  "('([^'\u0000]|'')*')"                                   // single quoted string, ' must be quoted as '' 
            +  "|" 
            +  "((?![\"'\\s])"                                          // unquoted value must not start with " or ' or space, would also like = but too late to change
            +   "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*"                  // control characters must be quoted 
            +  "(?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}])+)"            // allow any visible character for keyname except '='
            + "\\s*=\\s*"                                               // the equal sign divides the key and value parts
            + "(?"
            +  "(\\{([^\\}\u0000]|\\}\\})*\\})"                         // quoted string, starts with { and ends with } 
            +  "|"
            +  "((?![\\{\\s])"                                          // unquoted value must not start with { or space, would also like = but too late to change 
            +   "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*"                  // control characters must be quoted 
            +  "(? = in keywords
        //     first key-value pair wins
        //     quote values using \{ and \}, only driver= and pwd= appear to generically allow quoting
        //     do not strip quotes from value, or add quotes except for driver keyword 
        // OLEDB:
        //     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbconnectionstringsyntax.asp 
        //     support == -> = in keywords 
        //     last key-value pair wins
        //     quote values using \" or \' 
        //     strip quotes from value
        internal readonly bool UseOdbcRules;

        private System.Security.PermissionSet _permissionset; 

        // called by derived classes that may cache based on connectionString 
        public DbConnectionOptions(string connectionString) 
            : this(connectionString, null, false) {
        } 

        // synonyms hashtable is meant to be read-only translation of parsed string
        // keywords/synonyms to a known keyword string
        public DbConnectionOptions(string connectionString, Hashtable synonyms, bool useOdbcRules) { 
            UseOdbcRules = useOdbcRules;
            _parsetable = new Hashtable(); 
            _usersConnectionString = ((null != connectionString) ? connectionString : ""); 

            // first pass on parsing, initial syntax check 
            if (0 < _usersConnectionString.Length) {
                KeyChain = ParseInternal(_parsetable, _usersConnectionString, true, synonyms, UseOdbcRules);
                HasPasswordKeyword = (_parsetable.ContainsKey(KEY.Password) || _parsetable.ContainsKey(SYNONYM.Pwd));
            } 
        }
 
#if !ORACLE 
        protected DbConnectionOptions(DbConnectionOptions connectionOptions) { // Clone used by SqlConnectionString
            _usersConnectionString = connectionOptions._usersConnectionString; 
            HasPasswordKeyword = connectionOptions.HasPasswordKeyword;
            UseOdbcRules = connectionOptions.UseOdbcRules;
            _parsetable = connectionOptions._parsetable;
            KeyChain = connectionOptions.KeyChain; 
        }
#endif 
 

        public string UsersConnectionString(bool hidePassword) { 
            return UsersConnectionString(hidePassword, false);
        }

        private string UsersConnectionString(bool hidePassword, bool forceHidePassword) { 
            string connectionString = _usersConnectionString;
            if (HasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword))) { 
                ReplacePasswordPwd(out connectionString, false); 
            }
            return ((null != connectionString) ? connectionString : ""); 
        }

        internal string UsersConnectionStringForTrace() {
            return UsersConnectionString(true, true); 
        }
 
        internal bool HasBlankPassword { 
            get {
                if (!ConvertValueToIntegratedSecurity()) { 
                    if (_parsetable.ContainsKey(KEY.Password)) {
                        return ADP.IsEmpty((string)_parsetable[KEY.Password]);
                    } else
                    if (_parsetable.ContainsKey(SYNONYM.Pwd)) { 
                        return ADP.IsEmpty((string)_parsetable[SYNONYM.Pwd]); // MDAC 83097
                    } else { 
                        return ((_parsetable.ContainsKey(KEY.User_ID) && !ADP.IsEmpty((string)_parsetable[KEY.User_ID])) || (_parsetable.ContainsKey(SYNONYM.UID) && !ADP.IsEmpty((string)_parsetable[SYNONYM.UID]))); 
                    }
                } 
                return false;
            }
        }
 
        internal bool HasPersistablePassword {
            get { 
                if (HasPasswordKeyword) { 
                    return ConvertValueToBoolean(KEY.Persist_Security_Info, false);
                } 
                return true; // no password means persistable password so we don't have to munge
            }
        }
 
        public bool IsEmpty {
            get { return (null == KeyChain); } 
        } 

        internal Hashtable Parsetable { 
            get { return _parsetable; }
        }

#if !ORACLE 
        public ICollection Keys {
            get { return _parsetable.Keys; } 
        } 

        public string this[string keyword] { 
            get { return (string)_parsetable[keyword]; }
        }

        internal static void AppendKeyValuePairBuilder(StringBuilder builder, string keyName, string keyValue, bool useOdbcRules) { 
            ADP.CheckArgumentNull(builder, "builder");
            ADP.CheckArgumentLength(keyName, "keyName"); 
 
            if ((null == keyName) || !ConnectionStringValidKeyRegex.IsMatch(keyName)) {
                throw ADP.InvalidKeyname(keyName); 
            }
            if ((null != keyValue) && !IsValueValidInternal(keyValue)) {
                throw ADP.InvalidValue(keyName);
            } 

            if ((0 < builder.Length) && (';' != builder[builder.Length-1])) { 
                builder.Append(";"); 
            }
 
            if (useOdbcRules) {
                builder.Append(keyName);
            }
            else { 
                builder.Append(keyName.Replace("=", "=="));
            } 
            builder.Append("="); 

            if (null != keyValue) { // else =; 
                if (useOdbcRules) {
                    if ((0 < keyValue.Length) &&
                        (('{' == keyValue[0]) || (0 <= keyValue.IndexOf(';')) || (0 == String.Compare(DbConnectionStringKeywords.Driver, keyName, StringComparison.OrdinalIgnoreCase))) &&
                        !ConnectionStringQuoteOdbcValueRegex.IsMatch(keyValue)) 
                    {
                        // always quote Driver value (required for ODBC Version 2.65 and earlier) 
                        // always quote values that contain a ';' 
                        builder.Append('{').Append(keyValue.Replace("}", "}}")).Append('}');
                    } 
                    else {
                        builder.Append(keyValue);
                    }
                } 
                else if (ConnectionStringQuoteValueRegex.IsMatch(keyValue)) {
                    //  ->  
                    builder.Append(keyValue); 
                }
                else if ((-1 != keyValue.IndexOf('\"')) && (-1 == keyValue.IndexOf('\''))) { 
                    //  -> <'val"ue'>
                    builder.Append('\'');
                    builder.Append(keyValue);
                    builder.Append('\''); 
                }
                else { 
                    //  -> <"val'ue"> 
                    // <=value> -> <"=value">
                    // <;value> -> <";value"> 
                    // < value> -> <" value">
                    //  -> <"va lue">
                    //  -> <"va'""lue">
                    builder.Append('\"'); 
                    builder.Append(keyValue.Replace("\"", "\"\""));
                    builder.Append('\"'); 
                } 
            }
        } 

#endif
        public bool ConvertValueToBoolean(string keyName, bool defaultValue) {
            object value = _parsetable[keyName]; 
            if (null == value) {
                return defaultValue; 
            } 
            return ConvertValueToBooleanInternal(keyName, (string) value);
        } 

        internal static bool ConvertValueToBooleanInternal(string keyName, string stringValue) {
            if (CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
                return true; 
            else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no"))
                return false; 
            else { 
                string tmp = stringValue.Trim();  // Remove leading & trailing white space.
                if (CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes")) 
                    return true;
                else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
                    return false;
                else { 
                    throw ADP.InvalidConnectionOptionValue(keyName);
                } 
            } 
        }
 
        // same as Boolean, but with SSPI thrown in as valid yes
        public bool ConvertValueToIntegratedSecurity() {
            object value = _parsetable[KEY.Integrated_Security];
            if (null == value) { 
                return false;
            } 
            return ConvertValueToIntegratedSecurityInternal((string) value); 
        }
 
        internal bool ConvertValueToIntegratedSecurityInternal(string stringValue) {
            if (CompareInsensitiveInvariant(stringValue, "sspi") || CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
                return true;
            else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no")) 
                return false;
            else { 
                string tmp = stringValue.Trim();  // Remove leading & trailing white space. 
                if (CompareInsensitiveInvariant(tmp, "sspi") || CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes"))
                    return true; 
                else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
                    return false;
                else {
                    throw ADP.InvalidConnectionOptionValue(KEY.Integrated_Security); 
                }
            } 
        } 

        public int ConvertValueToInt32(string keyName, int defaultValue) { 
            object value = _parsetable[keyName];
            if (null == value) {
                return defaultValue;
            } 
            return ConvertToInt32Internal(keyName, (string) value);
        } 
 
        internal static int ConvertToInt32Internal(string keyname, string stringValue) {
            try { 
                return System.Int32.Parse(stringValue, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture);
            }
            catch (FormatException e) {
                throw ADP.InvalidConnectionOptionValue(keyname, e); 
            }
            catch (OverflowException e) { 
                throw ADP.InvalidConnectionOptionValue(keyname, e); 
            }
        } 

        public string ConvertValueToString(string keyName, string defaultValue) {
            string value = (string)_parsetable[keyName];
            return ((null != value) ? value : defaultValue); 
        }
 
        static private bool CompareInsensitiveInvariant(string strvalue, string strconst) { 
            return (0 == StringComparer.OrdinalIgnoreCase.Compare(strvalue, strconst));
        } 

#if !ORACLE
        public bool ContainsKey(string keyword) {
            return _parsetable.ContainsKey(keyword); 
        }
#endif 
 
        protected internal virtual System.Security.PermissionSet CreatePermissionSet() {
            return null; 
        }

        internal void DemandPermission() {
            if (null == _permissionset) { 
                _permissionset = CreatePermissionSet();
            } 
            _permissionset.Demand(); 
        }
 
        protected internal virtual string Expand() {
            return _usersConnectionString;
        }
 
#if !ORACLE
        // SxS notes: 
        // * this method queries "DataDirectory" value from the current AppDomain. 
        //   This string is used for to replace "!DataDirectory!" values in the connection string, it is not considered as an "exposed resource".
        // * This method uses GetFullPath to validate that root path is valid, the result is not exposed out. 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal static string ExpandDataDirectory(string keyword, string value, ref string datadir) {
            string fullPath = null; 
            if ((null != value) && value.StartsWith(DataDirectory, StringComparison.OrdinalIgnoreCase)) {
 
                string rootFolderPath = datadir; 
                if (null == rootFolderPath) {
                    // find the replacement path 
                    object rootFolderObject = AppDomain.CurrentDomain.GetData("DataDirectory");
                    rootFolderPath = (rootFolderObject as string);
                    if ((null != rootFolderObject) && (null == rootFolderPath)) {
                        throw ADP.InvalidDataDirectory(); 
                    }
                    else if (ADP.IsEmpty(rootFolderPath)) { 
                        rootFolderPath = AppDomain.CurrentDomain.BaseDirectory; 
                    }
                    if (null == rootFolderPath) { 
                        rootFolderPath = "";
                    }
                    // cache the |DataDir| for ExpandDataDirectories
                    datadir = rootFolderPath; 
                }
 
                // We don't know if rootFolderpath ends with '\', and we don't know if the given name starts with onw 
                int fileNamePosition = DataDirectory.Length;    // filename starts right after the '|datadirectory|' keyword
                bool rootFolderEndsWith = (0 < rootFolderPath.Length) && rootFolderPath[rootFolderPath.Length-1] == '\\'; 
                bool fileNameStartsWith = (fileNamePosition < value.Length) && value[fileNamePosition] == '\\';

                // replace |datadirectory| with root folder path
                if (!rootFolderEndsWith && !fileNameStartsWith) { 
                    // need to insert '\'
                    fullPath = rootFolderPath + '\\' + value.Substring(fileNamePosition); 
                } 
                else if (rootFolderEndsWith && fileNameStartsWith) {
                    // need to strip one out 
                    fullPath = rootFolderPath + value.Substring(fileNamePosition+1);
                }
                else {
                    // simply concatenate the strings 
                    fullPath = rootFolderPath + value.Substring(fileNamePosition);
                } 
 
                // verify root folder path is a real path without unexpected "..\"
                if (!ADP.GetFullPath(fullPath).StartsWith(rootFolderPath, StringComparison.Ordinal)) { 
                    throw ADP.InvalidConnectionOptionValue(keyword);
                }
            }
            return fullPath; 
        }
 
        internal string ExpandDataDirectories(ref string filename, ref int position) { 
            string value = null;
            StringBuilder builder = new StringBuilder(_usersConnectionString.Length); 
            string datadir = null;

            int copyPosition = 0;
            bool expanded = false; 

            for(NameValuePair current = KeyChain; null != current; current = current.Next) { 
                value = current.Value; 

                // remove duplicate keyswords from connectionstring 
                //if ((object)this[current.Name] != (object)value) {
                //    expanded = true;
                //    copyPosition += current.Length;
                //    continue; 
                //}
 
                // There is a set of keywords we explictly do NOT want to expand |DataDirectory| on 
                if (UseOdbcRules) {
                    switch(current.Name) { 
                    case DbConnectionOptionKeywords.Driver:
                    case DbConnectionOptionKeywords.Pwd:
                    case DbConnectionOptionKeywords.UID:
                        break; 
                    default:
                        value = ExpandDataDirectory(current.Name, value, ref datadir); 
                        break; 
                    }
                } 
                else {
                    switch(current.Name) {
                    case DbConnectionOptionKeywords.Provider:
                    case DbConnectionOptionKeywords.DataProvider: 
                    case DbConnectionOptionKeywords.RemoteProvider:
                    case DbConnectionOptionKeywords.ExtendedProperties: 
                    case DbConnectionOptionKeywords.UserID: 
                    case DbConnectionOptionKeywords.Password:
                    case DbConnectionOptionKeywords.UID: 
                    case DbConnectionOptionKeywords.Pwd:
                        break;
                    default:
                        value = ExpandDataDirectory(current.Name, value, ref datadir); 
                        break;
                    } 
                } 
                if (null == value) {
                    value = current.Value; 
                }
                if (UseOdbcRules || (DbConnectionOptionKeywords.FileName != current.Name)) {
                    if (value != current.Value) {
                        expanded = true; 
                        AppendKeyValuePairBuilder(builder, current.Name, value, UseOdbcRules);
                        builder.Append(';'); 
                    } 
                    else {
                        builder.Append(_usersConnectionString, copyPosition, current.Length); 
                    }
                }
                else {
                    // strip out 'File Name=myconnection.udl' for OleDb 
                    // remembering is value for which UDL file to open
                    // and where to insert the strnig 
                    expanded = true; 
                    filename = value;
                    position = builder.Length; 
                }
                copyPosition += current.Length;
            }
 
            if (expanded) {
                value = builder.ToString(); 
            } 
            else {
                value = null; 
            }
            return value;
        }
 
        internal string ExpandKeyword(string keyword, string replacementValue) {
            // preserve duplicates, updated keyword value with replacement value 
            // if keyword not specified, append to end of the string 
            bool expanded = false;
            int copyPosition = 0; 

            StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
            for(NameValuePair current = KeyChain; null != current; current = current.Next) {
                if ((current.Name == keyword) && (current.Value == this[keyword])) { 
                    // only replace the parse end-result value instead of all values
                    // so that when duplicate-keywords occur other original values remain in place 
                    AppendKeyValuePairBuilder(builder, current.Name, replacementValue, UseOdbcRules); 
                    builder.Append(';');
                    expanded = true; 
                }
                else {
                    builder.Append(_usersConnectionString, copyPosition, current.Length);
                } 
                copyPosition += current.Length;
            } 
 
            if (!expanded) {
                // 
                Debug.Assert(!UseOdbcRules, "ExpandKeyword not ready for Odbc");
                AppendKeyValuePairBuilder(builder, keyword, replacementValue, UseOdbcRules);
            }
            return builder.ToString(); 
        }
#endif 
#if DEBUG 
        [System.Diagnostics.Conditional("DEBUG")]
        private static void DebugTraceKeyValuePair(string keyname, string keyvalue, Hashtable synonyms) { 
            if (Bid.AdvancedOn) {
                Debug.Assert(keyname == keyname.ToLower(CultureInfo.InvariantCulture), "missing ToLower");

                string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname); 
                if ((KEY.Password != realkeyname) && (SYNONYM.Pwd != realkeyname)) { // don't trace passwords ever!
                    if (null != keyvalue) { 
                        Bid.Trace(" KeyName='%ls', KeyValue='%ls'\n", keyname, keyvalue); 
                    }
                    else { 
                        Bid.Trace(" KeyName='%ls'\n", keyname);
                    }
                }
            } 
        }
#endif 
 
        static private string GetKeyName(StringBuilder buffer) {
            int count = buffer.Length; 
            while ((0 < count) && Char.IsWhiteSpace(buffer[count-1])) {
                count--; // trailing whitespace
            }
            return buffer.ToString(0, count).ToLower(CultureInfo.InvariantCulture); 
        }
 
        static private string GetKeyValue(StringBuilder buffer, bool trimWhitespace) { 
            int count = buffer.Length;
            int index = 0; 
            if (trimWhitespace) {
                while ((index < count) && Char.IsWhiteSpace(buffer[index])) {
                    index++; // leading whitespace
                } 
                while ((0 < count) && Char.IsWhiteSpace(buffer[count-1])) {
                    count--; // trailing whitespace 
                } 
            }
            return buffer.ToString(index, count - index); 
        }

        // transistion states used for parsing
        private enum ParserState { 
            NothingYet=1,   //start point
            Key, 
            KeyEqual, 
            KeyEnd,
            UnquotedValue, 
            DoubleQuoteValue,
            DoubleQuoteValueQuote,
            SingleQuoteValue,
            SingleQuoteValueQuote, 
            BraceQuoteValue,
            BraceQuoteValueQuote, 
            QuotedValueEnd, 
            NullTermination,
        }; 

        static internal int GetKeyValuePair(string connectionString, int currentPosition, StringBuilder buffer, bool useOdbcRules, out string keyname, out string keyvalue) {
            int startposition = currentPosition;
 
            buffer.Length = 0;
            keyname = null; 
            keyvalue = null; 

            char currentChar = '\0'; 

            ParserState parserState = ParserState.NothingYet;
            int length = connectionString.Length;
            for (; currentPosition < length; ++currentPosition) { 
                currentChar = connectionString[currentPosition];
 
                switch(parserState) { 
                case ParserState.NothingYet: // [\\s;]*
                    if ((';' == currentChar) || Char.IsWhiteSpace(currentChar)) { 
                        continue;
                    }
                    if ('\0' == currentChar)            { parserState = ParserState.NullTermination; continue; } // MDAC 83540
                    if (Char.IsControl(currentChar))    { throw ADP.ConnectionStringSyntax(startposition); } 
                    startposition = currentPosition;
                    if ('=' != currentChar) { // MDAC 86902 
                        parserState = ParserState.Key; 
                        break;
                    } 
                    else {
                        parserState = ParserState.KeyEqual;
                        continue;
                    } 

                case ParserState.Key: // (?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}]|\\s+==|==)+) 
                    if ('=' == currentChar)             { parserState = ParserState.KeyEqual;       continue; } 
                    if (Char.IsWhiteSpace(currentChar)) { break; }
                    if (Char.IsControl(currentChar))    { throw ADP.ConnectionStringSyntax(startposition); } 
                    break;

                case ParserState.KeyEqual: // \\s*=(?!=)\\s*
                    if (!useOdbcRules && '=' == currentChar) { parserState = ParserState.Key;            break; } 
                    keyname = GetKeyName(buffer);
                    if (ADP.IsEmpty(keyname))           { throw ADP.ConnectionStringSyntax(startposition); } 
                    buffer.Length = 0; 
                    parserState = ParserState.KeyEnd;
                    goto case ParserState.KeyEnd; 

                case ParserState.KeyEnd:
                    if (Char.IsWhiteSpace(currentChar)) { continue; }
                    if (useOdbcRules) { 
                        if ('{' == currentChar)             { parserState = ParserState.BraceQuoteValue; break; }
                    } 
                    else { 
                        if ('\'' == currentChar)            { parserState = ParserState.SingleQuoteValue; continue; }
                        if ('"' == currentChar)             { parserState = ParserState.DoubleQuoteValue; continue; } 
                    }
                    if (';' == currentChar)             { goto ParserExit; }
                    if ('\0' == currentChar)            { goto ParserExit; }
                    if (Char.IsControl(currentChar))    { throw ADP.ConnectionStringSyntax(startposition); } 
                    parserState = ParserState.UnquotedValue;
                    break; 
 
                case ParserState.UnquotedValue: // "((?![\"'\\s])" + "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*" + "(?");
                    Debug.Assert(value1 == value2, "ParseInternal code vs. regex mismatch keyvalue <" + value1 + "> <" + value2 +">");
                }
 
            }
            catch(ArgumentException f) { 
                if (null != e) { 
                    string msg1 = e.Message;
                    string msg2 = f.Message; 
                    if (msg1.StartsWith("Keyword not supported:", StringComparison.Ordinal) && msg2.StartsWith("Format of the initialization string", StringComparison.Ordinal)) {
                    }
                    else {
                        Debug.Assert(msg1 == msg2, "ParseInternal code vs regex message mismatch: <"+msg1+"> <"+msg2+">"); 
                    }
                } 
                else { 
                    Debug.Assert(false, "ParseInternal code vs regex throw mismatch " + f.Message);
                } 
                e = null;
            }
            if (null != e) {
                Debug.Assert(false, "ParseInternal code threw exception vs regex mismatch"); 
            }
        } 
#endif 
        private static NameValuePair ParseInternal(Hashtable parsetable, string connectionString, bool buildChain, Hashtable synonyms, bool firstKey) {
            Debug.Assert(null != connectionString, "null connectionstring"); 
            StringBuilder buffer = new StringBuilder();
            NameValuePair localKeychain = null, keychain = null;
#if DEBUG
            try { 
#endif
                int nextStartPosition = 0; 
                int endPosition = connectionString.Length; 
                while (nextStartPosition < endPosition) {
                    int startPosition = nextStartPosition; 

                    string keyname, keyvalue;
                    nextStartPosition = GetKeyValuePair(connectionString, startPosition, buffer, firstKey, out keyname, out keyvalue);
                    if (ADP.IsEmpty(keyname)) { 
                        // if (nextStartPosition != endPosition) { throw; }
                        break; 
                    } 
#if DEBUG
                    DebugTraceKeyValuePair(keyname, keyvalue, synonyms); 

                    Debug.Assert(IsKeyNameValid(keyname), "ParseFailure, invalid keyname");
                    Debug.Assert(IsValueValidInternal(keyvalue), "parse failure, invalid keyvalue");
#endif 
                    string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname);
                    if (!IsKeyNameValid(realkeyname)) { 
                        throw ADP.KeywordNotSupported(keyname); 
                    }
                    if (!firstKey || !parsetable.Contains(realkeyname)) { 
                        parsetable[realkeyname] = keyvalue; // last key-value pair wins (or first)
                    }

                    if(null != localKeychain) { 
                        localKeychain = localKeychain.Next = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
                    } 
                    else if (buildChain) { // first time only - don't contain modified chain from UDL file 
                        keychain = localKeychain = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
                    } 
                }
#if DEBUG
            }
            catch(ArgumentException e) { 
                ParseComparision(parsetable, connectionString, synonyms, firstKey, e);
                throw; 
            } 
            ParseComparision(parsetable, connectionString, synonyms, firstKey, null);
#endif 
            return keychain;
        }

        internal NameValuePair ReplacePasswordPwd(out string constr, bool fakePassword) { 
            bool expanded = false;
            int copyPosition = 0; 
            NameValuePair head = null, tail = null, next = null; 
            StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
            for(NameValuePair current = KeyChain; null != current; current = current.Next) { 
                if ((KEY.Password != current.Name) && (SYNONYM.Pwd != current.Name)) {
                    builder.Append(_usersConnectionString, copyPosition, current.Length);
                    if (fakePassword) {
                        next = new NameValuePair(current.Name, current.Value, current.Length); 
                    }
                } 
                else if (fakePassword) { // replace user password/pwd value with * 
                    const string equalstar = "=*;";
                    builder.Append(current.Name).Append(equalstar); 
                    next = new NameValuePair(current.Name, "*", current.Name.Length + equalstar.Length);
                    expanded = true;
                }
                else { // drop the password/pwd completely in returning for user 
                    expanded = true;
                } 
 
                if (fakePassword) {
                    if (null != tail) { 
                        tail = tail.Next = next;
                    }
                    else {
                        tail = head = next; 
                    }
                } 
                copyPosition += current.Length; 
            }
            Debug.Assert(expanded, "password/pwd was not removed"); 
            constr = builder.ToString();
            return head;
        }
 
#if !ORACLE
        internal static void ValidateKeyValuePair(string keyword, string value) { 
            if ((null == keyword) || !ConnectionStringValidKeyRegex.IsMatch(keyword)) { 
                throw ADP.InvalidKeyname(keyword);
            } 
            if ((null != value) && !ConnectionStringValidValueRegex.IsMatch(value)) {
                throw ADP.InvalidValue(keyword);
            }
        } 
#endif
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.Common {
 
    using System;
    using System.Collections;
    using System.Data;
#if ORACLE 
    using System.Data.OracleClient;
#endif //ORACLE 
    using System.Diagnostics; 
    using System.Globalization;
    using System.Runtime.Serialization; 
    using System.Security.Permissions;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Runtime.Versioning; 

    internal class DbConnectionOptions { 
        // instances of this class are intended to be immutable, i.e readonly 
        // used by pooling classes so it is much easier to verify correctness
        // when not worried about the class being modified during execution 

#if DEBUG
        /*private const string ConnectionStringPatternV1 =
             "[\\s;]*" 
            +"(?([^=\\s]|\\s+[^=\\s]|\\s+==|==)+)"
            +   "\\s*=(?!=)\\s*" 
            +"(?(" 
            +   "(" + "\"" + "([^\"]|\"\")*" + "\"" + ")"
            +   "|" 
            +   "(" + "'" + "([^']|'')*" + "'" + ")"
            +   "|"
            +   "(" + "(?![\"'])" + "([^\\s;]|\\s+[^\\s;])*" + "(?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}]|\\s+==|==)+)"  // allow any visible character for keyname except '=' which must quoted as '=='
            + "\\s*=(?!=)\\s*"                                          // the equal sign divides the key and value parts
            + "(?"
            +  "(\"([^\"\u0000]|\"\")*\")"                              // double quoted string, " must be quoted as "" 
            +  "|"
            +  "('([^'\u0000]|'')*')"                                   // single quoted string, ' must be quoted as '' 
            +  "|" 
            +  "((?![\"'\\s])"                                          // unquoted value must not start with " or ' or space, would also like = but too late to change
            +   "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*"                  // control characters must be quoted 
            +  "(?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}])+)"            // allow any visible character for keyname except '='
            + "\\s*=\\s*"                                               // the equal sign divides the key and value parts
            + "(?"
            +  "(\\{([^\\}\u0000]|\\}\\})*\\})"                         // quoted string, starts with { and ends with } 
            +  "|"
            +  "((?![\\{\\s])"                                          // unquoted value must not start with { or space, would also like = but too late to change 
            +   "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*"                  // control characters must be quoted 
            +  "(? = in keywords
        //     first key-value pair wins
        //     quote values using \{ and \}, only driver= and pwd= appear to generically allow quoting
        //     do not strip quotes from value, or add quotes except for driver keyword 
        // OLEDB:
        //     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbconnectionstringsyntax.asp 
        //     support == -> = in keywords 
        //     last key-value pair wins
        //     quote values using \" or \' 
        //     strip quotes from value
        internal readonly bool UseOdbcRules;

        private System.Security.PermissionSet _permissionset; 

        // called by derived classes that may cache based on connectionString 
        public DbConnectionOptions(string connectionString) 
            : this(connectionString, null, false) {
        } 

        // synonyms hashtable is meant to be read-only translation of parsed string
        // keywords/synonyms to a known keyword string
        public DbConnectionOptions(string connectionString, Hashtable synonyms, bool useOdbcRules) { 
            UseOdbcRules = useOdbcRules;
            _parsetable = new Hashtable(); 
            _usersConnectionString = ((null != connectionString) ? connectionString : ""); 

            // first pass on parsing, initial syntax check 
            if (0 < _usersConnectionString.Length) {
                KeyChain = ParseInternal(_parsetable, _usersConnectionString, true, synonyms, UseOdbcRules);
                HasPasswordKeyword = (_parsetable.ContainsKey(KEY.Password) || _parsetable.ContainsKey(SYNONYM.Pwd));
            } 
        }
 
#if !ORACLE 
        protected DbConnectionOptions(DbConnectionOptions connectionOptions) { // Clone used by SqlConnectionString
            _usersConnectionString = connectionOptions._usersConnectionString; 
            HasPasswordKeyword = connectionOptions.HasPasswordKeyword;
            UseOdbcRules = connectionOptions.UseOdbcRules;
            _parsetable = connectionOptions._parsetable;
            KeyChain = connectionOptions.KeyChain; 
        }
#endif 
 

        public string UsersConnectionString(bool hidePassword) { 
            return UsersConnectionString(hidePassword, false);
        }

        private string UsersConnectionString(bool hidePassword, bool forceHidePassword) { 
            string connectionString = _usersConnectionString;
            if (HasPasswordKeyword && (forceHidePassword || (hidePassword && !HasPersistablePassword))) { 
                ReplacePasswordPwd(out connectionString, false); 
            }
            return ((null != connectionString) ? connectionString : ""); 
        }

        internal string UsersConnectionStringForTrace() {
            return UsersConnectionString(true, true); 
        }
 
        internal bool HasBlankPassword { 
            get {
                if (!ConvertValueToIntegratedSecurity()) { 
                    if (_parsetable.ContainsKey(KEY.Password)) {
                        return ADP.IsEmpty((string)_parsetable[KEY.Password]);
                    } else
                    if (_parsetable.ContainsKey(SYNONYM.Pwd)) { 
                        return ADP.IsEmpty((string)_parsetable[SYNONYM.Pwd]); // MDAC 83097
                    } else { 
                        return ((_parsetable.ContainsKey(KEY.User_ID) && !ADP.IsEmpty((string)_parsetable[KEY.User_ID])) || (_parsetable.ContainsKey(SYNONYM.UID) && !ADP.IsEmpty((string)_parsetable[SYNONYM.UID]))); 
                    }
                } 
                return false;
            }
        }
 
        internal bool HasPersistablePassword {
            get { 
                if (HasPasswordKeyword) { 
                    return ConvertValueToBoolean(KEY.Persist_Security_Info, false);
                } 
                return true; // no password means persistable password so we don't have to munge
            }
        }
 
        public bool IsEmpty {
            get { return (null == KeyChain); } 
        } 

        internal Hashtable Parsetable { 
            get { return _parsetable; }
        }

#if !ORACLE 
        public ICollection Keys {
            get { return _parsetable.Keys; } 
        } 

        public string this[string keyword] { 
            get { return (string)_parsetable[keyword]; }
        }

        internal static void AppendKeyValuePairBuilder(StringBuilder builder, string keyName, string keyValue, bool useOdbcRules) { 
            ADP.CheckArgumentNull(builder, "builder");
            ADP.CheckArgumentLength(keyName, "keyName"); 
 
            if ((null == keyName) || !ConnectionStringValidKeyRegex.IsMatch(keyName)) {
                throw ADP.InvalidKeyname(keyName); 
            }
            if ((null != keyValue) && !IsValueValidInternal(keyValue)) {
                throw ADP.InvalidValue(keyName);
            } 

            if ((0 < builder.Length) && (';' != builder[builder.Length-1])) { 
                builder.Append(";"); 
            }
 
            if (useOdbcRules) {
                builder.Append(keyName);
            }
            else { 
                builder.Append(keyName.Replace("=", "=="));
            } 
            builder.Append("="); 

            if (null != keyValue) { // else =; 
                if (useOdbcRules) {
                    if ((0 < keyValue.Length) &&
                        (('{' == keyValue[0]) || (0 <= keyValue.IndexOf(';')) || (0 == String.Compare(DbConnectionStringKeywords.Driver, keyName, StringComparison.OrdinalIgnoreCase))) &&
                        !ConnectionStringQuoteOdbcValueRegex.IsMatch(keyValue)) 
                    {
                        // always quote Driver value (required for ODBC Version 2.65 and earlier) 
                        // always quote values that contain a ';' 
                        builder.Append('{').Append(keyValue.Replace("}", "}}")).Append('}');
                    } 
                    else {
                        builder.Append(keyValue);
                    }
                } 
                else if (ConnectionStringQuoteValueRegex.IsMatch(keyValue)) {
                    //  ->  
                    builder.Append(keyValue); 
                }
                else if ((-1 != keyValue.IndexOf('\"')) && (-1 == keyValue.IndexOf('\''))) { 
                    //  -> <'val"ue'>
                    builder.Append('\'');
                    builder.Append(keyValue);
                    builder.Append('\''); 
                }
                else { 
                    //  -> <"val'ue"> 
                    // <=value> -> <"=value">
                    // <;value> -> <";value"> 
                    // < value> -> <" value">
                    //  -> <"va lue">
                    //  -> <"va'""lue">
                    builder.Append('\"'); 
                    builder.Append(keyValue.Replace("\"", "\"\""));
                    builder.Append('\"'); 
                } 
            }
        } 

#endif
        public bool ConvertValueToBoolean(string keyName, bool defaultValue) {
            object value = _parsetable[keyName]; 
            if (null == value) {
                return defaultValue; 
            } 
            return ConvertValueToBooleanInternal(keyName, (string) value);
        } 

        internal static bool ConvertValueToBooleanInternal(string keyName, string stringValue) {
            if (CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
                return true; 
            else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no"))
                return false; 
            else { 
                string tmp = stringValue.Trim();  // Remove leading & trailing white space.
                if (CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes")) 
                    return true;
                else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
                    return false;
                else { 
                    throw ADP.InvalidConnectionOptionValue(keyName);
                } 
            } 
        }
 
        // same as Boolean, but with SSPI thrown in as valid yes
        public bool ConvertValueToIntegratedSecurity() {
            object value = _parsetable[KEY.Integrated_Security];
            if (null == value) { 
                return false;
            } 
            return ConvertValueToIntegratedSecurityInternal((string) value); 
        }
 
        internal bool ConvertValueToIntegratedSecurityInternal(string stringValue) {
            if (CompareInsensitiveInvariant(stringValue, "sspi") || CompareInsensitiveInvariant(stringValue, "true") || CompareInsensitiveInvariant(stringValue, "yes"))
                return true;
            else if (CompareInsensitiveInvariant(stringValue, "false") || CompareInsensitiveInvariant(stringValue, "no")) 
                return false;
            else { 
                string tmp = stringValue.Trim();  // Remove leading & trailing white space. 
                if (CompareInsensitiveInvariant(tmp, "sspi") || CompareInsensitiveInvariant(tmp, "true") || CompareInsensitiveInvariant(tmp, "yes"))
                    return true; 
                else if (CompareInsensitiveInvariant(tmp, "false") || CompareInsensitiveInvariant(tmp, "no"))
                    return false;
                else {
                    throw ADP.InvalidConnectionOptionValue(KEY.Integrated_Security); 
                }
            } 
        } 

        public int ConvertValueToInt32(string keyName, int defaultValue) { 
            object value = _parsetable[keyName];
            if (null == value) {
                return defaultValue;
            } 
            return ConvertToInt32Internal(keyName, (string) value);
        } 
 
        internal static int ConvertToInt32Internal(string keyname, string stringValue) {
            try { 
                return System.Int32.Parse(stringValue, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture);
            }
            catch (FormatException e) {
                throw ADP.InvalidConnectionOptionValue(keyname, e); 
            }
            catch (OverflowException e) { 
                throw ADP.InvalidConnectionOptionValue(keyname, e); 
            }
        } 

        public string ConvertValueToString(string keyName, string defaultValue) {
            string value = (string)_parsetable[keyName];
            return ((null != value) ? value : defaultValue); 
        }
 
        static private bool CompareInsensitiveInvariant(string strvalue, string strconst) { 
            return (0 == StringComparer.OrdinalIgnoreCase.Compare(strvalue, strconst));
        } 

#if !ORACLE
        public bool ContainsKey(string keyword) {
            return _parsetable.ContainsKey(keyword); 
        }
#endif 
 
        protected internal virtual System.Security.PermissionSet CreatePermissionSet() {
            return null; 
        }

        internal void DemandPermission() {
            if (null == _permissionset) { 
                _permissionset = CreatePermissionSet();
            } 
            _permissionset.Demand(); 
        }
 
        protected internal virtual string Expand() {
            return _usersConnectionString;
        }
 
#if !ORACLE
        // SxS notes: 
        // * this method queries "DataDirectory" value from the current AppDomain. 
        //   This string is used for to replace "!DataDirectory!" values in the connection string, it is not considered as an "exposed resource".
        // * This method uses GetFullPath to validate that root path is valid, the result is not exposed out. 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        internal static string ExpandDataDirectory(string keyword, string value, ref string datadir) {
            string fullPath = null; 
            if ((null != value) && value.StartsWith(DataDirectory, StringComparison.OrdinalIgnoreCase)) {
 
                string rootFolderPath = datadir; 
                if (null == rootFolderPath) {
                    // find the replacement path 
                    object rootFolderObject = AppDomain.CurrentDomain.GetData("DataDirectory");
                    rootFolderPath = (rootFolderObject as string);
                    if ((null != rootFolderObject) && (null == rootFolderPath)) {
                        throw ADP.InvalidDataDirectory(); 
                    }
                    else if (ADP.IsEmpty(rootFolderPath)) { 
                        rootFolderPath = AppDomain.CurrentDomain.BaseDirectory; 
                    }
                    if (null == rootFolderPath) { 
                        rootFolderPath = "";
                    }
                    // cache the |DataDir| for ExpandDataDirectories
                    datadir = rootFolderPath; 
                }
 
                // We don't know if rootFolderpath ends with '\', and we don't know if the given name starts with onw 
                int fileNamePosition = DataDirectory.Length;    // filename starts right after the '|datadirectory|' keyword
                bool rootFolderEndsWith = (0 < rootFolderPath.Length) && rootFolderPath[rootFolderPath.Length-1] == '\\'; 
                bool fileNameStartsWith = (fileNamePosition < value.Length) && value[fileNamePosition] == '\\';

                // replace |datadirectory| with root folder path
                if (!rootFolderEndsWith && !fileNameStartsWith) { 
                    // need to insert '\'
                    fullPath = rootFolderPath + '\\' + value.Substring(fileNamePosition); 
                } 
                else if (rootFolderEndsWith && fileNameStartsWith) {
                    // need to strip one out 
                    fullPath = rootFolderPath + value.Substring(fileNamePosition+1);
                }
                else {
                    // simply concatenate the strings 
                    fullPath = rootFolderPath + value.Substring(fileNamePosition);
                } 
 
                // verify root folder path is a real path without unexpected "..\"
                if (!ADP.GetFullPath(fullPath).StartsWith(rootFolderPath, StringComparison.Ordinal)) { 
                    throw ADP.InvalidConnectionOptionValue(keyword);
                }
            }
            return fullPath; 
        }
 
        internal string ExpandDataDirectories(ref string filename, ref int position) { 
            string value = null;
            StringBuilder builder = new StringBuilder(_usersConnectionString.Length); 
            string datadir = null;

            int copyPosition = 0;
            bool expanded = false; 

            for(NameValuePair current = KeyChain; null != current; current = current.Next) { 
                value = current.Value; 

                // remove duplicate keyswords from connectionstring 
                //if ((object)this[current.Name] != (object)value) {
                //    expanded = true;
                //    copyPosition += current.Length;
                //    continue; 
                //}
 
                // There is a set of keywords we explictly do NOT want to expand |DataDirectory| on 
                if (UseOdbcRules) {
                    switch(current.Name) { 
                    case DbConnectionOptionKeywords.Driver:
                    case DbConnectionOptionKeywords.Pwd:
                    case DbConnectionOptionKeywords.UID:
                        break; 
                    default:
                        value = ExpandDataDirectory(current.Name, value, ref datadir); 
                        break; 
                    }
                } 
                else {
                    switch(current.Name) {
                    case DbConnectionOptionKeywords.Provider:
                    case DbConnectionOptionKeywords.DataProvider: 
                    case DbConnectionOptionKeywords.RemoteProvider:
                    case DbConnectionOptionKeywords.ExtendedProperties: 
                    case DbConnectionOptionKeywords.UserID: 
                    case DbConnectionOptionKeywords.Password:
                    case DbConnectionOptionKeywords.UID: 
                    case DbConnectionOptionKeywords.Pwd:
                        break;
                    default:
                        value = ExpandDataDirectory(current.Name, value, ref datadir); 
                        break;
                    } 
                } 
                if (null == value) {
                    value = current.Value; 
                }
                if (UseOdbcRules || (DbConnectionOptionKeywords.FileName != current.Name)) {
                    if (value != current.Value) {
                        expanded = true; 
                        AppendKeyValuePairBuilder(builder, current.Name, value, UseOdbcRules);
                        builder.Append(';'); 
                    } 
                    else {
                        builder.Append(_usersConnectionString, copyPosition, current.Length); 
                    }
                }
                else {
                    // strip out 'File Name=myconnection.udl' for OleDb 
                    // remembering is value for which UDL file to open
                    // and where to insert the strnig 
                    expanded = true; 
                    filename = value;
                    position = builder.Length; 
                }
                copyPosition += current.Length;
            }
 
            if (expanded) {
                value = builder.ToString(); 
            } 
            else {
                value = null; 
            }
            return value;
        }
 
        internal string ExpandKeyword(string keyword, string replacementValue) {
            // preserve duplicates, updated keyword value with replacement value 
            // if keyword not specified, append to end of the string 
            bool expanded = false;
            int copyPosition = 0; 

            StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
            for(NameValuePair current = KeyChain; null != current; current = current.Next) {
                if ((current.Name == keyword) && (current.Value == this[keyword])) { 
                    // only replace the parse end-result value instead of all values
                    // so that when duplicate-keywords occur other original values remain in place 
                    AppendKeyValuePairBuilder(builder, current.Name, replacementValue, UseOdbcRules); 
                    builder.Append(';');
                    expanded = true; 
                }
                else {
                    builder.Append(_usersConnectionString, copyPosition, current.Length);
                } 
                copyPosition += current.Length;
            } 
 
            if (!expanded) {
                // 
                Debug.Assert(!UseOdbcRules, "ExpandKeyword not ready for Odbc");
                AppendKeyValuePairBuilder(builder, keyword, replacementValue, UseOdbcRules);
            }
            return builder.ToString(); 
        }
#endif 
#if DEBUG 
        [System.Diagnostics.Conditional("DEBUG")]
        private static void DebugTraceKeyValuePair(string keyname, string keyvalue, Hashtable synonyms) { 
            if (Bid.AdvancedOn) {
                Debug.Assert(keyname == keyname.ToLower(CultureInfo.InvariantCulture), "missing ToLower");

                string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname); 
                if ((KEY.Password != realkeyname) && (SYNONYM.Pwd != realkeyname)) { // don't trace passwords ever!
                    if (null != keyvalue) { 
                        Bid.Trace(" KeyName='%ls', KeyValue='%ls'\n", keyname, keyvalue); 
                    }
                    else { 
                        Bid.Trace(" KeyName='%ls'\n", keyname);
                    }
                }
            } 
        }
#endif 
 
        static private string GetKeyName(StringBuilder buffer) {
            int count = buffer.Length; 
            while ((0 < count) && Char.IsWhiteSpace(buffer[count-1])) {
                count--; // trailing whitespace
            }
            return buffer.ToString(0, count).ToLower(CultureInfo.InvariantCulture); 
        }
 
        static private string GetKeyValue(StringBuilder buffer, bool trimWhitespace) { 
            int count = buffer.Length;
            int index = 0; 
            if (trimWhitespace) {
                while ((index < count) && Char.IsWhiteSpace(buffer[index])) {
                    index++; // leading whitespace
                } 
                while ((0 < count) && Char.IsWhiteSpace(buffer[count-1])) {
                    count--; // trailing whitespace 
                } 
            }
            return buffer.ToString(index, count - index); 
        }

        // transistion states used for parsing
        private enum ParserState { 
            NothingYet=1,   //start point
            Key, 
            KeyEqual, 
            KeyEnd,
            UnquotedValue, 
            DoubleQuoteValue,
            DoubleQuoteValueQuote,
            SingleQuoteValue,
            SingleQuoteValueQuote, 
            BraceQuoteValue,
            BraceQuoteValueQuote, 
            QuotedValueEnd, 
            NullTermination,
        }; 

        static internal int GetKeyValuePair(string connectionString, int currentPosition, StringBuilder buffer, bool useOdbcRules, out string keyname, out string keyvalue) {
            int startposition = currentPosition;
 
            buffer.Length = 0;
            keyname = null; 
            keyvalue = null; 

            char currentChar = '\0'; 

            ParserState parserState = ParserState.NothingYet;
            int length = connectionString.Length;
            for (; currentPosition < length; ++currentPosition) { 
                currentChar = connectionString[currentPosition];
 
                switch(parserState) { 
                case ParserState.NothingYet: // [\\s;]*
                    if ((';' == currentChar) || Char.IsWhiteSpace(currentChar)) { 
                        continue;
                    }
                    if ('\0' == currentChar)            { parserState = ParserState.NullTermination; continue; } // MDAC 83540
                    if (Char.IsControl(currentChar))    { throw ADP.ConnectionStringSyntax(startposition); } 
                    startposition = currentPosition;
                    if ('=' != currentChar) { // MDAC 86902 
                        parserState = ParserState.Key; 
                        break;
                    } 
                    else {
                        parserState = ParserState.KeyEqual;
                        continue;
                    } 

                case ParserState.Key: // (?([^=\\s\\p{Cc}]|\\s+[^=\\s\\p{Cc}]|\\s+==|==)+) 
                    if ('=' == currentChar)             { parserState = ParserState.KeyEqual;       continue; } 
                    if (Char.IsWhiteSpace(currentChar)) { break; }
                    if (Char.IsControl(currentChar))    { throw ADP.ConnectionStringSyntax(startposition); } 
                    break;

                case ParserState.KeyEqual: // \\s*=(?!=)\\s*
                    if (!useOdbcRules && '=' == currentChar) { parserState = ParserState.Key;            break; } 
                    keyname = GetKeyName(buffer);
                    if (ADP.IsEmpty(keyname))           { throw ADP.ConnectionStringSyntax(startposition); } 
                    buffer.Length = 0; 
                    parserState = ParserState.KeyEnd;
                    goto case ParserState.KeyEnd; 

                case ParserState.KeyEnd:
                    if (Char.IsWhiteSpace(currentChar)) { continue; }
                    if (useOdbcRules) { 
                        if ('{' == currentChar)             { parserState = ParserState.BraceQuoteValue; break; }
                    } 
                    else { 
                        if ('\'' == currentChar)            { parserState = ParserState.SingleQuoteValue; continue; }
                        if ('"' == currentChar)             { parserState = ParserState.DoubleQuoteValue; continue; } 
                    }
                    if (';' == currentChar)             { goto ParserExit; }
                    if ('\0' == currentChar)            { goto ParserExit; }
                    if (Char.IsControl(currentChar))    { throw ADP.ConnectionStringSyntax(startposition); } 
                    parserState = ParserState.UnquotedValue;
                    break; 
 
                case ParserState.UnquotedValue: // "((?![\"'\\s])" + "([^;\\s\\p{Cc}]|\\s+[^;\\s\\p{Cc}])*" + "(?");
                    Debug.Assert(value1 == value2, "ParseInternal code vs. regex mismatch keyvalue <" + value1 + "> <" + value2 +">");
                }
 
            }
            catch(ArgumentException f) { 
                if (null != e) { 
                    string msg1 = e.Message;
                    string msg2 = f.Message; 
                    if (msg1.StartsWith("Keyword not supported:", StringComparison.Ordinal) && msg2.StartsWith("Format of the initialization string", StringComparison.Ordinal)) {
                    }
                    else {
                        Debug.Assert(msg1 == msg2, "ParseInternal code vs regex message mismatch: <"+msg1+"> <"+msg2+">"); 
                    }
                } 
                else { 
                    Debug.Assert(false, "ParseInternal code vs regex throw mismatch " + f.Message);
                } 
                e = null;
            }
            if (null != e) {
                Debug.Assert(false, "ParseInternal code threw exception vs regex mismatch"); 
            }
        } 
#endif 
        private static NameValuePair ParseInternal(Hashtable parsetable, string connectionString, bool buildChain, Hashtable synonyms, bool firstKey) {
            Debug.Assert(null != connectionString, "null connectionstring"); 
            StringBuilder buffer = new StringBuilder();
            NameValuePair localKeychain = null, keychain = null;
#if DEBUG
            try { 
#endif
                int nextStartPosition = 0; 
                int endPosition = connectionString.Length; 
                while (nextStartPosition < endPosition) {
                    int startPosition = nextStartPosition; 

                    string keyname, keyvalue;
                    nextStartPosition = GetKeyValuePair(connectionString, startPosition, buffer, firstKey, out keyname, out keyvalue);
                    if (ADP.IsEmpty(keyname)) { 
                        // if (nextStartPosition != endPosition) { throw; }
                        break; 
                    } 
#if DEBUG
                    DebugTraceKeyValuePair(keyname, keyvalue, synonyms); 

                    Debug.Assert(IsKeyNameValid(keyname), "ParseFailure, invalid keyname");
                    Debug.Assert(IsValueValidInternal(keyvalue), "parse failure, invalid keyvalue");
#endif 
                    string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname);
                    if (!IsKeyNameValid(realkeyname)) { 
                        throw ADP.KeywordNotSupported(keyname); 
                    }
                    if (!firstKey || !parsetable.Contains(realkeyname)) { 
                        parsetable[realkeyname] = keyvalue; // last key-value pair wins (or first)
                    }

                    if(null != localKeychain) { 
                        localKeychain = localKeychain.Next = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
                    } 
                    else if (buildChain) { // first time only - don't contain modified chain from UDL file 
                        keychain = localKeychain = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
                    } 
                }
#if DEBUG
            }
            catch(ArgumentException e) { 
                ParseComparision(parsetable, connectionString, synonyms, firstKey, e);
                throw; 
            } 
            ParseComparision(parsetable, connectionString, synonyms, firstKey, null);
#endif 
            return keychain;
        }

        internal NameValuePair ReplacePasswordPwd(out string constr, bool fakePassword) { 
            bool expanded = false;
            int copyPosition = 0; 
            NameValuePair head = null, tail = null, next = null; 
            StringBuilder builder = new StringBuilder(_usersConnectionString.Length);
            for(NameValuePair current = KeyChain; null != current; current = current.Next) { 
                if ((KEY.Password != current.Name) && (SYNONYM.Pwd != current.Name)) {
                    builder.Append(_usersConnectionString, copyPosition, current.Length);
                    if (fakePassword) {
                        next = new NameValuePair(current.Name, current.Value, current.Length); 
                    }
                } 
                else if (fakePassword) { // replace user password/pwd value with * 
                    const string equalstar = "=*;";
                    builder.Append(current.Name).Append(equalstar); 
                    next = new NameValuePair(current.Name, "*", current.Name.Length + equalstar.Length);
                    expanded = true;
                }
                else { // drop the password/pwd completely in returning for user 
                    expanded = true;
                } 
 
                if (fakePassword) {
                    if (null != tail) { 
                        tail = tail.Next = next;
                    }
                    else {
                        tail = head = next; 
                    }
                } 
                copyPosition += current.Length; 
            }
            Debug.Assert(expanded, "password/pwd was not removed"); 
            constr = builder.ToString();
            return head;
        }
 
#if !ORACLE
        internal static void ValidateKeyValuePair(string keyword, string value) { 
            if ((null == keyword) || !ConnectionStringValidKeyRegex.IsMatch(keyword)) { 
                throw ADP.InvalidKeyname(keyword);
            } 
            if ((null != value) && !ConnectionStringValidValueRegex.IsMatch(value)) {
                throw ADP.InvalidValue(keyword);
            }
        } 
#endif
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK