PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Accelerator/Synchronization/MimeTypes.cs

https://bitbucket.org/zgramana/azure-accelerators-project
C# | 303 lines | 181 code | 27 blank | 95 comment | 11 complexity | 7057eb534ade740618860684796c12e3 MD5 | raw file
Possible License(s): LGPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Xml;
  7. using System.Xml.Linq;
  8. using System.Xml.Schema;
  9. using System.Xml.Serialization;
  10. using System.Xml.XPath;
  11. using Microsoft.Win32;
  12. namespace Microsoft.WindowsAzure.Accelerator.Synchronization
  13. {
  14. /// <summary>
  15. /// Content type for storing file extension to mime type relationships.
  16. /// </summary>
  17. public class ContentType
  18. {
  19. private SortedDictionary<String, MimeType> _mimeTypes;
  20. /// <summary>
  21. /// Gets or sets the file extension.
  22. /// </summary>
  23. public String FileExtension { get; set; }
  24. /// <summary>
  25. /// Gets or sets the MIME types.
  26. /// </summary>
  27. public SortedDictionary<String, MimeType> Types
  28. {
  29. get { return _mimeTypes ?? (_mimeTypes = new SortedDictionary<String, MimeType>()); }
  30. set { _mimeTypes = value; }
  31. }
  32. }
  33. /// <summary>
  34. /// Mime type.
  35. /// </summary>
  36. public class MimeType
  37. {
  38. /// <summary>
  39. /// Gets or sets a value indicating whether this MIME type is allowed.
  40. /// </summary>
  41. public Boolean IsAllowed { get; set; }
  42. /// <summary>
  43. /// Gets or sets the MIME types origin information.
  44. /// </summary>
  45. public MimeSource MimeSource { get; set; }
  46. /// <summary>
  47. /// Gets or sets the type.
  48. /// </summary>
  49. public String Type { get; set; }
  50. }
  51. /// <summary>
  52. /// Mime type origin information.
  53. /// </summary>
  54. [Flags]
  55. public enum MimeSource
  56. {
  57. /// <summary>
  58. /// Mime content loaded from Xml file.
  59. /// </summary>
  60. XML = 1,
  61. /// <summary>
  62. /// Mime content types loaded from registry.
  63. /// </summary>
  64. Registry = 2,
  65. /// <summary>
  66. /// Mime content type loaded from application host file.
  67. /// </summary>
  68. IIS = 4,
  69. /// <summary>
  70. /// User suplied or default content.
  71. /// </summary>
  72. Unknown = 8
  73. }
  74. /// <summary>
  75. /// Based on public domain file extension and mime type information. This class is neither connected
  76. /// or dependant upon IIS metadata.
  77. /// </summary>
  78. /// <remarks>
  79. /// The 'isAllowed' field of the XML is implemented as 'isEnabled' due to time constrains. Need to
  80. /// update this as time permits.
  81. /// </remarks>
  82. public sealed class MimeTypes : IXmlSerializable
  83. {
  84. private const String XmlFile = @"Synchronization\MimeTypes.xml";
  85. private String _defaultMimeType = @"application/octet-stream";
  86. private static volatile MimeTypes _instance;
  87. private static Object _syncRoot = new Object();
  88. private SortedDictionary<String, ContentType> _types;
  89. /// <summary>
  90. /// Gets the single instance of this class.
  91. /// </summary>
  92. public static MimeTypes Instance { get { if (_instance == null){ lock (_syncRoot){ return _instance ?? ( _instance = new MimeTypes() ); } } return _instance; } }
  93. /// <summary>
  94. /// Gets or sets the default mime content type for unknown file extensions.
  95. /// </summary>
  96. public ContentType DefaultContentType { get; set; }
  97. /// <summary>
  98. /// Sorted list of mime content types.
  99. /// </summary>
  100. private SortedDictionary<String, ContentType> ContentTypes { get { return _types ?? (_types = new SortedDictionary<String, ContentType>()); } }
  101. /// <summary>
  102. /// Initializes a new instance of the <see cref="MimeTypes"/> class.
  103. /// </summary>
  104. private MimeTypes()
  105. {
  106. try {
  107. LoadFromRegistry();
  108. Trace.TraceInformation("Successfully loaded MIME types from Registry.");
  109. } catch {
  110. Trace.TraceError("Unable to load MIME types from registry.");
  111. }
  112. try {
  113. LoadFromIIS();
  114. Trace.TraceInformation("Successfully loaded MIME types from IIS.");
  115. } catch {
  116. Trace.TraceError("Unable to load MIME types from IIS.");
  117. }
  118. try {
  119. LoadFromXml();
  120. Trace.TraceInformation("Successfully loaded MIME types from XML.");
  121. } catch {
  122. Trace.TraceError("Unable to load MIME types from '{0}'.", XmlFile);
  123. }
  124. DefaultContentType = new ContentType
  125. {
  126. FileExtension = "",
  127. Types = new SortedDictionary<String, MimeType>
  128. {
  129. { _defaultMimeType, new MimeType
  130. {
  131. IsAllowed = true,
  132. Type = _defaultMimeType,
  133. MimeSource = MimeSource.Unknown
  134. }}
  135. }
  136. };
  137. }
  138. /// <summary>
  139. /// Gets or sets the content mime type associated with the specified file extension.
  140. /// </summary>
  141. /// <value>Content type.</value>
  142. public String this[String fileExtension]
  143. {
  144. get { return GetMimeType(fileExtension).Type; }
  145. }
  146. /// <summary>
  147. /// Gets the content type for the file extension; return the default content type if file extension not found.
  148. /// </summary>
  149. /// <param name="fileExtension">The file extension.</param>
  150. /// <returns>Content type.</returns>
  151. private MimeType GetMimeType(String fileExtension)
  152. {
  153. String lExt = fileExtension.ToLower().EnsureStartsWith(".");
  154. return ContentTypes.ContainsKey(lExt)
  155. ? ContentTypes[lExt].Types.Values.FirstOrDefault()
  156. : DefaultContentType.Types.Values.FirstOrDefault();
  157. }
  158. /// <summary>
  159. /// Loads from mime types from an XML file.
  160. /// </summary>
  161. private void LoadFromXml()
  162. {
  163. if (File.Exists(XmlFile))
  164. {
  165. XDocument xdoc = XDocument.Load(XmlFile);
  166. foreach (var e in xdoc.XPathSelectElements("//MimeType").ToList())
  167. {
  168. AddType(e.GetAttribute("fileExtension"), e.GetAttribute("type"), MimeSource.XML, Boolean.Parse(e.GetAttribute("isAllowed")));
  169. }
  170. }
  171. }
  172. /// <summary>
  173. /// Load mime types from the application hosts configuration.
  174. /// </summary>
  175. private void LoadFromIIS()
  176. {
  177. String xApplicationHost = Environment.ExpandEnvironmentVariables(@"%windir%\system32\inetsrv\config\applicationHost.config");
  178. if (File.Exists(xApplicationHost))
  179. {
  180. XDocument xdoc = XDocument.Load(xApplicationHost);
  181. foreach (var e in xdoc.XPathSelectElements("//staticContent/mimeMap").ToList())
  182. {
  183. AddType(e.GetAttribute("fileExtension"), e.GetAttribute("mimeType"), MimeSource.IIS, true);
  184. }
  185. }
  186. }
  187. /// <summary>
  188. /// Gets the registry MIME types.
  189. /// </summary>
  190. private void LoadFromRegistry()
  191. {
  192. using (RegistryKey contentTypes = Registry.ClassesRoot.OpenSubKey("MIME\\Database\\Content Type"))
  193. {
  194. if (contentTypes != null)
  195. {
  196. foreach (String name in contentTypes.GetSubKeyNames())
  197. {
  198. RegistryKey contentKey = contentTypes.OpenSubKey(name);
  199. if (contentKey != null)
  200. {
  201. String extension = contentKey.GetValue("Extension") as String;
  202. if (extension != null)
  203. {
  204. AddType(extension, name, MimeSource.Registry, true);
  205. }
  206. }
  207. }
  208. }
  209. }
  210. }
  211. /// <summary>
  212. /// Adds the type.
  213. /// </summary>
  214. /// <param name="fileExtension">The file extension.</param>
  215. /// <param name="mimeType">Type of the MIME.</param>
  216. /// <param name="mimeSource">The MIME source.</param>
  217. /// <param name="isAllowed">if set to <c>true</c> [is allowed].</param>
  218. private void AddType(String fileExtension, String mimeType, MimeSource mimeSource, Boolean isAllowed)
  219. {
  220. String lType = mimeType.ToLower();
  221. String lExt = fileExtension.ToLower().EnsureStartsWith(".");
  222. ContentType ct = ContentTypes.ContainsKey(lExt)
  223. ? ContentTypes[lExt]
  224. : new ContentType
  225. {
  226. FileExtension = fileExtension
  227. };
  228. MimeType mt = ct.Types.ContainsKey(lType)
  229. ? ct.Types[lType]
  230. : new MimeType
  231. {
  232. Type = mimeType
  233. };
  234. mt.MimeSource = mt.MimeSource | mimeSource;
  235. mt.IsAllowed = mt.IsAllowed | isAllowed;
  236. ct.Types[lType] = mt;
  237. ContentTypes[lExt] = ct;
  238. }
  239. /// <summary>
  240. /// 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.
  241. /// </summary>
  242. /// <returns>
  243. /// 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.
  244. /// </returns>
  245. public XmlSchema GetSchema()
  246. {
  247. return null;
  248. }
  249. /// <summary>
  250. /// Generates an object from its XML representation.
  251. /// </summary>
  252. /// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized.</param>
  253. public void ReadXml(XmlReader reader)
  254. {
  255. throw new NotImplementedException();
  256. }
  257. /// <summary>
  258. /// Converts an object into its XML representation.
  259. /// </summary>
  260. /// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized.</param>
  261. public void WriteXml(XmlWriter writer)
  262. {
  263. Func<MimeSource, String> source = (MimeSource ms) => (from MimeSource v in Enum.GetValues(typeof (MimeSource))
  264. where (ms & v) == v
  265. select v).Aggregate(String.Empty, (current, v) => current + Enum.GetName(typeof (MimeSource), v) + ',').Trim(',');
  266. var e = new XElement("ContentTypes", ContentTypes.Select(ct =>
  267. new XElement("ContentType",
  268. new XAttribute("fileExtension", ct.Value.FileExtension), ct.Value.Types.Select(mt =>
  269. new XElement("mimeType",
  270. new XAttribute("type", mt.Value.Type),
  271. new XAttribute("source", source(mt.Value.MimeSource)),
  272. new XAttribute("isAllowed", mt.Value.IsAllowed))))));
  273. writer.WriteNode(e.CreateReader(), true);
  274. }
  275. }
  276. }