@npcz/magic
Version:
Emscripten port of libmagic (https://darwinsys.com/file/) with javascript interface
290 lines • 13.6 kB
JavaScript
;
// 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