#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
* Copyright 2009-2016 Ethan Lee and the MonoGame Team
*
* Released under the Microsoft Public License.
* See LICENSE for details.
*/
#endregion
#region Using Statements
using System;
using System.IO;
#endregion
namespace Microsoft.Xna.Framework.Storage
{
///
/// Contains a logical collection of files used for user-data storage.
///
///
/// MSDN documentation contains related conceptual article:
/// http://msdn.microsoft.com/en-us/library/bb200105.aspx#ID4EDB
///
public class StorageContainer : IDisposable
{
#region Public Properties
///
/// The title's (i.e. "game's") filename.
///
public string DisplayName
{
get;
private set;
}
///
/// A bool value indicating whether the instance has been disposed.
///
public bool IsDisposed
{
get;
private set;
}
///
/// The that holds logical files for the container.
///
public StorageDevice StorageDevice
{
get;
private set;
}
#endregion
#region Internal Variables
private readonly string storagePath;
#endregion
#region Events
///
/// Fired when is called or object is finalized or collected
/// by the garbage collector.
///
public event EventHandler Disposing;
#endregion
#region Internal Constructors
///
/// Initializes a new instance of the class.
///
/// The attached storage-device.
/// The title's filename.
/// The path of the storage root folder
///
/// The index of the player whose data is being saved, or null if data is for all
/// players.
///
internal StorageContainer(
StorageDevice device,
string name,
string rootPath,
PlayerIndex? playerIndex
) {
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException("A title name has to be provided in parameter name.");
}
StorageDevice = device;
DisplayName = name;
// Generate the path of the game's savefolder
storagePath = Path.Combine(
rootPath,
Path.GetFileNameWithoutExtension(
AppDomain.CurrentDomain.FriendlyName
)
);
// Create the root folder for all titles, if needed.
if (!Directory.Exists(storagePath))
{
Directory.CreateDirectory(storagePath);
}
storagePath = Path.Combine(storagePath, name);
// Create the sub-folder for this container/title's files, if needed.
if (!Directory.Exists(storagePath))
{
Directory.CreateDirectory(storagePath);
}
/* There are two types of subfolders within a StorageContainer.
* The first is a PlayerX folder, X being a specified PlayerIndex.
* The second is AllPlayers, when PlayerIndex is NOT specified.
* Basically, you should NEVER expect to have ANY file in the root
* game save folder.
* -flibit
*/
if (playerIndex.HasValue)
{
storagePath = Path.Combine(storagePath, "Player" + ((int) playerIndex.Value + 1).ToString());
}
else
{
storagePath = Path.Combine(storagePath, "AllPlayers");
}
// Create the player folder, if needed.
if (!Directory.Exists(storagePath))
{
Directory.CreateDirectory(storagePath);
}
}
#endregion
#region Public Dispose Method
///
/// Disposes un-managed objects referenced by this object.
///
public void Dispose()
{
if (Disposing != null)
{
Disposing(this, null);
}
IsDisposed = true;
}
#endregion
#region Public Create Methods
///
/// Creates a new directory in the storage-container.
///
/// Relative path of the directory to be created.
public void CreateDirectory(string directory)
{
if (string.IsNullOrEmpty(directory))
{
throw new ArgumentNullException("Parameter directory must contain a value.");
}
// Directory name is relative, so combine with our path.
string dirPath = Path.Combine(storagePath, directory);
// Now let's try to create it.
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
}
///
/// Creates a file in the storage-container.
///
/// Relative path of the file to be created.
/// Returns for the created file.
public Stream CreateFile(string file)
{
if (string.IsNullOrEmpty(file))
{
throw new ArgumentNullException("Parameter file must contain a value.");
}
// File name is relative, so combine with our path.
string filePath = Path.Combine(storagePath, file);
// Return a new file with read/write access.
return File.Create(filePath);
}
#endregion
#region Public Delete Methods
///
/// Deletes specified directory from the storage-container.
///
/// The relative path of the directory to be deleted.
public void DeleteDirectory(string directory)
{
if (string.IsNullOrEmpty(directory))
{
throw new ArgumentNullException("Parameter directory must contain a value.");
}
// Directory name is relative, so combine with our path.
string dirPath = Path.Combine(storagePath, directory);
// Now let's try to delete it.
Directory.Delete(dirPath);
}
///
/// Deletes a file from the storage-container.
///
/// The relative path of the file to be deleted.
public void DeleteFile(string file)
{
if (string.IsNullOrEmpty(file))
{
throw new ArgumentNullException("Parameter file must contain a value.");
}
// Relative, so combine with our path.
string filePath = Path.Combine(storagePath, file);
// Now let's try to delete it.
File.Delete(filePath);
}
#endregion
#region Public Exists Methods
///
/// Returns true if specified path exists in the storage-container, false otherwise.
///
/// The relative path of the directory to query for.
/// True if the directory path exists, false otherwise.
public bool DirectoryExists(string directory)
{
if (string.IsNullOrEmpty(directory))
{
throw new ArgumentNullException("Parameter directory must contain a value.");
}
// Directory name is relative, so combine with our path.
string dirPath = Path.Combine(storagePath, directory);
return Directory.Exists(dirPath);
}
///
/// Returns true if the specified file exists in the storage-container, false otherwise.
///
/// The relative path of the file to query for.
/// True if file exists, false otherwise.
public bool FileExists(string file)
{
if (string.IsNullOrEmpty(file))
{
throw new ArgumentNullException("Parameter file must contain a value.");
}
// File name is relative, so combine with our path.
string filePath = Path.Combine(storagePath, file);
// Return a new file with read/write access.
return File.Exists(filePath);
}
#endregion
#region Public GetNames Methods
///
/// Returns an array of the directory names in the storage-container.
///
/// Array of directory names.
public string[] GetDirectoryNames()
{
string[] names = Directory.GetDirectories(storagePath);
for (int i = 0; i < names.Length; i += 1)
{
names[i] = names[i].Substring(storagePath.Length + 1);
}
return names;
}
///
/// Returns an array of directory names with given search pattern.
///
///
/// A search pattern that supports single-character ("?") and multicharacter ("*")
/// wildcards.
///
/// Array of matched directory names.
public string[] GetDirectoryNames(string searchPattern)
{
if (string.IsNullOrEmpty(searchPattern))
{
throw new ArgumentNullException("Parameter searchPattern must contain a value.");
}
string[] names = Directory.GetDirectories(storagePath, searchPattern);
for (int i = 0; i < names.Length; i += 1)
{
names[i] = names[i].Substring(storagePath.Length + 1);
}
return names;
}
///
/// Returns an array of file names in the storage-container.
///
/// Array of file names.
public string[] GetFileNames()
{
string[] names = Directory.GetFiles(storagePath);
for (int i = 0; i < names.Length; i += 1)
{
names[i] = names[i].Substring(storagePath.Length + 1);
}
return names;
}
///
/// Returns an array of file names with given search pattern.
///
///
/// A search pattern that supports single-character ("?") and multicharacter ("*")
/// wildcards.
///
/// Array of matched file names.
public string[] GetFileNames(string searchPattern)
{
if (string.IsNullOrEmpty(searchPattern))
{
throw new ArgumentNullException("Parameter searchPattern must contain a value.");
}
string[] names = Directory.GetFiles(storagePath, searchPattern);
for (int i = 0; i < names.Length; i += 1)
{
names[i] = names[i].Substring(storagePath.Length + 1);
}
return names;
}
#endregion
#region Public OpenFile Methods
///
/// Opens a file contained in storage-container.
///
/// Relative path of the file.
///
/// that specifies how the file is to be opened.
///
/// object for the opened file.
public Stream OpenFile(
string file,
FileMode fileMode
) {
return OpenFile(
file,
fileMode,
FileAccess.ReadWrite,
FileShare.ReadWrite
);
}
///
/// Opens a file contained in storage-container.
///
/// Relative path of the file.
///
/// that specifies how the file is to be opened.
///
///
/// that specifies access mode.
///
/// object for the opened file.
public Stream OpenFile(
string file,
FileMode fileMode,
FileAccess fileAccess
) {
return OpenFile(
file,
fileMode,
fileAccess,
FileShare.ReadWrite
);
}
///
/// Opens a file contained in storage-container.
///
/// Relative path of the file.
///
/// that specifies how the file is to be opened.
///
///
/// that specifies access mode.
///
/// A bitwise combination of
/// enumeration values that specifies access modes for other stream objects.
/// object for the opened file.
public Stream OpenFile(
string file,
FileMode fileMode,
FileAccess fileAccess,
FileShare fileShare
) {
if (string.IsNullOrEmpty(file))
{
throw new ArgumentNullException("Parameter file must contain a value.");
}
// Filename is relative, so combine with our path.
string filePath = Path.Combine(storagePath, file);
return File.Open(filePath, fileMode, fileAccess, fileShare);
}
#endregion
}
}