Add RIFF container support.
This commit is contained in:
parent
ccf46a765c
commit
f9792e2bcf
105
ReMime/ContentResolvers/RiffResolver.cs
Normal file
105
ReMime/ContentResolvers/RiffResolver.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ReMime.ContentResolvers
|
||||
{
|
||||
public class RiffResolver : IMediaTypeResolver, IMediaContentResolver
|
||||
{
|
||||
public readonly List<MediaType> _mediaTypes = new List<MediaType>();
|
||||
public readonly Dictionary<string, MediaType> _extensions = new Dictionary<string, MediaType>();
|
||||
public readonly Dictionary<int, MediaType> _magicValues = new Dictionary<int, MediaType>();
|
||||
|
||||
public IReadOnlyCollection<MediaType> MediaTypes { get; }
|
||||
|
||||
public RiffResolver()
|
||||
{
|
||||
MediaTypes = _mediaTypes.AsReadOnly();
|
||||
|
||||
List<MagicValueDatabaseEntry> entries;
|
||||
|
||||
using (Stream str = typeof(MagicContentResolver).Assembly.GetManifestResourceStream("ReMime.ContentResolvers.riff.jsonc")!)
|
||||
{
|
||||
entries = MagicValueDatabaseEntry.GetEntries(str);
|
||||
}
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
AddRiffType((MagicValueMediaType)entry);
|
||||
}
|
||||
}
|
||||
|
||||
public RiffResolver(IEnumerable<MagicValueMediaType> values) : this()
|
||||
{
|
||||
foreach (MagicValueMediaType value in values)
|
||||
AddRiffType(value);
|
||||
}
|
||||
|
||||
public bool TryResolve(Stream str, [NotNullWhen(true)] out MediaType? mediaType)
|
||||
{
|
||||
Span<byte> content = stackalloc byte[Unsafe.SizeOf<RiffChunk>()];
|
||||
str.Read(content);
|
||||
return TryResolve(content, out mediaType);
|
||||
}
|
||||
|
||||
public bool TryResolve(ReadOnlySpan<byte> content, [NotNullWhen(true)] out MediaType? mediaType)
|
||||
{
|
||||
mediaType = null;
|
||||
|
||||
if (content.Length < Unsafe.SizeOf<RiffChunk>())
|
||||
return false;
|
||||
|
||||
ref readonly RiffChunk chunk = ref MemoryMarshal.Cast<byte, RiffChunk>(content)[0];
|
||||
|
||||
if (chunk.Riff != RiffChunk.RiffValue)
|
||||
return false;
|
||||
|
||||
return _magicValues.TryGetValue(chunk.FirstChunkType, out mediaType);
|
||||
}
|
||||
|
||||
public bool TryResolve(string extension, out MediaType? mediaType)
|
||||
{
|
||||
return _extensions.TryGetValue(extension, out mediaType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a RIFF sub-magic value to this resolver.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
public void AddRiffType(MagicValueMediaType type)
|
||||
{
|
||||
if (type.MagicValues.Length == 0)
|
||||
throw new ArgumentException("Expected at least one media type.");
|
||||
|
||||
_mediaTypes.Add(type.MediaType);
|
||||
|
||||
foreach (string extension in type.Extensions)
|
||||
{
|
||||
_extensions.Add(extension, type.MediaType);
|
||||
}
|
||||
|
||||
foreach (MagicValue magic in type.MagicValues)
|
||||
{
|
||||
if (magic.Value.Length != 4)
|
||||
continue;
|
||||
|
||||
int i = MemoryMarshal.Cast<byte, int>(magic.Value)[0];
|
||||
|
||||
_magicValues.Add(i, type.MediaType);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto, Size = 12)]
|
||||
private struct RiffChunk
|
||||
{
|
||||
public int Riff;
|
||||
public int Size;
|
||||
public int FirstChunkType;
|
||||
|
||||
public const int RiffValue = 1179011410;
|
||||
}
|
||||
}
|
||||
}
|
21
ReMime/ContentResolvers/riff.jsonc
Normal file
21
ReMime/ContentResolvers/riff.jsonc
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* ReMime RIFF file types database.
|
||||
* This is a self compiled list of magic values, file extensions and
|
||||
* their media-types. Please contribute common file formats if you come
|
||||
* across them.
|
||||
*
|
||||
* This file is only for RIFF based formats. Please do not add magic values
|
||||
* for other file types here, as the magic values in this file are used
|
||||
*/
|
||||
[
|
||||
{ "type": "video/avi", "magic": ["'AVI '"], "extensions": ["avi"]},
|
||||
{ "type": "audio/wav", "magic": ["'WAVE'"], "extensions": ["wav"] },
|
||||
{ "type": "image/vnd.microsoft.icon", "magic": ["'ACON'"], "extensions": ["ani"] },
|
||||
|
||||
// Whilst we speak about WEBP...
|
||||
// My kindest f*ck you to Google for impeding standards like JPEG-XL
|
||||
// for their own benefit. WEBP itself might be a fine file format
|
||||
// but I do not support it if you maliciously stop implementing other
|
||||
// file formats into your browsers and applications.
|
||||
{ "type": "image/webp", "magic": ["'WEBP'"], "extensions": ["webp"] }
|
||||
]
|
@ -50,6 +50,7 @@ namespace ReMime
|
||||
|
||||
static MediaTypeResolver()
|
||||
{
|
||||
AddResolver(new RiffResolver(), 9997);
|
||||
AddResolver(new MagicContentResolver(), 9998);
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ContentResolvers/database.jsonc" />
|
||||
<EmbeddedResource Include="ContentResolvers/riff.jsonc" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user