//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
namespace System.Data.EntityClient
{
using System.Collections;
using System.Diagnostics;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
///
/// Copied from System.Data.dll
///
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 ConnectionStringPattern = // may not contain embedded null except trailing last value
"([\\s;]*" // leading whitespace and extra semicolons
+ "(?![\\s;])" // key does not start with space or semicolon
+ "(?([^=\\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}]|\\s+==|==)+)
if ('=' == currentChar) { parserState = ParserState.KeyEqual; continue; }
if (Char.IsWhiteSpace(currentChar)) { break; }
if (Char.IsControl(currentChar)) { throw EntityUtil.ConnectionStringSyntax(startposition); }
break;
case ParserState.KeyEqual: // \\s*=(?!=)\\s*
if ('=' == currentChar) { parserState = ParserState.Key; break; }
keyname = GetKeyName(buffer);
if (string.IsNullOrEmpty(keyname)) { throw EntityUtil.ConnectionStringSyntax(startposition); }
buffer.Length = 0;
parserState = ParserState.KeyEnd;
goto case ParserState.KeyEnd;
case ParserState.KeyEnd:
if (Char.IsWhiteSpace(currentChar)) { continue; }
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 EntityUtil.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
{
// Does not always hold.
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, Hashtable synonyms)
{
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, out keyname, out keyvalue);
if (string.IsNullOrEmpty(keyname))
{
// if (nextStartPosition != endPosition) { throw; }
break;
}
#if DEBUG
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 EntityUtil.ADP_KeywordNotSupported(keyname);
}
parsetable[realkeyname] = keyvalue; // last key-value pair wins (or first)
if (null != localKeychain)
{
localKeychain = localKeychain.Next = new NameValuePair(realkeyname, keyvalue, nextStartPosition - startPosition);
}
else
{ // 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, e);
throw;
}
ParseComparision(parsetable, connectionString, synonyms, null);
#endif
return keychain;
}
}
}