Skip to content

Instantly share code, notes, and snippets.

@dbeattie71
Last active August 29, 2015 14:05
Show Gist options
  • Save dbeattie71/dad8d2338ac63b8d4e13 to your computer and use it in GitHub Desktop.
Save dbeattie71/dad8d2338ac63b8d4e13 to your computer and use it in GitHub Desktop.
PCLStorage stuff
using System;
using PCLStorage;
namespace Flashlist.Common
{
//https://github.com/mono/mono/blob/master/mcs/class/corlib/System.IO/Path.cs
public static class PortablePathEx
{
public static string ChangeExtension(string path, string extension)
{
if (path == null)
return null;
if (path.IndexOfAny(InvalidPathChars) != -1)
throw new ArgumentException("Illegal characters in path.");
var iExt = findExtension(path);
if (extension == null)
return iExt < 0 ? path : path.Substring(0, iExt);
if (extension.Length == 0)
return iExt < 0 ? path + '.' : path.Substring(0, iExt + 1);
if (path.Length != 0)
{
if (extension.Length > 0 && extension[0] != '.')
extension = "." + extension;
}
else
extension = String.Empty;
if (iExt < 0)
return path + extension;
if (iExt > 0)
{
var temp = path.Substring(0, iExt);
return temp + extension;
}
return extension;
}
public static string Combine(string path1, string path2)
{
if (path1 == null)
throw new ArgumentNullException("path1");
if (path2 == null)
throw new ArgumentNullException("path2");
if (path1.Length == 0)
return path2;
if (path2.Length == 0)
return path1;
if (path1.IndexOfAny(InvalidPathChars) != -1)
throw new ArgumentException("Illegal characters in path.");
if (path2.IndexOfAny(InvalidPathChars) != -1)
throw new ArgumentException("Illegal characters in path.");
//TODO???: UNC names
if (IsPathRooted(path2))
return path2;
var p1end = path1[path1.Length - 1];
if (p1end != DirectorySeparatorChar && p1end != AltDirectorySeparatorChar && p1end != VolumeSeparatorChar)
return path1 + DirectorySeparatorStr + path2;
return path1 + path2;
}
public static string GetDirectoryName(string path)
{
// LAMESPEC: For empty string MS docs say both
// return null AND throw exception. Seems .NET throws.
if (path == String.Empty)
throw new ArgumentException("Invalid path");
if (path == null || GetPathRoot(path) == path)
return null;
if (path.Trim().Length == 0)
throw new ArgumentException("Argument string consists of whitespace characters only.");
if (path.IndexOfAny(InvalidPathChars) > -1)
throw new ArgumentException("Path contains invalid characters");
var nLast = path.LastIndexOfAny(PathSeparatorChars);
if (nLast == 0)
nLast++;
if (nLast > 0)
{
var ret = path.Substring(0, nLast);
var l = ret.Length;
if (l >= 2 && DirectorySeparatorChar == '\\' && ret[l - 1] == VolumeSeparatorChar)
return ret + DirectorySeparatorChar;
if (l == 1 && DirectorySeparatorChar == '\\' && path.Length >= 2 && path[nLast] == VolumeSeparatorChar)
return ret + VolumeSeparatorChar;
//
// Important: do not use CanonicalizePath here, use
// the custom CleanPath here, as this should not
// return absolute paths
//
return CleanPath(ret);
}
return String.Empty;
}
public static string GetExtension(string path)
{
if (path == null)
return null;
if (path.IndexOfAny(InvalidPathChars) != -1)
throw new ArgumentException("Illegal characters in path.");
var iExt = findExtension(path);
if (iExt > -1)
if (iExt < path.Length - 1)
return path.Substring(iExt);
return string.Empty;
}
public static string GetFileName(string path)
{
if (path == null || path.Length == 0)
return path;
if (path.IndexOfAny(InvalidPathChars) != -1)
throw new ArgumentException("Illegal characters in path.");
var nLast = path.LastIndexOfAny(PathSeparatorChars);
if (nLast >= 0)
return path.Substring(nLast + 1);
return path;
}
public static string GetFileNameWithoutExtension(string path)
{
return ChangeExtension(GetFileName(path), null);
}
public static string GetPathRoot(string path)
{
if (path == null)
return null;
if (path.Trim().Length == 0)
throw new ArgumentException("The specified path is not of a legal form.");
if (!IsPathRooted(path))
return String.Empty;
if (DirectorySeparatorChar == '/')
// UNIX
return IsDsc(path[0]) ? DirectorySeparatorStr : String.Empty;
// Windows
var len = 2;
if (path.Length == 1 && IsDsc(path[0]))
return DirectorySeparatorStr;
if (path.Length < 2)
return String.Empty;
if (IsDsc(path[0]) && IsDsc(path[1]))
{
// UNC: \\server or \\server\share
// Get server
while (len < path.Length && !IsDsc(path[len])) len++;
// Get share
if (len < path.Length)
{
len++;
while (len < path.Length && !IsDsc(path[len])) len++;
}
return DirectorySeparatorStr +
DirectorySeparatorStr +
path.Substring(2, len - 2).Replace(AltDirectorySeparatorChar, DirectorySeparatorChar);
}
if (IsDsc(path[0]))
// path starts with '\' or '/'
return DirectorySeparatorStr;
if (path[1] == VolumeSeparatorChar)
{
// C:\folder
if (path.Length >= 3 && (IsDsc(path[2]))) len++;
}
else
// return Directory.GetCurrentDirectory().Substring(0, 2);// + path.Substring (0, len);
return GetCurrentDirectory().Substring(0, 2); // + path.Substring (0, len);
return path.Substring(0, len);
}
public static bool IsPathRooted(string path)
{
if (path == null || path.Length == 0)
return false;
if (path.IndexOfAny(InvalidPathChars) != -1)
throw new ArgumentException("Illegal characters in path.");
var c = path[0];
return (c == DirectorySeparatorChar ||
c == AltDirectorySeparatorChar ||
(!dirEqualsVolume && path.Length > 1 && path[1] == VolumeSeparatorChar));
}
public static char[] GetInvalidPathChars()
{
// return a new array as we do not want anyone to be able to change the values
//if (Environment.IsRunningOnWindows) {
return new char[36]
{
'\x22', '\x3C', '\x3E', '\x7C', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
'\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
'\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
'\x1E', '\x1F'
};
//} else {
// return new char [1] { '\x00' };
//}
}
private static bool IsDsc(char c)
{
return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar;
}
private static string GetCurrentDirectory()
{
return FileSystem.Current.LocalStorage.Path;
}
private static int findExtension(string path)
{
// method should return the index of the path extension
// start or -1 if no valid extension
if (path != null)
{
var iLastDot = path.LastIndexOf('.');
var iLastSep = path.LastIndexOfAny(PathSeparatorChars);
if (iLastDot > iLastSep)
return iLastDot;
}
return -1;
}
public static readonly char[] InvalidPathChars;
public static readonly char AltDirectorySeparatorChar;
public static readonly char DirectorySeparatorChar;
public static readonly char VolumeSeparatorChar;
public static readonly char PathSeparator;
internal static readonly string DirectorySeparatorStr;
internal static readonly char[] PathSeparatorChars;
private static readonly bool dirEqualsVolume;
internal static string CleanPath(string s)
{
var l = s.Length;
var sub = 0;
var start = 0;
// Host prefix?
var s0 = s[0];
if (l > 2 && s0 == '\\' && s[1] == '\\') start = 2;
// We are only left with root
if (l == 1 && (s0 == DirectorySeparatorChar || s0 == AltDirectorySeparatorChar))
return s;
// Cleanup
for (var i = start; i < l; i++)
{
var c = s[i];
if (c != DirectorySeparatorChar && c != AltDirectorySeparatorChar)
continue;
if (i + 1 == l)
sub++;
else
{
c = s[i + 1];
if (c == DirectorySeparatorChar || c == AltDirectorySeparatorChar)
sub++;
}
}
if (sub == 0)
return s;
var copy = new char[l - sub];
if (start != 0)
{
copy[0] = '\\';
copy[1] = '\\';
}
for (int i = start, j = start; i < l && j < copy.Length; i++)
{
var c = s[i];
if (c != DirectorySeparatorChar && c != AltDirectorySeparatorChar)
{
copy[j++] = c;
continue;
}
// For non-trailing cases.
if (j + 1 != copy.Length)
{
copy[j++] = DirectorySeparatorChar;
for (; i < l - 1; i++)
{
c = s[i + 1];
if (c != DirectorySeparatorChar && c != AltDirectorySeparatorChar)
break;
}
}
}
return new String(copy);
}
static PortablePathEx()
{
//VolumeSeparatorChar = MonoIO.VolumeSeparatorChar;
//DirectorySeparatorChar = MonoIO.DirectorySeparatorChar;
//AltDirectorySeparatorChar = MonoIO.AltDirectorySeparatorChar;
VolumeSeparatorChar = ':';
DirectorySeparatorChar = '\\';
AltDirectorySeparatorChar = '/';
//PathSeparator = MonoIO.PathSeparator;
PathSeparator = ';';
// this copy will be modifiable ("by design")
InvalidPathChars = GetInvalidPathChars();
// internal fields
DirectorySeparatorStr = DirectorySeparatorChar.ToString();
PathSeparatorChars = new[]
{
DirectorySeparatorChar,
AltDirectorySeparatorChar,
VolumeSeparatorChar
};
dirEqualsVolume = (DirectorySeparatorChar == VolumeSeparatorChar);
}
}
}
using System;
using System.IO;
using System.Threading.Tasks;
using Flashlist.Common;
using PCLStorage;
namespace Flashlist.Services
{
public interface IStorageService
{
Task<TryResult<string>> TryReadTextFileAsync(string path);
Task WriteFileAsync(string path, string contents);
}
public class StorageService : IStorageService
{
public async Task<TryResult<string>> TryReadTextFileAsync(string path)
{
var content = "";
var operationSucceeded = await TryReadFileCommonAsync(path, async stream =>
{
using (var reader = new StreamReader(stream))
{
content = await reader.ReadToEndAsync().ConfigureAwait(false);
return true;
}
}).ConfigureAwait(false);
return TryResult.Create(operationSucceeded, content);
}
public async Task WriteFileAsync(string path, string contents)
{
await WriteFileCommonAsync(path, async stream =>
{
using (var writer = new StreamWriter(stream))
{
await writer.WriteAsync(contents).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
private static async Task<bool> TryReadFileCommonAsync(string path, Func<Stream, Task<bool>> streamAction)
{
var fullPath = FullPath(path);
var file = await FileSystem.GetFileFromPathAsync(fullPath);
if (file == null)
return false;
return await streamAction(await file.OpenAsync(FileAccess.Read)).ConfigureAwait(false);
}
private static string FullPath(string path)
{
return PortablePath.Combine(PCLStorage.FileSystem.Current.LocalStorage.Path, path);
}
private async Task WriteFileCommonAsync(string path, Func<Stream, Task> streamAction)
{
var fullPath = FullPath(path);
var file = await FileSystem.GetFileFromPathAsync(fullPath);
if (file != null)
await file.DeleteAsync();
var folderPath = PortablePathEx.GetDirectoryName(fullPath);
var folder = await FileSystem.GetFolderFromPathAsync(folderPath);
if (folder == null)
throw new Exception("Folder does not exist.");
var filename = PortablePathEx.GetFileName(path);
var newFile = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
using (var fileStream = await newFile.OpenAsync(FileAccess.ReadAndWrite))
{
await streamAction(fileStream).ConfigureAwait(false);
}
}
private static readonly IFileSystem FileSystem = PCLStorage.FileSystem.Current;
}
public static class TryResult
{
public static TryResult<TResult> Create<TResult>(bool operationSucceeded, TResult result)
{
return new TryResult<TResult>(operationSucceeded, result);
}
}
public class TryResult<TResult>
{
public bool OperationSucceeded { get; private set; }
public TResult Result { get; private set; }
public TryResult(bool operationSucceeded, TResult result = default(TResult))
{
OperationSucceeded = operationSucceeded;
Result = result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment