aboutsummaryrefslogtreecommitdiff
path: root/node_modules/file-type
diff options
context:
space:
mode:
authorMinteck <freeziv.ytb@gmail.com>2021-03-07 18:29:17 +0100
committerMinteck <freeziv.ytb@gmail.com>2021-03-07 18:29:17 +0100
commit0f79e708bf07721b73ea41e5d341be08e8ea4dce (patch)
treef3c63cd6a9f4ef0b26f95eec6a031600232e80c8 /node_modules/file-type
downloadelectrode-0f79e708bf07721b73ea41e5d341be08e8ea4dce.tar.gz
electrode-0f79e708bf07721b73ea41e5d341be08e8ea4dce.tar.bz2
electrode-0f79e708bf07721b73ea41e5d341be08e8ea4dce.zip
Initial commit
Diffstat (limited to 'node_modules/file-type')
-rw-r--r--node_modules/file-type/browser.d.ts50
-rw-r--r--node_modules/file-type/browser.js50
-rw-r--r--node_modules/file-type/core.d.ts379
-rw-r--r--node_modules/file-type/core.js1433
-rw-r--r--node_modules/file-type/index.d.ts27
-rw-r--r--node_modules/file-type/index.js32
-rw-r--r--node_modules/file-type/license9
-rw-r--r--node_modules/file-type/package.json245
-rw-r--r--node_modules/file-type/readme.md436
-rw-r--r--node_modules/file-type/supported.js271
-rw-r--r--node_modules/file-type/util.js40
11 files changed, 2972 insertions, 0 deletions
diff --git a/node_modules/file-type/browser.d.ts b/node_modules/file-type/browser.d.ts
new file mode 100644
index 0000000..5aeacb6
--- /dev/null
+++ b/node_modules/file-type/browser.d.ts
@@ -0,0 +1,50 @@
+/// <reference lib="dom"/>
+import * as core from './core';
+
+export type FileTypeResult = core.FileTypeResult;
+export type FileExtension = core.FileExtension;
+export type MimeType = core.MimeType;
+
+/**
+Determine file type from a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
+
+```
+import FileType = require('file-type/browser');
+
+const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';
+
+(async () => {
+ const response = await fetch(url);
+ const fileType = await FileType.fromStream(response.body);
+
+ console.log(fileType);
+ //=> {ext: 'jpg', mime: 'image/jpeg'}
+})();
+```
+*/
+export declare function fromStream(stream: ReadableStream): Promise<core.FileTypeResult | undefined>;
+
+/**
+Determine file type from a [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
+
+```
+import FileType = require('file-type/browser');
+
+(async () => {
+ const blob = new Blob(['<?xml version="1.0" encoding="ISO-8859-1" ?>'], {
+ type: 'plain/text',
+ endings: 'native'
+ });
+
+ console.log(await FileType.fromBlob(blob));
+ //=> {ext: 'txt', mime: 'plain/text'}
+})();
+```
+*/
+export declare function fromBlob(blob: Blob): Promise<core.FileTypeResult | undefined>;
+
+export {
+ fromBuffer,
+ extensions,
+ mimeTypes
+} from './core';
diff --git a/node_modules/file-type/browser.js b/node_modules/file-type/browser.js
new file mode 100644
index 0000000..1de2437
--- /dev/null
+++ b/node_modules/file-type/browser.js
@@ -0,0 +1,50 @@
+'use strict';
+const {ReadableWebToNodeStream} = require('readable-web-to-node-stream');
+const toBuffer = require('typedarray-to-buffer');
+const core = require('./core');
+
+async function fromStream(stream) {
+ const readableWebToNodeStream = new ReadableWebToNodeStream(stream);
+ const fileType = await core.fromStream(readableWebToNodeStream);
+ await readableWebToNodeStream.close();
+ return fileType;
+}
+
+async function fromBlob(blob) {
+ const buffer = await convertBlobToBuffer(blob);
+ return core.fromBuffer(buffer);
+}
+
+/**
+Convert Web API File to Node Buffer.
+@param {Blob} blob - Web API Blob.
+@returns {Promise<Buffer>}
+*/
+function convertBlobToBuffer(blob) {
+ return new Promise((resolve, reject) => {
+ const fileReader = new FileReader();
+ fileReader.addEventListener('loadend', event => {
+ let data = event.target.result;
+ if (data instanceof ArrayBuffer) {
+ data = toBuffer(new Uint8Array(event.target.result));
+ }
+
+ resolve(data);
+ });
+
+ fileReader.addEventListener('error', event => {
+ reject(new Error(event.message));
+ });
+
+ fileReader.addEventListener('abort', event => {
+ reject(new Error(event.type));
+ });
+
+ fileReader.readAsArrayBuffer(blob);
+ });
+}
+
+Object.assign(module.exports, core, {
+ fromStream,
+ fromBlob
+});
diff --git a/node_modules/file-type/core.d.ts b/node_modules/file-type/core.d.ts
new file mode 100644
index 0000000..569ed18
--- /dev/null
+++ b/node_modules/file-type/core.d.ts
@@ -0,0 +1,379 @@
+/// <reference types="node"/>
+import {Readable as ReadableStream} from 'stream';
+import {ITokenizer} from 'strtok3/lib/core';
+
+declare namespace core {
+ type FileExtension =
+ | 'jpg'
+ | 'png'
+ | 'apng'
+ | 'gif'
+ | 'webp'
+ | 'flif'
+ | 'cr2'
+ | 'cr3'
+ | 'orf'
+ | 'arw'
+ | 'dng'
+ | 'nef'
+ | 'rw2'
+ | 'raf'
+ | 'tif'
+ | 'bmp'
+ | 'icns'
+ | 'jxr'
+ | 'psd'
+ | 'indd'
+ | 'zip'
+ | 'tar'
+ | 'rar'
+ | 'gz'
+ | 'bz2'
+ | '7z'
+ | 'dmg'
+ | 'mp4'
+ | 'mid'
+ | 'mkv'
+ | 'webm'
+ | 'mov'
+ | 'avi'
+ | 'mpg'
+ | 'mp2'
+ | 'mp3'
+ | 'm4a'
+ | 'ogg'
+ | 'opus'
+ | 'flac'
+ | 'wav'
+ | 'qcp'
+ | 'amr'
+ | 'pdf'
+ | 'epub'
+ | 'mobi'
+ | 'exe'
+ | 'swf'
+ | 'rtf'
+ | 'woff'
+ | 'woff2'
+ | 'eot'
+ | 'ttf'
+ | 'otf'
+ | 'ico'
+ | 'flv'
+ | 'ps'
+ | 'xz'
+ | 'sqlite'
+ | 'nes'
+ | 'crx'
+ | 'xpi'
+ | 'cab'
+ | 'deb'
+ | 'ar'
+ | 'rpm'
+ | 'Z'
+ | 'lz'
+ | 'cfb'
+ | 'mxf'
+ | 'mts'
+ | 'wasm'
+ | 'blend'
+ | 'bpg'
+ | 'docx'
+ | 'pptx'
+ | 'xlsx'
+ | '3gp'
+ | '3g2'
+ | 'jp2'
+ | 'jpm'
+ | 'jpx'
+ | 'mj2'
+ | 'aif'
+ | 'odt'
+ | 'ods'
+ | 'odp'
+ | 'xml'
+ | 'heic'
+ | 'cur'
+ | 'ktx'
+ | 'ape'
+ | 'wv'
+ | 'asf'
+ | 'dcm'
+ | 'mpc'
+ | 'ics'
+ | 'glb'
+ | 'pcap'
+ | 'dsf'
+ | 'lnk'
+ | 'alias'
+ | 'voc'
+ | 'ac3'
+ | 'm4b'
+ | 'm4p'
+ | 'm4v'
+ | 'f4a'
+ | 'f4b'
+ | 'f4p'
+ | 'f4v'
+ | 'mie'
+ | 'ogv'
+ | 'ogm'
+ | 'oga'
+ | 'spx'
+ | 'ogx'
+ | 'arrow'
+ | 'shp'
+ | 'aac'
+ | 'mp1'
+ | 'it'
+ | 's3m'
+ | 'xm'
+ | 'ai'
+ | 'skp'
+ | 'avif'
+ | 'eps'
+ | 'lzh'
+ | 'pgp'
+ | 'asar'
+ | 'stl'
+ | 'chm'
+ | '3mf';
+
+ type MimeType =
+ | 'image/jpeg'
+ | 'image/png'
+ | 'image/gif'
+ | 'image/webp'
+ | 'image/flif'
+ | 'image/x-canon-cr2'
+ | 'image/x-canon-cr3'
+ | 'image/tiff'
+ | 'image/bmp'
+ | 'image/icns'
+ | 'image/vnd.ms-photo'
+ | 'image/vnd.adobe.photoshop'
+ | 'application/x-indesign'
+ | 'application/epub+zip'
+ | 'application/x-xpinstall'
+ | 'application/vnd.oasis.opendocument.text'
+ | 'application/vnd.oasis.opendocument.spreadsheet'
+ | 'application/vnd.oasis.opendocument.presentation'
+ | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ | 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
+ | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ | 'application/zip'
+ | 'application/x-tar'
+ | 'application/x-rar-compressed'
+ | 'application/gzip'
+ | 'application/x-bzip2'
+ | 'application/x-7z-compressed'
+ | 'application/x-apple-diskimage'
+ | 'video/mp4'
+ | 'audio/midi'
+ | 'video/x-matroska'
+ | 'video/webm'
+ | 'video/quicktime'
+ | 'video/vnd.avi'
+ | 'audio/vnd.wave'
+ | 'audio/qcelp'
+ | 'audio/x-ms-asf'
+ | 'video/x-ms-asf'
+ | 'application/vnd.ms-asf'
+ | 'video/mpeg'
+ | 'video/3gpp'
+ | 'audio/mpeg'
+ | 'audio/mp4' // RFC 4337
+ | 'audio/opus'
+ | 'video/ogg'
+ | 'audio/ogg'
+ | 'application/ogg'
+ | 'audio/x-flac'
+ | 'audio/ape'
+ | 'audio/wavpack'
+ | 'audio/amr'
+ | 'application/pdf'
+ | 'application/x-msdownload'
+ | 'application/x-shockwave-flash'
+ | 'application/rtf'
+ | 'application/wasm'
+ | 'font/woff'
+ | 'font/woff2'
+ | 'application/vnd.ms-fontobject'
+ | 'font/ttf'
+ | 'font/otf'
+ | 'image/x-icon'
+ | 'video/x-flv'
+ | 'application/postscript'
+ | 'application/eps'
+ | 'application/x-xz'
+ | 'application/x-sqlite3'
+ | 'application/x-nintendo-nes-rom'
+ | 'application/x-google-chrome-extension'
+ | 'application/vnd.ms-cab-compressed'
+ | 'application/x-deb'
+ | 'application/x-unix-archive'
+ | 'application/x-rpm'
+ | 'application/x-compress'
+ | 'application/x-lzip'
+ | 'application/x-cfb'
+ | 'application/x-mie'
+ | 'application/x-apache-arrow'
+ | 'application/mxf'
+ | 'video/mp2t'
+ | 'application/x-blender'
+ | 'image/bpg'
+ | 'image/jp2'
+ | 'image/jpx'
+ | 'image/jpm'
+ | 'image/mj2'
+ | 'audio/aiff'
+ | 'application/xml'
+ | 'application/x-mobipocket-ebook'
+ | 'image/heif'
+ | 'image/heif-sequence'
+ | 'image/heic'
+ | 'image/heic-sequence'
+ | 'image/ktx'
+ | 'application/dicom'
+ | 'audio/x-musepack'
+ | 'text/calendar'
+ | 'model/gltf-binary'
+ | 'application/vnd.tcpdump.pcap'
+ | 'audio/x-dsf' // Non-standard
+ | 'application/x.ms.shortcut' // Invented by us
+ | 'application/x.apple.alias' // Invented by us
+ | 'audio/x-voc'
+ | 'audio/vnd.dolby.dd-raw'
+ | 'audio/x-m4a'
+ | 'image/apng'
+ | 'image/x-olympus-orf'
+ | 'image/x-sony-arw'
+ | 'image/x-adobe-dng'
+ | 'image/x-nikon-nef'
+ | 'image/x-panasonic-rw2'
+ | 'image/x-fujifilm-raf'
+ | 'video/x-m4v'
+ | 'video/3gpp2'
+ | 'application/x-esri-shape'
+ | 'audio/aac'
+ | 'audio/x-it'
+ | 'audio/x-s3m'
+ | 'audio/x-xm'
+ | 'video/MP1S'
+ | 'video/MP2P'
+ | 'application/vnd.sketchup.skp'
+ | 'image/avif'
+ | 'application/x-lzh-compressed'
+ | 'application/pgp-encrypted'
+ | 'application/x-asar'
+ | 'model/stl'
+ | 'application/vnd.ms-htmlhelp'
+ | 'model/3mf';
+
+ interface FileTypeResult {
+ /**
+ One of the supported [file types](https://github.com/sindresorhus/file-type#supported-file-types).
+ */
+ readonly ext: FileExtension;
+
+ /**
+ The detected [MIME type](https://en.wikipedia.org/wiki/Internet_media_type).
+ */
+ readonly mime: MimeType;
+ }
+
+ type ReadableStreamWithFileType = ReadableStream & {
+ readonly fileType?: FileTypeResult;
+ };
+
+ /**
+ Detect the file type of a `Buffer`, `Uint8Array`, or `ArrayBuffer`.
+
+ 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.
+
+ If file access is available, it is recommended to use `.fromFile()` instead.
+
+ @param buffer - A buffer representing file data. It works best if the buffer contains the entire file, it may work with a smaller portion as well.
+ @returns The detected file type and MIME type, or `undefined` when there is no match.
+ */
+ function fromBuffer(buffer: Buffer | Uint8Array | ArrayBuffer): Promise<core.FileTypeResult | undefined>;
+
+ /**
+ Detect the file type of a Node.js [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable).
+
+ 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.
+
+ @param stream - A readable stream representing file data.
+ @returns The detected file type and MIME type, or `undefined` when there is no match.
+ */
+ function fromStream(stream: ReadableStream): Promise<core.FileTypeResult | undefined>;
+
+ /**
+ Detect the file type from an [`ITokenizer`](https://github.com/Borewit/strtok3#tokenizer) source.
+
+ This method is used internally, but can also be used for a special "tokenizer" reader.
+
+ A tokenizer propagates the internal read functions, allowing alternative transport mechanisms, to access files, to be implemented and used.
+
+ 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.
+
+ ```
+ import {makeTokenizer} = require('@tokenizer/http');
+ import FileType = require('file-type');
+
+ const audioTrackUrl = 'https://test-audio.netlify.com/Various%20Artists%20-%202009%20-%20netBloc%20Vol%2024_%20tiuqottigeloot%20%5BMP3-V2%5D/01%20-%20Diablo%20Swing%20Orchestra%20-%20Heroines.mp3';
+
+ (async () => {
+ const httpTokenizer = await makeTokenizer(audioTrackUrl);
+ const fileType = await FileType.fromTokenizer(httpTokenizer);
+
+ console.log(fileType);
+ //=> {ext: 'mp3', mime: 'audio/mpeg'}
+ })();
+ ```
+
+ @param tokenizer - File source implementing the tokenizer interface.
+ @returns The detected file type and MIME type, or `undefined` when there is no match.
+ */
+ function fromTokenizer(tokenizer: ITokenizer): Promise<core.FileTypeResult | undefined>;
+
+ /**
+ Supported file extensions.
+ */
+ const extensions: Set<core.FileExtension>;
+
+ /**
+ Supported MIME types.
+ */
+ const mimeTypes: readonly core.MimeType[];
+
+ /**
+ Detect the file type of a readable stream.
+
+ @param readableStream - A [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable) containing a file to examine.
+ @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 `FileType.fromFile()`.
+
+ @example
+ ```
+ import * as fs from 'fs';
+ import * as crypto from 'crypto';
+ import fileType = require('file-type');
+
+ (async () => {
+ const read = fs.createReadStream('encrypted.enc');
+ const decipher = crypto.createDecipheriv(alg, key, iv);
+ const stream = await fileType.stream(read.pipe(decipher));
+
+ console.log(stream.fileType);
+ //=> {ext: 'mov', mime: 'video/quicktime'}
+
+ const write = fs.createWriteStream(`decrypted.${stream.fileType.ext}`);
+ stream.pipe(write);
+ })();
+ ```
+ */
+ function stream(readableStream: ReadableStream): Promise<core.ReadableStreamWithFileType>
+}
+
+export = core;
+
diff --git a/node_modules/file-type/core.js b/node_modules/file-type/core.js
new file mode 100644
index 0000000..5a1f516
--- /dev/null
+++ b/node_modules/file-type/core.js
@@ -0,0 +1,1433 @@
+'use strict';
+const Token = require('token-types');
+const strtok3 = require('strtok3/lib/core');
+const {
+ stringToBytes,
+ tarHeaderChecksumMatches,
+ uint32SyncSafeToken
+} = require('./util');
+const supported = require('./supported');
+
+const minimumBytes = 4100; // A fair amount of file-types are detectable within this range
+
+async function fromStream(stream) {
+ const tokenizer = await strtok3.fromStream(stream);
+ try {
+ return await fromTokenizer(tokenizer);
+ } finally {
+ await tokenizer.close();
+ }
+}
+
+async function fromBuffer(input) {
+ if (!(input instanceof Uint8Array || input instanceof ArrayBuffer || Buffer.isBuffer(input))) {
+ throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`Buffer\` or \`ArrayBuffer\`, got \`${typeof input}\``);
+ }
+
+ const buffer = input instanceof Buffer ? input : Buffer.from(input);
+
+ if (!(buffer && buffer.length > 1)) {
+ return;
+ }
+
+ const tokenizer = strtok3.fromBuffer(buffer);
+ return fromTokenizer(tokenizer);
+}
+
+function _check(buffer, headers, options) {
+ options = {
+ offset: 0,
+ ...options
+ };
+
+ for (const [index, header] of headers.entries()) {
+ // If a bitmask is set
+ if (options.mask) {
+ // If header doesn't equal `buf` with bits masked off
+ if (header !== (options.mask[index] & buffer[index + options.offset])) {
+ return false;
+ }
+ } else if (header !== buffer[index + options.offset]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+async function fromTokenizer(tokenizer) {
+ try {
+ return _fromTokenizer(tokenizer);
+ } catch (error) {
+ if (!(error instanceof strtok3.EndOfStreamError)) {
+ throw error;
+ }
+ }
+}
+
+async function _fromTokenizer(tokenizer) {
+ let buffer = Buffer.alloc(minimumBytes);
+ const bytesRead = 12;
+ const check = (header, options) => _check(buffer, header, options);
+ const checkString = (header, options) => check(stringToBytes(header), options);
+
+ // Keep reading until EOF if the file size is unknown.
+ if (!tokenizer.fileInfo.size) {
+ tokenizer.fileInfo.size = Number.MAX_SAFE_INTEGER;
+ }
+
+ await tokenizer.peekBuffer(buffer, {length: bytesRead, mayBeLess: true});
+
+ // -- 2-byte signatures --
+
+ if (check([0x42, 0x4D])) {
+ return {
+ ext: 'bmp',
+ mime: 'image/bmp'
+ };
+ }
+
+ if (check([0x0B, 0x77])) {
+ return {
+ ext: 'ac3',
+ mime: 'audio/vnd.dolby.dd-raw'
+ };
+ }
+
+ if (check([0x78, 0x01])) {
+ return {
+ ext: 'dmg',
+ mime: 'application/x-apple-diskimage'
+ };
+ }
+
+ if (check([0x4D, 0x5A])) {
+ return {
+ ext: 'exe',
+ mime: 'application/x-msdownload'
+ };
+ }
+
+ if (check([0x25, 0x21])) {
+ await tokenizer.peekBuffer(buffer, {length: 24, mayBeLess: true});
+
+ if (checkString('PS-Adobe-', {offset: 2}) &&
+ checkString(' EPSF-', {offset: 14})) {
+ return {
+ ext: 'eps',
+ mime: 'application/eps'
+ };
+ }
+
+ return {
+ ext: 'ps',
+ mime: 'application/postscript'
+ };
+ }
+
+ if (
+ check([0x1F, 0xA0]) ||
+ check([0x1F, 0x9D])
+ ) {
+ return {
+ ext: 'Z',
+ mime: 'application/x-compress'
+ };
+ }
+
+ // -- 3-byte signatures --
+
+ if (check([0xFF, 0xD8, 0xFF])) {
+ return {
+ ext: 'jpg',
+ mime: 'image/jpeg'
+ };
+ }
+
+ if (check([0x49, 0x49, 0xBC])) {
+ return {
+ ext: 'jxr',
+ mime: 'image/vnd.ms-photo'
+ };
+ }
+
+ if (check([0x1F, 0x8B, 0x8])) {
+ return {
+ ext: 'gz',
+ mime: 'application/gzip'
+ };
+ }
+
+ if (check([0x42, 0x5A, 0x68])) {
+ return {
+ ext: 'bz2',
+ mime: 'application/x-bzip2'
+ };
+ }
+
+ if (checkString('ID3')) {
+ await tokenizer.ignore(6); // Skip ID3 header until the header size
+ const id3HeaderLen = await tokenizer.readToken(uint32SyncSafeToken);
+ if (tokenizer.position + id3HeaderLen > tokenizer.fileInfo.size) {
+ // Guess file type based on ID3 header for backward compatibility
+ return {
+ ext: 'mp3',
+ mime: 'audio/mpeg'
+ };
+ }
+
+ await tokenizer.ignore(id3HeaderLen);
+ return fromTokenizer(tokenizer); // Skip ID3 header, recursion
+ }
+
+ // Musepack, SV7
+ if (checkString('MP+')) {
+ return {
+ ext: 'mpc',
+ mime: 'audio/x-musepack'
+ };
+ }
+
+ if (
+ (buffer[0] === 0x43 || buffer[0] === 0x46) &&
+ check([0x57, 0x53], {offset: 1})
+ ) {
+ return {
+ ext: 'swf',
+ mime: 'application/x-shockwave-flash'
+ };
+ }
+
+ // -- 4-byte signatures --
+
+ if (check([0x47, 0x49, 0x46])) {
+ return {
+ ext: 'gif',
+ mime: 'image/gif'
+ };
+ }
+
+ if (checkString('FLIF')) {
+ return {
+ ext: 'flif',
+ mime: 'image/flif'
+ };
+ }
+
+ if (checkString('8BPS')) {
+ return {
+ ext: 'psd',
+ mime: 'image/vnd.adobe.photoshop'
+ };
+ }
+
+ if (checkString('WEBP', {offset: 8})) {
+ return {
+ ext: 'webp',
+ mime: 'image/webp'
+ };
+ }
+
+ // Musepack, SV8
+ if (checkString('MPCK')) {
+ return {
+ ext: 'mpc',
+ mime: 'audio/x-musepack'
+ };
+ }
+
+ if (checkString('FORM')) {
+ return {
+ ext: 'aif',
+ mime: 'audio/aiff'
+ };
+ }
+
+ if (checkString('icns', {offset: 0})) {
+ return {
+ ext: 'icns',
+ mime: 'image/icns'
+ };
+ }
+
+ // Zip-based file formats
+ // Need to be before the `zip` check
+ if (check([0x50, 0x4B, 0x3, 0x4])) { // Local file header signature
+ try {
+ while (tokenizer.position + 30 < tokenizer.fileInfo.size) {
+ await tokenizer.readBuffer(buffer, {length: 30});
+
+ // https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
+ const zipHeader = {
+ compressedSize: buffer.readUInt32LE(18),
+ uncompressedSize: buffer.readUInt32LE(22),
+ filenameLength: buffer.readUInt16LE(26),
+ extraFieldLength: buffer.readUInt16LE(28)
+ };
+
+ zipHeader.filename = await tokenizer.readToken(new Token.StringType(zipHeader.filenameLength, 'utf-8'));
+ await tokenizer.ignore(zipHeader.extraFieldLength);
+
+ // Assumes signed `.xpi` from addons.mozilla.org
+ if (zipHeader.filename === 'META-INF/mozilla.rsa') {
+ return {
+ ext: 'xpi',
+ mime: 'application/x-xpinstall'
+ };
+ }
+
+ if (zipHeader.filename.endsWith('.rels') || zipHeader.filename.endsWith('.xml')) {
+ const type = zipHeader.filename.split('/')[0];
+ switch (type) {
+ case '_rels':
+ break;
+ case 'word':
+ return {
+ ext: 'docx',
+ mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ };
+ case 'ppt':
+ return {
+ ext: 'pptx',
+ mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
+ };
+ case 'xl':
+ return {
+ ext: 'xlsx',
+ mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ };
+ default:
+ break;
+ }
+ }
+
+ if (zipHeader.filename.startsWith('xl/')) {
+ return {
+ ext: 'xlsx',
+ mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ };
+ }
+
+ if (zipHeader.filename.startsWith('3D/') && zipHeader.filename.endsWith('.model')) {
+ return {
+ ext: '3mf',
+ mime: 'model/3mf'
+ };
+ }
+
+ // The docx, xlsx and pptx file types extend the Office Open XML file format:
+ // https://en.wikipedia.org/wiki/Office_Open_XML_file_formats
+ // We look for:
+ // - one entry named '[Content_Types].xml' or '_rels/.rels',
+ // - one entry indicating specific type of file.
+ // MS Office, OpenOffice and LibreOffice may put the parts in different order, so the check should not rely on it.
+ if (zipHeader.filename === 'mimetype' && zipHeader.compressedSize === zipHeader.uncompressedSize) {
+ const mimeType = await tokenizer.readToken(new Token.StringType(zipHeader.compressedSize, 'utf-8'));
+
+ switch (mimeType) {
+ case 'application/epub+zip':
+ return {
+ ext: 'epub',
+ mime: 'application/epub+zip'
+ };
+ case 'application/vnd.oasis.opendocument.text':
+ return {
+ ext: 'odt',
+ mime: 'application/vnd.oasis.opendocument.text'
+ };
+ case 'application/vnd.oasis.opendocument.spreadsheet':
+ return {
+ ext: 'ods',
+ mime: 'application/vnd.oasis.opendocument.spreadsheet'
+ };
+ case 'application/vnd.oasis.opendocument.presentation':
+ return {
+ ext: 'odp',
+ mime: 'application/vnd.oasis.opendocument.presentation'
+ };
+ default:
+ }
+ }
+
+ // Try to find next header manually when current one is corrupted
+ if (zipHeader.compressedSize === 0) {
+ let nextHeaderIndex = -1;
+
+ while (nextHeaderIndex < 0 && (tokenizer.position < tokenizer.fileInfo.size)) {
+ await tokenizer.peekBuffer(buffer, {mayBeLess: true});
+
+ nextHeaderIndex = buffer.indexOf('504B0304', 0, 'hex');
+ // Move position to the next header if found, skip the whole buffer otherwise
+ await tokenizer.ignore(nextHeaderIndex >= 0 ? nextHeaderIndex : buffer.length);
+ }
+ } else {
+ await tokenizer.ignore(zipHeader.compressedSize);
+ }
+ }
+ } catch (error) {
+ if (!(error instanceof strtok3.EndOfStreamError)) {
+ throw error;
+ }
+ }
+
+ return {
+ ext: 'zip',
+ mime: 'application/zip'
+ };
+ }
+
+ if (checkString('OggS')) {
+ // This is an OGG container
+ await tokenizer.ignore(28);
+ const type = Buffer.alloc(8);
+ await tokenizer.readBuffer(type);
+
+ // Needs to be before `ogg` check
+ if (_check(type, [0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64])) {
+ return {
+ ext: 'opus',
+ mime: 'audio/opus'
+ };
+ }
+
+ // If ' theora' in header.
+ if (_check(type, [0x80, 0x74, 0x68, 0x65, 0x6F, 0x72, 0x61])) {
+ return {
+ ext: 'ogv',
+ mime: 'video/ogg'
+ };
+ }
+
+ // If '\x01video' in header.
+ if (_check(type, [0x01, 0x76, 0x69, 0x64, 0x65, 0x6F, 0x00])) {
+ return {
+ ext: 'ogm',
+ mime: 'video/ogg'
+ };
+ }
+
+ // If ' FLAC' in header https://xiph.org/flac/faq.html
+ if (_check(type, [0x7F, 0x46, 0x4C, 0x41, 0x43])) {
+ return {
+ ext: 'oga',
+ mime: 'audio/ogg'
+ };
+ }
+
+ // 'Speex ' in header https://en.wikipedia.org/wiki/Speex
+ if (_check(type, [0x53, 0x70, 0x65, 0x65, 0x78, 0x20, 0x20])) {
+ return {
+ ext: 'spx',
+ mime: 'audio/ogg'
+ };
+ }
+
+ // If '\x01vorbis' in header
+ if (_check(type, [0x01, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73])) {
+ return {
+ ext: 'ogg',
+ mime: 'audio/ogg'
+ };
+ }
+
+ // Default OGG container https://www.iana.org/assignments/media-types/application/ogg
+ return {
+ ext: 'ogx',
+ mime: 'application/ogg'
+ };
+ }
+
+ if (
+ check([0x50, 0x4B]) &&
+ (buffer[2] === 0x3 || buffer[2] === 0x5 || buffer[2] === 0x7) &&
+ (buffer[3] === 0x4 || buffer[3] === 0x6 || buffer[3] === 0x8)
+ ) {
+ return {
+ ext: 'zip',
+ mime: 'application/zip'
+ };
+ }
+
+ //
+
+ // File Type Box (https://en.wikipedia.org/wiki/ISO_base_media_file_format)
+ // It's not required to be first, but it's recommended to be. Almost all ISO base media files start with `ftyp` box.
+ // `ftyp` box must contain a brand major identifier, which must consist of ISO 8859-1 printable characters.
+ // Here we check for 8859-1 printable characters (for simplicity, it's a mask which also catches one non-printable character).
+ if (
+ checkString('ftyp', {offset: 4}) &&
+ (buffer[8] & 0x60) !== 0x00 // Brand major, first character ASCII?
+ ) {
+ // They all can have MIME `video/mp4` except `application/mp4` special-case which is hard to detect.
+ // For some cases, we're specific, everything else falls to `video/mp4` with `mp4` extension.
+ const brandMajor = buffer.toString('binary', 8, 12).replace('\0', ' ').trim();
+ switch (brandMajor) {
+ case 'avif':
+ return {ext: 'avif', mime: 'image/avif'};
+ case 'mif1':
+ return {ext: 'heic', mime: 'image/heif'};
+ case 'msf1':
+ return {ext: 'heic', mime: 'image/heif-sequence'};
+ case 'heic':
+ case 'heix':
+ return {ext: 'heic', mime: 'image/heic'};
+ case 'hevc':
+ case 'hevx':
+ return {ext: 'heic', mime: 'image/heic-sequence'};
+ case 'qt':
+ return {ext: 'mov', mime: 'video/quicktime'};
+ case 'M4V':
+ case 'M4VH':
+ case 'M4VP':
+ return {ext: 'm4v', mime: 'video/x-m4v'};
+ case 'M4P':
+ return {ext: 'm4p', mime: 'video/mp4'};
+ case 'M4B':
+ return {ext: 'm4b', mime: 'audio/mp4'};
+ case 'M4A':
+ return {ext: 'm4a', mime: 'audio/x-m4a'};
+ case 'F4V':
+ return {ext: 'f4v', mime: 'video/mp4'};
+ case 'F4P':
+ return {ext: 'f4p', mime: 'video/mp4'};
+ case 'F4A':
+ return {ext: 'f4a', mime: 'audio/mp4'};
+ case 'F4B':
+ return {ext: 'f4b', mime: 'audio/mp4'};
+ case 'crx':
+ return {ext: 'cr3', mime: 'image/x-canon-cr3'};
+ default:
+ if (brandMajor.startsWith('3g')) {
+ if (brandMajor.startsWith('3g2')) {
+ return {ext: '3g2', mime: 'video/3gpp2'};
+ }
+
+ return {ext: '3gp', mime: 'video/3gpp'};
+ }
+
+ return {ext: 'mp4', mime: 'video/mp4'};
+ }
+ }
+
+ if (checkString('MThd')) {
+ return {
+ ext: 'mid',
+ mime: 'audio/midi'
+ };
+ }
+
+ if (
+ checkString('wOFF') &&
+ (
+ check([0x00, 0x01, 0x00, 0x00], {offset: 4}) ||
+ checkString('OTTO', {offset: 4})
+ )
+ ) {
+ return {
+ ext: 'woff',
+ mime: 'font/woff'
+ };
+ }
+
+ if (
+ checkString('wOF2') &&
+ (
+ check([0x00, 0x01, 0x00, 0x00], {offset: 4}) ||
+ checkString('OTTO', {offset: 4})
+ )
+ ) {
+ return {
+ ext: 'woff2',
+ mime: 'font/woff2'
+ };
+ }
+
+ if (check([0xD4, 0xC3, 0xB2, 0xA1]) || check([0xA1, 0xB2, 0xC3, 0xD4])) {
+ return {
+ ext: 'pcap',
+ mime: 'application/vnd.tcpdump.pcap'
+ };
+ }
+
+ // Sony DSD Stream File (DSF)
+ if (checkString('DSD ')) {
+ return {
+ ext: 'dsf',
+ mime: 'audio/x-dsf' // Non-standard
+ };
+ }
+
+ if (checkString('LZIP')) {
+ return {
+ ext: 'lz',
+ mime: 'application/x-lzip'
+ };
+ }
+
+ if (checkString('fLaC')) {
+ return {
+ ext: 'flac',
+ mime: 'audio/x-flac'
+ };
+ }
+
+ if (check([0x42, 0x50, 0x47, 0xFB])) {
+ return {
+ ext: 'bpg',
+ mime: 'image/bpg'
+ };
+ }
+
+ if (checkString('wvpk')) {
+ return {
+ ext: 'wv',
+ mime: 'audio/wavpack'
+ };
+ }
+
+ if (checkString('%PDF')) {
+ await tokenizer.ignore(1350);
+ const maxBufferSize = 10 * 1024 * 1024;
+ const buffer = Buffer.alloc(Math.min(maxBufferSize, tokenizer.fileInfo.size));
+ await tokenizer.readBuffer(buffer, {mayBeLess: true});
+
+ // Check if this is an Adobe Illustrator file
+ if (buffer.includes(Buffer.from('AIPrivateData'))) {
+ return {
+ ext: 'ai',
+ mime: 'application/postscript'
+ };
+ }
+
+ // Assume this is just a normal PDF
+ return {
+ ext: 'pdf',
+ mime: 'application/pdf'
+ };
+ }
+
+ if (check([0x00, 0x61, 0x73, 0x6D])) {
+ return {
+ ext: 'wasm',
+ mime: 'application/wasm'
+ };
+ }
+
+ // TIFF, little-endian type
+ if (check([0x49, 0x49, 0x2A, 0x0])) {
+ if (checkString('CR', {offset: 8})) {
+ return {
+ ext: 'cr2',
+ mime: 'image/x-canon-cr2'
+ };
+ }
+
+ if (check([0x1C, 0x00, 0xFE, 0x00], {offset: 8}) || check([0x1F, 0x00, 0x0B, 0x00], {offset: 8})) {
+ return {
+ ext: 'nef',
+ mime: 'image/x-nikon-nef'
+ };
+ }
+
+ if (
+ check([0x08, 0x00, 0x00, 0x00], {offset: 4}) &&
+ (check([0x2D, 0x00, 0xFE, 0x00], {offset: 8}) ||
+ check([0x27, 0x00, 0xFE, 0x00], {offset: 8}))
+ ) {
+ return {
+ ext: 'dng',
+ mime: 'image/x-adobe-dng'
+ };
+ }
+
+ buffer = Buffer.alloc(24);
+ await tokenizer.peekBuffer(buffer);
+ if (
+ (check([0x10, 0xFB, 0x86, 0x01], {offset: 4}) || check([0x08, 0x00, 0x00, 0x00], {offset: 4})) &&
+ // This pattern differentiates ARW from other TIFF-ish file types:
+ check([0x00, 0xFE, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01], {offset: 9})
+ ) {
+ return {
+ ext: 'arw',
+ mime: 'image/x-sony-arw'
+ };
+ }
+
+ return {
+ ext: 'tif',
+ mime: 'image/tiff'
+ };
+ }
+
+ // TIFF, big-endian type
+ if (check([0x4D, 0x4D, 0x0, 0x2A])) {
+ return {
+ ext: 'tif',
+ mime: 'image/tiff'
+ };
+ }
+
+ if (checkString('MAC ')) {
+ return {
+ ext: 'ape',
+ mime: 'audio/ape'
+ };
+ }
+
+ // https://github.com/threatstack/libmagic/blob/master/magic/Magdir/matroska
+ if (check([0x1A, 0x45, 0xDF, 0xA3])) { // Root element: EBML
+ async function readField() {
+ const msb = await tokenizer.peekNumber(Token.UINT8);
+ let mask = 0x80;
+ let ic = 0; // 0 = A, 1 = B, 2 = C, 3 = D
+
+ while ((msb & mask) === 0) {
+ ++ic;
+ mask >>= 1;
+ }
+
+ const id = Buffer.alloc(ic + 1);
+ await tokenizer.readBuffer(id);
+ return id;
+ }
+
+ async function readElement() {
+ const id = await readField();
+ const lenField = await readField();
+ lenField[0] ^= 0x80 >> (lenField.length - 1);
+ const nrLen = Math.min(6, lenField.length); // JavaScript can max read 6 bytes integer
+ return {
+ id: id.readUIntBE(0, id.length),
+ len: lenField.readUIntBE(lenField.length - nrLen, nrLen)
+ };
+ }
+
+ async function readChildren(level, children) {
+ while (children > 0) {
+ const e = await readElement();
+ if (e.id === 0x4282) {
+ return tokenizer.readToken(new Token.StringType(e.len, 'utf-8')); // Return DocType
+ }
+
+ await tokenizer.ignore(e.len); // ignore payload
+ --children;
+ }
+ }
+
+ const re = await readElement();
+ const docType = await readChildren(1, re.len);
+
+ switch (docType) {
+ case 'webm':
+ return {
+ ext: 'webm',
+ mime: 'video/webm'
+ };
+
+ case 'matroska':
+ return {
+ ext: 'mkv',
+ mime: 'video/x-matroska'
+ };
+
+ default:
+ return;
+ }
+ }
+
+ // RIFF file format which might be AVI, WAV, QCP, etc
+ if (check([0x52, 0x49, 0x46, 0x46])) {
+ if (check([0x41, 0x56, 0x49], {offset: 8})) {
+ return {
+ ext: 'avi',
+ mime: 'video/vnd.avi'
+ };
+ }
+
+ if (check([0x57, 0x41, 0x56, 0x45], {offset: 8})) {
+ return {
+ ext: 'wav',
+ mime: 'audio/vnd.wave'
+ };
+ }
+
+ // QLCM, QCP file
+ if (check([0x51, 0x4C, 0x43, 0x4D], {offset: 8})) {
+ return {
+ ext: 'qcp',
+ mime: 'audio/qcelp'
+ };
+ }
+ }
+
+ if (checkString('SQLi')) {
+ return {
+ ext: 'sqlite',
+ mime: 'application/x-sqlite3'
+ };
+ }
+
+ if (check([0x4E, 0x45, 0x53, 0x1A])) {
+ return {
+ ext: 'nes',
+ mime: 'application/x-nintendo-nes-rom'
+ };
+ }
+
+ if (checkString('Cr24')) {
+ return {
+ ext: 'crx',
+ mime: 'application/x-google-chrome-extension'
+ };
+ }
+
+ if (
+ checkString('MSCF') ||
+ checkString('ISc(')
+ ) {
+ return {
+ ext: 'cab',
+ mime: 'application/vnd.ms-cab-compressed'
+ };
+ }
+
+ if (check([0xED, 0xAB, 0xEE, 0xDB])) {
+ return {
+ ext: 'rpm',
+ mime: 'application/x-rpm'
+ };
+ }
+
+ if (check([0xC5, 0xD0, 0xD3, 0xC6])) {
+ return {
+ ext: 'eps',
+ mime: 'application/eps'
+ };
+ }
+
+ // -- 5-byte signatures --
+
+ if (check([0x4F, 0x54, 0x54, 0x4F, 0x00])) {
+ return {
+ ext: 'otf',
+ mime: 'font/otf'
+ };
+ }
+
+ if (checkString('#!AMR')) {
+ return {
+ ext: 'amr',
+ mime: 'audio/amr'
+ };
+ }
+
+ if (checkString('{\\rtf')) {
+ return {
+ ext: 'rtf',
+ mime: 'application/rtf'
+ };
+ }
+
+ if (check([0x46, 0x4C, 0x56, 0x01])) {
+ return {
+ ext: 'flv',
+ mime: 'video/x-flv'
+ };
+ }
+
+ if (checkString('IMPM')) {
+ return {
+ ext: 'it',
+ mime: 'audio/x-it'
+ };
+ }
+
+ if (
+ checkString('-lh0-', {offset: 2}) ||
+ checkString('-lh1-', {offset: 2}) ||
+ checkString('-lh2-', {offset: 2}) ||
+ checkString('-lh3-', {offset: 2}) ||
+ checkString('-lh4-', {offset: 2}) ||
+ checkString('-lh5-', {offset: 2}) ||
+ checkString('-lh6-', {offset: 2}) ||
+ checkString('-lh7-', {offset: 2}) ||
+ checkString('-lzs-', {offset: 2}) ||
+ checkString('-lz4-', {offset: 2}) ||
+ checkString('-lz5-', {offset: 2}) ||
+ checkString('-lhd-', {offset: 2})
+ ) {
+ return {
+ ext: 'lzh',
+ mime: 'application/x-lzh-compressed'
+ };
+ }
+
+ // MPEG program stream (PS or MPEG-PS)
+ if (check([0x00, 0x00, 0x01, 0xBA])) {
+ // MPEG-PS, MPEG-1 Part 1
+ if (check([0x21], {offset: 4, mask: [0xF1]})) {
+ return {
+ ext: 'mpg', // May also be .ps, .mpeg
+ mime: 'video/MP1S'
+ };
+ }
+
+ // MPEG-PS, MPEG-2 Part 1
+ if (check([0x44], {offset: 4, mask: [0xC4]})) {
+ return {
+ ext: 'mpg', // May also be .mpg, .m2p, .vob or .sub
+ mime: 'video/MP2P'
+ };
+ }
+ }
+
+ if (checkString('ITSF')) {
+ return {
+ ext: 'chm',
+ mime: 'application/vnd.ms-htmlhelp'
+ };
+ }
+
+ // -- 6-byte signatures --
+
+ if (check([0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00])) {
+ return {
+ ext: 'xz',
+ mime: 'application/x-xz'
+ };
+ }
+
+ if (checkString('<?xml ')) {
+ return {
+ ext: 'xml',
+ mime: 'application/xml'
+ };
+ }
+
+ if (checkString('BEGIN:')) {
+ return {
+ ext: 'ics',
+ mime: 'text/calendar'
+ };
+ }
+
+ if (check([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) {
+ return {
+ ext: '7z',
+ mime: 'application/x-7z-compressed'
+ };
+ }
+
+ if (
+ check([0x52, 0x61, 0x72, 0x21, 0x1A, 0x7]) &&
+ (buffer[6] === 0x0 || buffer[6] === 0x1)
+ ) {
+ return {
+ ext: 'rar',
+ mime: 'application/x-rar-compressed'
+ };
+ }
+
+ if (checkString('solid ')) {
+ return {
+ ext: 'stl',
+ mime: 'model/stl'
+ };
+ }
+
+ // -- 7-byte signatures --
+
+ if (checkString('BLENDER')) {
+ return {
+ ext: 'blend',
+ mime: 'application/x-blender'
+ };
+ }
+
+ if (checkString('!<arch>')) {
+ await tokenizer.ignore(8);
+ const str = await tokenizer.readToken(new Token.StringType(13, 'ascii'));
+ if (str === 'debian-binary') {
+ return {
+ ext: 'deb',
+ mime: 'application/x-deb'
+ };
+ }
+
+ return {
+ ext: 'ar',
+ mime: 'application/x-unix-archive'
+ };
+ }
+
+ // -- 8-byte signatures --
+
+ if (check([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {
+ // APNG format (https://wiki.mozilla.org/APNG_Specification)
+ // 1. Find the first IDAT (image data) chunk (49 44 41 54)
+ // 2. Check if there is an "acTL" chunk before the IDAT one (61 63 54 4C)
+
+ // Offset calculated as follows:
+ // - 8 bytes: PNG signature
+ // - 4 (length) + 4 (chunk type) + 13 (chunk data) + 4 (CRC): IHDR chunk
+
+ await tokenizer.ignore(8); // ignore PNG signature
+
+ async function readChunkHeader() {
+ return {
+ length: await tokenizer.readToken(Token.INT32_BE),
+ type: await tokenizer.readToken(new Token.StringType(4, 'binary'))
+ };
+ }
+
+ do {
+ const chunk = await readChunkHeader();
+ if (chunk.length < 0) {
+ return; // Invalid chunk length
+ }
+
+ switch (chunk.type) {
+ case 'IDAT':
+ return {
+ ext: 'png',
+ mime: 'image/png'
+ };
+ case 'acTL':
+ return {
+ ext: 'apng',
+ mime: 'image/apng'
+ };
+ default:
+ await tokenizer.ignore(chunk.length + 4); // Ignore chunk-data + CRC
+ }
+ } while (tokenizer.position + 8 < tokenizer.fileInfo.size);
+
+ return {
+ ext: 'png',
+ mime: 'image/png'
+ };
+ }
+
+ if (check([0x41, 0x52, 0x52, 0x4F, 0x57, 0x31, 0x00, 0x00])) {
+ return {
+ ext: 'arrow',
+ mime: 'application/x-apache-arrow'
+ };
+ }
+
+ if (check([0x67, 0x6C, 0x54, 0x46, 0x02, 0x00, 0x00, 0x00])) {
+ return {
+ ext: 'glb',
+ mime: 'model/gltf-binary'
+ };
+ }
+
+ // `mov` format variants
+ if (
+ check([0x66, 0x72, 0x65, 0x65], {offset: 4}) || // `free`
+ check([0x6D, 0x64, 0x61, 0x74], {offset: 4}) || // `mdat` MJPEG
+ check([0x6D, 0x6F, 0x6F, 0x76], {offset: 4}) || // `moov`
+ check([0x77, 0x69, 0x64, 0x65], {offset: 4}) // `wide`
+ ) {
+ return {
+ ext: 'mov',
+ mime: 'video/quicktime'
+ };
+ }
+
+ // -- 9-byte signatures --
+
+ if (check([0x49, 0x49, 0x52, 0x4F, 0x08, 0x00, 0x00, 0x00, 0x18])) {
+ return {
+ ext: 'orf',
+ mime: 'image/x-olympus-orf'
+ };
+ }
+
+ // -- 12-byte signatures --
+
+ if (check([0x49, 0x49, 0x55, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0xE7, 0x74, 0xD8])) {
+ return {
+ ext: 'rw2',
+ mime: 'image/x-panasonic-rw2'
+ };
+ }
+
+ // ASF_Header_Object first 80 bytes
+ if (check([0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9])) {
+ async function readHeader() {
+ const guid = Buffer.alloc(16);
+ await tokenizer.readBuffer(guid);
+ return {
+ id: guid,
+ size: await tokenizer.readToken(Token.UINT64_LE)
+ };
+ }
+
+ await tokenizer.ignore(30);
+ // Search for header should be in first 1KB of file.
+ while (tokenizer.position + 24 < tokenizer.fileInfo.size) {
+ const header = await readHeader();
+ let payload = header.size - 24;
+ if (_check(header.id, [0x91, 0x07, 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65])) {
+ // Sync on Stream-Properties-Object (B7DC0791-A9B7-11CF-8EE6-00C00C205365)
+ const typeId = Buffer.alloc(16);
+ payload -= await tokenizer.readBuffer(typeId);
+
+ if (_check(typeId, [0x40, 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B])) {
+ // Found audio:
+ return {
+ ext: 'asf',
+ mime: 'audio/x-ms-asf'
+ };
+ }
+
+ if (_check(typeId, [0xC0, 0xEF, 0x19, 0xBC, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B])) {
+ // Found video:
+ return {
+ ext: 'asf',
+ mime: 'video/x-ms-asf'
+ };
+ }
+
+ break;
+ }
+
+ await tokenizer.ignore(payload);
+ }
+
+ // Default to ASF generic extension
+ return {
+ ext: 'asf',
+ mime: 'application/vnd.ms-asf'
+ };
+ }
+
+ if (check([0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A])) {
+ return {
+ ext: 'ktx',
+ mime: 'image/ktx'
+ };
+ }
+
+ if ((check([0x7E, 0x10, 0x04]) || check([0x7E, 0x18, 0x04])) && check([0x30, 0x4D, 0x49, 0x45], {offset: 4})) {
+ return {
+ ext: 'mie',
+ mime: 'application/x-mie'
+ };
+ }
+
+ if (check([0x27, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], {offset: 2})) {
+ return {
+ ext: 'shp',
+ mime: 'application/x-esri-shape'
+ };
+ }
+
+ if (check([0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A])) {
+ // JPEG-2000 family
+
+ await tokenizer.ignore(20);
+ const type = await tokenizer.readToken(new Token.StringType(4, 'ascii'));
+ switch (type) {
+ case 'jp2 ':
+ return {
+ ext: 'jp2',
+ mime: 'image/jp2'
+ };
+ case 'jpx ':
+ return {
+ ext: 'jpx',
+ mime: 'image/jpx'
+ };
+ case 'jpm ':
+ return {
+ ext: 'jpm',
+ mime: 'image/jpm'
+ };
+ case 'mjp2':
+ return {
+ ext: 'mj2',
+ mime: 'image/mj2'
+ };
+ default:
+ return;
+ }
+ }
+
+ // -- Unsafe signatures --
+
+ if (
+ check([0x0, 0x0, 0x1, 0xBA]) ||
+ check([0x0, 0x0, 0x1, 0xB3])
+ ) {
+ return {
+ ext: 'mpg',
+ mime: 'video/mpeg'
+ };
+ }
+
+ if (check([0x00, 0x01, 0x00, 0x00, 0x00])) {
+ return {
+ ext: 'ttf',
+ mime: 'font/ttf'
+ };
+ }
+
+ if (check([0x00, 0x00, 0x01, 0x00])) {
+ return {
+ ext: 'ico',
+ mime: 'image/x-icon'
+ };
+ }
+
+ if (check([0x00, 0x00, 0x02, 0x00])) {
+ return {
+ ext: 'cur',
+ mime: 'image/x-icon'
+ };
+ }
+
+ if (check([0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1])) {
+ // Detected Microsoft Compound File Binary File (MS-CFB) Format.
+ return {
+ ext: 'cfb',
+ mime: 'application/x-cfb'
+ };
+ }
+
+ // Increase sample size from 12 to 256.
+ await tokenizer.peekBuffer(buffer, {length: Math.min(256, tokenizer.fileInfo.size), mayBeLess: true});
+
+ // `raf` is here just to keep all the raw image detectors together.
+ if (checkString('FUJIFILMCCD-RAW')) {
+ return {
+ ext: 'raf',
+ mime: 'image/x-fujifilm-raf'
+ };
+ }
+
+ if (checkString('Extended Module:')) {
+ return {
+ ext: 'xm',
+ mime: 'audio/x-xm'
+ };
+ }
+
+ if (checkString('Creative Voice File')) {
+ return {
+ ext: 'voc',
+ mime: 'audio/x-voc'
+ };
+ }
+
+ if (check([0x04, 0x00, 0x00, 0x00]) && buffer.length >= 16) { // Rough & quick check Pickle/ASAR
+ const jsonSize = buffer.readUInt32LE(12);
+ if (jsonSize > 12 && jsonSize < 240 && buffer.length >= jsonSize + 16) {
+ try {
+ const header = buffer.slice(16, jsonSize + 16).toString();
+ const json = JSON.parse(header);
+ // Check if Pickle is ASAR
+ if (json.files) { // Final check, assuring Pickle/ASAR format
+ return {
+ ext: 'asar',
+ mime: 'application/x-asar'
+ };
+ }
+ } catch (_) {
+ }
+ }
+ }
+
+ if (check([0x06, 0x0E, 0x2B, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x01, 0x02])) {
+ return {
+ ext: 'mxf',
+ mime: 'application/mxf'
+ };
+ }
+
+ if (checkString('SCRM', {offset: 44})) {
+ return {
+ ext: 's3m',
+ mime: 'audio/x-s3m'
+ };
+ }
+
+ if (check([0x47], {offset: 4}) && (check([0x47], {offset: 192}) || check([0x47], {offset: 196}))) {
+ return {
+ ext: 'mts',
+ mime: 'video/mp2t'
+ };
+ }
+
+ if (check([0x42, 0x4F, 0x4F, 0x4B, 0x4D, 0x4F, 0x42, 0x49], {offset: 60})) {
+ return {
+ ext: 'mobi',
+ mime: 'application/x-mobipocket-ebook'
+ };
+ }
+
+ if (check([0x44, 0x49, 0x43, 0x4D], {offset: 128})) {
+ return {
+ ext: 'dcm',
+ mime: 'application/dicom'
+ };
+ }
+
+ if (check([0x4C, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46])) {
+ return {
+ ext: 'lnk',
+ mime: 'application/x.ms.shortcut' // Invented by us
+ };
+ }
+
+ if (check([0x62, 0x6F, 0x6F, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x72, 0x6B, 0x00, 0x00, 0x00, 0x00])) {
+ return {
+ ext: 'alias',
+ mime: 'application/x.apple.alias' // Invented by us
+ };
+ }
+
+ if (
+ check([0x4C, 0x50], {offset: 34}) &&
+ (
+ check([0x00, 0x00, 0x01], {offset: 8}) ||
+ check([0x01, 0x00, 0x02], {offset: 8}) ||
+ check([0x02, 0x00, 0x02], {offset: 8})
+ )
+ ) {
+ return {
+ ext: 'eot',
+ mime: 'application/vnd.ms-fontobject'
+ };
+ }
+
+ if (check([0x06, 0x06, 0xED, 0xF5, 0xD8, 0x1D, 0x46, 0xE5, 0xBD, 0x31, 0xEF, 0xE7, 0xFE, 0x74, 0xB7, 0x1D])) {
+ return {
+ ext: 'indd',
+ mime: 'application/x-indesign'
+ };
+ }
+
+ // Increase sample size from 256 to 512
+ await tokenizer.peekBuffer(buffer, {length: Math.min(512, tokenizer.fileInfo.size), mayBeLess: true});
+
+ // Requires a buffer size of 512 bytes
+ if (tarHeaderChecksumMatches(buffer)) {
+ return {
+ ext: 'tar',
+ mime: 'application/x-tar'
+ };
+ }
+
+ if (check([0xFF, 0xFE, 0xFF, 0x0E, 0x53, 0x00, 0x6B, 0x00, 0x65, 0x00, 0x74, 0x00, 0x63, 0x00, 0x68, 0x00, 0x55, 0x00, 0x70, 0x00, 0x20, 0x00, 0x4D, 0x00, 0x6F, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6C, 0x00])) {
+ return {
+ ext: 'skp',
+ mime: 'application/vnd.sketchup.skp'
+ };
+ }
+
+ if (checkString('-----BEGIN PGP MESSAGE-----')) {
+ return {
+ ext: 'pgp',
+ mime: 'application/pgp-encrypted'
+ };
+ }
+
+ // Check for MPEG header at different starting offsets
+ for (let start = 0; start < 2 && start < (buffer.length - 16); start++) {
+ // Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE)
+ if (buffer.length >= start + 2 && check([0xFF, 0xE0], {offset: start, mask: [0xFF, 0xE0]})) {
+ if (check([0x10], {offset: start + 1, mask: [0x16]})) {
+ // Check for (ADTS) MPEG-2
+ if (check([0x08], {offset: start + 1, mask: [0x08]})) {
+ return {
+ ext: 'aac',
+ mime: 'audio/aac'
+ };
+ }
+
+ // Must be (ADTS) MPEG-4
+ return {
+ ext: 'aac',
+ mime: 'audio/aac'
+ };
+ }
+
+ // MPEG 1 or 2 Layer 3 header
+ // Check for MPEG layer 3
+ if (check([0x02], {offset: start + 1, mask: [0x06]})) {
+ return {
+ ext: 'mp3',
+ mime: 'audio/mpeg'
+ };
+ }
+
+ // Check for MPEG layer 2
+ if (check([0x04], {offset: start + 1, mask: [0x06]})) {
+ return {
+ ext: 'mp2',
+ mime: 'audio/mpeg'
+ };
+ }
+
+ // Check for MPEG layer 1
+ if (check([0x06], {offset: start + 1, mask: [0x06]})) {
+ return {
+ ext: 'mp1',
+ mime: 'audio/mpeg'
+ };
+ }
+ }
+ }
+}
+
+const stream = readableStream => new Promise((resolve, reject) => {
+ // Using `eval` to work around issues when bundling with Webpack
+ const stream = eval('require')('stream'); // eslint-disable-line no-eval
+
+ readableStream.on('error', reject);
+ readableStream.once('readable', async () => {
+ // Set up output stream
+ const pass = new stream.PassThrough();
+ let outputStream;
+ if (stream.pipeline) {
+ outputStream = stream.pipeline(readableStream, pass, () => {
+ });
+ } else {
+ outputStream = readableStream.pipe(pass);
+ }
+
+ // Read the input stream and detect the filetype
+ const chunk = readableStream.read(minimumBytes) || readableStream.read() || Buffer.alloc(0);
+ try {
+ const fileType = await fromBuffer(chunk);
+ pass.fileType = fileType;
+ } catch (error) {
+ reject(error);
+ }
+
+ resolve(outputStream);
+ });
+});
+
+const fileType = {
+ fromStream,
+ fromTokenizer,
+ fromBuffer,
+ stream
+};
+
+Object.defineProperty(fileType, 'extensions', {
+ get() {
+ return new Set(supported.extensions);
+ }
+});
+
+Object.defineProperty(fileType, 'mimeTypes', {
+ get() {
+ return new Set(supported.mimeTypes);
+ }
+});
+
+module.exports = fileType;
diff --git a/node_modules/file-type/index.d.ts b/node_modules/file-type/index.d.ts
new file mode 100644
index 0000000..30c8eff
--- /dev/null
+++ b/node_modules/file-type/index.d.ts
@@ -0,0 +1,27 @@
+/// <reference types="node"/>
+import {Readable as ReadableStream} from 'stream';
+import * as core from './core';
+
+export type ReadableStreamWithFileType = core.ReadableStreamWithFileType;
+export type FileTypeResult = core.FileTypeResult;
+export type FileExtension = core.FileExtension;
+export type MimeType = core.MimeType;
+
+/**
+Detect the file type of a file path.
+
+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.
+
+@param path - The file path to parse.
+@returns The detected file type and MIME type or `undefined` when there is no match.
+*/
+export function fromFile(path: string): Promise<core.FileTypeResult | undefined>;
+
+export {
+ fromBuffer,
+ fromStream,
+ fromTokenizer,
+ extensions,
+ mimeTypes,
+ stream
+} from './core';
diff --git a/node_modules/file-type/index.js b/node_modules/file-type/index.js
new file mode 100644
index 0000000..2c42ac0
--- /dev/null
+++ b/node_modules/file-type/index.js
@@ -0,0 +1,32 @@
+'use strict';
+const strtok3 = require('strtok3');
+const core = require('./core');
+
+async function fromFile(path) {
+ const tokenizer = await strtok3.fromFile(path);
+ try {
+ return await core.fromTokenizer(tokenizer);
+ } finally {
+ await tokenizer.close();
+ }
+}
+
+const fileType = {
+ fromFile
+};
+
+Object.assign(fileType, core);
+
+Object.defineProperty(fileType, 'extensions', {
+ get() {
+ return core.extensions;
+ }
+});
+
+Object.defineProperty(fileType, 'mimeTypes', {
+ get() {
+ return core.mimeTypes;
+ }
+});
+
+module.exports = fileType;
diff --git a/node_modules/file-type/license b/node_modules/file-type/license
new file mode 100644
index 0000000..fa7ceba
--- /dev/null
+++ b/node_modules/file-type/license
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/file-type/package.json b/node_modules/file-type/package.json
new file mode 100644
index 0000000..3ede47b
--- /dev/null
+++ b/node_modules/file-type/package.json
@@ -0,0 +1,245 @@
+{
+ "_from": "file-type",
+ "_id": "file-type@16.2.0",
+ "_inBundle": false,
+ "_integrity": "sha512-1Wwww3mmZCMmLjBfslCluwt2mxH80GsAXYrvPnfQ42G1EGWag336kB1iyCgyn7UXiKY3cJrNykXPrCwA7xb5Ag==",
+ "_location": "/file-type",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "tag",
+ "registry": true,
+ "raw": "file-type",
+ "name": "file-type",
+ "escapedName": "file-type",
+ "rawSpec": "",
+ "saveSpec": null,
+ "fetchSpec": "latest"
+ },
+ "_requiredBy": [
+ "#USER",
+ "/"
+ ],
+ "_resolved": "https://registry.npmjs.org/file-type/-/file-type-16.2.0.tgz",
+ "_shasum": "d4f1da71ddda758db7f15f93adfaed09ce9e2715",
+ "_spec": "file-type",
+ "_where": "/data/dev/Projets/FNS Electrode/Projets/FNS Electrode",
+ "author": {
+ "name": "Sindre Sorhus",
+ "email": "sindresorhus@gmail.com",
+ "url": "https://sindresorhus.com"
+ },
+ "bugs": {
+ "url": "https://github.com/sindresorhus/file-type/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "readable-web-to-node-stream": "^3.0.0",
+ "strtok3": "^6.0.3",
+ "token-types": "^2.0.0",
+ "typedarray-to-buffer": "^3.1.5"
+ },
+ "deprecated": false,
+ "description": "Detect the file type of a Buffer/Uint8Array/ArrayBuffer",
+ "devDependencies": {
+ "@types/node": "^13.1.4",
+ "ava": "^2.3.0",
+ "noop-stream": "^0.1.0",
+ "read-chunk": "^3.2.0",
+ "tsd": "^0.11.0",
+ "xo": "^0.25.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "files": [
+ "index.js",
+ "index.d.ts",
+ "browser.js",
+ "browser.d.ts",
+ "core.js",
+ "core.d.ts",
+ "supported.js",
+ "util.js"
+ ],
+ "funding": "https://github.com/sindresorhus/file-type?sponsor=1",
+ "homepage": "https://github.com/sindresorhus/file-type#readme",
+ "keywords": [
+ "mime",
+ "file",
+ "type",
+ "magic",
+ "archive",
+ "image",
+ "img",
+ "pic",
+ "picture",
+ "flash",
+ "photo",
+ "video",
+ "detect",
+ "check",
+ "is",
+ "exif",
+ "exe",
+ "binary",
+ "buffer",
+ "uint8array",
+ "jpg",
+ "png",
+ "apng",
+ "gif",
+ "webp",
+ "flif",
+ "cr2",
+ "cr3",
+ "orf",
+ "arw",
+ "dng",
+ "nef",
+ "rw2",
+ "raf",
+ "tif",
+ "bmp",
+ "icns",
+ "jxr",
+ "psd",
+ "indd",
+ "zip",
+ "tar",
+ "rar",
+ "gz",
+ "bz2",
+ "7z",
+ "dmg",
+ "mp4",
+ "mid",
+ "mkv",
+ "webm",
+ "mov",
+ "avi",
+ "mpg",
+ "mp2",
+ "mp3",
+ "m4a",
+ "ogg",
+ "opus",
+ "flac",
+ "wav",
+ "amr",
+ "pdf",
+ "epub",
+ "mobi",
+ "swf",
+ "rtf",
+ "woff",
+ "woff2",
+ "eot",
+ "ttf",
+ "otf",
+ "ico",
+ "flv",
+ "ps",
+ "xz",
+ "sqlite",
+ "xpi",
+ "cab",
+ "deb",
+ "ar",
+ "rpm",
+ "Z",
+ "lz",
+ "cfb",
+ "mxf",
+ "mts",
+ "wasm",
+ "webassembly",
+ "blend",
+ "bpg",
+ "docx",
+ "pptx",
+ "xlsx",
+ "3gp",
+ "jp2",
+ "jpm",
+ "jpx",
+ "mj2",
+ "aif",
+ "odt",
+ "ods",
+ "odp",
+ "xml",
+ "heic",
+ "ics",
+ "glb",
+ "pcap",
+ "dsf",
+ "lnk",
+ "alias",
+ "voc",
+ "ac3",
+ "3g2",
+ "m4b",
+ "m4p",
+ "m4v",
+ "f4a",
+ "f4b",
+ "f4p",
+ "f4v",
+ "mie",
+ "qcp",
+ "asf",
+ "ogv",
+ "ogm",
+ "oga",
+ "spx",
+ "ogx",
+ "ape",
+ "wv",
+ "cur",
+ "nes",
+ "crx",
+ "ktx",
+ "dcm",
+ "mpc",
+ "arrow",
+ "shp",
+ "aac",
+ "mp1",
+ "it",
+ "s3m",
+ "xm",
+ "ai",
+ "skp",
+ "avif",
+ "eps",
+ "lzh",
+ "pgp",
+ "asar",
+ "stl",
+ "chm",
+ "3mf"
+ ],
+ "license": "MIT",
+ "name": "file-type",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/sindresorhus/file-type.git"
+ },
+ "scripts": {
+ "ava": "ava --serial --verbose",
+ "test": "xo && ava && tsd"
+ },
+ "version": "16.2.0",
+ "xo": {
+ "envs": [
+ "node",
+ "browser"
+ ],
+ "rules": {
+ "no-inner-declarations": "warn",
+ "no-await-in-loop": "warn",
+ "promise/prefer-await-to-then": "warn",
+ "prefer-named-capture-group": "off"
+ }
+ }
+}
diff --git a/node_modules/file-type/readme.md b/node_modules/file-type/readme.md
new file mode 100644
index 0000000..795677e
--- /dev/null
+++ b/node_modules/file-type/readme.md
@@ -0,0 +1,436 @@
+# file-type
+
+> Detect the file type of a Buffer/Uint8Array/ArrayBuffer
+
+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.
+
+This package is for detecting binary-based file formats, not text-based formats like `.txt`, `.csv`, `.svg`, etc.
+
+## Install
+
+```
+$ npm install file-type
+```
+
+## Usage
+
+#### Node.js
+
+Determine file type from a file:
+
+```js
+const FileType = require('file-type');
+
+(async () => {
+ console.log(await FileType.fromFile('Unicorn.png'));
+ //=> {ext: 'png', mime: 'image/png'}
+})();
+```
+
+Determine file type from a Buffer, which may be a portion of the beginning of a file:
+
+```js
+const FileType = require('file-type');
+const readChunk = require('read-chunk');
+
+(async () => {
+ const buffer = readChunk.sync('Unicorn.png', 0, 4100);
+
+ console.log(await FileType.fromBuffer(buffer));
+ //=> {ext: 'png', mime: 'image/png'}
+})();
+```
+
+Determine file type from a stream:
+
+```js
+const fs = require('fs');
+const FileType = require('file-type');
+
+(async () => {
+ const stream = fs.createReadStream('Unicorn.mp4');
+
+ console.log(await FileType.fromStream(stream));
+ //=> {ext: 'mp4', mime: 'video/mp4'}
+}
+)();
+```
+
+The stream method can also be used to read from a remote location:
+
+```js
+const got = require('got');
+const FileType = require('file-type');
+
+const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';
+
+(async () => {
+ const stream = got.stream(url);
+
+ console.log(await FileType.fromStream(stream));
+ //=> {ext: 'jpg', mime: 'image/jpeg'}
+})();
+```
+
+Another stream example:
+
+```js
+const stream = require('stream');
+const fs = require('fs');
+const crypto = require('crypto');
+const FileType = require('file-type');
+
+(async () => {
+ const read = fs.createReadStream('encrypted.enc');
+ const decipher = crypto.createDecipheriv(alg, key, iv);
+
+ const fileTypeStream = await FileType.stream(stream.pipeline(read, decipher));
+
+ console.log(fileTypeStream.fileType);
+ //=> {ext: 'mov', mime: 'video/quicktime'}
+
+ const write = fs.createWriteStream(`decrypted.${fileTypeStream.fileType.ext}`);
+ fileTypeStream.pipe(write);
+})();
+```
+
+#### Browser
+
+```js
+const FileType = require('file-type/browser');
+
+const url = 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg';
+
+(async () => {
+ const response = await fetch(url);
+ const fileType = await FileType.fromStream(response.body);
+
+ console.log(fileType);
+ //=> {ext: 'jpg', mime: 'image/jpeg'}
+})();
+```
+
+```js
+const FileType = require('file-type/browser');
+
+(async () => {
+ const blob = new Blob(['<?xml version="1.0" encoding="ISO-8859-1" ?>'], {
+ type: 'plain/text',
+ endings: 'native'
+ });
+
+ console.log(await FileType.fromBlob(blob));
+ //=> {ext: 'txt', mime: 'plain/text'}
+})();
+```
+
+## API
+
+### FileType.fromBuffer(buffer)
+
+Detect the file type of a `Buffer`, `Uint8Array`, or `ArrayBuffer`.
+
+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.
+
+If file access is available, it is recommended to use `FileType.fromFile()` instead.
+
+Returns a `Promise` for an object with the detected file type and MIME type:
+
+- `ext` - One of the [supported file types](#supported-file-types)
+- `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
+
+Or `undefined` when there is no match.
+
+#### buffer
+
+Type: `Buffer | Uint8Array | ArrayBuffer`
+
+A buffer representing file data. It works best if the buffer contains the entire file, it may work with a smaller portion as well.
+
+### FileType.fromFile(filePath)
+
+Detect the file type of a file path.
+
+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.
+
+Returns a `Promise` for an object with the detected file type and MIME type:
+
+- `ext` - One of the [supported file types](#supported-file-types)
+- `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
+
+Or `undefined` when there is no match.
+
+#### filePath
+
+Type: `string`
+
+The file path to parse.
+
+### FileType.fromStream(stream)
+
+Detect the file type of a Node.js [readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable).
+
+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.
+
+Returns a `Promise` for an object with the detected file type and MIME type:
+
+- `ext` - One of the [supported file types](#supported-file-types)
+- `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
+
+Or `undefined` when there is no match.
+
+#### stream
+
+Type: [`stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable)
+
+A readable stream representing file data.
+
+### FileType.fromTokenizer(tokenizer)
+
+Detect the file type from an `ITokenizer` source.
+
+This method is used internally, but can also be used for a special "tokenizer" reader.
+
+A tokenizer propagates the internal read functions, allowing alternative transport mechanisms, to access files, to be implemented and used.
+
+Returns a `Promise` for an object with the detected file type and MIME type:
+
+- `ext` - One of the [supported file types](#supported-file-types)
+- `mime` - The [MIME type](https://en.wikipedia.org/wiki/Internet_media_type)
+
+Or `undefined` when there is no match.
+
+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 can *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.
+
+```js
+const {makeTokenizer} = require('@tokenizer/http');
+const FileType = require('file-type');
+
+const audioTrackUrl = 'https://test-audio.netlify.com/Various%20Artists%20-%202009%20-%20netBloc%20Vol%2024_%20tiuqottigeloot%20%5BMP3-V2%5D/01%20-%20Diablo%20Swing%20Orchestra%20-%20Heroines.mp3';
+
+(async () => {
+ const httpTokenizer = await makeTokenizer(audioTrackUrl);
+ const fileType = await FileType.fromTokenizer(httpTokenizer);
+
+ console.log(fileType);
+ //=> {ext: 'mp3', mime: 'audio/mpeg'}
+})();
+```
+
+Or use [`@tokenizer/s3`](https://github.com/Borewit/tokenizer-s3) to determine the file type of a file stored on [Amazon S3](https://aws.amazon.com/s3):
+
+```js
+const FileType = require('file-type');
+const S3 = require('aws-sdk/clients/s3');
+const {makeTokenizer} = require('@tokenizer/s3');
+
+(async () => {
+ // Initialize the S3 client
+ const s3 = new S3();
+
+ // Initialize the S3 tokenizer.
+ const s3Tokenizer = await makeTokenizer(s3, {
+ Bucket: 'affectlab',
+ Key: '1min_35sec.mp4'
+ });
+
+ // Figure out what kind of file it is.
+ const fileType = await FileType.fromTokenizer(s3Tokenizer);
+ console.log(fileType);
+})();
+```
+
+Note that only the minimum amount of data required to determine the file type is read (okay, just a bit extra to prevent too many fragmented reads).
+
+#### tokenizer
+
+Type: [`ITokenizer`](https://github.com/Borewit/strtok3#tokenizer)
+
+A file source implementing the [tokenizer interface](https://github.com/Borewit/strtok3#tokenizer).
+
+### FileType.stream(readableStream)
+
+Detect the file type of a readable stream.
+
+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 `FileType.fromFile()`.
+
+*Note:* This method is only available using Node.js.
+
+#### readableStream
+
+Type: [`stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable)
+
+The input stream.
+
+### FileType.extensions
+
+Returns a set of supported file extensions.
+
+### FileType.mimeTypes
+
+Returns a set of supported MIME types.
+
+## Supported file types
+
+- [`jpg`](https://en.wikipedia.org/wiki/JPEG)
+- [`png`](https://en.wikipedia.org/wiki/Portable_Network_Graphics)
+- [`apng`](https://en.wikipedia.org/wiki/APNG) - Animated Portable Network Graphics
+- [`gif`](https://en.wikipedia.org/wiki/GIF)
+- [`webp`](https://en.wikipedia.org/wiki/WebP)
+- [`flif`](https://en.wikipedia.org/wiki/Free_Lossless_Image_Format)
+- [`cr2`](https://fileinfo.com/extension/cr2) - Canon Raw image file (v2)
+- [`cr3`](https://fileinfo.com/extension/cr3) - Canon Raw image file (v3)
+- [`orf`](https://en.wikipedia.org/wiki/ORF_format) - Olympus Raw image file
+- [`arw`](https://en.wikipedia.org/wiki/Raw_image_format#ARW) - Sony Alpha Raw image file
+- [`dng`](https://en.wikipedia.org/wiki/Digital_Negative) - Adobe Digital Negative image file
+- [`nef`](https://www.nikonusa.com/en/learn-and-explore/a/products-and-innovation/nikon-electronic-format-nef.html) - Nikon Electronic Format image file
+- [`rw2`](https://en.wikipedia.org/wiki/Raw_image_format) - Panasonic RAW image file
+- [`raf`](https://en.wikipedia.org/wiki/Raw_image_format) - Fujifilm RAW image file
+- [`tif`](https://en.wikipedia.org/wiki/Tagged_Image_File_Format)
+- [`bmp`](https://en.wikipedia.org/wiki/BMP_file_format)
+- [`icns`](https://en.wikipedia.org/wiki/Apple_Icon_Image_format)
+- [`jxr`](https://en.wikipedia.org/wiki/JPEG_XR)
+- [`psd`](https://en.wikipedia.org/wiki/Adobe_Photoshop#File_format)
+- [`indd`](https://en.wikipedia.org/wiki/Adobe_InDesign#File_format)
+- [`zip`](https://en.wikipedia.org/wiki/Zip_(file_format))
+- [`tar`](https://en.wikipedia.org/wiki/Tar_(computing)#File_format)
+- [`rar`](https://en.wikipedia.org/wiki/RAR_(file_format))
+- [`gz`](https://en.wikipedia.org/wiki/Gzip)
+- [`bz2`](https://en.wikipedia.org/wiki/Bzip2)
+- [`7z`](https://en.wikipedia.org/wiki/7z)
+- [`dmg`](https://en.wikipedia.org/wiki/Apple_Disk_Image)
+- [`mp4`](https://en.wikipedia.org/wiki/MPEG-4_Part_14#Filename_extensions)
+- [`mid`](https://en.wikipedia.org/wiki/MIDI)
+- [`mkv`](https://en.wikipedia.org/wiki/Matroska)
+- [`webm`](https://en.wikipedia.org/wiki/WebM)
+- [`mov`](https://en.wikipedia.org/wiki/QuickTime_File_Format)
+- [`avi`](https://en.wikipedia.org/wiki/Audio_Video_Interleave)
+- [`mpg`](https://en.wikipedia.org/wiki/MPEG-1)
+- [`mp1`](https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_I) - MPEG-1 Audio Layer I
+- [`mp2`](https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_II)
+- [`mp3`](https://en.wikipedia.org/wiki/MP3)
+- [`ogg`](https://en.wikipedia.org/wiki/Ogg)
+- [`ogv`](https://en.wikipedia.org/wiki/Ogg)
+- [`ogm`](https://en.wikipedia.org/wiki/Ogg)
+- [`oga`](https://en.wikipedia.org/wiki/Ogg)
+- [`spx`](https://en.wikipedia.org/wiki/Ogg)
+- [`ogx`](https://en.wikipedia.org/wiki/Ogg)
+- [`opus`](https://en.wikipedia.org/wiki/Opus_(audio_format))
+- [`flac`](https://en.wikipedia.org/wiki/FLAC)
+- [`wav`](https://en.wikipedia.org/wiki/WAV)
+- [`qcp`](https://en.wikipedia.org/wiki/QCP)
+- [`amr`](https://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec)
+- [`pdf`](https://en.wikipedia.org/wiki/Portable_Document_Format)
+- [`epub`](https://en.wikipedia.org/wiki/EPUB)
+- [`mobi`](https://en.wikipedia.org/wiki/Mobipocket) - Mobipocket
+- [`exe`](https://en.wikipedia.org/wiki/.exe)
+- [`swf`](https://en.wikipedia.org/wiki/SWF)
+- [`rtf`](https://en.wikipedia.org/wiki/Rich_Text_Format)
+- [`woff`](https://en.wikipedia.org/wiki/Web_Open_Font_Format)
+- [`woff2`](https://en.wikipedia.org/wiki/Web_Open_Font_Format)
+- [`eot`](https://en.wikipedia.org/wiki/Embedded_OpenType)
+- [`ttf`](https://en.wikipedia.org/wiki/TrueType)
+- [`otf`](https://en.wikipedia.org/wiki/OpenType)
+- [`ico`](https://en.wikipedia.org/wiki/ICO_(file_format))
+- [`flv`](https://en.wikipedia.org/wiki/Flash_Video)
+- [`ps`](https://en.wikipedia.org/wiki/Postscript)
+- [`xz`](https://en.wikipedia.org/wiki/Xz)
+- [`sqlite`](https://www.sqlite.org/fileformat2.html)
+- [`nes`](https://fileinfo.com/extension/nes)
+- [`crx`](https://developer.chrome.com/extensions/crx)
+- [`xpi`](https://en.wikipedia.org/wiki/XPInstall)
+- [`cab`](https://en.wikipedia.org/wiki/Cabinet_(file_format))
+- [`deb`](https://en.wikipedia.org/wiki/Deb_(file_format))
+- [`ar`](https://en.wikipedia.org/wiki/Ar_(Unix))
+- [`rpm`](https://fileinfo.com/extension/rpm)
+- [`Z`](https://fileinfo.com/extension/z)
+- [`lz`](https://en.wikipedia.org/wiki/Lzip)
+- [`cfb`](https://en.wikipedia.org/wiki/Compound_File_Binary_Format)
+- [`mxf`](https://en.wikipedia.org/wiki/Material_Exchange_Format)
+- [`mts`](https://en.wikipedia.org/wiki/.m2ts)
+- [`wasm`](https://en.wikipedia.org/wiki/WebAssembly)
+- [`blend`](https://wiki.blender.org/index.php/Dev:Source/Architecture/File_Format)
+- [`bpg`](https://bellard.org/bpg/)
+- [`docx`](https://en.wikipedia.org/wiki/Office_Open_XML)
+- [`pptx`](https://en.wikipedia.org/wiki/Office_Open_XML)
+- [`xlsx`](https://en.wikipedia.org/wiki/Office_Open_XML)
+- [`jp2`](https://en.wikipedia.org/wiki/JPEG_2000) - JPEG 2000
+- [`jpm`](https://en.wikipedia.org/wiki/JPEG_2000) - JPEG 2000
+- [`jpx`](https://en.wikipedia.org/wiki/JPEG_2000) - JPEG 2000
+- [`mj2`](https://en.wikipedia.org/wiki/Motion_JPEG_2000) - Motion JPEG 2000
+- [`aif`](https://en.wikipedia.org/wiki/Audio_Interchange_File_Format)
+- [`odt`](https://en.wikipedia.org/wiki/OpenDocument) - OpenDocument for word processing
+- [`ods`](https://en.wikipedia.org/wiki/OpenDocument) - OpenDocument for spreadsheets
+- [`odp`](https://en.wikipedia.org/wiki/OpenDocument) - OpenDocument for presentations
+- [`xml`](https://en.wikipedia.org/wiki/XML)
+- [`heic`](https://nokiatech.github.io/heif/technical.html)
+- [`cur`](https://en.wikipedia.org/wiki/ICO_(file_format))
+- [`ktx`](https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/)
+- [`ape`](https://en.wikipedia.org/wiki/Monkey%27s_Audio) - Monkey's Audio
+- [`wv`](https://en.wikipedia.org/wiki/WavPack) - WavPack
+- [`asf`](https://en.wikipedia.org/wiki/Advanced_Systems_Format) - Advanced Systems Format
+- [`dcm`](https://en.wikipedia.org/wiki/DICOM#Data_format) - DICOM Image File
+- [`mpc`](https://en.wikipedia.org/wiki/Musepack) - Musepack (SV7 & SV8)
+- [`ics`](https://en.wikipedia.org/wiki/ICalendar#Data_format) - iCalendar
+- [`glb`](https://github.com/KhronosGroup/glTF) - GL Transmission Format
+- [`pcap`](https://wiki.wireshark.org/Development/LibpcapFileFormat) - Libpcap File Format
+- [`dsf`](https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf) - Sony DSD Stream File (DSF)
+- [`lnk`](https://en.wikipedia.org/wiki/Shortcut_%28computing%29#Microsoft_Windows) - Microsoft Windows file shortcut
+- [`alias`](https://en.wikipedia.org/wiki/Alias_%28Mac_OS%29) - macOS Alias file
+- [`voc`](https://wiki.multimedia.cx/index.php/Creative_Voice) - Creative Voice File
+- [`ac3`](https://www.atsc.org/standard/a522012-digital-audio-compression-ac-3-e-ac-3-standard-12172012/) - ATSC A/52 Audio File
+- [`3gp`](https://en.wikipedia.org/wiki/3GP_and_3G2#3GP) - Multimedia container format defined by the Third Generation Partnership Project (3GPP) for 3G UMTS multimedia services
+- [`3g2`](https://en.wikipedia.org/wiki/3GP_and_3G2#3G2) - Multimedia container format defined by the 3GPP2 for 3G CDMA2000 multimedia services
+- [`m4v`](https://en.wikipedia.org/wiki/M4V) - MPEG-4 Visual bitstreams
+- [`m4p`](https://en.wikipedia.org/wiki/MPEG-4_Part_14#Filename_extensions) - MPEG-4 files with audio streams encrypted by FairPlay Digital Rights Management as were sold through the iTunes Store
+- [`m4a`](https://en.wikipedia.org/wiki/M4A) - Audio-only MPEG-4 files
+- [`m4b`](https://en.wikipedia.org/wiki/M4B) - Audiobook and podcast MPEG-4 files, which also contain metadata including chapter markers, images, and hyperlinks
+- [`f4v`](https://en.wikipedia.org/wiki/Flash_Video) - ISO base media file format used by Adobe Flash Player
+- [`f4p`](https://en.wikipedia.org/wiki/Flash_Video) - ISO base media file format protected by Adobe Access DRM used by Adobe Flash Player
+- [`f4a`](https://en.wikipedia.org/wiki/Flash_Video) - Audio-only ISO base media file format used by Adobe Flash Player
+- [`f4b`](https://en.wikipedia.org/wiki/Flash_Video) - Audiobook and podcast ISO base media file format used by Adobe Flash Player
+- [`mie`](https://en.wikipedia.org/wiki/Sidecar_file) - Dedicated meta information format which supports storage of binary as well as textual meta information
+- [`shp`](https://en.wikipedia.org/wiki/Shapefile) - Geospatial vector data format
+- [`arrow`](https://arrow.apache.org) - Columnar format for tables of data
+- [`aac`](https://en.wikipedia.org/wiki/Advanced_Audio_Coding) - Advanced Audio Coding
+- [`it`](https://wiki.openmpt.org/Manual:_Module_formats#The_Impulse_Tracker_format_.28.it.29) - Audio module format: Impulse Tracker
+- [`s3m`](https://wiki.openmpt.org/Manual:_Module_formats#The_ScreamTracker_3_format_.28.s3m.29) - Audio module format: ScreamTracker 3
+- [`xm`](https://wiki.openmpt.org/Manual:_Module_formats#The_FastTracker_2_format_.28.xm.29) - Audio module format: FastTracker 2
+- [`ai`](https://en.wikipedia.org/wiki/Adobe_Illustrator_Artwork) - Adobe Illustrator Artwork
+- [`skp`](https://en.wikipedia.org/wiki/SketchUp) - SketchUp
+- [`avif`](https://en.wikipedia.org/wiki/AV1#AV1_Image_File_Format_(AVIF)) - AV1 Image File Format
+- [`eps`](https://en.wikipedia.org/wiki/Encapsulated_PostScript) - Encapsulated PostScript
+- [`lzh`](https://en.wikipedia.org/wiki/LHA_(file_format)) - LZH archive
+- [`pgp`](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) - Pretty Good Privacy
+- [`asar`](https://github.com/electron/asar#format) - Archive format primarily used to enclose Electron applications
+- [`stl`](https://en.wikipedia.org/wiki/STL_(file_format)) - Standard Tesselated Geometry File Format (ASCII only)
+- [`chm`](https://en.wikipedia.org/wiki/Microsoft_Compiled_HTML_Help) - Microsoft Compiled HTML Help
+- [`3mf`](https://en.wikipedia.org/wiki/3D_Manufacturing_Format) - 3D Manufacturing Format
+
+*Pull requests are welcome for additional commonly used file types.*
+
+The following file types will not be accepted:
+- [MS-CFB: Microsoft Compound File Binary File Format based formats](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/53989ce4-7b05-4f8d-829b-d08d6148375b), too old and difficult to parse:
+ - `.doc` - Microsoft Word 97-2003 Document
+ - `.xls` - Microsoft Excel 97-2003 Document
+ - `.ppt` - Microsoft PowerPoint97-2003 Document
+ - `.msi` - Microsoft Windows Installer
+- `.csv` - [Reason.](https://github.com/sindresorhus/file-type/issues/264#issuecomment-568439196)
+- `.svg` - Detecting it requires a full-blown parser. Check out [`is-svg`](https://github.com/sindresorhus/is-svg) for something that mostly works.
+
+## file-type for enterprise
+
+Available as part of the Tidelift Subscription.
+
+The maintainers of file-type and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-file-type?utm_source=npm-file-type&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+
+## Related
+
+- [file-type-cli](https://github.com/sindresorhus/file-type-cli) - CLI for this module
+
+## Maintainers
+
+- [Sindre Sorhus](https://github.com/sindresorhus)
+- [Mikael Finstad](https://github.com/mifi)
+- [Ben Brook](https://github.com/bencmbrook)
+- [Borewit](https://github.com/Borewit)
diff --git a/node_modules/file-type/supported.js b/node_modules/file-type/supported.js
new file mode 100644
index 0000000..2febb18
--- /dev/null
+++ b/node_modules/file-type/supported.js
@@ -0,0 +1,271 @@
+'use strict';
+
+module.exports = {
+ extensions: [
+ 'jpg',
+ 'png',
+ 'apng',
+ 'gif',
+ 'webp',
+ 'flif',
+ 'cr2',
+ 'cr3',
+ 'orf',
+ 'arw',
+ 'dng',
+ 'nef',
+ 'rw2',
+ 'raf',
+ 'tif',
+ 'bmp',
+ 'icns',
+ 'jxr',
+ 'psd',
+ 'indd',
+ 'zip',
+ 'tar',
+ 'rar',
+ 'gz',
+ 'bz2',
+ '7z',
+ 'dmg',
+ 'mp4',
+ 'mid',
+ 'mkv',
+ 'webm',
+ 'mov',
+ 'avi',
+ 'mpg',
+ 'mp2',
+ 'mp3',
+ 'm4a',
+ 'oga',
+ 'ogg',
+ 'ogv',
+ 'opus',
+ 'flac',
+ 'wav',
+ 'spx',
+ 'amr',
+ 'pdf',
+ 'epub',
+ 'exe',
+ 'swf',
+ 'rtf',
+ 'wasm',
+ 'woff',
+ 'woff2',
+ 'eot',
+ 'ttf',
+ 'otf',
+ 'ico',
+ 'flv',
+ 'ps',
+ 'xz',
+ 'sqlite',
+ 'nes',
+ 'crx',
+ 'xpi',
+ 'cab',
+ 'deb',
+ 'ar',
+ 'rpm',
+ 'Z',
+ 'lz',
+ 'cfb',
+ 'mxf',
+ 'mts',
+ 'blend',
+ 'bpg',
+ 'docx',
+ 'pptx',
+ 'xlsx',
+ '3gp',
+ '3g2',
+ 'jp2',
+ 'jpm',
+ 'jpx',
+ 'mj2',
+ 'aif',
+ 'qcp',
+ 'odt',
+ 'ods',
+ 'odp',
+ 'xml',
+ 'mobi',
+ 'heic',
+ 'cur',
+ 'ktx',
+ 'ape',
+ 'wv',
+ 'dcm',
+ 'ics',
+ 'glb',
+ 'pcap',
+ 'dsf',
+ 'lnk',
+ 'alias',
+ 'voc',
+ 'ac3',
+ 'm4v',
+ 'm4p',
+ 'm4b',
+ 'f4v',
+ 'f4p',
+ 'f4b',
+ 'f4a',
+ 'mie',
+ 'asf',
+ 'ogm',
+ 'ogx',
+ 'mpc',
+ 'arrow',
+ 'shp',
+ 'aac',
+ 'mp1',
+ 'it',
+ 's3m',
+ 'xm',
+ 'ai',
+ 'skp',
+ 'avif',
+ 'eps',
+ 'lzh',
+ 'pgp',
+ 'asar',
+ 'stl',
+ 'chm',
+ '3mf'
+ ],
+ mimeTypes: [
+ 'image/jpeg',
+ 'image/png',
+ 'image/gif',
+ 'image/webp',
+ 'image/flif',
+ 'image/x-canon-cr2',
+ 'image/x-canon-cr3',
+ 'image/tiff',
+ 'image/bmp',
+ 'image/vnd.ms-photo',
+ 'image/vnd.adobe.photoshop',
+ 'application/x-indesign',
+ 'application/epub+zip',
+ 'application/x-xpinstall',
+ 'application/vnd.oasis.opendocument.text',
+ 'application/vnd.oasis.opendocument.spreadsheet',
+ 'application/vnd.oasis.opendocument.presentation',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'application/zip',
+ 'application/x-tar',
+ 'application/x-rar-compressed',
+ 'application/gzip',
+ 'application/x-bzip2',
+ 'application/x-7z-compressed',
+ 'application/x-apple-diskimage',
+ 'application/x-apache-arrow',
+ 'video/mp4',
+ 'audio/midi',
+ 'video/x-matroska',
+ 'video/webm',
+ 'video/quicktime',
+ 'video/vnd.avi',
+ 'audio/vnd.wave',
+ 'audio/qcelp',
+ 'audio/x-ms-asf',
+ 'video/x-ms-asf',
+ 'application/vnd.ms-asf',
+ 'video/mpeg',
+ 'video/3gpp',
+ 'audio/mpeg',
+ 'audio/mp4', // RFC 4337
+ 'audio/opus',
+ 'video/ogg',
+ 'audio/ogg',
+ 'application/ogg',
+ 'audio/x-flac',
+ 'audio/ape',
+ 'audio/wavpack',
+ 'audio/amr',
+ 'application/pdf',
+ 'application/x-msdownload',
+ 'application/x-shockwave-flash',
+ 'application/rtf',
+ 'application/wasm',
+ 'font/woff',
+ 'font/woff2',
+ 'application/vnd.ms-fontobject',
+ 'font/ttf',
+ 'font/otf',
+ 'image/x-icon',
+ 'video/x-flv',
+ 'application/postscript',
+ 'application/eps',
+ 'application/x-xz',
+ 'application/x-sqlite3',
+ 'application/x-nintendo-nes-rom',
+ 'application/x-google-chrome-extension',
+ 'application/vnd.ms-cab-compressed',
+ 'application/x-deb',
+ 'application/x-unix-archive',
+ 'application/x-rpm',
+ 'application/x-compress',
+ 'application/x-lzip',
+ 'application/x-cfb',
+ 'application/x-mie',
+ 'application/mxf',
+ 'video/mp2t',
+ 'application/x-blender',
+ 'image/bpg',
+ 'image/jp2',
+ 'image/jpx',
+ 'image/jpm',
+ 'image/mj2',
+ 'audio/aiff',
+ 'application/xml',
+ 'application/x-mobipocket-ebook',
+ 'image/heif',
+ 'image/heif-sequence',
+ 'image/heic',
+ 'image/heic-sequence',
+ 'image/icns',
+ 'image/ktx',
+ 'application/dicom',
+ 'audio/x-musepack',
+ 'text/calendar',
+ 'model/gltf-binary',
+ 'application/vnd.tcpdump.pcap',
+ 'audio/x-dsf', // Non-standard
+ 'application/x.ms.shortcut', // Invented by us
+ 'application/x.apple.alias', // Invented by us
+ 'audio/x-voc',
+ 'audio/vnd.dolby.dd-raw',
+ 'audio/x-m4a',
+ 'image/apng',
+ 'image/x-olympus-orf',
+ 'image/x-sony-arw',
+ 'image/x-adobe-dng',
+ 'image/x-nikon-nef',
+ 'image/x-panasonic-rw2',
+ 'image/x-fujifilm-raf',
+ 'video/x-m4v',
+ 'video/3gpp2',
+ 'application/x-esri-shape',
+ 'audio/aac',
+ 'audio/x-it',
+ 'audio/x-s3m',
+ 'audio/x-xm',
+ 'video/MP1S',
+ 'video/MP2P',
+ 'application/vnd.sketchup.skp',
+ 'image/avif',
+ 'application/x-lzh-compressed',
+ 'application/pgp-encrypted',
+ 'application/x-asar',
+ 'model/stl',
+ 'application/vnd.ms-htmlhelp',
+ 'model/3mf'
+ ]
+};
diff --git a/node_modules/file-type/util.js b/node_modules/file-type/util.js
new file mode 100644
index 0000000..d9cd54d
--- /dev/null
+++ b/node_modules/file-type/util.js
@@ -0,0 +1,40 @@
+'use strict';
+
+exports.stringToBytes = string => [...string].map(character => character.charCodeAt(0));
+
+/**
+Checks whether the TAR checksum is valid.
+
+@param {Buffer} buffer - The TAR header `[offset ... offset + 512]`.
+@param {number} offset - TAR header offset.
+@returns {boolean} `true` if the TAR checksum is valid, otherwise `false`.
+*/
+exports.tarHeaderChecksumMatches = (buffer, offset = 0) => {
+ const readSum = parseInt(buffer.toString('utf8', 148, 154).replace(/\0.*$/, '').trim(), 8); // Read sum in header
+ if (isNaN(readSum)) {
+ return false;
+ }
+
+ let sum = 8 * 0x20; // Initialize signed bit sum
+
+ for (let i = offset; i < offset + 148; i++) {
+ sum += buffer[i];
+ }
+
+ for (let i = offset + 156; i < offset + 512; i++) {
+ sum += buffer[i];
+ }
+
+ return readSum === sum;
+};
+
+/**
+ID3 UINT32 sync-safe tokenizer token.
+28 bits (representing up to 256MB) integer, the msb is 0 to avoid "false syncsignals".
+*/
+exports.uint32SyncSafeToken = {
+ get: (buffer, offset) => {
+ return (buffer[offset + 3] & 0x7F) | ((buffer[offset + 2]) << 7) | ((buffer[offset + 1]) << 14) | ((buffer[offset]) << 21);
+ },
+ len: 4
+};