A game framework written with osu! in mind.
at master 110 lines 4.3 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Collections.Generic; 6using System.IO; 7using System.Linq; 8using JetBrains.Annotations; 9 10namespace osu.Framework.Platform 11{ 12 public class NativeStorage : Storage 13 { 14 private readonly GameHost host; 15 16 public NativeStorage(string path, GameHost host = null) 17 : base(path) 18 { 19 this.host = host; 20 } 21 22 public override bool Exists(string path) => File.Exists(GetFullPath(path)); 23 24 public override bool ExistsDirectory(string path) => Directory.Exists(GetFullPath(path)); 25 26 public override void DeleteDirectory(string path) 27 { 28 path = GetFullPath(path); 29 30 // handles the case where the directory doesn't exist, which will throw a DirectoryNotFoundException. 31 if (Directory.Exists(path)) 32 Directory.Delete(path, true); 33 } 34 35 public override void Delete(string path) 36 { 37 path = GetFullPath(path); 38 39 if (File.Exists(path)) 40 File.Delete(path); 41 } 42 43 public override IEnumerable<string> GetDirectories(string path) => getRelativePaths(Directory.GetDirectories(GetFullPath(path))); 44 45 public override IEnumerable<string> GetFiles(string path, string pattern = "*") => getRelativePaths(Directory.GetFiles(GetFullPath(path), pattern)); 46 47 private IEnumerable<string> getRelativePaths(IEnumerable<string> paths) 48 { 49 string basePath = Path.GetFullPath(GetFullPath(string.Empty)); 50 return paths.Select(Path.GetFullPath).Select(path => 51 { 52 if (!path.StartsWith(basePath, StringComparison.Ordinal)) throw new ArgumentException($"\"{path}\" does not start with \"{basePath}\" and is probably malformed"); 53 54 return path.AsSpan(basePath.Length).TrimStart(Path.DirectorySeparatorChar).ToString(); 55 }); 56 } 57 58 public override string GetFullPath(string path, bool createIfNotExisting = false) 59 { 60 path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); 61 62 var basePath = Path.GetFullPath(BasePath).TrimEnd(Path.DirectorySeparatorChar); 63 var resolvedPath = Path.GetFullPath(Path.Combine(basePath, path)); 64 65 if (!resolvedPath.StartsWith(basePath, StringComparison.Ordinal)) throw new ArgumentException($"\"{resolvedPath}\" traverses outside of \"{basePath}\" and is probably malformed"); 66 67 if (createIfNotExisting) Directory.CreateDirectory(Path.GetDirectoryName(resolvedPath)); 68 return resolvedPath; 69 } 70 71 public override void OpenPathInNativeExplorer(string path) => 72 host?.OpenFileExternally(GetFullPath(path)); 73 74 public override Stream GetStream(string path, FileAccess access = FileAccess.Read, FileMode mode = FileMode.OpenOrCreate) 75 { 76 path = GetFullPath(path, access != FileAccess.Read); 77 78 if (string.IsNullOrEmpty(path)) 79 throw new ArgumentNullException(nameof(path)); 80 81 switch (access) 82 { 83 case FileAccess.Read: 84 if (!File.Exists(path)) return null; 85 86 return File.Open(path, FileMode.Open, access, FileShare.Read); 87 88 default: 89 return File.Open(path, mode, access); 90 } 91 } 92 93 public override string GetDatabaseConnectionString(string name) => string.Concat("Data Source=", GetFullPath($@"{name}.db", true)); 94 95 public override void DeleteDatabase(string name) => Delete($@"{name}.db"); 96 97 public override Storage GetStorageForDirectory([NotNull] string path) 98 { 99 if (path == null) throw new ArgumentNullException(nameof(path)); 100 101 if (path.Length > 0 && !path.EndsWith(Path.DirectorySeparatorChar)) 102 path += Path.DirectorySeparatorChar; 103 104 // create non-existing path. 105 var fullPath = GetFullPath(path, true); 106 107 return (Storage)Activator.CreateInstance(GetType(), fullPath, host); 108 } 109 } 110}