private string ParseNoExceptions (UriKind kind, string uriString)
{
//
// From RFC 2396 :
//
// ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
// 12 3 4 5 6 7 8 9
//
uriString = uriString.Trim();
int len = uriString.Length;
if (len == 0){
if (kind == UriKind.Relative || kind == UriKind.RelativeOrAbsolute){
isAbsoluteUri = false;
return null;
}
}
if (len <= 1 && (kind != UriKind.Relative))
return "Absolute URI is too short";
int pos = 0;
// 1, 2
// Identify Windows path, unix path, or standard URI.
pos = uriString.IndexOf (':');
if (pos == 0) {
return "Invalid URI: The format of the URI could not be determined.";
} else if (pos < 0) {
// It must be Unix file path or Windows UNC
if (uriString [0] == '/' && Path.DirectorySeparatorChar == '/'){
ParseAsUnixAbsoluteFilePath (uriString);
#if NET_2_1 && !MONOTOUCH
isAbsoluteUri = false;
#else
if (kind == UriKind.Relative)
isAbsoluteUri = false;
#endif
} else if (uriString.Length >= 2 && uriString [0] == '\\' && uriString [1] == '\\')
ParseAsWindowsUNC (uriString);
else {
/* Relative path */
isAbsoluteUri = false;
path = uriString;
}
return null;
} else if (pos == 1) {
if (!IsAlpha (uriString [0]))
return "URI scheme must start with a letter.";
// This means 'a:' == windows full path.
string msg = ParseAsWindowsAbsoluteFilePath (uriString);
if (msg != null)
return msg;
return null;
}
// scheme
scheme = uriString.Substring (0, pos).ToLower (CultureInfo.InvariantCulture);
// Check scheme name characters as specified in RFC2396.
// Note: different checks in 1.x and 2.0
if (!CheckSchemeName (scheme))
return Locale.GetText ("URI scheme must start with a letter and must consist of one of alphabet, digits, '+', '-' or '.' character.");
// from here we're practically working on uriString.Substring(startpos,endpos-startpos)
int startpos = pos + 1;
int endpos = uriString.Length;
// 8 fragment
pos = uriString.IndexOf ('#', startpos);
if (!IsUnc && pos != -1) {
if (userEscaped)
fragment = uriString.Substring (pos);
else
fragment = "#" + EscapeString (uriString.Substring (pos+1));
endpos = pos;
}
// 6 query
pos = uriString.IndexOf ('?', startpos, endpos-startpos);
if (pos != -1) {
query = uriString.Substring (pos, endpos-pos);
endpos = pos;
if (!userEscaped)
query = EscapeString (query);
}
// 3
if (IsPredefinedScheme (scheme) && scheme != UriSchemeMailto && scheme != UriSchemeNews && (
(endpos-startpos < 2) ||
(endpos-startpos >= 2 && uriString [startpos] == '/' && uriString [startpos+1] != '/')))
return "Invalid URI: The Authority/Host could not be parsed.";
bool startsWithSlashSlash = endpos-startpos >= 2 && uriString [startpos] == '/' && uriString [startpos+1] == '/';
bool unixAbsPath = scheme == UriSchemeFile && startsWithSlashSlash && (endpos-startpos == 2 || uriString [startpos+2] == '/');
bool windowsFilePath = false;
if (startsWithSlashSlash) {
if (kind == UriKind.Relative)
return "Absolute URI when we expected a relative one";
if (scheme != UriSchemeMailto && scheme != UriSchemeNews)
startpos += 2;
if (scheme == UriSchemeFile) {
int num_leading_slash = 2;
for (int i = startpos; i < endpos; i++) {
if (uriString [i] != '/')
break;
num_leading_slash++;
}
if (num_leading_slash >= 4) {
unixAbsPath = false;
while (startpos < endpos && uriString[startpos] == '/') {
startpos++;
}
} else if (num_leading_slash >= 3) {
startpos += 1;
}
}
if (endpos - startpos > 1 && uriString [startpos + 1] == ':') {
unixAbsPath = false;
windowsFilePath = true;
}
} else if (!IsPredefinedScheme (scheme)) {
path = uriString.Substring(startpos, endpos-startpos);
isOpaquePart = true;
return null;
}
// 5 path
if (unixAbsPath) {
pos = -1;
} else {
pos = uriString.IndexOf ('/', startpos, endpos-startpos);
if (pos == -1 && windowsFilePath)
pos = uriString.IndexOf ('\\', startpos, endpos-startpos);
}
if (pos == -1) {
if ((scheme != Uri.UriSchemeMailto) &&
#if ONLY_1_1
(scheme != Uri.UriSchemeFile) &&
#endif
(scheme != Uri.UriSchemeNews))
path = "/";
} else {
path = uriString.Substring (pos, endpos-pos);
endpos = pos;
}
// 4.a user info
if (unixAbsPath)
pos = -1;
else
pos = uriString.IndexOf ('@', startpos, endpos-startpos);
if (pos != -1) {
userinfo = uriString.Substring (startpos, pos-startpos);
startpos = pos + 1;
}
// 4.b port
port = -1;
if (unixAbsPath)
pos = -1;
else
pos = uriString.LastIndexOf (':', endpos-1, endpos-startpos);
if (pos != -1 && pos != endpos - 1) {
string portStr = uriString.Substring(pos + 1, endpos - (pos + 1));
if (portStr.Length > 0 && portStr[portStr.Length - 1] != ']') {
#if NET_2_0
if (!Int32.TryParse (portStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out port) ||
port < 0 || port > UInt16.MaxValue)
return "Invalid URI: Invalid port number";
endpos = pos;
#else
try {
port = (int) UInt32.Parse (portStr, CultureInfo.InvariantCulture);
endpos = pos;
} catch (Exception) {
return "Invalid URI: Invalid port number";
}
#endif
} else {
if (port == -1) {
port = GetDefaultPort (scheme);
}
}
} else {
if (port == -1) {
port = GetDefaultPort (scheme);
}
}
// 4 authority
uriString = uriString.Substring(startpos, endpos-startpos);
host = uriString;
if (unixAbsPath) {
path = Reduce ('/' + uriString, true);
host = String.Empty;
} else if (host.Length == 2 && host [1] == ':') {
// windows filepath
path = host + path;
host = String.Empty;
} else if (isUnixFilePath) {
uriString = "//" + uriString;
host = String.Empty;
} else if (scheme == UriSchemeFile) {
isUnc = true;
} else if (scheme == UriSchemeNews) {
// no host for 'news', misinterpreted path
if (host.Length > 0) {
path = host;
host = String.Empty;
}
} else if (host.Length == 0 &&
(scheme == UriSchemeHttp || scheme == UriSchemeGopher || scheme == UriSchemeNntp ||
scheme == UriSchemeHttps || scheme == UriSchemeFtp)) {
return "Invalid URI: The hostname could not be parsed";
}
bool badhost = ((host.Length > 0) && (CheckHostName (host) == UriHostNameType.Unknown));
if (!badhost && (host.Length > 1) && (host[0] == '[') && (host[host.Length - 1] == ']')) {
IPv6Address ipv6addr;
if (IPv6Address.TryParse (host, out ipv6addr))
host = "[" + ipv6addr.ToString (true) + "]";
else
badhost = true;
}
#if NET_2_0
if (badhost && (Parser is DefaultUriParser || Parser == null))
return Locale.GetText ("Invalid URI: The hostname could not be parsed. (" + host + ")");
UriFormatException ex = null;
if (Parser != null)
Parser.InitializeAndValidate (this, out ex);
if (ex != null)
return ex.Message;
#else
if (badhost)
return Locale.GetText ("Invalid URI: The hostname could not be parsed. (" + host + ")");
#endif
if ((scheme != Uri.UriSchemeMailto) &&
(scheme != Uri.UriSchemeNews) &&
(scheme != Uri.UriSchemeFile)) {
path = Reduce (path, CompactEscaped (scheme));
}
return null;
}