using System; using System.Data; using System.Configuration; using System.Xml; using System.IO; using System.IO.Packaging; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Diagnostics; /// /// Summary description for XmlZipResolver /// /// A subclass of the XmlUrlResolver class which allows you /// to resolve references inside zip files. /// public class XmlZipResolver : XmlUrlResolver { private XmlUrlResolver urlResolver; public XmlZipResolver() { urlResolver = new XmlUrlResolver(); } // Summary: // Sets credentials used to authenticate Web requests. // // Returns: // An System.Net.ICredentials object. If this property is not set, the value // defaults to null; that is, the XmlUrlResolver has no user credentials. public override ICredentials Credentials { set { urlResolver.Credentials = value; } } // Summary: // Maps a URI to an object containing the actual resource. // // 1) Tests whether the URL starts with "jar:" or "zip:" // 2) If not, pass the URL to XmlUrlResolver (to the superclass) // 3) If it does, then interprets it like the apache version: // a) Strip out leading "zip:" or "jar:" // b) Split into two strings, before and after the "!" // c) use the first string as a ZIP file, use the second as an ZIP path to a file // d) return a stream from that file // // Parameters: // // absoluteUri: // The URI returned from System.Xml.XmlResolver.ResolveUri(System.Uri,System.String) // // role: // The current implementation does not use this parameter when resolving URIs. // This is provided for future extensibility purposes. For example, this can // be mapped to the xlink:role and used as an implementation specific argument // in other scenarios. // // ofObjectToReturn: // The type of object to return. The current implementation only returns System.IO.Stream // objects. // // Returns: // A System.IO.Stream object or null if a type other than stream is specified. // // Exceptions: // System.Xml.XmlException: // ofObjectToReturn is neither null nor a Stream type. // // System.UriFormatException: // The specified URI is not an absolute URI. // // System.NullReferenceException: // absoluteUri is null. // // System.Exception: // There is a runtime error (for example, an interrupted server connection). public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) { //if (!ofObjectToReturn.Equals(typeof(Stream))) return null; Debug.WriteLine("GetEntity:"); // Test whether the URL starts with "jar:" or "zip:" String uriString = absoluteUri.ToString(); String zipRegex = "^(jar|zip):"; Match zipMatch = Regex.Match(uriString, zipRegex); if (zipMatch.Success) { // Strip out leading "zip:" or "jar:" String stripedUriString = Regex.Replace(uriString, zipRegex, ""); // Split into two strings, before and after the "!" String uriRegex = "^([^!]+)!(/[^!]+)$"; Match uriMatch = Regex.Match(stripedUriString, uriRegex); if (uriMatch.Success) { Debug.Indent(); Debug.WriteLine("uriMatch.Success:"); String zipFilePath = uriMatch.Groups[1].ToString(); String xmlInZipPath = uriMatch.Groups[2].ToString(); Debug.Indent(); Debug.WriteLine("zipFilePath = " + zipFilePath); Debug.WriteLine("xmlInZipPath = " + xmlInZipPath); // Use the first string as a ZIP file, use the second as a ZIP path to a file Package zipPackage; zipPackage = Package.Open(zipFilePath, FileMode.Open, FileAccess.Read); Debug.WriteLine("Opened " + zipFilePath); Uri xmlInZipUri = new Uri(xmlInZipPath, UriKind.Relative); PackagePart xmlFile = zipPackage.GetPart(xmlInZipUri); Debug.WriteLine("Returning stream of: " + xmlInZipPath); Debug.Unindent(); Debug.Unindent(); // Make a deep copy of the stream of the XML file so that the zip package // can be closed Stream outputStream = FileUtilities.deepCopyXmlStream(xmlFile.GetStream()); zipPackage.Close(); return outputStream; } else { throw new System.UriFormatException("Zip URI does not have a '!' between the zip file path and " + "the path to the xml within the zip file, or path to xml does not start with a '/' " + "(ie, Zip URI does not follow the regular expression '" + uriRegex + "'). Zip URI found was '" + uriString + "'"); } } else { // If not a zip uri, pass the URL to XmlUrlResolver return urlResolver.GetEntity(absoluteUri, role, ofObjectToReturn); } } // // Summary: // Resolves the absolute URI from the base and relative URIs. // Uses the base class method. // Parameters: // baseUri: // The base URI used to resolve the relative URI. // // relativeUri: // The URI to resolve. The URI can be absolute or relative. If absolute, this // value effectively replaces the baseUri value. If relative, it combines with // the baseUri to make an absolute URI. // // Returns: // A System.Uri representing the absolute URI or null if the relative URI cannot // be resolved. // // Exceptions: // System.ArgumentException: // relativeUri is null public override Uri ResolveUri(Uri baseUri, string relativeUri) { Uri resolvedUri = base.ResolveUri(baseUri, relativeUri); Debug.WriteLine("ResolveUri:"); Debug.Indent(); Debug.WriteLine("baseUri = " + ((baseUri == null) ? "" : baseUri.ToString())); Debug.WriteLine("relativeUri = " + relativeUri); Debug.WriteLine("resolvedUri = " + resolvedUri); Debug.Unindent(); return resolvedUri; } }