...
 
Commits (10)
......@@ -37,6 +37,9 @@
<setting name="Cleaning_PerformPartialCleanupOnExternal" serializeAs="String">
<value>1</value>
</setting>
<setting name="Formatting_CommentXmlKeepTagsTogether" serializeAs="String">
<value>True</value>
</setting>
</SteveCadwallader.CodeMaid.Properties.Settings>
</userSettings>
</configuration>
\ No newline at end of file
......@@ -3,12 +3,30 @@
*Simple dictionary that provides a few methods to lookup by mime type/extension,
generated from [Apache's mime.types](https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types).*
This library tries to be as much compatible as possible with [MediaTypeMap.Core](https://www.nuget.org/packages/MediaTypeMap.Core/) package,
with following caveats:
- An empty string will not be returned to unknown inputs when `throwIfMissing` is false.
+ Missing mime types will receive `.bin` as default extension.
+ Missing extensions will receive `application/octet-stream` as default mime type.
- For valid mime types, the same extension will be returned, with following exceptions:
+ `application/pkcs7-mime` now returns `p7m` instead of `p7c`.
I am no security expert, but `p7m` seemed to be the most common of the two.
+ `application/vnd.ms-works` now returns `wps` instead of `wks`.
`wks` seemed to be produced by IBM Lotus 1-2-3, which is less common than Microsoft Works (`wps`).
+ `application/x-msmediaview` now returns `mvb` instead of `m13`.
I found no trace of `m13` extension on top Google search results.
+ `application/x-x509-ca-cert` now returns `der` instead of `cer`.
Apache maps `cer` to `application/pkix-cert` mime type.
+ `audio/x-pn-realaudio-plugin` now returns `rmp` instead of `rpm`.
That seemed a typo, since `rpm` stands for Red Hat Package Manager.
## Summary
* Build status on [GitLab](https://gitlab.com/pomma89/mime-types/pipelines): [![pipeline status](https://gitlab.com/pomma89/mime-types/badges/master/pipeline.svg)](https://gitlab.com/pomma89/mime-types/commits/master)
* [DocFX](hhttps://dotnet.github.io/docfx/) generated API documentation: [https://pomma89.gitlab.io/mime-types/](https://pomma89.gitlab.io/mime-types/)
* [NuGet](https://www.nuget.org) package(s):
+ [PommaLabs.MimeTypes](https://www.nuget.org/packages/PommaLabs.MimeTypes/), main package.
- Build status on [GitLab](https://gitlab.com/pomma89/mime-types/pipelines): [![pipeline status](https://gitlab.com/pomma89/mime-types/badges/master/pipeline.svg)](https://gitlab.com/pomma89/mime-types/commits/master)
- [DocFX](hhttps://dotnet.github.io/docfx/) generated API documentation: [https://pomma89.gitlab.io/mime-types/](https://pomma89.gitlab.io/mime-types/)
- [NuGet](https://www.nuget.org) package(s):
+ [PommaLabs.MimeTypes](https://www.nuget.org/packages/PommaLabs.MimeTypes/), main package.
## About this repository and its maintainer
......@@ -24,9 +42,9 @@ However, if this project helps you, then you might offer me an hot cup of coffee
This project was inspired by the following open source projects:
* [https://github.com/hey-red/MimeTypesMap](https://github.com/hey-red/MimeTypesMap)
* [https://github.com/samuelneff/MimeTypes](https://github.com/samuelneff/MimeTypes)
- [https://github.com/hey-red/MimeTypesMap](https://github.com/hey-red/MimeTypesMap)
- [https://github.com/samuelneff/MimeTypes](https://github.com/samuelneff/MimeTypes)
Moreover, this project heavily relies on the following open source projects:
* [DotLiquid](https://github.com/dotliquid/dotliquid), used to process Liquid templates.
\ No newline at end of file
- [DotLiquid](https://github.com/dotliquid/dotliquid), used to process Liquid templates.
\ No newline at end of file
......@@ -53,51 +53,113 @@ namespace PommaLabs.MimeTypes
};
/// <summary>
/// Adds or updates the entry for given mime type and extension.
/// Adds or updates the entry for <paramref name="mimeType"/> and extension.
/// </summary>
/// <param name="mimeType">Mime type.</param>
/// <param name="extension">Extension.</param>
public static void AddOrUpdate(string mimeType, string extension)
{
mimeType = mimeType?.ToLowerInvariant();
extension = extension?.ToLowerInvariant();
mimeType = mimeType.ToLowerInvariant();
extension = extension.ToLowerInvariant();
s_extensionMap[extension] = mimeType;
s_mimeTypeMap[mimeType] = extension;
}
/// <summary>
/// Retrieves the extension linked to given mime type. If given mime type is not mapped,
/// then the default ".bin" extension is returned.
/// Retrieves the extension linked to <paramref name="mimeType"/>. If
/// <paramref name="mimeType"/> is not mapped, then an exception will be thrown.
/// </summary>
/// <param name="mimeType">Mime type.</param>
/// <returns>The extension linked to given mime type.</returns>
public static string GetExtension(string mimeType)
{
return s_mimeTypeMap.TryGetValue(mimeType, out var extension) ? extension : DefaultExtension;
}
/// <returns>The extension linked to <paramref name="mimeType"/>.</returns>
/// <exception cref="ArgumentException"><paramref name="mimeType"/> is not mapped.</exception>
public static string GetExtension(string mimeType) => GetExtension(mimeType, true);
/// <summary>
/// Retrieves the extension linked to given mime type and strips the leading dot
/// character. If given mime type is not mapped, then the default "bin" extension is returned.
/// Retrieves the extension linked to <paramref name="mimeType"/>. If
/// <paramref name="mimeType"/> is not mapped, then an exception will be thrown if
/// <paramref name="throwIfMissing"/> is true; otherwise, the default ".bin" extension is returned.
/// </summary>
/// <param name="mimeType">Mime type.</param>
/// <returns>The extension linked to given mime type, without the leading dot character.</returns>
public static string GetExtensionWithoutDot(string mimeType)
/// <param name="throwIfMissing">
/// If true, throws an exception if <paramref name="mimeType"/> is not mapped.
/// </param>
/// <returns>The extension linked to <paramref name="mimeType"/>.</returns>
/// <exception cref="ArgumentException">
/// <paramref name="mimeType"/> is not mapped and <paramref name="throwIfMissing"/> is true.
/// </exception>
public static string GetExtension(string mimeType, bool throwIfMissing)
{
return GetExtension(mimeType).Substring(1);
return s_mimeTypeMap.TryGetValue(mimeType, out var extension)
? extension
: throwIfMissing
? throw new ArgumentException($"Requested mime type is not mapped: {mimeType}")
: DefaultExtension;
}
/// <summary>
/// Retrieves the mime type linked to the extension of given file. If the extension is not
/// mapped, then the default "application/octet-stream" mime type is returned.
/// Retrieves the extension linked to <paramref name="mimeType"/> and strips the leading
/// dot character. If <paramref name="mimeType"/> is not mapped, then an exception will be thrown.
/// </summary>
/// <param name="mimeType">Mime type.</param>
/// <returns>
/// The extension linked to <paramref name="mimeType"/>, without the leading dot character.
/// </returns>
/// <exception cref="ArgumentException"><paramref name="mimeType"/> is not mapped.</exception>
public static string GetExtensionWithoutDot(string mimeType) => GetExtensionWithoutDot(mimeType, true);
/// <summary>
/// Retrieves the extension linked to <paramref name="mimeType"/> and strips the leading
/// dot character. If <paramref name="mimeType"/> is not mapped, then an exception will be
/// thrown if <paramref name="throwIfMissing"/> is true; otherwise, the default "bin"
/// extension is returned.
/// </summary>
/// <param name="mimeType">Mime type.</param>
/// <param name="throwIfMissing">
/// If true, throws an exception if <paramref name="mimeType"/> is not mapped.
/// </param>
/// <returns>
/// The extension linked to <paramref name="mimeType"/>, without the leading dot character.
/// </returns>
/// <exception cref="ArgumentException">
/// <paramref name="mimeType"/> is not mapped and <paramref name="throwIfMissing"/> is true.
/// </exception>
public static string GetExtensionWithoutDot(string mimeType, bool throwIfMissing) => GetExtension(mimeType, throwIfMissing).Substring(1);
/// <summary>
/// Retrieves the mime type linked to the extension of <paramref name="filePath"/>. If the
/// extension is not mapped, then an exception will be thrown.
/// </summary>
/// <param name="filePath">File path.</param>
/// <returns>The mime type linked to the extension of <paramref name="filePath"/>.</returns>
/// <exception cref="ArgumentException">
/// The extension of <paramref name="filePath"/> is not mapped.
/// </exception>
public static string GetMimeType(string filePath) => GetMimeType(filePath, true);
/// <summary>
/// Retrieves the mime type linked to the extension of <paramref name="filePath"/>. If the
/// extension is not mapped, then an exception will be thrown if
/// <paramref name="throwIfMissing"/> is true; otherwise, the default
/// "application/octet-stream" mime type is returned.
/// </summary>
/// <param name="filePath">File path.</param>
/// <returns>The mime type linked to the extension of given file.</returns>
public static string GetMimeType(string filePath)
/// <param name="throwIfMissing">
/// If true, throws an exception if the extension of <paramref name="filePath"/> is not mapped.
/// </param>
/// <returns>The mime type linked to the extension of <paramref name="filePath"/>.</returns>
/// <exception cref="ArgumentException">
/// The extension of <paramref name="filePath"/> is not mapped and
/// <paramref name="throwIfMissing"/> is true.
/// </exception>
public static string GetMimeType(string filePath, bool throwIfMissing)
{
var extension = Path.GetExtension(filePath);
return s_extensionMap.TryGetValue(extension, out var mimeType) ? mimeType : DefaultMimeType;
return s_extensionMap.TryGetValue(extension, out var mimeType)
? mimeType
: throwIfMissing
? throw new ArgumentException($"Requested extension is not mapped: {extension}")
: DefaultMimeType;
}
}
}
\ No newline at end of file
......@@ -21,6 +21,7 @@
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
// WARNING: This file was auto generated by DotLiquid at {{ utc_now }}. DON'T modify it manually.
......@@ -28,6 +29,9 @@ namespace PommaLabs.MimeTypes.UnitTests
{
public sealed class MimeTypeMapTests
{
private const string DefaultExtension = ".bin";
private const string DefaultMimeType = "application/octet-stream";
{% for kv in mime_types -%}
[TestCase("{{ kv.Key }}", ".{{ kv.Value }}")]
{% endfor -%}
......@@ -37,9 +41,48 @@ namespace PommaLabs.MimeTypes.UnitTests
}
[Test]
public void GetExtension_MissingMimeTypeShouldBeMatchedToBinExtension()
public void GetExtension_MissingMimeTypeShouldBeMatchedToBinExtensionWhenThrowExceptionIsFalse()
{
Assert.That(MimeTypeMap.GetExtension("image/bread", false), Is.EqualTo(DefaultExtension));
}
[Test]
public void GetExtension_MissingMimeTypeShouldCauseArgumentException()
{
Assert.That(MimeTypeMap.GetExtension("image/bread"), Is.EqualTo(".bin"));
Assert.Throws<ArgumentException>(() => MimeTypeMap.GetExtension("image/bread"));
}
{% for kv in mime_types -%}
[TestCase("{{ kv.Key }}")]
{% endfor -%}
public void GetExtension_ResultShouldBeConsistentWithMediaTypeMapCore(string mimeType)
{
// As documented in this project README, not all mime types could be mapped
// consistently. When adding new mime types here, please ensure that they are documented
// in the README.
var isDeprecatedMimeType = mimeType switch
{
"application/pkcs7-mime" => true,
"application/vnd.ms-works" => true,
"application/x-msmediaview" => true,
"application/x-x509-ca-cert" => true,
"audio/x-pn-realaudio-plugin" => true,
_ => false,
};
if (isDeprecatedMimeType)
{
Assert.Pass($"MediaTypeMap.Core probably returns a wrong extension for {mimeType}");
}
var mediaTypeMapCoreResult = global::MimeTypes.MimeTypeMap.GetExtension(mimeType, false);
if (string.IsNullOrWhiteSpace(mediaTypeMapCoreResult) || mediaTypeMapCoreResult == DefaultExtension)
{
Assert.Pass($"MediaTypeMap.Core probably does not support mime type {mimeType}");
}
var mimeTypesResult = MimeTypeMap.GetExtension(mimeType);
Assert.That(mimeTypesResult, Is.EqualTo(mediaTypeMapCoreResult));
}
{% for kv in mime_types -%}
......@@ -51,9 +94,15 @@ namespace PommaLabs.MimeTypes.UnitTests
}
[Test]
public void GetExtensionWithoutDot_MissingMimeTypeShouldBeMatchedToBinExtension()
public void GetExtensionWithoutDot_MissingMimeTypeShouldBeMatchedToBinExtensionWhenThrowExceptionIsFalse()
{
Assert.That(MimeTypeMap.GetExtensionWithoutDot("image/bread", false), Is.EqualTo(DefaultExtension.Substring(1)));
}
[Test]
public void GetExtensionWithoutDot_MissingMimeTypeShouldCauseArgumentException()
{
Assert.That(MimeTypeMap.GetExtensionWithoutDot("image/bread"), Is.EqualTo("bin"));
Assert.Throws<ArgumentException>(() => MimeTypeMap.GetExtensionWithoutDot("image/bread"));
}
{% for kv in extensions -%}
......@@ -65,9 +114,15 @@ namespace PommaLabs.MimeTypes.UnitTests
}
[Test]
public void GetMimeType_MissingExtensionShouldBeMatchedToApplicationOctetStreamMimeType()
public void GetMimeType_MissingExtensionShouldBeMatchedToApplicationOctetStreamMimeTypeWhenThrowExceptionIsFalse()
{
Assert.That(MimeTypeMap.GetMimeType("file.bread", false), Is.EqualTo(DefaultMimeType));
}
[Test]
public void GetMimeType_MissingExtensionShouldCauseArgumentException()
{
Assert.That(MimeTypeMap.GetMimeType("file.bread"), Is.EqualTo("application/octet-stream"));
Assert.Throws<ArgumentException>(() => MimeTypeMap.GetMimeType("file.bread"));
}
}
}
......@@ -23,10 +23,11 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using DotLiquid;
using StringMap = System.Collections.Generic.Dictionary<string, string>;
using StringMap = System.Collections.Generic.SortedList<string, string>;
namespace PommaLabs.MimeTypeMap.Generator
{
......@@ -100,8 +101,8 @@ namespace PommaLabs.MimeTypeMap.Generator
using var webClient = new WebClient();
var response = webClient.DownloadString(new Uri(ApacheMimeTypesUrl));
var extensions = new StringMap();
var mimeTypes = new StringMap();
var extensions = new StringMap(StringComparer.OrdinalIgnoreCase);
var mimeTypes = new StringMap(StringComparer.OrdinalIgnoreCase);
using var reader = new StringReader(response);
string line;
......@@ -118,22 +119,41 @@ namespace PommaLabs.MimeTypeMap.Generator
continue;
}
for (var i = 1; i < parts.Length; i++)
{
var mimeType = parts[0].ToLowerInvariant();
var extension = parts[i].ToLowerInvariant();
var mimeType = parts[0].ToLowerInvariant();
var extensionList = parts[1..].Select(x => x.ToLowerInvariant());
var first = true;
foreach (var extension in extensionList)
{
if (!extensions.ContainsKey(extension))
{
extensions.Add(extension, mimeType);
}
if (i == 1)
if (first)
{
mimeTypes.Add(mimeType, extension);
first = false;
}
}
}
// Following overrides ensures best compatibility with MediaTypeMap.Core results.
// Complete compatibility cannot be achieved because some results of that library were
// simply wrong and they are documented in this project README.
extensions["3gp2"] = "video/3gpp2";
extensions["one"] = "application/onenote";
mimeTypes["application/onenote"] = "one";
mimeTypes["application/postscript"] = "eps";
mimeTypes["application/x-msdownload"] = "dll";
mimeTypes["application/x-texinfo"] = "texi";
mimeTypes["audio/basic"] = "snd";
mimeTypes["audio/mpeg"] = "mp3";
mimeTypes["audio/x-pn-realaudio"] = "ra";
mimeTypes["image/jpeg"] = "jpg";
mimeTypes["video/3gpp2"] = "3gp2";
mimeTypes["video/mpeg"] = "mpg";
mimeTypes["video/quicktime"] = "mov";
return (extensions, mimeTypes);
}
}
......
......@@ -23,4 +23,5 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "<Pending>")]
[assembly: SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "MimeTypes library uses validation methods")]
[assembly: SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "MimeTypes library defaults to lowercase strings")]
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4,6 +4,7 @@
<PropertyGroup>
<AssemblyTitle>MimeTypes - Dictionary of Apache's mime.types</AssemblyTitle>
<TargetFrameworks>netstandard2.1;net472</TargetFrameworks>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Label="NuGet">
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -5,6 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MediaTypeMap.Core" Version="2.3.3" />
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
......