using System; using System.IO; using System.Net; using System.Reflection; using System.Web; using System.Xml; using System.Xml.Schema; using NUnit.Framework; using Spring.Core.IO; namespace Spring { /// <summary> /// Supports obtaining embedded resources from assembly. /// </summary> /// <remarks> /// <para> /// The first <c>context</c> argument is always the namespace scope to be used for resolving resource names. /// </para> /// <para> /// Upon first usage, TestResourceLoader registers the "testres://" protocol prefix for loading embedded resources. /// A testres:// Url must be of the form "testres://./<context-typename>#<ext" - <see cref="GetStream"/>. /// </para> /// </remarks> public class TestResourceLoader { #region WebRequest public class TestResourceWebResponse : WebResponse { private Type resourceType; private string resourceName; public TestResourceWebResponse(Uri requestUri) { string typeName = HttpUtility.UrlDecode(requestUri.AbsolutePath.Substring(1)); // strip leading '/' resourceType = Type.GetType(typeName, true); resourceName = HttpUtility.UrlDecode(requestUri.Fragment.Substring(1)); // strip leading '#' } public override System.IO.Stream GetResponseStream() { Stream stm = TestResourceLoader.GetStream(resourceType, resourceName); return stm; } } public class TestResourceWebRequest : WebRequest { private Uri requestUri; public TestResourceWebRequest(Uri requestUri) { this.requestUri = requestUri; } public override WebResponse GetResponse() { return new TestResourceWebResponse(requestUri); } } public class TestResourceWebRequestFactory : IWebRequestCreate { public WebRequest Create(Uri uri) { return new TestResourceWebRequest(uri); } } #endregion static TestResourceLoader() { WebRequest.RegisterPrefix("testres", new TestResourceWebRequestFactory()); } private TestResourceLoader() { } /// <summary> /// Returns an Uri of the form "testres://./resourcname" that may be passed into <see cref="WebRequest.Create(string)"/> etc. /// </summary> /// <param name="context"></param> /// <param name="ext"></param> /// <returns></returns> public static Uri GetUri(object context, string ext) { string resname = context.GetType().AssemblyQualifiedName + "#" + ext; Uri uri = new Uri("testres://inline/" + resname); return uri; } public static string GetText(object context, string ext) { Stream stm = GetStream(context, ext); return new StreamReader(stm).ReadToEnd(); } public static XmlDocument GetXml(object context, string ext) { Stream stm = GetStream(context, ext); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(stm); return xmlDoc; } public static XmlDocument GetXmlValidated(object context, string ext, params IResource[] schemaResources) { using (Stream stm = GetStream(context, ext)) { XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; XmlSchemaSet schemas = settings.Schemas; foreach (IResource schemaResource in schemaResources) { XmlDocument schemaDoc = new XmlDocument(); using (Stream inputStream = schemaResource.InputStream) { schemaDoc.Load(inputStream); } XmlElement root = schemaDoc.DocumentElement; string targetNamespace = root.GetAttribute("targetNamespace", string.Empty); schemas.Add(targetNamespace, new XmlNodeReader(schemaDoc)); } XmlReader validatingReader = XmlReader.Create(stm, settings); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(validatingReader); validatingReader.Close(); return xmlDoc; } } /// <summary> /// Returns an embedded assembly resource, who's name is constructed from the given parameters as /// <c>context.GetType().FullName + ext</c> /// </summary> public static Stream GetStream(object context, string ext) { Type contextType = (context is Type) ? (Type)context : context.GetType(); string resname = contextType.FullName + ext; Stream stm = contextType.Assembly.GetManifestResourceStream(resname); Assert.IsNotNull(stm, "Resource '{0}' in assembly '{1}' not found", resname, contextType.Assembly.FullName); return stm; } /// <summary> /// Exports a resource obtained via <see cref="GetStream"/> to the specified destination. /// </summary> public static FileInfo ExportResource(object context, string ext, FileInfo destination) { Stream istm = GetStream(context, ext); using(istm) { FileStream ostm = destination.OpenWrite(); using (ostm) { byte[] buffer = new byte[2048]; int bytesRead = istm.Read(buffer, 0, buffer.Length); while (bytesRead > 0) { ostm.Write(buffer, 0, bytesRead); bytesRead = istm.Read(buffer, 0, buffer.Length); } ostm.Flush(); ostm.Close(); } istm.Close(); } return destination; } /// <summary> /// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified type. /// ("assembly://hint.assemblyname_without_version/hint.Namespace/name") /// </summary> /// <see cref="Assembly.GetManifestResourceStream(Type,string)"/> public static string GetAssemblyResourceUri(Type hint, string name) { return "assembly://" + hint.Assembly.FullName.Split(',')[0].Trim() + "/" + hint.Namespace + ((name.IndexOf('/')>-1)?".":"/") + name; } /// <summary> /// returns an "assembly://" uri for the specified manifest resource, scoped by the namespace of the specified instance's type. /// ("assembly://hint.assemblyname_without_version/hint.Namespace/name") /// </summary> /// <see cref="Assembly.GetManifestResourceStream(Type,string)"/> public static string GetAssemblyResourceUri(object hint, string name) { Type hintType = hint.GetType(); return GetAssemblyResourceUri(hintType, name); } } }