UNPKG

@npcz/magic

Version:

Emscripten port of libmagic (https://darwinsys.com/file/) with javascript interface

290 lines 13.6 kB
"use strict"; // Copyright (c) 2019-2019 The Authors. // SPDX-License-Identifier: BSD-3-Clause Object.defineProperty(exports, "__esModule", { value: true }); exports.FileMagic = exports.MagicFlags = void 0; var createBindingModule = require('@npcz/magic/dist/magic-js'); /** * Reproduces exactly the same values than in magic.h of libmagic but using * a much more type safe enum. */ var MagicFlags; (function (MagicFlags) { /** No flags */ MagicFlags[MagicFlags["MAGIC_NONE"] = 0] = "MAGIC_NONE"; /** Turn on debugging */ MagicFlags[MagicFlags["MAGIC_DEBUG"] = 1] = "MAGIC_DEBUG"; /** Follow symlinks */ MagicFlags[MagicFlags["MAGIC_SYMLINK"] = 2] = "MAGIC_SYMLINK"; /** Check inside compressed files */ MagicFlags[MagicFlags["MAGIC_COMPRESS"] = 4] = "MAGIC_COMPRESS"; /** Look at the contents of devices */ MagicFlags[MagicFlags["MAGIC_DEVICES"] = 4] = "MAGIC_DEVICES"; /** Return the MIME type */ MagicFlags[MagicFlags["MAGIC_MIME_TYPE"] = 16] = "MAGIC_MIME_TYPE"; /** Return all matches */ MagicFlags[MagicFlags["MAGIC_CONTINUE"] = 32] = "MAGIC_CONTINUE"; /** Print warnings to stderr */ MagicFlags[MagicFlags["MAGIC_CHECK"] = 64] = "MAGIC_CHECK"; /** Restore access time on exit - should only be used on systems that support it */ MagicFlags[MagicFlags["MAGIC_PRESERVE_ATIME"] = 128] = "MAGIC_PRESERVE_ATIME"; /** Don't convert unprintable chars */ MagicFlags[MagicFlags["MAGIC_RAW"] = 256] = "MAGIC_RAW"; /** Handle ENOENT etc as real errors */ MagicFlags[MagicFlags["MAGIC_ERROR"] = 512] = "MAGIC_ERROR"; /** Return the MIME encoding */ MagicFlags[MagicFlags["MAGIC_MIME_ENCODING"] = 1024] = "MAGIC_MIME_ENCODING"; /** Return both the mime type and the encoding */ MagicFlags[MagicFlags["MAGIC_MIME"] = 1040] = "MAGIC_MIME"; /** Return the Apple creator/type */ MagicFlags[MagicFlags["MAGIC_APPLE"] = 2048] = "MAGIC_APPLE"; /** Return a /-separated list of extensions */ MagicFlags[MagicFlags["MAGIC_EXTENSION"] = 16777216] = "MAGIC_EXTENSION"; /** Check inside compressed files but not report compression */ MagicFlags[MagicFlags["MAGIC_COMPRESS_TRANSP"] = 33554432] = "MAGIC_COMPRESS_TRANSP"; /** Equivalent to MAGIC_EXTENSION|MAGIC_MIME|MAGIC_APPLE */ MagicFlags[MagicFlags["MAGIC_NODESC"] = 16780304] = "MAGIC_NODESC"; /** Don't check for compressed files */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_COMPRESS"] = 4096] = "MAGIC_NO_CHECK_COMPRESS"; /** Don't check for tar files */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_TAR"] = 8192] = "MAGIC_NO_CHECK_TAR"; /** Don't check magic entries */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_SOFT"] = 16384] = "MAGIC_NO_CHECK_SOFT"; /** Don't check application type */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_APPTYPE"] = 32768] = "MAGIC_NO_CHECK_APPTYPE"; /** Don't check for elf details */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_ELF"] = 65536] = "MAGIC_NO_CHECK_ELF"; /** Don't check for text files */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_TEXT"] = 131072] = "MAGIC_NO_CHECK_TEXT"; /** Don't check for cdf files */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_CDF"] = 262144] = "MAGIC_NO_CHECK_CDF"; /** Don't check for CSV files */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_CSV"] = 524288] = "MAGIC_NO_CHECK_CSV"; /** Don't check tokens */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_TOKENS"] = 1048576] = "MAGIC_NO_CHECK_TOKENS"; /** Don't check text encodings */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_ENCODING"] = 2097152] = "MAGIC_NO_CHECK_ENCODING"; /** Don't check for JSON files */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_JSON"] = 4194304] = "MAGIC_NO_CHECK_JSON"; /** No built-in tests; only consult the magic file */ MagicFlags[MagicFlags["MAGIC_NO_CHECK_BUILTIN"] = 8368128] = "MAGIC_NO_CHECK_BUILTIN"; })(MagicFlags = exports.MagicFlags || (exports.MagicFlags = {})); /** * Enhanced interface to the libmagic binding. */ var FileMagic = /** @class */ (function () { /** * Private constructor to prevent creation of instances of this class * except through the getInstance() method. */ function FileMagic() { } /** * Get the single instance of FileMagic. * * This method can be called as many times as needed to obtain the single * instance of FileMagic. During the first call, libmagic binding is * initialized using the magic file path and the flags current values * respectively in the magicFile and flags properties. * * @param locateFile custom function to locate the WASM file. This is * particularly helpful when the wasm file is moved away from the js * binding file or when it needs to be fetched via http. * @return a Promise of the single instance of FileMagic that resolves * after the binding is properly initialized, or rejects with an Error * when it fails. */ FileMagic.getInstance = function (locateFile) { if (!FileMagic._instance) { return new Promise(function (resolve, reject) { createBindingModule({ locateFile: locateFile }).then(function (moduleInstance) { // Initialize libmagic var status = moduleInstance.MagicBinding.init(FileMagic.magicFile, FileMagic.defaultFlags); if (status === -1) { reject('failed to initialize libmagic'); } // Initialize the instance members for direct access in later calls FileMagic._binding = moduleInstance.MagicBinding; FileMagic._instance = new FileMagic(); FileMagic._instance._magic = new moduleInstance.MagicBinding(); resolve(FileMagic._instance); }); }); } return Promise.resolve(FileMagic._instance); }; Object.defineProperty(FileMagic.prototype, "flags", { /** * Get the flags currently used in the libmagic binding. * * These flags are a property of the class and therefore apply to all * instances of the binding created by calling new binding.MagicBinding(). * They are set when calling the init() method and can be overridden during * the detect call. * * @example<caption>Making multiple detect calls with different flags</caption> * magic.detect(file, binding.MagicBinding.flags() | binding.MAGIC_MIME) * * @return the flags set for the binding instance. * @throws Error when used after the binding is closed. * @see init * @see detect */ get: function () { if (FileMagic._binding) { return FileMagic._binding.flags(); } else { throw new Error('FileMagic has not been initialized. Did you forget to call getInstance()?'); } }, enumerable: false, configurable: true }); /** * Get the version of libmagic. * * @returns The version of libmagic, e.g. 835. * @throws Error when used after the binding is closed. */ FileMagic.prototype.version = function () { if (FileMagic._binding) { return FileMagic._binding.version(); } else { throw new Error('FileMagic has not been initialized. Did you forget to call getInstance()?'); } }; /** * Destroy the binding and release any resources it was holding (e.g. memory, * file descriptors, etc...). * * This method must be called when the binding is no longer needed. After it * has been called, the binding can no longer be used and a new instance must * be created. */ FileMagic.close = function () { if (FileMagic._binding) { FileMagic._binding.destroy(); } FileMagic._instance = undefined; FileMagic._binding = undefined; }; /** * Run libmagic detection for the given file to produce a description of * its content. * * There are three sets of tests, performed in this order: filesystem tests, * magic tests, and language tests. The first test that succeeds causes the * detection to complete. * * The detection result will usually contain one of the words *text* (the * file contains only printing characters and a few com-mon control characters * and is probably safe to read on an ASCII terminal), *executable* (the * file an executable file understandable by whatever operating system it was * made for), or *data* meaning anything else (data is usually ``binary'' or * non-printable). * * The filesystem tests are based on examining the return from a stat(2) system * call. The library checks to see if the file is empty, or if it's some sort * of special file (sockets, symbolic links, or named pipes (FIFOs) on those * systems that implement them). * * The magic tests are used to check for files with data in particular fixed * formats. The canonical example of this is a binary executable file. These * files have a ``magic number'' stored in a particular place near the beginning * of the file. The concept of a *'magic'* has been applied by extension to data * files. Any file with some invariant identifier at a small fixed offset into * the file can usually be described in this way. The information identifying * these files is read from the compiled magic file. * * If a file does not match any of the entries in the magic file, it is examined * to see if it seems to be a text file and identify the character set it uses. * Any file that cannot be identified as having been written in any of the character * sets known to libmagic is simply said to be *'data'*. * * @param path path the file to be detected. * @param flags specific flags to be used for this detection request. To use * the default flags for the binding, pass -1; * @return a string containing the detection result (type description, mime type, * mime encoding, etc...) when successful. * @throws Error with an error message when the detection fails or when used * after the binding is closed. */ FileMagic.prototype.detect = function (path, flags) { if (FileMagic._binding) { var result = this._magic.detect(path, flags ? flags : -1); // Check for detection error if (result.startsWith('ERROR')) { throw new Error(result.substring('ERROR: '.length)); } return result; } else { throw new Error('FileMagic has not been initialized. Did you forget to call getInstance()?'); } }; /** * Run libmagic detection for the given file to produce a string with the * mime type corresponding to its content. * * @param path path the file to be detected. * @return a string containing the mime type of the file contents (e.g. * text/plain) when successful. * @throws Error with an error message when the detection fails or when used * after the binding is closed. * @see detect */ FileMagic.prototype.detectMimeType = function (path) { return this.detect(path, this.flags | MagicFlags.MAGIC_MIME_TYPE); }; /** * Run libmagic detection for the given file to produce a string with the * mime encoding corresponding to its content. * * @param path path the file to be detected. * @return a string containing the mime type of the file contents (e.g. * charset=us-ascii) when successful. * @throws Error with an error message when the detection fails or when used * after the binding is closed. * @see detect */ FileMagic.prototype.detectMimeEncoding = function (path) { return this.detect(path, this.flags | MagicFlags.MAGIC_MIME_ENCODING); }; /** * Run libmagic detection for the given file to produce a string with the * mime type and encoding corresponding to its content. * * @param path path the file to be detected. * @return a string containing the mime type of the file contents (e.g. * text/plain; charset=us-ascii) when successful. * @throws Error with an error message when the detection fails or when used * after the binding is closed. * @see detect */ FileMagic.prototype.detectMime = function (path) { return this.detect(path, this.flags | MagicFlags.MAGIC_MIME); }; /** * Path to the magic file. * * Can only be (and should be) changed before the first call to getInstance(). * * This path must be correct and pointing to the location of the magic.mgc file. * By default, it is expected to be in the current script working directory. */ FileMagic.magicFile = require.resolve('@npcz/magic/dist/magic.mgc'); /** * Default flags used by libmagic binding. * * These flags can customize the behavior of file type detection. The * default flags can be changed only before the first call to the * getInstance() method. After that, detection can always be customized * by providing specific flags to the detect() method. */ FileMagic.defaultFlags = MagicFlags.MAGIC_NONE; return FileMagic; }()); exports.FileMagic = FileMagic; //# sourceMappingURL=file-magic.js.map