/Accelerator/Synchronization/MimeTypes.cs
C# | 303 lines | 181 code | 27 blank | 95 comment | 11 complexity | 7057eb534ade740618860684796c12e3 MD5 | raw file
Possible License(s): LGPL-2.0
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Xml;
- using System.Xml.Linq;
- using System.Xml.Schema;
- using System.Xml.Serialization;
- using System.Xml.XPath;
- using Microsoft.Win32;
-
- namespace Microsoft.WindowsAzure.Accelerator.Synchronization
- {
- /// <summary>
- /// Content type for storing file extension to mime type relationships.
- /// </summary>
- public class ContentType
- {
- private SortedDictionary<String, MimeType> _mimeTypes;
-
- /// <summary>
- /// Gets or sets the file extension.
- /// </summary>
- public String FileExtension { get; set; }
-
- /// <summary>
- /// Gets or sets the MIME types.
- /// </summary>
- public SortedDictionary<String, MimeType> Types
- {
- get { return _mimeTypes ?? (_mimeTypes = new SortedDictionary<String, MimeType>()); }
- set { _mimeTypes = value; }
- }
- }
-
- /// <summary>
- /// Mime type.
- /// </summary>
- public class MimeType
- {
- /// <summary>
- /// Gets or sets a value indicating whether this MIME type is allowed.
- /// </summary>
- public Boolean IsAllowed { get; set; }
-
- /// <summary>
- /// Gets or sets the MIME types origin information.
- /// </summary>
- public MimeSource MimeSource { get; set; }
-
- /// <summary>
- /// Gets or sets the type.
- /// </summary>
- public String Type { get; set; }
- }
-
- /// <summary>
- /// Mime type origin information.
- /// </summary>
- [Flags]
- public enum MimeSource
- {
-
- /// <summary>
- /// Mime content loaded from Xml file.
- /// </summary>
- XML = 1,
- /// <summary>
- /// Mime content types loaded from registry.
- /// </summary>
- Registry = 2,
- /// <summary>
- /// Mime content type loaded from application host file.
- /// </summary>
- IIS = 4,
- /// <summary>
- /// User suplied or default content.
- /// </summary>
- Unknown = 8
- }
-
- /// <summary>
- /// Based on public domain file extension and mime type information. This class is neither connected
- /// or dependant upon IIS metadata.
- /// </summary>
- /// <remarks>
- /// The 'isAllowed' field of the XML is implemented as 'isEnabled' due to time constrains. Need to
- /// update this as time permits.
- /// </remarks>
- public sealed class MimeTypes : IXmlSerializable
- {
- private const String XmlFile = @"Synchronization\MimeTypes.xml";
- private String _defaultMimeType = @"application/octet-stream";
- private static volatile MimeTypes _instance;
- private static Object _syncRoot = new Object();
- private SortedDictionary<String, ContentType> _types;
-
- /// <summary>
- /// Gets the single instance of this class.
- /// </summary>
- public static MimeTypes Instance { get { if (_instance == null){ lock (_syncRoot){ return _instance ?? ( _instance = new MimeTypes() ); } } return _instance; } }
-
- /// <summary>
- /// Gets or sets the default mime content type for unknown file extensions.
- /// </summary>
- public ContentType DefaultContentType { get; set; }
-
- /// <summary>
- /// Sorted list of mime content types.
- /// </summary>
- private SortedDictionary<String, ContentType> ContentTypes { get { return _types ?? (_types = new SortedDictionary<String, ContentType>()); } }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="MimeTypes"/> class.
- /// </summary>
- private MimeTypes()
- {
- try {
- LoadFromRegistry();
- Trace.TraceInformation("Successfully loaded MIME types from Registry.");
- } catch {
- Trace.TraceError("Unable to load MIME types from registry.");
- }
-
- try {
- LoadFromIIS();
- Trace.TraceInformation("Successfully loaded MIME types from IIS.");
- } catch {
- Trace.TraceError("Unable to load MIME types from IIS.");
- }
-
- try {
- LoadFromXml();
- Trace.TraceInformation("Successfully loaded MIME types from XML.");
- } catch {
- Trace.TraceError("Unable to load MIME types from '{0}'.", XmlFile);
- }
-
- DefaultContentType = new ContentType
- {
- FileExtension = "",
- Types = new SortedDictionary<String, MimeType>
- {
- { _defaultMimeType, new MimeType
- {
- IsAllowed = true,
- Type = _defaultMimeType,
- MimeSource = MimeSource.Unknown
- }}
- }
- };
- }
-
- /// <summary>
- /// Gets or sets the content mime type associated with the specified file extension.
- /// </summary>
- /// <value>Content type.</value>
- public String this[String fileExtension]
- {
- get { return GetMimeType(fileExtension).Type; }
- }
-
- /// <summary>
- /// Gets the content type for the file extension; return the default content type if file extension not found.
- /// </summary>
- /// <param name="fileExtension">The file extension.</param>
- /// <returns>Content type.</returns>
- private MimeType GetMimeType(String fileExtension)
- {
- String lExt = fileExtension.ToLower().EnsureStartsWith(".");
- return ContentTypes.ContainsKey(lExt)
- ? ContentTypes[lExt].Types.Values.FirstOrDefault()
- : DefaultContentType.Types.Values.FirstOrDefault();
- }
-
- /// <summary>
- /// Loads from mime types from an XML file.
- /// </summary>
- private void LoadFromXml()
- {
- if (File.Exists(XmlFile))
- {
- XDocument xdoc = XDocument.Load(XmlFile);
- foreach (var e in xdoc.XPathSelectElements("//MimeType").ToList())
- {
- AddType(e.GetAttribute("fileExtension"), e.GetAttribute("type"), MimeSource.XML, Boolean.Parse(e.GetAttribute("isAllowed")));
- }
- }
- }
-
- /// <summary>
- /// Load mime types from the application hosts configuration.
- /// </summary>
- private void LoadFromIIS()
- {
- String xApplicationHost = Environment.ExpandEnvironmentVariables(@"%windir%\system32\inetsrv\config\applicationHost.config");
- if (File.Exists(xApplicationHost))
- {
- XDocument xdoc = XDocument.Load(xApplicationHost);
- foreach (var e in xdoc.XPathSelectElements("//staticContent/mimeMap").ToList())
- {
- AddType(e.GetAttribute("fileExtension"), e.GetAttribute("mimeType"), MimeSource.IIS, true);
- }
- }
- }
-
- /// <summary>
- /// Gets the registry MIME types.
- /// </summary>
- private void LoadFromRegistry()
- {
- using (RegistryKey contentTypes = Registry.ClassesRoot.OpenSubKey("MIME\\Database\\Content Type"))
- {
- if (contentTypes != null)
- {
- foreach (String name in contentTypes.GetSubKeyNames())
- {
- RegistryKey contentKey = contentTypes.OpenSubKey(name);
- if (contentKey != null)
- {
- String extension = contentKey.GetValue("Extension") as String;
- if (extension != null)
- {
- AddType(extension, name, MimeSource.Registry, true);
- }
- }
- }
- }
- }
- }
-
- /// <summary>
- /// Adds the type.
- /// </summary>
- /// <param name="fileExtension">The file extension.</param>
- /// <param name="mimeType">Type of the MIME.</param>
- /// <param name="mimeSource">The MIME source.</param>
- /// <param name="isAllowed">if set to <c>true</c> [is allowed].</param>
- private void AddType(String fileExtension, String mimeType, MimeSource mimeSource, Boolean isAllowed)
- {
- String lType = mimeType.ToLower();
- String lExt = fileExtension.ToLower().EnsureStartsWith(".");
- ContentType ct = ContentTypes.ContainsKey(lExt)
- ? ContentTypes[lExt]
- : new ContentType
- {
- FileExtension = fileExtension
- };
-
- MimeType mt = ct.Types.ContainsKey(lType)
- ? ct.Types[lType]
- : new MimeType
- {
- Type = mimeType
- };
- mt.MimeSource = mt.MimeSource | mimeSource;
- mt.IsAllowed = mt.IsAllowed | isAllowed;
- ct.Types[lType] = mt;
- ContentTypes[lExt] = ct;
- }
-
- /// <summary>
- /// This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> to the class.
- /// </summary>
- /// <returns>
- /// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> method.
- /// </returns>
- public XmlSchema GetSchema()
- {
- return null;
- }
-
- /// <summary>
- /// Generates an object from its XML representation.
- /// </summary>
- /// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized.</param>
- public void ReadXml(XmlReader reader)
- {
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Converts an object into its XML representation.
- /// </summary>
- /// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized.</param>
- public void WriteXml(XmlWriter writer)
- {
- Func<MimeSource, String> source = (MimeSource ms) => (from MimeSource v in Enum.GetValues(typeof (MimeSource))
- where (ms & v) == v
- select v).Aggregate(String.Empty, (current, v) => current + Enum.GetName(typeof (MimeSource), v) + ',').Trim(',');
-
- var e = new XElement("ContentTypes", ContentTypes.Select(ct =>
- new XElement("ContentType",
- new XAttribute("fileExtension", ct.Value.FileExtension), ct.Value.Types.Select(mt =>
- new XElement("mimeType",
- new XAttribute("type", mt.Value.Type),
- new XAttribute("source", source(mt.Value.MimeSource)),
- new XAttribute("isAllowed", mt.Value.IsAllowed))))));
- writer.WriteNode(e.CreateReader(), true);
- }
- }
- }