#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
* Copyright 2009-2015 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;
using System.Runtime.Remoting.Messaging;
#endregion
namespace Microsoft.Xna.Framework.Storage
{
///
/// Exposes a storage device for storing user data.
///
///
/// MSDN documentation contains related conceptual article:
/// http://msdn.microsoft.com/en-us/library/bb200105.aspx
///
public sealed class StorageDevice
{
#region Public Properties
///
/// Returns the amount of free space.
///
public long FreeSpace
{
get
{
try
{
return new DriveInfo(storageRoot).AvailableFreeSpace;
}
catch(Exception e)
{
// Storage root was invalid or unavailable.
throw new StorageDeviceNotConnectedException(
"The storage device bound to the container is not connected.",
e
);
}
}
}
///
/// Returns true if this StorageDevice path is accessible, false otherwise.
///
public bool IsConnected
{
get
{
if ( Game.Instance.Platform.OSVersion.Equals("Linux") ||
Game.Instance.Platform.OSVersion.Equals("Mac OS X") )
{
/* Linux and Mac use locally connected storage in the user's
* home location, which should always be "connected".
*/
return true;
}
else if (Game.Instance.Platform.OSVersion.Equals("Windows"))
{
try
{
return new DriveInfo(storageRoot).IsReady;
}
catch
{
// The storageRoot path is invalid / has been removed.
return false;
}
}
throw new Exception("StorageDevice: Platform.OSVersion not handled!");
}
}
///
/// Returns the total size of device.
///
public long TotalSpace
{
get
{
try
{
return new DriveInfo(storageRoot).TotalSize;
}
catch(Exception e)
{
// Storage root was invalid or unavailable.
throw new StorageDeviceNotConnectedException(
"The storage device bound to the container is not connected.",
e
);
}
}
}
#endregion
#region Private Variables
private PlayerIndex? devicePlayer;
private StorageContainer deviceContainer;
#endregion
#region Private Static Variables
private static readonly string storageRoot = GetStorageRoot();
#endregion
#region Events
///
/// Fired when a device is removed or inserted.
///
public static event EventHandler DeviceChanged;
private void OnDeviceChanged()
{
if (DeviceChanged != null)
{
DeviceChanged(this, null);
}
}
#endregion
#region Private Delegates
private delegate StorageDevice ShowSelectorAsynchronous(
PlayerIndex? player,
int sizeInBytes,
int directoryCount
);
private delegate StorageContainer OpenContainerAsynchronous(string displayName);
#endregion
#region Internal Constructors
///
/// Creates a new instance.
///
/// The playerIndex of the player.
/// Size of the storage device.
///
internal StorageDevice(PlayerIndex? player, int sizeInBytes, int directoryCount)
{
devicePlayer = player;
}
#endregion
#region Public OpenContainer Methods
///
/// Begins the open for a StorageContainer.
///
/// The open StorageContainer.
/// Name of file.
/// Method to call on completion.
/// Request identifier object for callback (can be null).
public IAsyncResult BeginOpenContainer(
string displayName,
AsyncCallback callback,
object state
) {
try
{
OpenContainerAsynchronous AsynchronousOpen = new OpenContainerAsynchronous(Open);
return AsynchronousOpen.BeginInvoke(displayName, callback, state);
}
finally
{
// TODO: No resources to clean up? Remove this finally block?
}
}
///
/// Ends the open container process.
///
/// The open StorageContainer.
/// Result of BeginOpenContainer.
public StorageContainer EndOpenContainer(IAsyncResult result)
{
StorageContainer returnValue = null;
try
{
// Retrieve the delegate.
AsyncResult asyncResult = result as AsyncResult;
if (asyncResult != null)
{
OpenContainerAsynchronous asyncDelegate = asyncResult.AsyncDelegate
as OpenContainerAsynchronous;
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Call EndInvoke to retrieve the results.
if (asyncDelegate != null)
{
returnValue = asyncDelegate.EndInvoke(result);
}
}
}
finally
{
// Close the wait handle.
result.AsyncWaitHandle.Dispose();
}
return returnValue;
}
#endregion
#region Public ShowSelector Methods
///
/// Begin process to display the StorageDevice selector UI.
///
/// The show selector.
/// Method to invoke when device is selected by player.
/// Request identifier object for callback (can be null).
public static IAsyncResult BeginShowSelector(
AsyncCallback callback,
object state
) {
return BeginShowSelector(
0,
0,
callback,
state
);
}
///
/// Begin process to display the StorageDevice selector UI.
///
/// The show selector.
/// The PlayerIndex. Only PlayerIndex.One is valid on Windows.
/// Method to invoke when device is selected by player.
/// Request identifier object for callback (can be null).
public static IAsyncResult BeginShowSelector(
PlayerIndex player,
AsyncCallback callback,
object state
) {
return BeginShowSelector(
player,
0,
0,
callback,
state
);
}
///
/// Begin process to display the StorageDevice selector UI.
///
/// The show selector.
/// Size (in bytes) of data to write.
/// Number of directories to write.
/// Method to invoke when device is selected by player.
/// Request identifier object for callback (can be null).
public static IAsyncResult BeginShowSelector(
int sizeInBytes,
int directoryCount,
AsyncCallback callback,
object state
) {
ShowSelectorAsynchronous del = new ShowSelectorAsynchronous(Show);
return del.BeginInvoke(null, sizeInBytes, directoryCount, callback, state);
}
///
/// Begin process to display the StorageDevice selector UI.
///
/// The show selector.
/// The PlayerIndex. Only PlayerIndex.One is valid on Windows.
/// Size (in bytes) of data to write.
/// Number of directories to write.
/// Method to invoke when device is selected by player.
/// Request identifier object for callback (can be null).
public static IAsyncResult BeginShowSelector(
PlayerIndex player,
int sizeInBytes,
int directoryCount,
AsyncCallback callback,
object state
) {
ShowSelectorAsynchronous del = new ShowSelectorAsynchronous(Show);
return del.BeginInvoke(player, sizeInBytes, directoryCount, callback, state);
}
///
/// Ends the show selector user interface display.
///
/// The storage device.
/// The result of BeginShowSelector.
public static StorageDevice EndShowSelector(IAsyncResult result)
{
if (!result.IsCompleted)
{
// Wait for the WaitHandle to become signaled.
try
{
result.AsyncWaitHandle.WaitOne();
}
finally
{
}
}
// Retrieve the delegate.
AsyncResult asyncResult = (AsyncResult) result;
ShowSelectorAsynchronous del = asyncResult.AsyncDelegate as ShowSelectorAsynchronous;
if (del != null)
{
return del.EndInvoke(result);
}
throw new ArgumentException("result");
}
#endregion
#region Public StorageContainer Delete Method
public void DeleteContainer(string titleName)
{
throw new NotImplementedException();
}
#endregion
#region Private OpenContainer Async Method
// Private method to handle the creation of the StorageDevice.
private StorageContainer Open(string displayName)
{
deviceContainer = new StorageContainer(
this,
displayName,
storageRoot,
devicePlayer
);
return deviceContainer;
}
#endregion
#region Private ShowSelector Async Method
// Private method to handle the creation of the StorageDevice.
private static StorageDevice Show(PlayerIndex? player, int sizeInBytes, int directoryCount)
{
return new StorageDevice(player, sizeInBytes, directoryCount);
}
#endregion
#region Private Static OS User Directory Path Method
private static string GetStorageRoot()
{
if (Game.Instance.Platform.OSVersion.Equals("Windows"))
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"SavedGames"
);
}
if (Game.Instance.Platform.OSVersion.Equals("Mac OS X"))
{
string osConfigDir = Environment.GetEnvironmentVariable("HOME");
if (String.IsNullOrEmpty(osConfigDir))
{
return "."; // Oh well.
}
osConfigDir += "/Library/Application Support";
return osConfigDir;
}
if (Game.Instance.Platform.OSVersion.Equals("Linux"))
{
// Assuming a non-OSX Unix platform will follow the XDG. Which it should.
string osConfigDir = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
if (String.IsNullOrEmpty(osConfigDir))
{
osConfigDir = Environment.GetEnvironmentVariable("HOME");
if (String.IsNullOrEmpty(osConfigDir))
{
return "."; // Oh well.
}
osConfigDir += "/.local/share";
}
return osConfigDir;
}
throw new Exception("StorageDevice: Platform.OSVersion not handled!");
}
#endregion
}
}