file-type 20.4.1 → 21.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core.d.ts +20 -5
- package/core.js +119 -104
- package/index.d.ts +9 -8
- package/index.js +4 -4
- package/package.json +10 -9
- package/readme.md +37 -6
- package/supported.js +13 -10
package/core.d.ts
CHANGED
|
@@ -24,16 +24,17 @@ export type FileTypeResult = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
Detect the file type of a `Uint8Array
|
|
27
|
+
Detect the file type of a `Uint8Array` or `ArrayBuffer`.
|
|
28
28
|
|
|
29
29
|
The file type is detected by checking the [magic number](https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) of the buffer.
|
|
30
30
|
|
|
31
31
|
If file access is available, it is recommended to use `.fromFile()` instead.
|
|
32
32
|
|
|
33
33
|
@param buffer - An Uint8Array or ArrayBuffer representing file data. It works best if the buffer contains the entire file. It may work with a smaller portion as well.
|
|
34
|
+
@param options - Options to override default behavior.
|
|
34
35
|
@returns The detected file type, or `undefined` when there is no match.
|
|
35
36
|
*/
|
|
36
|
-
export function fileTypeFromBuffer(buffer: Uint8Array | ArrayBuffer): Promise<FileTypeResult | undefined>;
|
|
37
|
+
export function fileTypeFromBuffer(buffer: Uint8Array | ArrayBuffer, options?: FileTypeOptions): Promise<FileTypeResult | undefined>;
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
Detect the file type of a [web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
|
|
@@ -41,9 +42,10 @@ Detect the file type of a [web `ReadableStream`](https://developer.mozilla.org/e
|
|
|
41
42
|
The file type is detected by checking the [magic number](https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) of the buffer.
|
|
42
43
|
|
|
43
44
|
@param stream - A [web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) streaming a file to examine.
|
|
45
|
+
@param options - Options to override default behavior.
|
|
44
46
|
@returns A `Promise` for an object with the detected file type, or `undefined` when there is no match.
|
|
45
47
|
*/
|
|
46
|
-
export function fileTypeFromStream(stream: AnyWebByteStream): Promise<FileTypeResult | undefined>;
|
|
48
|
+
export function fileTypeFromStream(stream: AnyWebByteStream, options?: FileTypeOptions): Promise<FileTypeResult | undefined>;
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
Detect the file type from an [`ITokenizer`](https://github.com/Borewit/strtok3#tokenizer) source.
|
|
@@ -53,6 +55,7 @@ This method is used internally, but can also be used for a special "tokenizer" r
|
|
|
53
55
|
A tokenizer propagates the internal read functions, allowing alternative transport mechanisms, to access files, to be implemented and used.
|
|
54
56
|
|
|
55
57
|
@param tokenizer - File source implementing the tokenizer interface.
|
|
58
|
+
@param options - Options to override default behavior.
|
|
56
59
|
@returns The detected file type, or `undefined` when there is no match.
|
|
57
60
|
|
|
58
61
|
An example is [`@tokenizer/http`](https://github.com/Borewit/tokenizer-http), which requests data using [HTTP-range-requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests). A difference with a conventional stream and the [*tokenizer*](https://github.com/Borewit/strtok3#tokenizer), is that it is able to *ignore* (seek, fast-forward) in the stream. For example, you may only need and read the first 6 bytes, and the last 128 bytes, which may be an advantage in case reading the entire file would take longer.
|
|
@@ -71,7 +74,7 @@ console.log(fileType);
|
|
|
71
74
|
//=> {ext: 'mp3', mime: 'audio/mpeg'}
|
|
72
75
|
```
|
|
73
76
|
*/
|
|
74
|
-
export function fileTypeFromTokenizer(tokenizer: ITokenizer): Promise<FileTypeResult | undefined>;
|
|
77
|
+
export function fileTypeFromTokenizer(tokenizer: ITokenizer, options?: FileTypeOptions): Promise<FileTypeResult | undefined>;
|
|
75
78
|
|
|
76
79
|
/**
|
|
77
80
|
Supported file extensions.
|
|
@@ -96,6 +99,7 @@ export type StreamOptions = {
|
|
|
96
99
|
Detect the file type of a [`Blob`](https://nodejs.org/api/buffer.html#class-blob) or [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File).
|
|
97
100
|
|
|
98
101
|
@param blob - The [`Blob`](https://nodejs.org/api/buffer.html#class-blob) used for file detection.
|
|
102
|
+
@param options - Options to override default behavior.
|
|
99
103
|
@returns The detected file type, or `undefined` when there is no match.
|
|
100
104
|
|
|
101
105
|
@example
|
|
@@ -111,7 +115,7 @@ console.log(await fileTypeFromBlob(blob));
|
|
|
111
115
|
//=> {ext: 'txt', mime: 'text/plain'}
|
|
112
116
|
```
|
|
113
117
|
*/
|
|
114
|
-
export declare function fileTypeFromBlob(blob: Blob): Promise<FileTypeResult | undefined>;
|
|
118
|
+
export declare function fileTypeFromBlob(blob: Blob, options?: FileTypeOptions): Promise<FileTypeResult | undefined>;
|
|
115
119
|
|
|
116
120
|
/**
|
|
117
121
|
A custom file type detector.
|
|
@@ -184,6 +188,17 @@ export type Detector = {
|
|
|
184
188
|
|
|
185
189
|
export type FileTypeOptions = {
|
|
186
190
|
customDetectors?: Iterable<Detector>;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
Specifies the byte tolerance for locating the first MPEG audio frame (e.g. `.mp1`, `.mp2`, `.mp3`, `.aac`).
|
|
194
|
+
|
|
195
|
+
Allows detection to handle slight sync offsets between the expected and actual frame start. Common in malformed or incorrectly muxed files, which, while technically invalid, do occur in the wild.
|
|
196
|
+
|
|
197
|
+
A tolerance of 10 bytes covers most cases.
|
|
198
|
+
|
|
199
|
+
@default 0
|
|
200
|
+
*/
|
|
201
|
+
mpegOffsetTolerance?: number;
|
|
187
202
|
};
|
|
188
203
|
|
|
189
204
|
export declare class TokenizerPositionError extends Error {
|
package/core.js
CHANGED
|
@@ -5,7 +5,7 @@ Primary entry point, Node.js specific entry point is index.js
|
|
|
5
5
|
import * as Token from 'token-types';
|
|
6
6
|
import * as strtok3 from 'strtok3/core';
|
|
7
7
|
import {ZipHandler} from '@tokenizer/inflate';
|
|
8
|
-
import {
|
|
8
|
+
import {getUintBE} from 'uint8array-extras';
|
|
9
9
|
import {
|
|
10
10
|
stringToBytes,
|
|
11
11
|
tarHeaderChecksumMatches,
|
|
@@ -15,124 +15,135 @@ import {extensions, mimeTypes} from './supported.js';
|
|
|
15
15
|
|
|
16
16
|
export const reasonableDetectionSizeInBytes = 4100; // A fair amount of file-types are detectable within this range.
|
|
17
17
|
|
|
18
|
-
export async function fileTypeFromStream(stream) {
|
|
19
|
-
return new FileTypeParser().fromStream(stream);
|
|
18
|
+
export async function fileTypeFromStream(stream, options) {
|
|
19
|
+
return new FileTypeParser(options).fromStream(stream);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export async function fileTypeFromBuffer(input) {
|
|
23
|
-
return new FileTypeParser().fromBuffer(input);
|
|
22
|
+
export async function fileTypeFromBuffer(input, options) {
|
|
23
|
+
return new FileTypeParser(options).fromBuffer(input);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export async function fileTypeFromBlob(blob) {
|
|
27
|
-
return new FileTypeParser().fromBlob(blob);
|
|
26
|
+
export async function fileTypeFromBlob(blob, options) {
|
|
27
|
+
return new FileTypeParser(options).fromBlob(blob);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function getFileTypeFromMimeType(mimeType) {
|
|
31
|
+
mimeType = mimeType.toLowerCase();
|
|
31
32
|
switch (mimeType) {
|
|
32
33
|
case 'application/epub+zip':
|
|
33
34
|
return {
|
|
34
35
|
ext: 'epub',
|
|
35
|
-
mime:
|
|
36
|
+
mime: mimeType,
|
|
36
37
|
};
|
|
37
38
|
case 'application/vnd.oasis.opendocument.text':
|
|
38
39
|
return {
|
|
39
40
|
ext: 'odt',
|
|
40
|
-
mime:
|
|
41
|
+
mime: mimeType,
|
|
41
42
|
};
|
|
42
43
|
case 'application/vnd.oasis.opendocument.text-template':
|
|
43
44
|
return {
|
|
44
45
|
ext: 'ott',
|
|
45
|
-
mime:
|
|
46
|
+
mime: mimeType,
|
|
46
47
|
};
|
|
47
48
|
case 'application/vnd.oasis.opendocument.spreadsheet':
|
|
48
49
|
return {
|
|
49
50
|
ext: 'ods',
|
|
50
|
-
mime:
|
|
51
|
+
mime: mimeType,
|
|
51
52
|
};
|
|
52
53
|
case 'application/vnd.oasis.opendocument.spreadsheet-template':
|
|
53
54
|
return {
|
|
54
55
|
ext: 'ots',
|
|
55
|
-
mime:
|
|
56
|
+
mime: mimeType,
|
|
56
57
|
};
|
|
57
58
|
case 'application/vnd.oasis.opendocument.presentation':
|
|
58
59
|
return {
|
|
59
60
|
ext: 'odp',
|
|
60
|
-
mime:
|
|
61
|
+
mime: mimeType,
|
|
61
62
|
};
|
|
62
63
|
case 'application/vnd.oasis.opendocument.presentation-template':
|
|
63
64
|
return {
|
|
64
65
|
ext: 'otp',
|
|
65
|
-
mime:
|
|
66
|
+
mime: mimeType,
|
|
66
67
|
};
|
|
67
68
|
case 'application/vnd.oasis.opendocument.graphics':
|
|
68
69
|
return {
|
|
69
70
|
ext: 'odg',
|
|
70
|
-
mime:
|
|
71
|
+
mime: mimeType,
|
|
71
72
|
};
|
|
72
73
|
case 'application/vnd.oasis.opendocument.graphics-template':
|
|
73
74
|
return {
|
|
74
75
|
ext: 'otg',
|
|
75
|
-
mime:
|
|
76
|
+
mime: mimeType,
|
|
77
|
+
};
|
|
78
|
+
case 'application/vnd.openxmlformats-officedocument.presentationml.slideshow':
|
|
79
|
+
return {
|
|
80
|
+
ext: 'ppsx',
|
|
81
|
+
mime: mimeType,
|
|
76
82
|
};
|
|
77
83
|
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
|
|
78
84
|
return {
|
|
79
85
|
ext: 'xlsx',
|
|
80
|
-
mime:
|
|
86
|
+
mime: mimeType,
|
|
81
87
|
};
|
|
82
|
-
case 'application/vnd.ms-excel.sheet.
|
|
88
|
+
case 'application/vnd.ms-excel.sheet.macroenabled':
|
|
83
89
|
return {
|
|
84
90
|
ext: 'xlsm',
|
|
85
|
-
mime: 'application/vnd.ms-excel.sheet.
|
|
91
|
+
mime: 'application/vnd.ms-excel.sheet.macroenabled.12',
|
|
86
92
|
};
|
|
87
93
|
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.template':
|
|
88
94
|
return {
|
|
89
95
|
ext: 'xltx',
|
|
90
|
-
mime:
|
|
96
|
+
mime: mimeType,
|
|
91
97
|
};
|
|
92
|
-
case 'application/vnd.ms-excel.template.
|
|
98
|
+
case 'application/vnd.ms-excel.template.macroenabled':
|
|
93
99
|
return {
|
|
94
100
|
ext: 'xltm',
|
|
95
101
|
mime: 'application/vnd.ms-excel.template.macroenabled.12',
|
|
96
102
|
};
|
|
103
|
+
case 'application/vnd.ms-powerpoint.slideshow.macroenabled':
|
|
104
|
+
return {
|
|
105
|
+
ext: 'ppsm',
|
|
106
|
+
mime: 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
|
|
107
|
+
};
|
|
97
108
|
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
|
|
98
109
|
return {
|
|
99
110
|
ext: 'docx',
|
|
100
|
-
mime:
|
|
111
|
+
mime: mimeType,
|
|
101
112
|
};
|
|
102
|
-
case 'application/vnd.ms-word.document.
|
|
113
|
+
case 'application/vnd.ms-word.document.macroenabled':
|
|
103
114
|
return {
|
|
104
115
|
ext: 'docm',
|
|
105
|
-
mime: 'application/vnd.ms-word.document.
|
|
116
|
+
mime: 'application/vnd.ms-word.document.macroenabled.12',
|
|
106
117
|
};
|
|
107
118
|
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.template':
|
|
108
119
|
return {
|
|
109
120
|
ext: 'dotx',
|
|
110
|
-
mime:
|
|
121
|
+
mime: mimeType,
|
|
111
122
|
};
|
|
112
|
-
case 'application/vnd.ms-word.template.
|
|
123
|
+
case 'application/vnd.ms-word.template.macroenabledtemplate':
|
|
113
124
|
return {
|
|
114
125
|
ext: 'dotm',
|
|
115
|
-
mime: 'application/vnd.ms-word.template.
|
|
126
|
+
mime: 'application/vnd.ms-word.template.macroenabled.12',
|
|
116
127
|
};
|
|
117
128
|
case 'application/vnd.openxmlformats-officedocument.presentationml.template':
|
|
118
129
|
return {
|
|
119
130
|
ext: 'potx',
|
|
120
|
-
mime:
|
|
131
|
+
mime: mimeType,
|
|
121
132
|
};
|
|
122
|
-
case 'application/vnd.ms-powerpoint.template.
|
|
133
|
+
case 'application/vnd.ms-powerpoint.template.macroenabled':
|
|
123
134
|
return {
|
|
124
135
|
ext: 'potm',
|
|
125
|
-
mime: 'application/vnd.ms-powerpoint.template.
|
|
136
|
+
mime: 'application/vnd.ms-powerpoint.template.macroenabled.12',
|
|
126
137
|
};
|
|
127
138
|
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
|
|
128
139
|
return {
|
|
129
140
|
ext: 'pptx',
|
|
130
|
-
mime:
|
|
141
|
+
mime: mimeType,
|
|
131
142
|
};
|
|
132
|
-
case 'application/vnd.ms-powerpoint.presentation.
|
|
143
|
+
case 'application/vnd.ms-powerpoint.presentation.macroenabled':
|
|
133
144
|
return {
|
|
134
145
|
ext: 'pptm',
|
|
135
|
-
mime: 'application/vnd.ms-powerpoint.presentation.
|
|
146
|
+
mime: 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
|
|
136
147
|
};
|
|
137
148
|
case 'application/vnd.ms-visio.drawing':
|
|
138
149
|
return {
|
|
@@ -169,8 +180,8 @@ function _check(buffer, headers, options) {
|
|
|
169
180
|
return true;
|
|
170
181
|
}
|
|
171
182
|
|
|
172
|
-
export async function fileTypeFromTokenizer(tokenizer) {
|
|
173
|
-
return new FileTypeParser().fromTokenizer(tokenizer);
|
|
183
|
+
export async function fileTypeFromTokenizer(tokenizer, options) {
|
|
184
|
+
return new FileTypeParser(options).fromTokenizer(tokenizer);
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
export async function fileTypeStream(webStream, options) {
|
|
@@ -179,6 +190,11 @@ export async function fileTypeStream(webStream, options) {
|
|
|
179
190
|
|
|
180
191
|
export class FileTypeParser {
|
|
181
192
|
constructor(options) {
|
|
193
|
+
this.options = {
|
|
194
|
+
mpegOffsetTolerance: 0,
|
|
195
|
+
...options,
|
|
196
|
+
};
|
|
197
|
+
|
|
182
198
|
this.detectors = [...(options?.customDetectors ?? []),
|
|
183
199
|
{id: 'core', detect: this.detectConfident},
|
|
184
200
|
{id: 'core.imprecise', detect: this.detectImprecise}];
|
|
@@ -243,7 +259,7 @@ export class FileTypeParser {
|
|
|
243
259
|
if (!done && chunk) {
|
|
244
260
|
try {
|
|
245
261
|
// Attempt to detect the file type from the chunk
|
|
246
|
-
detectedFileType = await this.fromBuffer(chunk.
|
|
262
|
+
detectedFileType = await this.fromBuffer(chunk.subarray(0, sampleSize));
|
|
247
263
|
} catch (error) {
|
|
248
264
|
if (!(error instanceof strtok3.EndOfStreamError)) {
|
|
249
265
|
throw error; // Re-throw non-EndOfStreamError
|
|
@@ -699,7 +715,7 @@ export class FileTypeParser {
|
|
|
699
715
|
if (this.checkString('fLaC')) {
|
|
700
716
|
return {
|
|
701
717
|
ext: 'flac',
|
|
702
|
-
mime: 'audio/
|
|
718
|
+
mime: 'audio/flac',
|
|
703
719
|
};
|
|
704
720
|
}
|
|
705
721
|
|
|
@@ -718,28 +734,6 @@ export class FileTypeParser {
|
|
|
718
734
|
}
|
|
719
735
|
|
|
720
736
|
if (this.checkString('%PDF')) {
|
|
721
|
-
try {
|
|
722
|
-
const skipBytes = 1350;
|
|
723
|
-
if (skipBytes === await tokenizer.ignore(skipBytes)) {
|
|
724
|
-
const maxBufferSize = 10 * 1024 * 1024;
|
|
725
|
-
const buffer = new Uint8Array(Math.min(maxBufferSize, tokenizer.fileInfo.size - skipBytes));
|
|
726
|
-
await tokenizer.readBuffer(buffer, {mayBeLess: true});
|
|
727
|
-
|
|
728
|
-
// Check if this is an Adobe Illustrator file
|
|
729
|
-
if (includes(buffer, new TextEncoder().encode('AIPrivateData'))) {
|
|
730
|
-
return {
|
|
731
|
-
ext: 'ai',
|
|
732
|
-
mime: 'application/postscript',
|
|
733
|
-
};
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
} catch (error) {
|
|
737
|
-
// Swallow end of stream error if file is too small for the Adobe AI check
|
|
738
|
-
if (!(error instanceof strtok3.EndOfStreamError)) {
|
|
739
|
-
throw error;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
737
|
// Assume this is just a normal PDF
|
|
744
738
|
return {
|
|
745
739
|
ext: 'pdf',
|
|
@@ -836,7 +830,7 @@ export class FileTypeParser {
|
|
|
836
830
|
case 'matroska':
|
|
837
831
|
return {
|
|
838
832
|
ext: 'mkv',
|
|
839
|
-
mime: 'video/
|
|
833
|
+
mime: 'video/matroska',
|
|
840
834
|
};
|
|
841
835
|
|
|
842
836
|
default:
|
|
@@ -910,10 +904,10 @@ export class FileTypeParser {
|
|
|
910
904
|
};
|
|
911
905
|
}
|
|
912
906
|
|
|
913
|
-
if (this.checkString('PAR1')) {
|
|
907
|
+
if (this.checkString('PAR1') || this.checkString('PARE')) {
|
|
914
908
|
return {
|
|
915
909
|
ext: 'parquet',
|
|
916
|
-
mime: 'application/
|
|
910
|
+
mime: 'application/vnd.apache.parquet',
|
|
917
911
|
};
|
|
918
912
|
}
|
|
919
913
|
|
|
@@ -1189,7 +1183,7 @@ export class FileTypeParser {
|
|
|
1189
1183
|
if (this.check([0x41, 0x52, 0x52, 0x4F, 0x57, 0x31, 0x00, 0x00])) {
|
|
1190
1184
|
return {
|
|
1191
1185
|
ext: 'arrow',
|
|
1192
|
-
mime: 'application/
|
|
1186
|
+
mime: 'application/vnd.apache.arrow.file',
|
|
1193
1187
|
};
|
|
1194
1188
|
}
|
|
1195
1189
|
|
|
@@ -1531,7 +1525,7 @@ export class FileTypeParser {
|
|
|
1531
1525
|
|
|
1532
1526
|
if (jsonSize > 12 && this.buffer.length >= jsonSize + 16) {
|
|
1533
1527
|
try {
|
|
1534
|
-
const header = new TextDecoder().decode(this.buffer.
|
|
1528
|
+
const header = new TextDecoder().decode(this.buffer.subarray(16, jsonSize + 16));
|
|
1535
1529
|
const json = JSON.parse(header);
|
|
1536
1530
|
// Check if Pickle is ASAR
|
|
1537
1531
|
if (json.files) { // Final check, assuring Pickle/ASAR format
|
|
@@ -1634,7 +1628,8 @@ export class FileTypeParser {
|
|
|
1634
1628
|
await tokenizer.peekBuffer(this.buffer, {length: Math.min(512, tokenizer.fileInfo.size), mayBeLess: true});
|
|
1635
1629
|
|
|
1636
1630
|
// Requires a buffer size of 512 bytes
|
|
1637
|
-
if (
|
|
1631
|
+
if ((this.checkString('ustar', {offset: 257}) && (this.checkString('\0', {offset: 262}) || this.checkString(' ', {offset: 262})))
|
|
1632
|
+
|| (this.check([0, 0, 0, 0, 0, 0], {offset: 257}) && tarHeaderChecksumMatches(this.buffer))) {
|
|
1638
1633
|
return {
|
|
1639
1634
|
ext: 'tar',
|
|
1640
1635
|
mime: 'application/x-tar',
|
|
@@ -1704,47 +1699,16 @@ export class FileTypeParser {
|
|
|
1704
1699
|
};
|
|
1705
1700
|
}
|
|
1706
1701
|
|
|
1702
|
+
// Adjust buffer to `mpegOffsetTolerance`
|
|
1703
|
+
await tokenizer.peekBuffer(this.buffer, {length: Math.min(2 + this.options.mpegOffsetTolerance, tokenizer.fileInfo.size), mayBeLess: true});
|
|
1704
|
+
|
|
1707
1705
|
// Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE)
|
|
1708
|
-
if (this.buffer.length >= 2
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
if (
|
|
1712
|
-
return
|
|
1713
|
-
ext: 'aac',
|
|
1714
|
-
mime: 'audio/aac',
|
|
1715
|
-
};
|
|
1706
|
+
if (this.buffer.length >= (2 + this.options.mpegOffsetTolerance)) {
|
|
1707
|
+
for (let depth = 0; depth <= this.options.mpegOffsetTolerance; ++depth) {
|
|
1708
|
+
const type = this.scanMpeg(depth);
|
|
1709
|
+
if (type) {
|
|
1710
|
+
return type;
|
|
1716
1711
|
}
|
|
1717
|
-
|
|
1718
|
-
// Must be (ADTS) MPEG-4
|
|
1719
|
-
return {
|
|
1720
|
-
ext: 'aac',
|
|
1721
|
-
mime: 'audio/aac',
|
|
1722
|
-
};
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
// MPEG 1 or 2 Layer 3 header
|
|
1726
|
-
// Check for MPEG layer 3
|
|
1727
|
-
if (this.check([0x02], {offset: 1, mask: [0x06]})) {
|
|
1728
|
-
return {
|
|
1729
|
-
ext: 'mp3',
|
|
1730
|
-
mime: 'audio/mpeg',
|
|
1731
|
-
};
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// Check for MPEG layer 2
|
|
1735
|
-
if (this.check([0x04], {offset: 1, mask: [0x06]})) {
|
|
1736
|
-
return {
|
|
1737
|
-
ext: 'mp2',
|
|
1738
|
-
mime: 'audio/mpeg',
|
|
1739
|
-
};
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
// Check for MPEG layer 1
|
|
1743
|
-
if (this.check([0x06], {offset: 1, mask: [0x06]})) {
|
|
1744
|
-
return {
|
|
1745
|
-
ext: 'mp1',
|
|
1746
|
-
mime: 'audio/mpeg',
|
|
1747
|
-
};
|
|
1748
1712
|
}
|
|
1749
1713
|
}
|
|
1750
1714
|
};
|
|
@@ -1821,6 +1785,57 @@ export class FileTypeParser {
|
|
|
1821
1785
|
};
|
|
1822
1786
|
}
|
|
1823
1787
|
}
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
Scan check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE).
|
|
1791
|
+
|
|
1792
|
+
@param offset - Offset to scan for sync-preamble.
|
|
1793
|
+
@returns {{ext: string, mime: string}}
|
|
1794
|
+
*/
|
|
1795
|
+
scanMpeg(offset) {
|
|
1796
|
+
if (this.check([0xFF, 0xE0], {offset, mask: [0xFF, 0xE0]})) {
|
|
1797
|
+
if (this.check([0x10], {offset: offset + 1, mask: [0x16]})) {
|
|
1798
|
+
// Check for (ADTS) MPEG-2
|
|
1799
|
+
if (this.check([0x08], {offset: offset + 1, mask: [0x08]})) {
|
|
1800
|
+
return {
|
|
1801
|
+
ext: 'aac',
|
|
1802
|
+
mime: 'audio/aac',
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
// Must be (ADTS) MPEG-4
|
|
1807
|
+
return {
|
|
1808
|
+
ext: 'aac',
|
|
1809
|
+
mime: 'audio/aac',
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
// MPEG 1 or 2 Layer 3 header
|
|
1814
|
+
// Check for MPEG layer 3
|
|
1815
|
+
if (this.check([0x02], {offset: offset + 1, mask: [0x06]})) {
|
|
1816
|
+
return {
|
|
1817
|
+
ext: 'mp3',
|
|
1818
|
+
mime: 'audio/mpeg',
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// Check for MPEG layer 2
|
|
1823
|
+
if (this.check([0x04], {offset: offset + 1, mask: [0x06]})) {
|
|
1824
|
+
return {
|
|
1825
|
+
ext: 'mp2',
|
|
1826
|
+
mime: 'audio/mpeg',
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
// Check for MPEG layer 1
|
|
1831
|
+
if (this.check([0x06], {offset: offset + 1, mask: [0x06]})) {
|
|
1832
|
+
return {
|
|
1833
|
+
ext: 'mp1',
|
|
1834
|
+
mime: 'audio/mpeg',
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1824
1839
|
}
|
|
1825
1840
|
|
|
1826
1841
|
export const supportedExtensions = new Set(extensions);
|
package/index.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
type FileTypeResult,
|
|
9
9
|
type StreamOptions,
|
|
10
10
|
type AnyWebReadableStream,
|
|
11
|
-
type Detector,
|
|
12
11
|
type AnyWebReadableByteStreamWithFileType,
|
|
12
|
+
type FileTypeOptions,
|
|
13
13
|
FileTypeParser as DefaultFileTypeParser,
|
|
14
14
|
} from './core.js';
|
|
15
15
|
|
|
@@ -31,8 +31,8 @@ export declare class FileTypeParser extends DefaultFileTypeParser {
|
|
|
31
31
|
/**
|
|
32
32
|
Works the same way as {@link fileTypeStream}, additionally taking into account custom detectors (if any were provided to the constructor).
|
|
33
33
|
*/
|
|
34
|
-
toDetectionStream(readableStream: NodeReadableStream, options?: StreamOptions): Promise<ReadableStreamWithFileType>;
|
|
35
|
-
toDetectionStream(webStream: AnyWebReadableStream<Uint8Array>, options?: StreamOptions): Promise<AnyWebReadableByteStreamWithFileType>;
|
|
34
|
+
toDetectionStream(readableStream: NodeReadableStream, options?: FileTypeOptions & StreamOptions): Promise<ReadableStreamWithFileType>;
|
|
35
|
+
toDetectionStream(webStream: AnyWebReadableStream<Uint8Array>, options?: FileTypeOptions & StreamOptions): Promise<AnyWebReadableByteStreamWithFileType>;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -48,7 +48,7 @@ The file type is detected by checking the [magic number](https://en.wikipedia.or
|
|
|
48
48
|
|
|
49
49
|
@returns The detected file type and MIME type or `undefined` when there is no match.
|
|
50
50
|
*/
|
|
51
|
-
export function fileTypeFromFile(filePath: string, options?:
|
|
51
|
+
export function fileTypeFromFile(filePath: string, options?: FileTypeOptions): Promise<FileTypeResult | undefined>;
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
54
|
Detect the file type of a [web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
|
|
@@ -60,9 +60,10 @@ Direct support for Node.js streams will be dropped in the future, when Node.js s
|
|
|
60
60
|
The file type is detected by checking the [magic number](https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) of the buffer.
|
|
61
61
|
|
|
62
62
|
@param stream - A [web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) or [Node.js `stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable) streaming a file to examine.
|
|
63
|
-
@
|
|
63
|
+
@param options - Options to override default behaviour.
|
|
64
|
+
@returns A `Promise` for an object with the detected file type, or `undefined` when there is no match.
|
|
64
65
|
*/
|
|
65
|
-
export function fileTypeFromStream(stream: AnyWebReadableStream<Uint8Array> | NodeReadableStream): Promise<FileTypeResult | undefined>;
|
|
66
|
+
export function fileTypeFromStream(stream: AnyWebReadableStream<Uint8Array> | NodeReadableStream, options?: FileTypeOptions): Promise<FileTypeResult | undefined>;
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
69
|
Returns a `Promise` which resolves to the original readable stream argument, but with an added `fileType` property, which is an object like the one returned from `fileTypeFromFile()`.
|
|
@@ -91,7 +92,7 @@ if (stream2.fileType?.mime === 'image/jpeg') {
|
|
|
91
92
|
}
|
|
92
93
|
```
|
|
93
94
|
*/
|
|
94
|
-
export function fileTypeStream(readableStream: NodeReadableStream, options?: StreamOptions): Promise<ReadableStreamWithFileType>;
|
|
95
|
-
export function fileTypeStream(webStream: AnyWebByteStream, options?: StreamOptions): Promise<AnyWebReadableByteStreamWithFileType>;
|
|
95
|
+
export function fileTypeStream(readableStream: NodeReadableStream, options?: FileTypeOptions & StreamOptions): Promise<ReadableStreamWithFileType>;
|
|
96
|
+
export function fileTypeStream(webStream: AnyWebByteStream, options?: FileTypeOptions & StreamOptions): Promise<AnyWebReadableByteStreamWithFileType>;
|
|
96
97
|
|
|
97
98
|
export * from './core.js';
|
package/index.js
CHANGED
|
@@ -65,12 +65,12 @@ export class FileTypeParser extends DefaultFileTypeParser {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export async function fileTypeFromFile(path,
|
|
69
|
-
return (new FileTypeParser(
|
|
68
|
+
export async function fileTypeFromFile(path, options) {
|
|
69
|
+
return (new FileTypeParser(options)).fromFile(path, options);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export async function fileTypeFromStream(stream,
|
|
73
|
-
return (new FileTypeParser(
|
|
72
|
+
export async function fileTypeFromStream(stream, options) {
|
|
73
|
+
return (new FileTypeParser(options)).fromStream(stream);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export async function fileTypeStream(readableStream, options = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "file-type",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "21.0.0",
|
|
4
4
|
"description": "Detect the file type of a file, stream, or data",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/file-type",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"sideEffects": false,
|
|
37
37
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
38
|
+
"node": ">=20"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"test": "xo && ava && tsd"
|
|
@@ -198,7 +198,6 @@
|
|
|
198
198
|
"it",
|
|
199
199
|
"s3m",
|
|
200
200
|
"xm",
|
|
201
|
-
"ai",
|
|
202
201
|
"skp",
|
|
203
202
|
"avif",
|
|
204
203
|
"eps",
|
|
@@ -242,22 +241,24 @@
|
|
|
242
241
|
"potm",
|
|
243
242
|
"pptm",
|
|
244
243
|
"jar",
|
|
245
|
-
"rm"
|
|
244
|
+
"rm",
|
|
245
|
+
"ppsm",
|
|
246
|
+
"ppsx"
|
|
246
247
|
],
|
|
247
248
|
"dependencies": {
|
|
248
|
-
"@tokenizer/inflate": "^0.2.
|
|
249
|
-
"strtok3": "^10.2.
|
|
249
|
+
"@tokenizer/inflate": "^0.2.7",
|
|
250
|
+
"strtok3": "^10.2.2",
|
|
250
251
|
"token-types": "^6.0.0",
|
|
251
252
|
"uint8array-extras": "^1.4.0"
|
|
252
253
|
},
|
|
253
254
|
"devDependencies": {
|
|
254
255
|
"@tokenizer/token": "^0.3.0",
|
|
255
|
-
"@types/node": "^22.
|
|
256
|
-
"ava": "^6.0
|
|
256
|
+
"@types/node": "^22.15.21",
|
|
257
|
+
"ava": "^6.3.0",
|
|
257
258
|
"commonmark": "^0.31.2",
|
|
258
259
|
"get-stream": "^9.0.1",
|
|
259
260
|
"noop-stream": "^1.0.0",
|
|
260
|
-
"tsd": "^0.
|
|
261
|
+
"tsd": "^0.32.0",
|
|
261
262
|
"xo": "^0.60.0"
|
|
262
263
|
},
|
|
263
264
|
"xo": {
|
package/readme.md
CHANGED
|
@@ -109,7 +109,7 @@ console.log(fileType);
|
|
|
109
109
|
|
|
110
110
|
## API
|
|
111
111
|
|
|
112
|
-
### fileTypeFromBuffer(buffer)
|
|
112
|
+
### fileTypeFromBuffer(buffer, options)
|
|
113
113
|
|
|
114
114
|
Detect the file type of a `Uint8Array`, or `ArrayBuffer`.
|
|
115
115
|
|
|
@@ -130,13 +130,13 @@ Type: `Uint8Array | ArrayBuffer`
|
|
|
130
130
|
|
|
131
131
|
A buffer representing file data. It works best if the buffer contains the entire file. It may work with a smaller portion as well.
|
|
132
132
|
|
|
133
|
-
### fileTypeFromFile(filePath)
|
|
133
|
+
### fileTypeFromFile(filePath, options)
|
|
134
134
|
|
|
135
135
|
Detect the file type of a file path.
|
|
136
136
|
|
|
137
137
|
This is for Node.js only.
|
|
138
138
|
|
|
139
|
-
To read from a [`File`](https://developer.mozilla.org/docs/Web/API/File), see [`fileTypeFromBlob()`](#filetypefromblobblob).
|
|
139
|
+
To read from a [`File`](https://developer.mozilla.org/docs/Web/API/File), see [`fileTypeFromBlob()`](#filetypefromblobblob-options).
|
|
140
140
|
|
|
141
141
|
The file type is detected by checking the [magic number](https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files) of the buffer.
|
|
142
142
|
|
|
@@ -176,7 +176,7 @@ Type: [Web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/Re
|
|
|
176
176
|
|
|
177
177
|
A readable stream representing file data.
|
|
178
178
|
|
|
179
|
-
### fileTypeFromBlob(blob)
|
|
179
|
+
### fileTypeFromBlob(blob, options)
|
|
180
180
|
|
|
181
181
|
Detect the file type of a [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob),
|
|
182
182
|
|
|
@@ -225,7 +225,7 @@ async function readFromBlobWithoutStreaming(blob) {
|
|
|
225
225
|
|
|
226
226
|
Type: [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
|
227
227
|
|
|
228
|
-
### fileTypeFromTokenizer(tokenizer)
|
|
228
|
+
### fileTypeFromTokenizer(tokenizer, options)
|
|
229
229
|
|
|
230
230
|
Detect the file type from an `ITokenizer` source.
|
|
231
231
|
|
|
@@ -304,6 +304,8 @@ Type: [`stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream
|
|
|
304
304
|
|
|
305
305
|
Type: `object`
|
|
306
306
|
|
|
307
|
+
Supports the following options in addition to the [general options](#options):
|
|
308
|
+
|
|
307
309
|
##### sampleSize
|
|
308
310
|
|
|
309
311
|
Type: `number`\
|
|
@@ -341,6 +343,32 @@ Returns a `Set<string>` of supported file extensions.
|
|
|
341
343
|
|
|
342
344
|
Returns a `Set<string>` of supported MIME types.
|
|
343
345
|
|
|
346
|
+
### Options
|
|
347
|
+
|
|
348
|
+
#### customDetectors
|
|
349
|
+
|
|
350
|
+
Array of custom file type detectors to run before default detectors.
|
|
351
|
+
|
|
352
|
+
For example:
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
import {fileTypeFromFile} from 'file-type';
|
|
356
|
+
import {detectXml} from '@file-type/xml';
|
|
357
|
+
|
|
358
|
+
const fileType = await fileTypeFromFile('sample.kml', {customDetectors: [detectXml]});
|
|
359
|
+
console.log(fileType);
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### mpegOffsetTolerance
|
|
363
|
+
|
|
364
|
+
Default: `0`
|
|
365
|
+
|
|
366
|
+
Specifies the byte tolerance for locating the first MPEG audio frame (e.g. `.mp1`, `.mp2`, `.mp3`, `.aac`).
|
|
367
|
+
|
|
368
|
+
Allows detection to handle slight sync offsets between the expected and actual frame start. Common in malformed or incorrectly muxed files, which, while technically invalid, do occur in the wild.
|
|
369
|
+
|
|
370
|
+
A tolerance of 10 bytes covers most cases.
|
|
371
|
+
|
|
344
372
|
## Custom detectors
|
|
345
373
|
|
|
346
374
|
Custom file type detectors are plugins designed to extend the default detection capabilities.
|
|
@@ -353,6 +381,8 @@ Detectors can be added via the constructor options or by directly modifying `Fil
|
|
|
353
381
|
|
|
354
382
|
### Example adding a detector
|
|
355
383
|
|
|
384
|
+
For example:
|
|
385
|
+
|
|
356
386
|
```js
|
|
357
387
|
import {FileTypeParser} from 'file-type';
|
|
358
388
|
import {detectXml} from '@file-type/xml';
|
|
@@ -436,7 +466,6 @@ abortController.abort(); // Abort file-type reading from the Blob stream.
|
|
|
436
466
|
- [`aac`](https://en.wikipedia.org/wiki/Advanced_Audio_Coding) - Advanced Audio Coding
|
|
437
467
|
- [`ac3`](https://www.atsc.org/standard/a522012-digital-audio-compression-ac-3-e-ac-3-standard-12172012/) - ATSC A/52 Audio File
|
|
438
468
|
- [`ace`](https://en.wikipedia.org/wiki/ACE_(compressed_file_format)) - ACE archive
|
|
439
|
-
- [`ai`](https://en.wikipedia.org/wiki/Adobe_Illustrator_Artwork) - Adobe Illustrator Artwork
|
|
440
469
|
- [`aif`](https://en.wikipedia.org/wiki/Audio_Interchange_File_Format) - Audio Interchange file
|
|
441
470
|
- [`alias`](https://en.wikipedia.org/wiki/Alias_%28Mac_OS%29) - macOS Alias file
|
|
442
471
|
- [`amr`](https://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec) - Adaptive Multi-Rate audio codec
|
|
@@ -557,6 +586,8 @@ abortController.abort(); // Abort file-type reading from the Blob stream.
|
|
|
557
586
|
- [`png`](https://en.wikipedia.org/wiki/Portable_Network_Graphics) - Portable Network Graphics
|
|
558
587
|
- [`potm`](https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions) - Microsoft PowerPoint macro-enabled template
|
|
559
588
|
- [`potx`](https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions) - Microsoft PowerPoint template
|
|
589
|
+
- [`ppsm`](https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions#PowerPoint) - Office PowerPoint 2007 macro-enabled slide show
|
|
590
|
+
- [`ppsx`](https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions#PowerPoint) - Office PowerPoint 2007 slide show
|
|
560
591
|
- [`pptm`](https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions) - Microsoft PowerPoint macro-enabled document
|
|
561
592
|
- [`pptx`](https://en.wikipedia.org/wiki/Office_Open_XML) - Microsoft PowerPoint document
|
|
562
593
|
- [`ps`](https://en.wikipedia.org/wiki/Postscript) - Postscript
|
package/supported.js
CHANGED
|
@@ -128,7 +128,6 @@ export const extensions = [
|
|
|
128
128
|
'it',
|
|
129
129
|
's3m',
|
|
130
130
|
'xm',
|
|
131
|
-
'ai',
|
|
132
131
|
'skp',
|
|
133
132
|
'avif',
|
|
134
133
|
'eps',
|
|
@@ -173,6 +172,8 @@ export const extensions = [
|
|
|
173
172
|
'pptm',
|
|
174
173
|
'jar',
|
|
175
174
|
'rm',
|
|
175
|
+
'ppsm',
|
|
176
|
+
'ppsx',
|
|
176
177
|
];
|
|
177
178
|
|
|
178
179
|
export const mimeTypes = [
|
|
@@ -191,12 +192,14 @@ export const mimeTypes = [
|
|
|
191
192
|
'application/x-indesign',
|
|
192
193
|
'application/epub+zip',
|
|
193
194
|
'application/x-xpinstall',
|
|
195
|
+
'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
|
|
194
196
|
'application/vnd.oasis.opendocument.text',
|
|
195
197
|
'application/vnd.oasis.opendocument.spreadsheet',
|
|
196
198
|
'application/vnd.oasis.opendocument.presentation',
|
|
197
199
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
198
200
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
199
201
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
202
|
+
'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
|
200
203
|
'application/zip',
|
|
201
204
|
'application/x-tar',
|
|
202
205
|
'application/x-rar-compressed',
|
|
@@ -204,10 +207,10 @@ export const mimeTypes = [
|
|
|
204
207
|
'application/x-bzip2',
|
|
205
208
|
'application/x-7z-compressed',
|
|
206
209
|
'application/x-apple-diskimage',
|
|
207
|
-
'application/
|
|
210
|
+
'application/vnd.apache.arrow.file',
|
|
208
211
|
'video/mp4',
|
|
209
212
|
'audio/midi',
|
|
210
|
-
'video/
|
|
213
|
+
'video/matroska',
|
|
211
214
|
'video/webm',
|
|
212
215
|
'video/quicktime',
|
|
213
216
|
'video/vnd.avi',
|
|
@@ -224,7 +227,7 @@ export const mimeTypes = [
|
|
|
224
227
|
'audio/ogg',
|
|
225
228
|
'audio/ogg; codecs=opus',
|
|
226
229
|
'application/ogg',
|
|
227
|
-
'audio/
|
|
230
|
+
'audio/flac',
|
|
228
231
|
'audio/ape',
|
|
229
232
|
'audio/wavpack',
|
|
230
233
|
'audio/amr',
|
|
@@ -317,7 +320,7 @@ export const mimeTypes = [
|
|
|
317
320
|
'image/jls',
|
|
318
321
|
'application/vnd.ms-outlook',
|
|
319
322
|
'image/vnd.dwg',
|
|
320
|
-
'application/
|
|
323
|
+
'application/vnd.apache.parquet',
|
|
321
324
|
'application/java-vm',
|
|
322
325
|
'application/x-arj',
|
|
323
326
|
'application/x-cpio',
|
|
@@ -338,11 +341,11 @@ export const mimeTypes = [
|
|
|
338
341
|
'application/vnd.oasis.opendocument.presentation-template',
|
|
339
342
|
'application/vnd.oasis.opendocument.graphics',
|
|
340
343
|
'application/vnd.oasis.opendocument.graphics-template',
|
|
341
|
-
'application/vnd.ms-excel.sheet.
|
|
342
|
-
'application/vnd.ms-word.document.
|
|
343
|
-
'application/vnd.ms-word.template.
|
|
344
|
-
'application/vnd.ms-powerpoint.template.
|
|
345
|
-
'application/vnd.ms-powerpoint.presentation.
|
|
344
|
+
'application/vnd.ms-excel.sheet.macroenabled.12',
|
|
345
|
+
'application/vnd.ms-word.document.macroenabled.12',
|
|
346
|
+
'application/vnd.ms-word.template.macroenabled.12',
|
|
347
|
+
'application/vnd.ms-powerpoint.template.macroenabled.12',
|
|
348
|
+
'application/vnd.ms-powerpoint.presentation.macroenabled.12',
|
|
346
349
|
'application/java-archive',
|
|
347
350
|
'application/vnd.rn-realmedia',
|
|
348
351
|
];
|