A game framework written with osu! in mind.
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;
7
8namespace osu.Framework.Platform
9{
10 public abstract class Storage
11 {
12 protected string BasePath { get; }
13
14 protected Storage(string path, string subfolder = null)
15 {
16 static string filenameStrip(string entry)
17 {
18 foreach (char c in Path.GetInvalidFileNameChars())
19 entry = entry.Replace(c.ToString(), string.Empty);
20 return entry;
21 }
22
23 BasePath = path;
24
25 if (BasePath == null)
26 throw new InvalidOperationException($"{nameof(BasePath)} not correctly initialized!");
27
28 if (!string.IsNullOrEmpty(subfolder))
29 BasePath = Path.Combine(BasePath, filenameStrip(subfolder));
30 }
31
32 /// <summary>
33 /// Get a usable filesystem path for the provided incomplete path.
34 /// </summary>
35 /// <param name="path">An incomplete path, usually provided as user input.</param>
36 /// <param name="createIfNotExisting">Create the path if it doesn't already exist.</param>
37 /// <returns>A usable filesystem path.</returns>
38 public abstract string GetFullPath(string path, bool createIfNotExisting = false);
39
40 /// <summary>
41 /// Check whether a file exists at the specified path.
42 /// </summary>
43 /// <param name="path">The path to check.</param>
44 /// <returns>Whether a file exists.</returns>
45 public abstract bool Exists(string path);
46
47 /// <summary>
48 /// Check whether a directory exists at the specified path.
49 /// </summary>
50 /// <param name="path">The path to check.</param>
51 /// <returns>Whether a directory exists.</returns>
52 public abstract bool ExistsDirectory(string path);
53
54 /// <summary>
55 /// Delete a directory and all its contents recursively.
56 /// </summary>
57 /// <param name="path">The path of the directory to delete.</param>
58 public abstract void DeleteDirectory(string path);
59
60 /// <summary>
61 /// Delete a file.
62 /// </summary>
63 /// <param name="path">The path of the file to delete.</param>
64 public abstract void Delete(string path);
65
66 /// <summary>
67 /// Retrieve a list of directories at the specified path.
68 /// </summary>
69 /// <param name="path">The path to list.</param>
70 /// <returns>A list of directories in the path, relative to the path of this storage.</returns>
71 public abstract IEnumerable<string> GetDirectories(string path);
72
73 /// <summary>
74 /// Retrieve a list of files at the specified path.
75 /// </summary>
76 /// <param name="path">The path to list.</param>
77 /// <param name="pattern">An optional search pattern. Accepts "*" wildcard.</param>
78 /// <returns>A list of files in the path, relative to the path of this storage.</returns>
79 public abstract IEnumerable<string> GetFiles(string path, string pattern = "*");
80
81 /// <summary>
82 /// Retrieve a <see cref="Storage"/> for a contained directory.
83 /// Creates the path if not existing.
84 /// </summary>
85 /// <param name="path">The subdirectory to use as a root.</param>
86 /// <returns>A more specific storage.</returns>
87 public virtual Storage GetStorageForDirectory(string path)
88 {
89 if (string.IsNullOrEmpty(path))
90 throw new ArgumentException("Must be non-null and not empty string", nameof(path));
91
92 if (!path.EndsWith(Path.DirectorySeparatorChar))
93 path += Path.DirectorySeparatorChar;
94
95 // create non-existing path.
96 var fullPath = GetFullPath(path, true);
97
98 return (Storage)Activator.CreateInstance(GetType(), fullPath);
99 }
100
101 /// <summary>
102 /// Retrieve a stream from an underlying file inside this storage.
103 /// </summary>
104 /// <param name="path">The path of the file.</param>
105 /// <param name="access">The access requirements.</param>
106 /// <param name="mode">The mode in which the file should be opened.</param>
107 /// <returns>A stream associated with the requested path.</returns>
108 public abstract Stream GetStream(string path, FileAccess access = FileAccess.Read, FileMode mode = FileMode.OpenOrCreate);
109
110 /// <summary>
111 /// Retrieve an SQLite database connection string from within this storage.
112 /// </summary>
113 /// <param name="name">The name of the database.</param>
114 /// <returns>An SQLite connection string.</returns>
115 public abstract string GetDatabaseConnectionString(string name);
116
117 /// <summary>
118 /// Delete an SQLite database from within this storage.
119 /// </summary>
120 /// <param name="name">The name of the database to delete.</param>
121 public abstract void DeleteDatabase(string name);
122
123 /// <summary>
124 /// Opens a native file browser window to the root path of this storage.
125 /// </summary>
126 public void OpenInNativeExplorer() => OpenPathInNativeExplorer(string.Empty);
127
128 /// <summary>
129 /// Opens a native file browser window to the specified relative path.
130 /// </summary>
131 public abstract void OpenPathInNativeExplorer(string path);
132 }
133}