Skip to content
This repository was archived by the owner on Dec 6, 2024. It is now read-only.
This repository was archived by the owner on Dec 6, 2024. It is now read-only.

ExtensionMethod FileSystemInfo.ToUrl(..) #305

@HugoRoss

Description

@HugoRoss

I made an extension method that correctly converts a file path into a file url and returns it as URI. If you are interested in, feel free to implement it somehow...

using System;
using System.ComponentModel;
using System.IO;
using System.Text;

/// <summary>Defines an extension method called <see cref="ToUrl" /> for <see cref="FileInfo" /> and <see cref="DirectoryInfo" /> 
/// objects to retrieve their file URL (e.g. "file:///c:/foo/bar.txt").</summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class Ext_FileSystemInfo_ToUrl {

	//Public Extension Methods

	/// <summary>Converts the path of a file or folder into a file URL (e.g. "file:///c:/foo/bar.txt").</summary>
	/// <param name="fileOrFolder">The file or folder whose URL to return.</param>
	/// <returns>The properly escaped URL (you can call <see cref="Uri.LocalPath" /> on it to revert to the original file path, e.g. "C:\foo\bar.txt").</returns>
	/// <exception cref="System.NullReferenceException">A <see cref="NullReferenceException" /> (not an <see cref="ArgumentNullException" />!) is thrown if the given file or folder is null, to simulate instance method behavior.</exception>
	/// <exception cref="System.FormatException">A <see cref="NullReferenceException" /> (not an <see cref="ArgumentNullException" />!) is thrown if the given file or folder is null, to simulate instance method behavior.</exception>
	public static Uri ToUrl(this FileSystemInfo fileOrFolder) {
		//Check args (simulate instance method behavior)
		if (Object.ReferenceEquals(fileOrFolder, null)) throw new NullReferenceException();
		//Convert absolute path to file or folder
		String myFileUri = FilePathToFileUrl(fileOrFolder.FullName);
		Uri myResult = new Uri(myFileUri);
		//Return the result
		return myResult;
	}

	//Private Methods

	/// <summary>Converts a file path into a properly escaped file URI (e.g. "C:\foo, bar\Alice%33.txt" -&gt; "file:///C:/foo%2C%20bar/Alice%2533.txt"). 
	/// It intentionally does not use classes <see cref="Uri" /> nor <see cref="UriBuilder" /> for the escaping as they are rather buggy.</summary>
	/// <param name="filePath">The absolute path to the file or folder.</param>
	/// <returns>A properly escaped file URI.</returns>
	/// <exception cref="System.ArgumentNullException">An ArgumentNullException is thrown if the path is null or white-space.</exception>
	private static String FilePathToFileUrl(String filePath) {
		//Credits to poizan42 from http://stackoverflow.com/users/1555496/poizan42 who provided the logic this method is based on (MIT licensed).
		if (String.IsNullOrWhiteSpace(filePath)) throw new ArgumentNullException(nameof(filePath));
		StringBuilder myResult = new StringBuilder((Int32)(filePath.Length * 1.2) + 8); //Assumes that every 10th character must be escaped with 2 additional chars
		Char myDirectorySeparatorChar = '\\'; //Path.DirectorySeparatorChar
		Char myAltDirectorySeparatorChar = '/'; //Path.AltDirectorySeparatorChar
		String myOtherValidChars = ".+-_:~";
		foreach (Char c in filePath) {
			//Check whether it is a letter or digit or above ASC 255
			if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c > '\xFF')) {
				myResult.Append(c);
				continue;
			}
			//Check whether it is a directory separator
			if ((c == myDirectorySeparatorChar) || (c == myAltDirectorySeparatorChar)) {
				myResult.Append('/');
				continue;
			}
			//Check whether it is a valid sign
			if (myOtherValidChars.IndexOf(c) > -1) {
				myResult.Append(c);
				continue;
			}
			//Otherwise escape it
			myResult.AppendFormat("%{0:X2}", (int)c);
		}
		//Append prefix (UNC vs. ordinary path)
		String myPrefix = (myResult.Length >= 2 && myResult[0] == '/' && myResult[1] == '/') ? "file:" : "file:///";
		myResult.Insert(0, myPrefix);
		//Return result
		return myResult.ToString();
	}

}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions