// (C) 2001 Garrett Rooney
// (C) 2003 Ian MacLean
// (C) 2003 Ben Maurer
-// Copyright (C) 2003,2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2003,2009 Novell, Inc (http://www.novell.com)
+// Copyright (c) 2009 Stephane Delcroix
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
namespace System {
[Serializable]
-#if NET_2_0
-#if !NET_2_1
[TypeConverter (typeof (UriTypeConverter))]
-#endif
public class Uri : ISerializable {
-#else
- public class Uri : MarshalByRefObject, ISerializable {
-#endif
// NOTES:
// o scheme excludes the scheme delimiter
// o port is -1 to indicate no port is defined
public static readonly string UriSchemeMailto = "mailto";
public static readonly string UriSchemeNews = "news";
public static readonly string UriSchemeNntp = "nntp";
-#if NET_2_0
public static readonly string UriSchemeNetPipe = "net.pipe";
public static readonly string UriSchemeNetTcp = "net.tcp";
-#endif
// Constructors
+#if MOONLIGHT
+ public Uri (string uriString) : this (uriString, UriKind.Absolute)
+ {
+ }
+#else
public Uri (string uriString) : this (uriString, false)
{
}
-
- protected Uri (SerializationInfo serializationInfo,
- StreamingContext streamingContext) :
- this (serializationInfo.GetString ("AbsoluteUri"), true)
+#endif
+ protected Uri (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
+ string uri = serializationInfo.GetString ("AbsoluteUri");
+ if (uri.Length > 0) {
+ source = uri;
+ ParseUri(UriKind.Absolute);
+ } else {
+ uri = serializationInfo.GetString ("RelativeUri");
+ if (uri.Length > 0) {
+ source = uri;
+ ParseUri(UriKind.Relative);
+ } else {
+ throw new ArgumentException("Uri string was null or empty.");
+ }
+ }
}
-#if NET_2_0
public Uri (string uriString, UriKind uriKind)
{
source = uriString;
break;
default:
string msg = Locale.GetText ("Invalid UriKind value '{0}'.", uriKind);
- throw new ArgumentException ("uriKind", msg);
+ throw new ArgumentException (msg);
}
}
// An exception-less constructor, returns success
// condition on the out parameter `success'.
//
- internal Uri (string uriString, UriKind uriKind, out bool success)
+ Uri (string uriString, UriKind uriKind, out bool success)
{
- if (uriString == null){
+ if (uriString == null) {
success = false;
return;
}
+ if (uriKind != UriKind.RelativeOrAbsolute &&
+ uriKind != UriKind.Absolute &&
+ uriKind != UriKind.Relative) {
+ string msg = Locale.GetText ("Invalid UriKind value '{0}'.", uriKind);
+ throw new ArgumentException (msg);
+ }
+
source = uriString;
if (ParseNoExceptions (uriKind, uriString) != null)
success = false;
}
public Uri (Uri baseUri, Uri relativeUri)
- : this (baseUri, relativeUri.OriginalString, false)
{
+ Merge (baseUri, relativeUri == null ? String.Empty : relativeUri.OriginalString);
// FIXME: this should call UriParser.Resolve
}
throw new UriFormatException("Invalid URI: The format of the URI could not be "
+ "determined: " + uriString);
}
-#else
- public Uri (string uriString, bool dontEscape)
- {
- userEscaped = dontEscape;
- source = uriString;
- Parse ();
- if (!isAbsoluteUri)
- throw new UriFormatException("Invalid URI: The format of the URI could not be "
- + "determined.");
- }
-#endif
public Uri (Uri baseUri, string relativeUri)
- : this (baseUri, relativeUri, false)
{
+ Merge (baseUri, relativeUri);
// FIXME: this should call UriParser.Resolve
}
-#if NET_2_0
[Obsolete ("dontEscape is always false")]
-#endif
public Uri (Uri baseUri, string relativeUri, bool dontEscape)
{
-#if NET_2_0
+ userEscaped = dontEscape;
+ Merge (baseUri, relativeUri);
+ }
+
+ private void Merge (Uri baseUri, string relativeUri)
+ {
if (baseUri == null)
throw new ArgumentNullException ("baseUri");
+ if (!baseUri.IsAbsoluteUri)
+ throw new ArgumentOutOfRangeException ("baseUri");
if (relativeUri == null)
relativeUri = String.Empty;
-#else
- if (baseUri == null)
- throw new NullReferenceException ("baseUri");
-#endif
- // See RFC 2396 Par 5.2 and Appendix C
- userEscaped = dontEscape;
+ // See RFC 2396 Par 5.2 and Appendix C
// Check Windows UNC (for // it is scheme/host separator)
if (relativeUri.Length >= 2 && relativeUri [0] == '\\' && relativeUri [1] == '\\') {
source = relativeUri;
-#if NET_2_0
ParseUri (UriKind.Absolute);
-#else
- Parse ();
-#endif
return;
}
relativeUri.Length > pos + 1 &&
relativeUri [pos + 1] == '/') {
source = relativeUri;
-#if NET_2_0
ParseUri (UriKind.Absolute);
-#else
- Parse ();
-#endif
return;
}
else
this.isUnixFilePath = baseUri.isUnixFilePath;
this.isOpaquePart = baseUri.isOpaquePart;
- if (relativeUri == String.Empty) {
+ if (relativeUri.Length == 0) {
this.path = baseUri.path;
this.query = baseUri.query;
this.fragment = baseUri.fragment;
return;
}
-
+
// 8 fragment
// Note that in relative constructor, file URI cannot handle '#' as a filename character, but just regarded as a fragment identifier.
pos = relativeUri.IndexOf ('#');
fragment = relativeUri.Substring (pos);
else
fragment = "#" + EscapeString (relativeUri.Substring (pos+1));
- relativeUri = relativeUri.Substring (0, pos);
+ relativeUri = pos == 0 ? String.Empty : relativeUri.Substring (0, pos);
}
+ bool consider_query = false;
+
// 6 query
pos = relativeUri.IndexOf ('?');
if (pos != -1) {
query = relativeUri.Substring (pos);
if (!userEscaped)
query = EscapeString (query);
- relativeUri = relativeUri.Substring (0, pos);
+#if !NET_4_0 && !MOONLIGHT
+ consider_query = query.Length > 0;
+#endif
+ relativeUri = pos == 0 ? String.Empty : relativeUri.Substring (0, pos);
+ } else if (relativeUri.Length == 0) {
+ // if there is no relative path then we keep the Query and Fragment from the absolute
+ query = baseUri.query;
}
if (relativeUri.Length > 0 && relativeUri [0] == '/') {
if (relativeUri.Length > 1 && relativeUri [1] == '/') {
source = scheme + ':' + relativeUri;
-#if NET_2_0
ParseUri (UriKind.Absolute);
-#else
- Parse ();
-#endif
return;
} else {
path = relativeUri;
// par 5.2 step 6 a)
path = baseUri.path;
- if (relativeUri.Length > 0 || query.Length > 0) {
+ if ((relativeUri.Length > 0) || consider_query) {
pos = path.LastIndexOf ('/');
if (pos >= 0)
path = path.Substring (0, pos + 1);
path = path.Remove (pos + 1, path.Length - pos - 1);
}
+ // 6 g)
+ while (path.StartsWith ("/../"))
+ path = path.Substring (3);
+
if (!userEscaped)
path = EscapeString (path);
}
public string AbsolutePath {
get {
-#if NET_2_0
EnsureAbsoluteUri ();
switch (Scheme) {
case "mailto":
}
return path;
}
-#else
- return path;
-#endif
}
}
UriHostNameType ret = CheckHostName (Host);
if (ret != UriHostNameType.Unknown)
return ret;
-#if NET_2_0
switch (Scheme) {
case "mailto":
return UriHostNameType.Basic;
default:
return (IsFile) ? UriHostNameType.Basic : ret;
}
-#else
- // looks it always returns Basic...
- return UriHostNameType.Basic; //.Unknown;
-#endif
}
}
EnsureAbsoluteUri ();
if (Host.Length == 0) {
-#if NET_2_0
return IsFile;
-#else
- return false;
-#endif
}
if (host == "loopback" || host == "localhost")
else if (System.IO.Path.DirectorySeparatorChar == '\\') {
string h = host;
if (path.Length > 0) {
-#if NET_2_0
if ((path.Length > 1) || (path[0] != '/')) {
h += path.Replace ('/', '\\');
}
-#else
- h += path.Replace ('/', '\\');
-#endif
}
cachedLocalPath = "\\\\" + Unescape (h);
} else
}
}
-#if NET_2_0
[MonoTODO ("add support for IPv6 address")]
public string DnsSafeHost {
get {
}
}
- public bool IsAbsoluteUri {
+#if NET_2_0
+ public
+#else
+ internal
+#endif
+ bool IsAbsoluteUri {
get { return isAbsoluteUri; }
}
public string OriginalString {
get { return source != null ? source : ToString (); }
}
-#endif
// Methods
if (length == 0)
return false;
uint number;
-#if NET_2_0
if (!UInt32.TryParse (captures [i], out number))
return false;
-#else
- try {
- number = UInt32.Parse (captures [i]);
- } catch (Exception) {
- return false;
- }
-#endif
if (number > 255)
return false;
}
return true;
}
+#if !NET_2_1
-#if NET_2_0
[Obsolete("This method does nothing, it has been obsoleted")]
-#endif
protected virtual void Canonicalize ()
{
//
//
}
+ [MonoTODO ("Find out what this should do")]
+ [Obsolete]
+ protected virtual void CheckSecurity ()
+ {
+ }
+
+#endif // NET_2_1
+
// defined in RFC3986 as = ALPHA *( ALPHA / DIGIT / "+" / "-" / ".")
public static bool CheckSchemeName (string schemeName)
{
private static bool IsAlpha (char c)
{
-#if NET_2_0
// as defined in rfc2234
// %x41-5A / %x61-7A (A-Z / a-z)
int i = (int) c;
return (((i >= 0x41) && (i <= 0x5A)) || ((i >= 0x61) && (i <= 0x7A)));
-#else
- // Fx 1.x got this too large
- return Char.IsLetter (c);
-#endif
- }
-
- [MonoTODO ("Find out what this should do")]
-#if NET_2_0
- [Obsolete]
-#endif
- protected virtual void CheckSecurity ()
- {
}
public override bool Equals (object comparant)
// Assumes: uri != null
bool InternalEquals (Uri uri)
{
-#if NET_2_0
if (this.isAbsoluteUri != uri.isAbsoluteUri)
return false;
if (!this.isAbsoluteUri)
return this.source == uri.source;
-#endif
CultureInfo inv = CultureInfo.InvariantCulture;
return this.scheme.ToLower (inv) == uri.scheme.ToLower (inv)
&& this.host.ToLower (inv) == uri.host.ToLower (inv)
&& this.port == uri.port
-#if NET_2_0
&& this.query == uri.query
-#else
- // Note: MS.NET 1.x has bug - ignores query check altogether
- && this.query.ToLower (inv) == uri.query.ToLower (inv)
-#endif
&& this.path == uri.path;
}
-#if NET_2_0
public static bool operator == (Uri u1, Uri u2)
{
return object.Equals(u1, u2);
{
return !(u1 == u2);
}
-#endif
public override int GetHashCode ()
{
cachedHashCode = scheme.ToLower (inv).GetHashCode ()
^ host.ToLower (inv).GetHashCode ()
^ port
-#if NET_2_0
^ query.GetHashCode ()
-#else
- ^ query.ToLower (inv).GetHashCode ()
-#endif
^ path.GetHashCode ();
}
else {
sb.Append (':').Append (port);
if (path.Length > 0) {
-#if NET_2_0
switch (Scheme) {
case "mailto":
case "news":
sb.Append (path);
break;
default:
- sb.Append (Reduce (path));
+ sb.Append (Reduce (path, CompactEscaped (Scheme)));
break;
}
-#else
- sb.Append (path);
-#endif
}
return sb.ToString ();
}
IsHexDigit (pattern [index]));
}
-#if NET_2_0
//
// Implemented by copying most of the MakeRelative code
//
}
[Obsolete ("Use MakeRelativeUri(Uri uri) instead.")]
-#endif
public string MakeRelative (Uri toUri)
{
if ((this.Scheme != toUri.Scheme) ||
void AppendQueryAndFragment (ref string result)
{
if (query.Length > 0) {
- string q = query [0] == '?' ? '?' + Unescape (query.Substring (1), false) : Unescape (query, false);
+ string q = query [0] == '?' ? '?' + Unescape (query.Substring (1), true) : Unescape (query, false);
result += q;
}
if (fragment.Length > 0)
return cachedToString;
}
-#if NET_2_0
protected void GetObjectData (SerializationInfo info, StreamingContext context)
{
- info.AddValue ("AbsoluteUri", this.AbsoluteUri);
+ if (this.isAbsoluteUri) {
+ info.AddValue ("AbsoluteUri", this.AbsoluteUri);
+ } else {
+ info.AddValue("AbsoluteUri", String.Empty);
+ info.AddValue("RelativeUri", this.OriginalString);
+ }
}
-#endif
void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
{
- info.AddValue ("AbsoluteUri", this.AbsoluteUri);
+ GetObjectData (info, context);
}
// Internal Methods
-#if NET_2_0
[Obsolete]
-#endif
protected virtual void Escape ()
{
path = EscapeString (path);
}
-#if NET_2_0
+#if MOONLIGHT
+ static string EscapeString (string str)
+#else
[Obsolete]
-#endif
protected static string EscapeString (string str)
+#endif
{
return EscapeString (str, false, true, true);
}
// On .NET 1.x, this method is called from .ctor(). When overriden, we
// can avoid the "absolute uri" constraints of the .ctor() by
// overriding with custom code.
-#if NET_2_0
[Obsolete("The method has been deprecated. It is not used by the system.")]
-#endif
protected virtual void Parse ()
{
-#if !NET_2_0
- ParseUri (UriKind.Absolute);
-#endif
}
private void ParseUri (UriKind kind)
}
}
-#if NET_2_0
+#if MOONLIGHT
+ string Unescape (string str)
+#else
[Obsolete]
-#endif
protected virtual string Unescape (string str)
+#endif
{
return Unescape (str, false);
}
}
}
- if (len <= 1 && (kind != UriKind.Relative))
+ if (len <= 1 && (kind == UriKind.Absolute))
return "Absolute URI is too short";
int pos = 0;
// 1, 2
// Identify Windows path, unix path, or standard URI.
+ if (uriString [0] == '/' && Path.DirectorySeparatorChar == '/'){
+ //Unix Path
+ ParseAsUnixAbsoluteFilePath (uriString);
+#if MOONLIGHT
+ isAbsoluteUri = false;
+#else
+ if (kind == UriKind.Relative)
+ isAbsoluteUri = false;
+#endif
+ return null;
+ } else if (uriString.Length >= 2 && uriString [0] == '\\' && uriString [1] == '\\') {
+ //Windows UNC
+ ParseAsWindowsUNC (uriString);
+ return null;
+ }
+
+
pos = uriString.IndexOf (':');
if (pos == 0) {
- return "Invalid URI: The format of the URI could not be determined.";
+ if (kind == UriKind.Absolute)
+ return "Invalid URI: The format of the URI could not be determined.";
+ isAbsoluteUri = false;
+ path = uriString;
+ return null;
} else if (pos < 0) {
- // It must be Unix file path or Windows UNC
- if (uriString [0] == '/' && Path.DirectorySeparatorChar == '/'){
- ParseAsUnixAbsoluteFilePath (uriString);
- if (kind == UriKind.Relative)
- isAbsoluteUri = false;
-
- } else if (uriString.Length >= 2 && uriString [0] == '\\' && uriString [1] == '\\')
- ParseAsWindowsUNC (uriString);
- else {
- /* Relative path */
+ /* Relative path */
+ isAbsoluteUri = false;
+ path = uriString;
+ return null;
+ } else if (pos == 1) {
+ if (!IsAlpha (uriString [0])) {
+ if (kind == UriKind.Absolute)
+ return "URI scheme must start with a letter.";
isAbsoluteUri = false;
path = uriString;
+ return null;
}
- 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)
// 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.");
+ if (!CheckSchemeName (scheme)) {
+ if (kind == UriKind.Absolute)
+ return Locale.GetText ("URI scheme must start with a letter and must consist of one of alphabet, digits, '+', '-' or '.' character.");
+ isAbsoluteUri = false;
+ path = uriString;
+ return null;
+ }
// from here we're practically working on uriString.Substring(startpos,endpos-startpos)
int startpos = pos + 1;
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 (endpos - startpos > 1 && uriString [startpos + 1] == ':')
+ if (endpos - startpos > 1 && uriString [startpos + 1] == ':') {
unixAbsPath = false;
+ windowsFilePath = true;
+ }
} else if (!IsPredefinedScheme (scheme)) {
path = uriString.Substring(startpos, endpos-startpos);
}
// 5 path
- pos = uriString.IndexOf ('/', startpos, endpos-startpos);
- if (unixAbsPath)
+ 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
}
// 4.a user info
- pos = uriString.IndexOf ('@', startpos, endpos-startpos);
+ 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;
- pos = uriString.LastIndexOf (':', endpos-1, endpos-startpos);
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);
host = uriString;
if (unixAbsPath) {
- path = '/' + uriString;
+ path = Reduce ('/' + uriString, true);
host = String.Empty;
} else if (host.Length == 2 && host [1] == ':') {
// windows filepath
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 + ")");
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);
+ path = Reduce (path, CompactEscaped (scheme));
}
return null;
}
- private static string Reduce (string path)
+ private static bool CompactEscaped (string scheme)
+ {
+ switch (scheme) {
+ case "file":
+ case "http":
+ case "https":
+ case "net.pipe":
+ case "net.tcp":
+ return true;
+ }
+ return false;
+ }
+
+ // This is called "compacting" in the MSDN documentation
+ private static string Reduce (string path, bool compact_escaped)
{
- path = path.Replace ('\\','/');
+ // quick out, allocation-free, for a common case
+ if (path == "/")
+ return path;
+
+ StringBuilder res = new StringBuilder();
+
+ if (compact_escaped) {
+ // replace '\', %5C ('\') and %2f ('/') into '/'
+ // other escaped values seems to survive this step
+ for (int i=0; i < path.Length; i++) {
+ char c = path [i];
+ switch (c) {
+ case '\\':
+ res.Append ('/');
+ break;
+ case '%':
+ if (i < path.Length - 2) {
+ char c1 = path [i + 1];
+ char c2 = Char.ToUpper (path [i + 2]);
+ if (((c1 == '2') && (c2 == 'F')) || ((c1 == '5') && (c2 == 'C'))) {
+ res.Append ('/');
+ i += 2;
+ } else {
+ res.Append (c);
+ }
+ } else {
+ res.Append (c);
+ }
+ break;
+ default:
+ res.Append (c);
+ break;
+ }
+ }
+ path = res.ToString ();
+ } else {
+ path = path.Replace ('\\', '/');
+ }
+
ArrayList result = new ArrayList ();
+ bool begin = true;
for (int startpos = 0; startpos < path.Length; ) {
int endpos = path.IndexOf('/', startpos);
if (endpos == -1) endpos = path.Length;
string current = path.Substring (startpos, endpos-startpos);
startpos = endpos + 1;
- if (current.Length == 0 || current == "." )
+ if ((begin && current.Length == 0) || current == "." )
continue;
+ begin = false;
if (current == "..") {
int resultCount = result.Count;
-#if NET_2_0
// in 2.0 profile, skip leading ".." parts
if (resultCount == 0) {
continue;
result.RemoveAt (resultCount - 1);
continue;
-#else
- // in 1.x profile, retain leading ".." parts, and only reduce
- // URI is previous part is not ".."
- if (resultCount > 0) {
- if ((string) result[resultCount - 1] != "..") {
- result.RemoveAt (resultCount - 1);
- continue;
- }
- }
-#endif
}
result.Add (current);
if (result.Count == 0)
return "/";
- StringBuilder res = new StringBuilder();
+ res.Length = 0;
if (path [0] == '/')
res.Append ('/');
internal static int GetDefaultPort (string scheme)
{
-#if NET_2_0
UriParser parser = UriParser.GetParser (scheme);
if (parser == null)
return -1;
return parser.DefaultPort;
-#else
- for (int i = 0; i < schemes.Length; i++)
- if (schemes [i].scheme == scheme)
- return schemes [i].defaultPort;
- return -1;
-#endif
}
private string GetOpaqueWiseSchemeDelimiter ()
return GetSchemeDelimiter (scheme);
}
-#if NET_2_0
[Obsolete]
-#endif
protected virtual bool IsBadFileSystemCharacter (char ch)
{
// It does not always overlap with InvalidPathChars.
return false;
}
-#if NET_2_0
[Obsolete]
-#endif
protected static bool IsExcludedCharacter (char ch)
{
if (ch <= 32 || ch >= 127)
case "gopher":
case "mailto":
case "news":
-#if NET_2_0
case "net.pipe":
case "net.tcp":
-#endif
return true;
default:
return false;
}
}
-#if NET_2_0
[Obsolete]
-#endif
protected virtual bool IsReservedCharacter (char ch)
{
if (ch == '$' || ch == '&' || ch == '+' || ch == ',' ||
return true;
return false;
}
-#if NET_2_0
+
[NonSerialized]
private UriParser parser;
private UriParser Parser {
get {
- if (parser == null)
+ if (parser == null) {
parser = UriParser.GetParser (Scheme);
+ // no specific parser ? then use a default one
+ if (parser == null)
+ parser = new DefaultUriParser ("*");
+ }
return parser;
}
set { parser = value; }
public bool IsBaseOf (Uri uri)
{
+#if NET_4_0
+ if (uri == null)
+ throw new ArgumentNullException ("uri");
+#endif
return Parser.IsBaseOf (this, uri);
}
public bool IsWellFormedOriginalString ()
{
// funny, but it does not use the Parser's IsWellFormedOriginalString().
- return EscapeString (OriginalString) == OriginalString;
+ // Also, it seems we need to *not* escape hex.
+ return EscapeString (OriginalString, false, false, true) == OriginalString;
}
// static methods
{
if (uriString == null)
return false;
- Uri uri = new Uri (uriString, uriKind);
- return uri.IsWellFormedOriginalString ();
+
+ Uri uri;
+ if (Uri.TryCreate (uriString, uriKind, out uri))
+ return uri.IsWellFormedOriginalString ();
+ return false;
}
public static bool TryCreate (string uriString, UriKind uriKind, out Uri result)
{
bool success;
+
Uri r = new Uri (uriString, uriKind, out success);
- if (success){
+ if (success) {
result = r;
return true;
}
// FIXME: this should call UriParser.Resolve
result = new Uri (baseUri, relativeUri);
return true;
- }
- catch (UriFormatException) {
+ } catch (UriFormatException) {
result = null;
return false;
}
//[MonoTODO ("rework code to avoid exception catching")]
public static bool TryCreate (Uri baseUri, Uri relativeUri, out Uri result)
{
+#if NET_4_0
+ if (relativeUri == null) {
+ result = null;
+ return false;
+ }
+#endif
try {
// FIXME: this should call UriParser.Resolve
- result = new Uri (baseUri, relativeUri);
+ result = new Uri (baseUri, relativeUri.OriginalString);
return true;
- }
- catch (UriFormatException) {
+ } catch (UriFormatException) {
result = null;
return false;
}
if (!IsAbsoluteUri)
throw new InvalidOperationException ("This operation is not supported for a relative URI.");
}
-#else
- private void EnsureAbsoluteUri ()
- {
- }
-#endif
}
}