#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2011 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
#if !XBOX360
using System.Security.Cryptography;
using System.Text;
#endif
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Nuclex.Graphics;
namespace Nuclex.Game.Content {
/// Content manager for loading content from in-memory arrays
///
/// This is not much different from the resource content manager, since resources
/// are always loaded into a process and are "in-memory" as well, but this
/// content manager allows you to load content directly out of byte arrays.
///
public class MemoryContentManager : ContentManager {
///
/// Initializes a new embedded content manager using a directly specified
/// graphics device service for the resources.
///
///
/// Graphics device service to load the content asset in
///
public MemoryContentManager(IGraphicsDeviceService graphicsDeviceService) :
this(
GraphicsDeviceServiceHelper.MakePrivateServiceProvider(graphicsDeviceService)
) { }
///
/// Initializes a new embedded content manager using the provided game services
/// container for providing services for the loaded asset.
///
///
/// Service container containing the services the asset may access
///
public MemoryContentManager(IServiceProvider services) :
base(services) { }
#if WINDOWS
/// Loads the asset the embedded content manager was created for
/// Type of the asset to load
/// Content that will be loaded as an asset
/// The loaded asset
///
///
/// To mirror the behavior of the ResourceContentManager class, this method
/// calculates the SHA-1 of the provided array. Otherwise, you could request
/// the same asset two times and when you dispose one, the other requested
/// instance would still work, which does not match the behavior of
/// the ResourceContentManager.
///
///
/// It is recommended that you use the named LoadAsset method or control
/// asset lifetimes yourself by using the ReadAsset() method.
///
///
public AssetType Load(byte[] content) {
return Load(content, getSha1(content));
}
#endif
/// Loads the asset the embedded content manager was created for
/// Type of the asset to load
/// Content that will be loaded as an asset
/// Unique name of the resource
/// The loaded asset
///
/// This class avoids the SHA-1 calculation under the promise that the caller
/// will provide a name that is unique for each loaded asset.
///
public AssetType Load(byte[] content, string uniqueName) {
lock(this) {
this.content = content;
try {
return base.Load(uniqueName);
}
finally {
if(this.memoryStream != null) {
this.memoryStream.Dispose();
this.memoryStream = null;
}
this.content = null;
}
} // lock(this)
}
/// Loads an asset from the provided byte array
/// Type of the asset to load
/// Content that will be loaded as an asset
/// The loaded asset
public AssetType ReadAsset(byte[] content) {
lock(this) {
using(this.memoryStream = new MemoryStream(content, false)) {
return base.ReadAsset("null", null);
}
} // lock(this)
}
/// Opens a stream for reading the specified asset
/// The name of the asset to be read
/// The opened stream for the asset
protected override Stream OpenStream(string assetName) {
if(this.memoryStream == null) {
this.memoryStream = new MemoryStream(this.content, false);
}
return this.memoryStream;
}
#if WINDOWS
/// Calculates the SHA-1 hash of the provided byte array
/// Data that will be hashed
/// A string containing the SHA-1 sum of the byte array
private string getSha1(byte[] data) {
if(this.sha1HashProvider == null) {
this.sha1HashProvider = SHA1.Create();
}
byte[] hashCode = this.sha1HashProvider.ComputeHash(data);
StringBuilder builder = new StringBuilder(hashCode.Length * 2);
for(int index = 0; index < hashCode.Length; ++index) {
builder.AppendFormat("{0:x2}", hashCode[index]);
}
return builder.ToString();
}
#endif
/// Content that will be loaded by the embedded content manager
private MemoryStream memoryStream;
/// Content which is currently being loaded
private byte[] content;
#if WINDOWS
///
/// SHA-1 hash provider used to calculate SHA-1 sums of asset data
///
private SHA1 sha1HashProvider;
#endif
}
} // namespace Nuclex.Game.Content