OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of mime; | 5 library mime.mime_type; |
6 | 6 |
7 import 'default_extension_map.dart'; | |
8 import 'magic_number.dart'; | |
7 | 9 |
8 final MimeTypeResolver _globalResolver = new MimeTypeResolver(); | 10 final MimeTypeResolver _globalResolver = new MimeTypeResolver(); |
9 | 11 |
10 /** | 12 /** |
11 * The maximum number of bytes needed, to match all default magic-numbers. | 13 * The maximum number of bytes needed, to match all default magic-numbers. |
12 */ | 14 */ |
13 int get defaultMagicNumbersMaxLength => _DEFAULT_MAGIC_NUMBERS_MAX_LENGTH; | 15 // NOTE: this is not formatted AS_A_CONST to avoid a breaking change |
16 const int defaultMagicNumbersMaxLength = 12; | |
Anders Johnsen
2014/05/13 09:16:22
Thinking about it, this should really not be publi
kevmoo
2014/05/13 17:48:39
Let's talk about how to expose this. Perhaps we ca
Anders Johnsen
2014/05/14 07:36:07
But this entry is not useful for the user _at all_
| |
14 | 17 |
15 /** | 18 /** |
16 * Extract the extension from [path] and use that for MIME-type lookup, using | 19 * Extract the extension from [path] and use that for MIME-type lookup, using |
17 * the default extension map. | 20 * the default extension map. |
18 * | 21 * |
19 * If no matching MIME-type was found, `null` is returned. | 22 * If no matching MIME-type was found, `null` is returned. |
20 * | 23 * |
21 * If [headerBytes] is present, a match for known magic-numbers will be | 24 * If [headerBytes] is present, a match for known magic-numbers will be |
22 * performed first. This allows the correct mime-type to be found, even though | 25 * performed first. This allows the correct mime-type to be found, even though |
23 * a file have been saved using the wrong file-name extension. If less than | 26 * a file have been saved using the wrong file-name extension. If less than |
24 * [defaultMagicNumbersMaxLength] bytes was provided, some magic-numbers won't | 27 * [defaultMagicNumbersMaxLength] bytes was provided, some magic-numbers won't |
25 * be matched against. | 28 * be matched against. |
26 */ | 29 */ |
27 String lookupMimeType(String path, {List<int> headerBytes}) => | 30 String lookupMimeType(String path, {List<int> headerBytes}) => |
28 _globalResolver.lookup(path, headerBytes: headerBytes); | 31 _globalResolver.lookup(path, headerBytes: headerBytes); |
29 | 32 |
30 /** | 33 /** |
31 * MIME-type resolver class, used to customize the lookup of mime-types. | 34 * MIME-type resolver class, used to customize the lookup of mime-types. |
32 */ | 35 */ |
33 class MimeTypeResolver { | 36 class MimeTypeResolver { |
34 final Map<String, String> _extensionMap = {}; | 37 final Map<String, String> _extensionMap = {}; |
35 final List<_MagicNumber> _magicNumbers = []; | 38 final List<MagicNumber> _magicNumbers = []; |
36 final bool _useDefault; | 39 final bool _useDefault; |
37 int _magicNumbersMaxLength; | 40 int _magicNumbersMaxLength; |
38 | 41 |
39 /** | 42 /** |
40 * Create a new empty [MimeTypeResolver]. | 43 * Create a new empty [MimeTypeResolver]. |
41 */ | 44 */ |
42 MimeTypeResolver.empty() : _useDefault = false, _magicNumbersMaxLength = 0; | 45 MimeTypeResolver.empty() : _useDefault = false, _magicNumbersMaxLength = 0; |
43 | 46 |
44 /** | 47 /** |
45 * Create a new [MimeTypeResolver] containing the default scope. | 48 * Create a new [MimeTypeResolver] containing the default scope. |
46 */ | 49 */ |
47 MimeTypeResolver() : | 50 MimeTypeResolver() : |
48 _useDefault = true, | 51 _useDefault = true, |
49 _magicNumbersMaxLength = _DEFAULT_MAGIC_NUMBERS_MAX_LENGTH; | 52 _magicNumbersMaxLength = defaultMagicNumbersMaxLength; |
50 | 53 |
51 /** | 54 /** |
52 * Get the maximum number of bytes required to match all magic numbers, when | 55 * Get the maximum number of bytes required to match all magic numbers, when |
53 * performing [lookup] with headerBytes present. | 56 * performing [lookup] with headerBytes present. |
54 */ | 57 */ |
55 int get magicNumbersMaxLength => _magicNumbersMaxLength; | 58 int get magicNumbersMaxLength => _magicNumbersMaxLength; |
56 | 59 |
57 /** | 60 /** |
58 * Extract the extension from [path] and use that for MIME-type lookup. | 61 * Extract the extension from [path] and use that for MIME-type lookup. |
59 * | 62 * |
60 * If no matching MIME-type was found, `null` is returned. | 63 * If no matching MIME-type was found, `null` is returned. |
61 * | 64 * |
62 * If [headerBytes] is present, a match for known magic-numbers will be | 65 * If [headerBytes] is present, a match for known magic-numbers will be |
63 * performed first. This allows the correct mime-type to be found, even though | 66 * performed first. This allows the correct mime-type to be found, even though |
64 * a file have been saved using the wrong file-name extension. If less than | 67 * a file have been saved using the wrong file-name extension. If less than |
65 * [magicNumbersMaxLength] bytes was provided, some magic-numbers won't | 68 * [magicNumbersMaxLength] bytes was provided, some magic-numbers won't |
66 * be matched against. | 69 * be matched against. |
67 */ | 70 */ |
68 String lookup(String path, {List<int> headerBytes}) { | 71 String lookup(String path, {List<int> headerBytes}) { |
69 String result; | 72 String result; |
70 if (headerBytes != null) { | 73 if (headerBytes != null) { |
71 result = _matchMagic(headerBytes, _magicNumbers); | 74 result = _matchMagic(headerBytes, _magicNumbers); |
72 if (result != null) return result; | 75 if (result != null) return result; |
73 if (_useDefault) { | 76 if (_useDefault) { |
74 result = _matchMagic(headerBytes, _DEFAULT_MAGIC_NUMBERS); | 77 result = _matchMagic(headerBytes, DEFAULT_MAGIC_NUMBERS); |
75 if (result != null) return result; | 78 if (result != null) return result; |
76 } | 79 } |
77 } | 80 } |
78 var ext = _ext(path); | 81 var ext = _ext(path); |
79 result = _extensionMap[ext]; | 82 result = _extensionMap[ext]; |
80 if (result != null) return result; | 83 if (result != null) return result; |
81 if (_useDefault) { | 84 if (_useDefault) { |
82 result = _DEFAULT_EXTENSION_MAP[ext]; | 85 result = DEFAULT_EXTENSION_MAP[ext]; |
83 if (result != null) return result; | 86 if (result != null) return result; |
84 } | 87 } |
85 return null; | 88 return null; |
86 } | 89 } |
87 | 90 |
88 /** | 91 /** |
89 * Add a new MIME-type mapping to the [MimeTypeResolver]. If the [extension] | 92 * Add a new MIME-type mapping to the [MimeTypeResolver]. If the [extension] |
90 * is already present in the [MimeTypeResolver], it'll be overwritten. | 93 * is already present in the [MimeTypeResolver], it'll be overwritten. |
91 */ | 94 */ |
92 void addExtension(String extension, String mimeType) { | 95 void addExtension(String extension, String mimeType) { |
93 _extensionMap[extension] = mimeType; | 96 _extensionMap[extension] = mimeType; |
94 } | 97 } |
95 | 98 |
96 /** | 99 /** |
97 * Add a new magic-number mapping to the [MimeTypeResolver]. | 100 * Add a new magic-number mapping to the [MimeTypeResolver]. |
98 * | 101 * |
99 * If [mask] is present,the [mask] is used to only perform matching on | 102 * If [mask] is present,the [mask] is used to only perform matching on |
100 * selective bits. The [mask] must have the same length as [bytes]. | 103 * selective bits. The [mask] must have the same length as [bytes]. |
101 */ | 104 */ |
102 void addMagicNumber(List<int> bytes, String mimeType, {List<int> mask}) { | 105 void addMagicNumber(List<int> bytes, String mimeType, {List<int> mask}) { |
103 if (mask != null && bytes.length != mask.length) { | 106 if (mask != null && bytes.length != mask.length) { |
104 throw new ArgumentError('Bytes and mask are of different lengths'); | 107 throw new ArgumentError('Bytes and mask are of different lengths'); |
105 } | 108 } |
106 if (bytes.length > _magicNumbersMaxLength) { | 109 if (bytes.length > _magicNumbersMaxLength) { |
107 _magicNumbersMaxLength = bytes.length; | 110 _magicNumbersMaxLength = bytes.length; |
108 } | 111 } |
109 _magicNumbers.add(new _MagicNumber(mimeType, bytes, mask: mask)); | 112 _magicNumbers.add(new MagicNumber(mimeType, bytes, mask: mask)); |
110 } | 113 } |
111 | 114 |
112 static String _matchMagic(List<int> headerBytes, | 115 static String _matchMagic(List<int> headerBytes, |
113 List<_MagicNumber> magicNumbers) { | 116 List<MagicNumber> magicNumbers) { |
114 for (var mn in magicNumbers) { | 117 for (var mn in magicNumbers) { |
115 if (mn.matches(headerBytes)) return mn.mimeType; | 118 if (mn.matches(headerBytes)) return mn.mimeType; |
116 } | 119 } |
117 return null; | 120 return null; |
118 } | 121 } |
119 | 122 |
120 static String _ext(String path) { | 123 static String _ext(String path) { |
121 int index = path.lastIndexOf('.'); | 124 int index = path.lastIndexOf('.'); |
122 if (index < 0 || index + 1 >= path.length) return path; | 125 if (index < 0 || index + 1 >= path.length) return path; |
123 return path.substring(index + 1).toLowerCase(); | 126 return path.substring(index + 1).toLowerCase(); |
124 } | 127 } |
125 } | 128 } |
126 | 129 |
OLD | NEW |