in src/main/java/com/microsoft/sqlserver/jdbc/Util.java [241:523]
/* L0 */ static Properties parseUrl(String url, Logger logger) throws SQLServerException {
Properties p = new Properties();
String tmpUrl = url;
String sPrefix = "jdbc:sqlserver://";
StringBuilder result = new StringBuilder();
String name = "";
String value = "";
if (!tmpUrl.startsWith(sPrefix))
return null;
tmpUrl = tmpUrl.substring(sPrefix.length());
int i;
// Simple finite state machine.
// always look at one char at a time
final int inStart = 0;
final int inServerName = 1;
final int inPort = 2;
final int inInstanceName = 3;
final int inEscapedValueStart = 4;
final int inEscapedValueEnd = 5;
final int inValue = 6;
final int inName = 7;
int state = inStart;
char ch;
i = 0;
while (i < tmpUrl.length()) {
ch = tmpUrl.charAt(i);
switch (state) {
case inStart: {
if (ch == ';') {
// done immediately
state = inName;
} else {
result.append(ch);
state = inServerName;
}
break;
}
case inServerName: {
if (ch == ';' || ch == ':' || ch == '\\') {
// non escaped trim the string
String property = result.toString().trim();
if (property.length() > 0) {
p.put(SQLServerDriverStringProperty.SERVER_NAME.toString(), property);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Property:serverName " + "Value:" + property);
}
}
result.setLength(0);
if (ch == ';')
state = inName;
else if (ch == ':')
state = inPort;
else
state = inInstanceName;
} else {
result.append(ch);
// same state
}
break;
}
case inPort: {
if (ch == ';') {
String property = result.toString().trim();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Property:portNumber " + "Value:" + property);
}
p.put(SQLServerDriverIntProperty.PORT_NUMBER.toString(), property);
result.setLength(0);
state = inName;
} else {
result.append(ch);
// same state
}
break;
}
case inInstanceName: {
if (ch == ';' || ch == ':') {
// non escaped trim the string
String property = result.toString().trim();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Property:instanceName " + "Value:" + property);
}
p.put(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), property.toLowerCase(Locale.US));
result.setLength(0);
if (ch == ';')
state = inName;
else
state = inPort;
} else {
result.append(ch);
// same state
}
break;
}
case inName: {
if (ch == '=') {
// name is never escaped!
name = name.trim();
if (name.length() <= 0) {
SQLServerException.makeFromDriverError(null, null,
SQLServerException.getErrString("R_errorConnectionString"), null, true);
}
state = inValue;
} else if (ch == ';') {
name = name.trim();
if (name.length() > 0) {
SQLServerException.makeFromDriverError(null, null,
SQLServerException.getErrString("R_errorConnectionString"), null, true);
}
// same state
} else {
StringBuilder builder = new StringBuilder();
builder.append(name);
builder.append(ch);
name = builder.toString();
// same state
}
break;
}
case inValue: {
if (ch == ';') {
// simple value trim
value = value.trim();
name = SQLServerDriver.getNormalizedPropertyName(name, logger);
if (null != name) {
if (logger.isLoggable(Level.FINE)) {
if (!name.equals(SQLServerDriverStringProperty.USER.toString())) {
if (!name.toLowerCase(Locale.ENGLISH).contains("password")
&& !name.toLowerCase(Locale.ENGLISH).contains("keystoresecret")) {
logger.fine("Property:" + name + " Value:" + value);
} else {
logger.fine("Property:" + name);
}
}
}
p.put(name, value);
}
name = "";
value = "";
state = inName;
} else if (ch == '{') {
state = inEscapedValueStart;
value = value.trim();
if (value.length() > 0) {
SQLServerException.makeFromDriverError(null, null,
SQLServerException.getErrString("R_errorConnectionString"), null, true);
}
} else {
StringBuilder builder = new StringBuilder();
builder.append(value);
builder.append(ch);
value = builder.toString();
// same state
}
break;
}
case inEscapedValueStart: {
/*
* check for escaped }. when we see a }, first check to see if this is before the end of the string
* to avoid index out of range exception then check if the character immediately after is also a }.
* if it is, then we have a }}, which is not the closing of the escaped state.
*/
if (ch == '}' && i + 1 < tmpUrl.length() && tmpUrl.charAt(i + 1) == '}') {
StringBuilder builder = new StringBuilder();
builder.append(value);
builder.append(ch);
value = builder.toString();
i++; // escaped }} into a }, so increment the counter once more
// same state
} else {
if (ch == '}') {
// no trimming use the value as it is.
name = SQLServerDriver.getNormalizedPropertyName(name, logger);
if (null != name) {
if (logger.isLoggable(Level.FINE)) {
if (!name.equals(SQLServerDriverStringProperty.USER.toString())
&& !name.equals(SQLServerDriverStringProperty.PASSWORD.toString()))
logger.fine("Property:" + name + " Value:" + value);
}
p.put(name, value);
}
name = "";
value = "";
// to eat the spaces until the ; potentially we could do without the state but
// it would not be clean
state = inEscapedValueEnd;
} else {
StringBuilder builder = new StringBuilder();
builder.append(value);
builder.append(ch);
value = builder.toString();
// same state
}
}
break;
}
case inEscapedValueEnd: {
if (ch == ';') // eat space chars till ; anything else is an error
{
state = inName;
} else if (ch != ' ') {
// error if the chars are not space
SQLServerException.makeFromDriverError(null, null,
SQLServerException.getErrString("R_errorConnectionString"), null, true);
}
break;
}
default:
assert false : "parseURL: Invalid state " + state;
}
i++;
}
// Exit
switch (state) {
case inServerName:
String property = result.toString().trim();
if (property.length() > 0) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Property:serverName " + "Value:" + property);
}
p.put(SQLServerDriverStringProperty.SERVER_NAME.toString(), property);
}
break;
case inPort:
property = result.toString().trim();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Property:portNumber " + "Value:" + property);
}
p.put(SQLServerDriverIntProperty.PORT_NUMBER.toString(), property);
break;
case inInstanceName:
property = result.toString().trim();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Property:instanceName " + "Value:" + property);
}
p.put(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), property);
break;
case inValue:
// simple value trim
value = value.trim();
name = SQLServerDriver.getNormalizedPropertyName(name, logger);
if (null != name) {
if (logger.isLoggable(Level.FINE)) {
if (!name.equals(SQLServerDriverStringProperty.USER.toString())
&& !name.equals(SQLServerDriverStringProperty.PASSWORD.toString())
&& !name.equals(SQLServerDriverStringProperty.KEY_STORE_SECRET.toString()))
logger.fine("Property:" + name + " Value:" + value);
}
p.put(name, value);
}
break;
case inEscapedValueEnd:
case inStart:
// do nothing!
break;
case inName: {
name = name.trim();
if (name.length() > 0) {
SQLServerException.makeFromDriverError(null, null,
SQLServerException.getErrString("R_errorConnectionString"), null, true);
}
break;
}
default:
SQLServerException.makeFromDriverError(null, null,
SQLServerException.getErrString("R_errorConnectionString"), null, true);
}
return p;
}