QuickImage – Rev 7

Subversion Repositories:
Rev:
using MimeDetective;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MimeDetective.Storage;
using System.Security.Cryptography;
using MimeDetective.Engine;

namespace QuickImage.Utilities
{
    public class MagicMime
    {
        private static FileMutex _fileMutex;
        private static ConcurrentDictionary<string, MagicMimeFile> _fileMime;
        private static IContentInspector _mimeInspector;

        private MagicMime()
        {
            _fileMime = new ConcurrentDictionary<string, MagicMimeFile>();
            _mimeInspector = new ContentInspectorBuilder()
            {
                Definitions = new MimeDetective.Definitions.ExhaustiveBuilder()
                {
                    UsageType = MimeDetective.Definitions.Licensing.UsageType.PersonalNonCommercial
                }.Build()
            }.Build();
        }

        public MagicMime(FileMutex fileMutex) :this()
        {
            _fileMutex = fileMutex;
        }

        public async Task<MagicMimeFile> Identify(string fileName, CancellationToken cancellationToken)
        {
            await _fileMutex[fileName].WaitAsync(cancellationToken);
            try
            {
                var matches = new List<DefinitionMatch>(_mimeInspector.Inspect(fileName));
                matches.Sort(MimeInspectorDefinitionMatchComparer);
                var definitionMatch = matches.FirstOrDefault();
                if (definitionMatch == null)
                {
                    return null;
                }

                var magicMimeFile = new MagicMimeFile
                {
                    FileName = fileName, 
                    Definition = definitionMatch.Definition, 
                    FileHash = Cryptography.Hashes.MD5Hash(fileName)
                };

                _fileMime.AddOrUpdate(fileName, magicMimeFile,
                    (key, oldValue) => magicMimeFile);

                return magicMimeFile;
            }
            finally
            {
                _fileMutex[fileName].Release();
            }
        }

        private int MimeInspectorDefinitionMatchComparer(DefinitionMatch x, DefinitionMatch y)
        {
            return y.Points.CompareTo(x.Points);
        }

        public async Task<string> GetMimeType(string fileName, CancellationToken cancellationToken)
        {
            var identify = await Identify(fileName, cancellationToken);

            if(identify == null)
            {
                return string.Empty;
            }

            return identify.Definition.File.MimeType;
        }

        public MagicMimeFile Identify(string fileName, MemoryStream memoryStream, CancellationToken cancellationToken)
        {
            var definitionMatch = _mimeInspector.Inspect(memoryStream).FirstOrDefault();
            if (definitionMatch == null)
            {
                return null;
            }

            var magicMimeFile = new MagicMimeFile
            {
                FileName = fileName,
                Definition = definitionMatch.Definition,
                FileHash = Cryptography.Hashes.MD5Hash(fileName)
            };

            _fileMime.AddOrUpdate(fileName, magicMimeFile, (key, oldValue) => magicMimeFile);
            return magicMimeFile;
        }
    }
}