| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library mime.mime_type; |
| |
| import 'default_extension_map.dart'; |
| import 'magic_number.dart'; |
| |
| final MimeTypeResolver _globalResolver = MimeTypeResolver(); |
| |
| /// The maximum number of bytes needed, to match all default magic-numbers. |
| int get defaultMagicNumbersMaxLength => _globalResolver.magicNumbersMaxLength; |
| |
| /// Extract the extension from [path] and use that for MIME-type lookup, using |
| /// the default extension map. |
| /// |
| /// If no matching MIME-type was found, `null` is returned. |
| /// |
| /// If [headerBytes] is present, a match for known magic-numbers will be |
| /// performed first. This allows the correct mime-type to be found, even though |
| /// a file have been saved using the wrong file-name extension. If less than |
| /// [defaultMagicNumbersMaxLength] bytes was provided, some magic-numbers won't |
| /// be matched against. |
| String lookupMimeType(String path, {List<int> headerBytes}) => |
| _globalResolver.lookup(path, headerBytes: headerBytes); |
| |
| /// MIME-type resolver class, used to customize the lookup of mime-types. |
| class MimeTypeResolver { |
| final Map<String, String> _extensionMap = {}; |
| final List<MagicNumber> _magicNumbers = []; |
| final bool _useDefault; |
| int _magicNumbersMaxLength; |
| |
| /// Create a new empty [MimeTypeResolver]. |
| MimeTypeResolver.empty() |
| : _useDefault = false, |
| _magicNumbersMaxLength = 0; |
| |
| /// Create a new [MimeTypeResolver] containing the default scope. |
| MimeTypeResolver() |
| : _useDefault = true, |
| _magicNumbersMaxLength = DEFAULT_MAGIC_NUMBERS_MAX_LENGTH; |
| |
| /// Get the maximum number of bytes required to match all magic numbers, when |
| /// performing [lookup] with headerBytes present. |
| int get magicNumbersMaxLength => _magicNumbersMaxLength; |
| |
| /// Extract the extension from [path] and use that for MIME-type lookup. |
| /// |
| /// If no matching MIME-type was found, `null` is returned. |
| /// |
| /// If [headerBytes] is present, a match for known magic-numbers will be |
| /// performed first. This allows the correct mime-type to be found, even |
| /// though a file have been saved using the wrong file-name extension. If less |
| /// than [magicNumbersMaxLength] bytes was provided, some magic-numbers won't |
| /// be matched against. |
| String lookup(String path, {List<int> headerBytes}) { |
| String result; |
| if (headerBytes != null) { |
| result = _matchMagic(headerBytes, _magicNumbers); |
| if (result != null) return result; |
| if (_useDefault) { |
| result = _matchMagic(headerBytes, DEFAULT_MAGIC_NUMBERS); |
| if (result != null) return result; |
| } |
| } |
| var ext = _ext(path); |
| result = _extensionMap[ext]; |
| if (result != null) return result; |
| if (_useDefault) { |
| result = defaultExtensionMap[ext]; |
| if (result != null) return result; |
| } |
| return null; |
| } |
| |
| /// Add a new MIME-type mapping to the [MimeTypeResolver]. If the [extension] |
| /// is already present in the [MimeTypeResolver], it'll be overwritten. |
| void addExtension(String extension, String mimeType) { |
| _extensionMap[extension] = mimeType; |
| } |
| |
| /// Add a new magic-number mapping to the [MimeTypeResolver]. |
| /// |
| /// If [mask] is present,the [mask] is used to only perform matching on |
| /// selective bits. The [mask] must have the same length as [bytes]. |
| void addMagicNumber(List<int> bytes, String mimeType, {List<int> mask}) { |
| if (mask != null && bytes.length != mask.length) { |
| throw ArgumentError('Bytes and mask are of different lengths'); |
| } |
| if (bytes.length > _magicNumbersMaxLength) { |
| _magicNumbersMaxLength = bytes.length; |
| } |
| _magicNumbers.add(MagicNumber(mimeType, bytes, mask: mask)); |
| } |
| |
| static String _matchMagic( |
| List<int> headerBytes, List<MagicNumber> magicNumbers) { |
| for (var mn in magicNumbers) { |
| if (mn.matches(headerBytes)) return mn.mimeType; |
| } |
| return null; |
| } |
| |
| static String _ext(String path) { |
| int index = path.lastIndexOf('.'); |
| if (index < 0 || index + 1 >= path.length) return path; |
| return path.substring(index + 1).toLowerCase(); |
| } |
| } |